Merge branch 'master' of github.com:Ultimaker/Cura

This commit is contained in:
Diego Prado Gesto 2018-03-14 13:56:24 +01:00
commit ff676c98a6
25 changed files with 575 additions and 243 deletions

View file

@ -91,6 +91,7 @@ from cura.Settings.UserChangesModel import UserChangesModel
from cura.Settings.ExtrudersModel import ExtrudersModel from cura.Settings.ExtrudersModel import ExtrudersModel
from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
from cura.Settings.ContainerManager import ContainerManager from cura.Settings.ContainerManager import ContainerManager
from cura.Settings.SettingVisibilityPresetsModel import SettingVisibilityPresetsModel
from cura.ObjectsModel import ObjectsModel from cura.ObjectsModel import ObjectsModel
@ -140,6 +141,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 +189,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")
@ -373,19 +376,9 @@ 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() default_visibility_profile = SettingVisibilityPresetsModel.getInstance().getItem(0)
preferences.setDefault("general/visible_settings_preset", setting_visibily_preset_names)
preset_setting_visibility_choice = Preferences.getInstance().getValue("general/preset_setting_visibility_choice") preferences.setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"]))
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 +395,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())
@ -986,6 +894,7 @@ class CuraApplication(QtApplication):
qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator") qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
qmlRegisterType(UserChangesModel, "Cura", 1, 0, "UserChangesModel") qmlRegisterType(UserChangesModel, "Cura", 1, 0, "UserChangesModel")
qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager) qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager)
qmlRegisterSingletonType(SettingVisibilityPresetsModel, "Cura", 1, 0, "SettingVisibilityPresetsModel", SettingVisibilityPresetsModel.createSettingVisibilityPresetsModel)
# As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work. # As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work.
actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml"))) actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")))

View file

@ -56,12 +56,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")

View file

@ -212,16 +212,29 @@ class CuraContainerRegistry(ContainerRegistry):
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()
if expected_machine_definition is not None and profile_definition is not None and profile_definition != expected_machine_definition: # Get the expected machine definition.
# i.e.: We expect gcode for a UM2 Extended to be defined as normal UM2 gcode...
expected_machine_definition = getMachineDefinitionIDForQualitySearch(global_container_stack.definition)
# ...but that's not always the case for Cura 3.1 and older, so also get the current machine:
current_machine_definition = global_container_stack.definition.getId()
# And check if the profile_definition matches either one (showing error if not):
if profile_definition not in (expected_machine_definition, current_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)
@ -236,11 +249,11 @@ class CuraContainerRegistry(ContainerRegistry):
for idx, extruder in enumerate(global_container_stack.extruders.values()): for idx, extruder in enumerate(global_container_stack.extruders.values()):
profile_id = ContainerRegistry.getInstance().uniqueName(global_container_stack.getId() + "_extruder_" + str(idx + 1)) profile_id = ContainerRegistry.getInstance().uniqueName(global_container_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:

View file

@ -882,7 +882,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)

View file

@ -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):

View file

@ -0,0 +1,136 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import os
import urllib
from configparser import ConfigParser
from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot, QUrl
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
import cura.CuraApplication
class SettingVisibilityPresetsModel(ListModel):
IdRole = Qt.UserRole + 1
NameRole = Qt.UserRole + 2
SettingsRole = Qt.UserRole + 4
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()
self._preferences = Preferences.getInstance()
self._preferences.addPreference("cura/active_setting_visibility_preset", "custom") # Preference to store which preset is currently selected
self._preferences.addPreference("cura/custom_visible_settings", "") # Preference that stores the "custom" set so it can always be restored (even after a restart)
self._preferences.preferenceChanged.connect(self._onPreferencesChanged)
self._active_preset = self._preferences.getValue("cura/active_setting_visibility_preset")
if self.find("id", self._active_preset) < 0:
self._active_preset = "custom"
self.activePresetChanged.emit()
def _populate(self):
items = []
for item in Resources.getAllResourcesOfType(cura.CuraApplication.CuraApplication.ResourceTypes.SettingVisibilityPreset):
try:
mime_type = MimeTypeDatabase.getMimeTypeForFile(item)
except MimeTypeNotFoundError:
Logger.log("e", "Could not determine mime type of file %s", item)
continue
id = urllib.parse.unquote_plus(mime_type.stripExtension(os.path.basename(item)))
if not os.path.isfile(item):
continue
parser = ConfigParser(allow_no_value=True) # accept options without any value,
try:
parser.read([item])
if not parser.has_option("general", "name") and 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": id,
"name": parser["general"]["name"],
"weight": parser["general"]["weight"],
"settings": settings
})
except Exception as e:
Logger.log("e", "Failed to load setting preset %s: %s", file_path, str(e))
items.sort(key = lambda k: (k["weight"], k["id"]))
self.setItems(items)
@pyqtSlot(str)
def setActivePreset(self, preset_id):
if preset_id != "custom" and self.find("id", preset_id) == -1:
Logger.log("w", "Tried to set active preset to unknown id %s", preset_id)
return
if preset_id == "custom" and self._active_preset == "custom":
# Copy current visibility set to custom visibility set preference so it can be restored later
visibility_string = self._preferences.getValue("general/visible_settings")
self._preferences.setValue("cura/custom_visible_settings", visibility_string)
self._preferences.setValue("cura/active_setting_visibility_preset", preset_id)
self._active_preset = preset_id
self.activePresetChanged.emit()
activePresetChanged = pyqtSignal()
@pyqtProperty(str, notify = activePresetChanged)
def activePreset(self):
return self._active_preset
def _onPreferencesChanged(self, name):
if name != "general/visible_settings":
return
if self._active_preset != "custom":
return
# Copy current visibility set to custom visibility set preference so it can be restored later
visibility_string = self._preferences.getValue("general/visible_settings")
self._preferences.setValue("cura/custom_visible_settings", visibility_string)
# Factory function, used by QML
@staticmethod
def createSettingVisibilityPresetsModel(engine, js_engine):
return SettingVisibilityPresetsModel.getInstance()
## Get the singleton instance for this class.
@classmethod
def getInstance(cls) -> "SettingVisibilityPresetsModel":
# Note: Explicit use of class name to prevent issues with inheritance.
if not SettingVisibilityPresetsModel.__instance:
SettingVisibilityPresetsModel.__instance = cls()
return SettingVisibilityPresetsModel.__instance
__instance = None # type: "SettingVisibilityPresetsModel"

View file

@ -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

View file

@ -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:

View file

@ -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.

View file

@ -198,7 +198,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 +205,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 +267,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 +283,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 +301,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())

View file

@ -0,0 +1,38 @@
{
"version": 2,
"name": "Printrbot Simple Maker's Kit (1405)",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Timur Tabi",
"manufacturer": "Printrbot",
"file_formats": "text/x-gcode"
},
"overrides": {
"machine_name": { "default_value": "Printrbot Simple Maker's Kit (1405)" },
"machine_heated_bed": { "default_value": false },
"machine_width": { "default_value": 100 },
"machine_depth": { "default_value": 100 },
"machine_height": { "default_value": 115 },
"material_diameter": { "default_value": 1.75 },
"machine_nozzle_size": { "default_value": 0.4 },
"machine_head_with_fans_polygon": {
"default_value": [
[-40, 1000],
[-40, -10],
[60, 1000],
[60, -10]
]
},
"gantry_height": { "default_value": 1000 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": {
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;home X/Y\nG28 Z0 ;home Z\nG92 E0 ;zero the extruded length\nG29 ;initiate auto bed leveling sequence"
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nM106 S0 ;fan off\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit\nG1 Z+1 E-5 F9000 ;move Z up a bit and retract even more\nG28 X0 Y0 ;home X/Y, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
}
}
}

View file

@ -653,9 +653,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

View file

@ -59,7 +59,7 @@ 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

View file

@ -0,0 +1,82 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Menu
{
id: menu
title: catalog.i18nc("@action:inmenu", "Visible Settings")
property bool showingSearchResults
property bool showingAllSettings
signal showAllSettings()
signal showSettingVisibilityProfile()
MenuItem
{
text: catalog.i18nc("@action:inmenu", "Custom selection")
checkable: true
checked: !showingSearchResults && !showingAllSettings && Cura.SettingVisibilityPresetsModel.activePreset == "custom"
exclusiveGroup: group
onTriggered:
{
Cura.SettingVisibilityPresetsModel.setActivePreset("custom");
// Restore custom set from preference
UM.Preferences.setValue("general/visible_settings", UM.Preferences.getValue("cura/custom_visible_settings"));
showSettingVisibilityProfile();
}
}
MenuSeparator { }
Instantiator
{
model: Cura.SettingVisibilityPresetsModel
MenuItem
{
text: model.name
checkable: true
checked: model.id == Cura.SettingVisibilityPresetsModel.activePreset
exclusiveGroup: group
onTriggered:
{
Cura.SettingVisibilityPresetsModel.setActivePreset(model.id);
UM.Preferences.setValue("general/visible_settings", model.settings.join(";"));
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 }
}

View file

@ -26,8 +26,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.setDefaultPreset()
} }
resetEnabled: true; resetEnabled: true;
@ -37,6 +37,8 @@ UM.PreferencesPage
id: base; id: base;
anchors.fill: parent; anchors.fill: parent;
property bool inhibitSwitchToCustom: false
CheckBox CheckBox
{ {
id: toggleVisibleSettings id: toggleVisibleSettings
@ -84,7 +86,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,25 +112,13 @@ UM.PreferencesPage
ComboBox ComboBox
{ {
property int customOptionValue: 100 function setDefaultPreset()
function setBasicPreset()
{ {
var index = 0 visibilityPreset.currentIndex = 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
@ -137,56 +127,49 @@ UM.PreferencesPage
model: ListModel model: ListModel
{ {
id: presetNamesList id: visibilityPresetsModel
Component.onCompleted: Component.onCompleted:
{ {
// returned value is Dictionary (Ex: {1:"Basic"}, The number 1 is the weight and sort by weight) visibilityPresetsModel.append({text: catalog.i18nc("@action:inmenu", "Custom selection"), id: "custom"});
var itemsDict = UM.Preferences.getValue("general/visible_settings_preset")
var sorted = [];
for(var key in itemsDict) {
sorted[sorted.length] = key;
}
sorted.sort(); var presets = Cura.SettingVisibilityPresetsModel;
for(var i = 0; i < sorted.length; i++) { for(var i = 0; i < presets.rowCount(); i++)
presetNamesList.append({text: itemsDict[sorted[i]], value: i}); {
visibilityPresetsModel.append({text: presets.getItem(i)["name"], id: presets.getItem(i)["id"]});
} }
// 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 = Cura.SettingVisibilityPresetsModel.find("id", Cura.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 + 1; // "Custom selection" entry is added in front, so index is off by 1
} }
onActivated: onActivated:
{ {
// TODO What to do if user is selected "Custom from Combobox" ? base.inhibitSwitchToCustom = true;
if (model.get(index).text == "Custom"){ var preset_id = visibilityPresetsModel.get(index).id;
UM.Preferences.setValue("general/preset_setting_visibility_choice", model.get(index).text) Cura.SettingVisibilityPresetsModel.setActivePreset(preset_id);
return
}
var newVisibleSettings = CuraApplication.getVisibilitySettingPreset(model.get(index).text) UM.Preferences.setValue("cura/active_setting_visibility_preset", preset_id);
UM.Preferences.setValue("general/visible_settings", newVisibleSettings) if (preset_id != "custom")
UM.Preferences.setValue("general/preset_setting_visibility_choice", model.get(index).text) {
UM.Preferences.setValue("general/visible_settings", Cura.SettingVisibilityPresetsModel.getItem(index - 1).settings.join(";"));
// "Custom selection" entry is added in front, so index is off by 1
}
else
{
// Restore custom set from preference
UM.Preferences.setValue("general/visible_settings", UM.Preferences.getValue("cura/custom_visible_settings"));
}
base.inhibitSwitchToCustom = false;
} }
} }
@ -216,7 +199,16 @@ 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
{
onVisibilityChanged:
{
if(Cura.SettingVisibilityPresetsModel.activePreset != "" && !base.inhibitSwitchToCustom)
{
Cura.SettingVisibilityPresetsModel.setActivePreset("custom");
}
}
}
} }
delegate: Loader delegate: Loader
@ -259,19 +251,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)
}
}
}
} }
} }
} }

View file

@ -15,10 +15,11 @@ Item
{ {
id: base; id: base;
property Action configureSettings; property Action configureSettings
property bool findingSettings; property bool findingSettings
signal showTooltip(Item item, point location, string text); property bool showingAllSettings
signal hideTooltip(); signal showTooltip(Item item, point location, string text)
signal hideTooltip()
Item Item
{ {
@ -107,6 +108,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 +184,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 +220,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 +231,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 +274,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")
@ -491,9 +556,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 (Cura.SettingVisibilityPresetsModel.activePreset != "" && !showingAllSettings)
{
Cura.SettingVisibilityPresetsModel.setActivePreset("custom");
}
}
} }
MenuItem MenuItem
{ {
@ -509,7 +582,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,6 +593,11 @@ Item
{ {
definitionsModel.show(contextMenu.key); definitionsModel.show(contextMenu.key);
} }
// visible settings have changed, so we're no longer showing a preset
if (Cura.SettingVisibilityPresetsModel.activePreset != "" && !showingAllSettings)
{
Cura.SettingVisibilityPresetsModel.setActivePreset("custom");
}
} }
} }
MenuItem MenuItem

View file

@ -347,7 +347,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 +367,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"
} }
} }

View file

@ -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
{ {

View file

@ -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
} }
} }

View 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

View file

@ -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