Merge branch 'master' into feature_support_eraser_ux

This commit is contained in:
fieldOfView 2018-03-15 22:43:24 +01:00
commit d1d1307e6e
42 changed files with 1003 additions and 445 deletions

View File

@ -1,9 +1,6 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
#Type hinting.
from typing import Dict
from PyQt5.QtCore import QObject, QTimer
from PyQt5.QtNetwork import QLocalServer
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.MachineManagementModel import MachineManagementModel
from cura.Machines.Models.SettingVisibilityPresetsModel import SettingVisibilityPresetsModel
from cura.Machines.MachineErrorChecker import MachineErrorChecker
from cura.Settings.SettingInheritanceManager import SettingInheritanceManager
@ -91,7 +90,6 @@ from cura.Settings.UserChangesModel import UserChangesModel
from cura.Settings.ExtrudersModel import ExtrudersModel
from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
from cura.Settings.ContainerManager import ContainerManager
from cura.Settings.SettingVisibilityPresetsModel import SettingVisibilityPresetsModel
from cura.ObjectsModel import ObjectsModel
@ -101,7 +99,6 @@ from PyQt5.QtGui import QColor, QIcon
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType
from configparser import ConfigParser
import sys
import os.path
import numpy
@ -226,6 +223,7 @@ class CuraApplication(QtApplication):
self._object_manager = None
self._build_plate_model = None
self._multi_build_plate_model = None
self._setting_visibility_presets_model = None
self._setting_inheritance_manager = None
self._simple_mode_settings_manager = None
self._cura_scene_controller = None
@ -381,10 +379,6 @@ class CuraApplication(QtApplication):
preferences.setDefault("local_file/last_used_type", "text/x-gcode")
default_visibility_profile = SettingVisibilityPresetsModel.getInstance().getItem(0)
preferences.setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"]))
self.applicationShuttingDown.connect(self.saveSettings)
self.engineCreatedSignal.connect(self._onEngineCreated)
@ -457,27 +451,18 @@ class CuraApplication(QtApplication):
@pyqtSlot(str)
def discardOrKeepProfileChangesClosed(self, option):
global_stack = self.getGlobalContainerStack()
if option == "discard":
global_stack = self.getGlobalContainerStack()
for extruder in self._extruder_manager.getMachineExtruders(global_stack.getId()):
extruder.getTop().clear()
global_stack.getTop().clear()
for extruder in global_stack.extruders.values():
extruder.userChanges.clear()
global_stack.userChanges.clear()
# if the user decided to keep settings then the user settings should be re-calculated and validated for errors
# before slicing. To ensure that slicer uses right settings values
elif option == "keep":
global_stack = self.getGlobalContainerStack()
for extruder in self._extruder_manager.getMachineExtruders(global_stack.getId()):
user_extruder_container = extruder.getTop()
if user_extruder_container:
user_extruder_container.update()
user_global_container = global_stack.getTop()
if user_global_container:
user_global_container.update()
# notify listeners that quality has changed (after user selected discard or keep)
self.getMachineManager().activeQualityChanged.emit()
for extruder in global_stack.extruders.values():
extruder.userChanges.update()
global_stack.userChanges.update()
@pyqtSlot(int)
def messageBoxClosed(self, button):
@ -687,6 +672,11 @@ class CuraApplication(QtApplication):
self._print_information = PrintInformation.PrintInformation()
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
if self.getCommandLineOption("headless", False):
self.runWithoutGUI()
@ -769,6 +759,10 @@ class CuraApplication(QtApplication):
def hasGui(self):
return self._use_gui
@pyqtSlot(result = QObject)
def getSettingVisibilityPresetsModel(self, *args) -> SettingVisibilityPresetsModel:
return self._setting_visibility_presets_model
def getMachineErrorChecker(self, *args) -> MachineErrorChecker:
return self._machine_error_checker
@ -895,11 +889,11 @@ class CuraApplication(QtApplication):
qmlRegisterType(NozzleModel, "Cura", 1, 0, "NozzleModel")
qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")
qmlRegisterType(SettingVisibilityPresetsModel, "Cura", 1, 0, "SettingVisibilityPresetsModel")
qmlRegisterType(QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel")
qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
qmlRegisterType(UserChangesModel, "Cura", 1, 0, "UserChangesModel")
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.
actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")))

View 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()

View File

@ -18,6 +18,7 @@ class ExtruderOutputModel(QObject):
hotendTemperatureChanged = pyqtSignal()
activeMaterialChanged = pyqtSignal()
extruderConfigurationChanged = pyqtSignal()
isPreheatingChanged = pyqtSignal()
def __init__(self, printer: "PrinterOutputModel", position, parent=None):
super().__init__(parent)
@ -30,6 +31,21 @@ class ExtruderOutputModel(QObject):
self._extruder_configuration = ExtruderConfigurationModel()
self._extruder_configuration.position = self._position
self._is_preheating = False
def getPrinter(self):
return self._printer
def getPosition(self):
return self._position
# Does the printer support pre-heating the bed at all
@pyqtProperty(bool, constant=True)
def canPreHeatHotends(self):
if self._printer:
return self._printer.canPreHeatHotends
return False
@pyqtProperty(QObject, notify = activeMaterialChanged)
def activeMaterial(self) -> "MaterialOutputModel":
return self._active_material
@ -82,3 +98,25 @@ class ExtruderOutputModel(QObject):
if self._extruder_configuration.isValid():
return self._extruder_configuration
return None
def updateIsPreheating(self, pre_heating):
if self._is_preheating != pre_heating:
self._is_preheating = pre_heating
self.isPreheatingChanged.emit()
@pyqtProperty(bool, notify=isPreheatingChanged)
def isPreheating(self):
return self._is_preheating
## Pre-heats the extruder before printer.
#
# \param temperature The temperature to heat the extruder to, in degrees
# Celsius.
# \param duration How long the bed should stay warm, in seconds.
@pyqtSlot(float, float)
def preheatHotend(self, temperature, duration):
self._printer._controller.preheatHotend(self, temperature, duration)
@pyqtSlot()
def cancelPreheatHotend(self):
self._printer._controller.cancelPreheatHotend(self)

View File

@ -0,0 +1,151 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
from PyQt5.QtCore import QTimer
MYPY = False
if MYPY:
from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
class GenericOutputController(PrinterOutputController):
def __init__(self, output_device):
super().__init__(output_device)
self._preheat_bed_timer = QTimer()
self._preheat_bed_timer.setSingleShot(True)
self._preheat_bed_timer.timeout.connect(self._onPreheatBedTimerFinished)
self._preheat_printer = None
self._preheat_hotends_timer = QTimer()
self._preheat_hotends_timer.setSingleShot(True)
self._preheat_hotends_timer.timeout.connect(self._onPreheatHotendsTimerFinished)
self._preheat_hotends = set()
self._output_device.printersChanged.connect(self._onPrintersChanged)
self._active_printer = None
def _onPrintersChanged(self):
if self._active_printer:
self._active_printer.stateChanged.disconnect(self._onPrinterStateChanged)
self._active_printer.targetBedTemperatureChanged.disconnect(self._onTargetBedTemperatureChanged)
for extruder in self._active_printer.extruders:
extruder.targetHotendTemperatureChanged.disconnect(self._onTargetHotendTemperatureChanged)
self._active_printer = self._output_device.activePrinter
if self._active_printer:
self._active_printer.stateChanged.connect(self._onPrinterStateChanged)
self._active_printer.targetBedTemperatureChanged.connect(self._onTargetBedTemperatureChanged)
for extruder in self._active_printer.extruders:
extruder.targetHotendTemperatureChanged.connect(self._onTargetHotendTemperatureChanged)
def _onPrinterStateChanged(self):
if self._active_printer.state != "idle":
if self._preheat_bed_timer.isActive():
self._preheat_bed_timer.stop()
self._preheat_printer.updateIsPreheating(False)
if self._preheat_hotends_timer.isActive():
self._preheat_hotends_timer.stop()
for extruder in self._preheat_hotends:
extruder.updateIsPreheating(False)
self._preheat_hotends = set()
def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed):
self._output_device.sendCommand("G91")
self._output_device.sendCommand("G0 X%s Y%s Z%s F%s" % (x, y, z, speed))
self._output_device.sendCommand("G90")
def homeHead(self, printer):
self._output_device.sendCommand("G28 X")
self._output_device.sendCommand("G28 Y")
def homeBed(self, printer):
self._output_device.sendCommand("G28 Z")
def setJobState(self, job: "PrintJobOutputModel", state: str):
if state == "pause":
self._output_device.pausePrint()
job.updateState("paused")
elif state == "print":
self._output_device.resumePrint()
job.updateState("printing")
elif state == "abort":
self._output_device.cancelPrint()
pass
def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int):
self._output_device.sendCommand("M140 S%s" % temperature)
def _onTargetBedTemperatureChanged(self):
if self._preheat_bed_timer.isActive() and self._preheat_printer.targetBedTemperature == 0:
self._preheat_bed_timer.stop()
self._preheat_printer.updateIsPreheating(False)
def preheatBed(self, printer: "PrinterOutputModel", temperature, duration):
try:
temperature = round(temperature) # The API doesn't allow floating point.
duration = round(duration)
except ValueError:
return # Got invalid values, can't pre-heat.
self.setTargetBedTemperature(printer, temperature=temperature)
self._preheat_bed_timer.setInterval(duration * 1000)
self._preheat_bed_timer.start()
self._preheat_printer = printer
printer.updateIsPreheating(True)
def cancelPreheatBed(self, printer: "PrinterOutputModel"):
self.setTargetBedTemperature(printer, temperature=0)
self._preheat_bed_timer.stop()
printer.updateIsPreheating(False)
def _onPreheatBedTimerFinished(self):
self.setTargetBedTemperature(self._preheat_printer, 0)
self._preheat_printer.updateIsPreheating(False)
def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: int):
self._output_device.sendCommand("M104 S%s T%s" % (temperature, position))
def _onTargetHotendTemperatureChanged(self):
if not self._preheat_hotends_timer.isActive():
return
for extruder in self._active_printer.extruders:
if extruder in self._preheat_hotends and extruder.targetHotendTemperature == 0:
extruder.updateIsPreheating(False)
self._preheat_hotends.remove(extruder)
if not self._preheat_hotends:
self._preheat_hotends_timer.stop()
def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration):
position = extruder.getPosition()
number_of_extruders = len(extruder.getPrinter().extruders)
if position >= number_of_extruders:
return # Got invalid extruder nr, can't pre-heat.
try:
temperature = round(temperature) # The API doesn't allow floating point.
duration = round(duration)
except ValueError:
return # Got invalid values, can't pre-heat.
self.setTargetHotendTemperature(extruder.getPrinter(), position, temperature=temperature)
self._preheat_hotends_timer.setInterval(duration * 1000)
self._preheat_hotends_timer.start()
self._preheat_hotends.add(extruder)
extruder.updateIsPreheating(True)
def cancelPreheatHotend(self, extruder: "ExtruderOutputModel"):
self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), temperature=0)
if extruder in self._preheat_hotends:
extruder.updateIsPreheating(False)
self._preheat_hotends.remove(extruder)
if not self._preheat_hotends and self._preheat_hotends_timer.isActive():
self._preheat_hotends_timer.stop()
def _onPreheatHotendsTimerFinished(self):
for extruder in self._preheat_hotends:
self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), 0)
self._preheat_hotends = set()

View File

@ -3,6 +3,8 @@
from UM.Application import Application
from UM.Logger import Logger
from UM.Settings.ContainerRegistry import ContainerRegistry
from cura.CuraApplication import CuraApplication
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
@ -254,6 +256,9 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
self._last_manager_create_time = time()
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:
if onFinished is not None:
self._onFinishedCallbacks[reply.url().toString() + str(reply.operation())] = onFinished

View File

@ -15,6 +15,7 @@ class PrinterOutputController:
self.can_pause = True
self.can_abort = True
self.can_pre_heat_bed = True
self.can_pre_heat_hotends = True
self.can_control_manually = True
self._output_device = output_device
@ -33,6 +34,12 @@ class PrinterOutputController:
def preheatBed(self, printer: "PrinterOutputModel", temperature, duration):
Logger.log("w", "Preheat bed not implemented in controller")
def cancelPreheatHotend(self, extruder: "ExtruderOutputModel"):
Logger.log("w", "Cancel preheat hotend not implemented in controller")
def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration):
Logger.log("w", "Preheat hotend not implemented in controller")
def setHeadPosition(self, printer: "PrinterOutputModel", x, y, z, speed):
Logger.log("w", "Set head position not implemented in controller")

View File

@ -238,6 +238,13 @@ class PrinterOutputModel(QObject):
return self._controller.can_pre_heat_bed
return False
# Does the printer support pre-heating the bed at all
@pyqtProperty(bool, constant=True)
def canPreHeatHotends(self):
if self._controller:
return self._controller.can_pre_heat_hotends
return False
# Does the printer support pause at all
@pyqtProperty(bool, constant=True)
def canPause(self):

View File

@ -173,12 +173,13 @@ class CuraContainerRegistry(ContainerRegistry):
plugin_registry = PluginRegistry.getInstance()
extension = file_name.split(".")[-1]
global_container_stack = Application.getInstance().getGlobalContainerStack()
if not global_container_stack:
global_stack = Application.getInstance().getGlobalContainerStack()
if not global_stack:
return
machine_extruders = list(ExtruderManager.getInstance().getMachineExtruders(global_container_stack.getId()))
machine_extruders.sort(key = lambda k: k.getMetaDataEntry("position"))
machine_extruders = []
for position in sorted(global_stack.extruders):
machine_extruders.append(global_stack.extruders[position])
for plugin_id, meta_data in self._getIOPlugins("profile_reader"):
if meta_data["profile_reader"][0]["extension"] != extension:
@ -200,13 +201,18 @@ class CuraContainerRegistry(ContainerRegistry):
# First check if this profile is suitable for this machine
global_profile = None
extruder_profiles = []
if len(profile_or_list) == 1:
global_profile = profile_or_list[0]
else:
for profile in profile_or_list:
if not profile.getMetaDataEntry("position"):
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:
Logger.log("e", "Incorrect profile [%s]. Could not find global profile", file_name)
return { "status": "error",
@ -227,7 +233,7 @@ class CuraContainerRegistry(ContainerRegistry):
# 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_container_stack.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:
@ -251,8 +257,8 @@ class CuraContainerRegistry(ContainerRegistry):
if len(profile_or_list) == 1:
global_profile = profile_or_list[0]
extruder_profiles = []
for idx, extruder in enumerate(global_container_stack.extruders.values()):
profile_id = ContainerRegistry.getInstance().uniqueName(global_container_stack.getId() + "_extruder_" + str(idx + 1))
for idx, extruder in enumerate(global_stack.extruders.values()):
profile_id = ContainerRegistry.getInstance().uniqueName(global_stack.getId() + "_extruder_" + str(idx + 1))
profile = InstanceContainer(profile_id)
profile.setName(quality_name)
profile.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
@ -264,12 +270,12 @@ class CuraContainerRegistry(ContainerRegistry):
if idx == 0:
# move all per-extruder settings to the first extruder's quality_changes
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")
if settable_per_extruder:
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.setProperty("value", setting_value)
new_instance.resetState() # Ensure that the state is not seen as a user state.
@ -286,7 +292,7 @@ class CuraContainerRegistry(ContainerRegistry):
for profile_index, profile in enumerate(profile_or_list):
if profile_index == 0:
# 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:
# This is assumed to be an extruder profile

View File

@ -210,6 +210,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
item = {
"id": "",
"name": catalog.i18nc("@menuitem", "Not overridden"),
"enabled": True,
"color": "#ffffff",
"index": -1,
"definition": ""

View File

@ -10,7 +10,6 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Signal import Signal
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, QTimer
import UM.FlameProfiler
from UM.FlameProfiler import pyqtSlot
from UM import Util
@ -24,7 +23,6 @@ from UM.Settings.SettingFunction import SettingFunction
from UM.Signal import postponeSignals, CompressTechnique
from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch
from cura.Machines.VariantManager import VariantType
from cura.PrinterOutputDevice import PrinterOutputDevice
from cura.PrinterOutput.ConfigurationModel import ConfigurationModel
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.
activeStackValidationChanged = pyqtSignal() # Emitted whenever a validation inside active container 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
@ -470,13 +469,13 @@ class MachineManager(QObject):
@pyqtProperty(str, notify = outputDevicesChanged)
def activeMachineNetworkKey(self) -> str:
if self._global_container_stack:
return self._global_container_stack.getMetaDataEntry("um_network_key")
return self._global_container_stack.getMetaDataEntry("um_network_key", "")
return ""
@pyqtProperty(str, notify = outputDevicesChanged)
def activeMachineNetworkGroupName(self) -> str:
if self._global_container_stack:
return self._global_container_stack.getMetaDataEntry("connect_group_name")
return self._global_container_stack.getMetaDataEntry("connect_group_name", "")
return ""
@pyqtProperty(QObject, notify = globalContainerChanged)
@ -662,12 +661,22 @@ class MachineManager(QObject):
if other_machine_stacks:
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)
containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(type = "user", machine = machine_id)
for container in containers:
ContainerRegistry.getInstance().removeContainer(container["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)
def hasMaterials(self) -> bool:
if self._global_container_stack:
@ -872,7 +881,13 @@ class MachineManager(QObject):
for position, extruder in self._global_container_stack.extruders.items():
if extruder.isEnabled:
extruder_count += 1
definition_changes_container.setProperty("extruders_enabled_count", "value", extruder_count)
if self.numberExtrudersEnabled != 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)
def defaultExtruderPosition(self):
@ -1193,6 +1208,26 @@ class MachineManager(QObject):
if machine.getMetaDataEntry(key) == 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)
## This method checks if there is an instance connected to the given network_key
def existNetworkInstances(self, network_key: str) -> bool:
metadata_filter = {"um_network_key": network_key}
containers = ContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter)
if containers:
return True
return False
@pyqtSlot("QVariant")
def setGlobalVariant(self, container_node):
self.blurSettings.emit()
@ -1242,6 +1277,13 @@ class MachineManager(QObject):
if not no_dialog and self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1:
self._application.discardOrKeepProfileChanges()
@pyqtSlot()
def resetToUseDefaultQuality(self):
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
self._setQualityGroup(self._current_quality_group)
for stack in [self._global_container_stack] + list(self._global_container_stack.extruders.values()):
stack.userChanges.clear()
@pyqtProperty(QObject, fset = setQualityChangesGroup, notify = activeQualityChangesGroupChanged)
def activeQualityChangesGroup(self):
return self._current_quality_changes_group

View File

@ -1,136 +0,0 @@
# 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

@ -16,7 +16,8 @@ class SimpleModeSettingsManager(QObject):
self._is_profile_user_created = False # True when profile was custom created by user
self._machine_manager.activeStackValueChanged.connect(self._updateIsProfileCustomized)
self._machine_manager.activeQualityChanged.connect(self._updateIsProfileUserCreated)
self._machine_manager.activeQualityGroupChanged.connect(self._updateIsProfileUserCreated)
self._machine_manager.activeQualityChangesGroupChanged.connect(self._updateIsProfileUserCreated)
# update on create as the activeQualityChanged signal is emitted before this manager is created when Cura starts
self._updateIsProfileCustomized()

View File

@ -1,17 +1,17 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import re # For escaping characters in the settings.
import json
import copy
from UM.Mesh.MeshWriter import MeshWriter
from UM.Logger import Logger
from UM.Application import Application
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Util import parseBool
from cura.Settings.ExtruderManager import ExtruderManager
from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch
import re #For escaping characters in the settings.
import json
import copy
## Writes g-code to a file.
#
@ -45,6 +45,8 @@ class GCodeWriter(MeshWriter):
def __init__(self):
super().__init__()
self._application = Application.getInstance()
## Writes the g-code for the entire scene to a stream.
#
# Note that even though the function accepts a collection of nodes, the
@ -94,7 +96,6 @@ class GCodeWriter(MeshWriter):
return flat_container
## Serialises a container stack to prepare it for writing at the end of the
# g-code.
#
@ -104,15 +105,21 @@ class GCodeWriter(MeshWriter):
# \param settings A container stack to serialise.
# \return A serialised string of the settings.
def _serialiseSettings(self, stack):
container_registry = self._application.getContainerRegistry()
quality_manager = self._application.getQualityManager()
prefix = ";SETTING_" + str(GCodeWriter.version) + " " # The prefix to put before each line.
prefix_length = len(prefix)
quality_name = stack.qualityChanges.getName()
quality_type = stack.quality.getMetaDataEntry("quality_type")
container_with_profile = stack.qualityChanges
if container_with_profile.getId() == "empty_quality_changes":
Logger.log("e", "No valid quality profile found, not writing settings to g-code!")
return ""
# If the global quality changes is empty, create a new one
quality_name = container_registry.uniqueName(stack.quality.getName())
container_with_profile = quality_manager._createQualityChanges(quality_type, quality_name, stack, None)
flat_global_container = self._createFlattenedContainerInstance(stack.getTop(), container_with_profile)
flat_global_container = self._createFlattenedContainerInstance(stack.userChanges, container_with_profile)
# If the quality changes is not set, we need to set type manually
if flat_global_container.getMetaDataEntry("type", None) is None:
flat_global_container.addMetaDataEntry("type", "quality_changes")
@ -121,41 +128,47 @@ class GCodeWriter(MeshWriter):
if flat_global_container.getMetaDataEntry("quality_type", None) is None:
flat_global_container.addMetaDataEntry("quality_type", stack.quality.getMetaDataEntry("quality_type", "normal"))
# Change the default defintion
default_machine_definition = "fdmprinter"
if parseBool(stack.getMetaDataEntry("has_machine_quality", "False")):
default_machine_definition = stack.getMetaDataEntry("quality_definition")
if not default_machine_definition:
default_machine_definition = stack.definition.getId()
flat_global_container.setMetaDataEntry("definition", default_machine_definition)
# Get the machine definition ID for quality profiles
machine_definition_id_for_quality = getMachineDefinitionIDForQualitySearch(stack.definition)
flat_global_container.setMetaDataEntry("definition", machine_definition_id_for_quality)
serialized = flat_global_container.serialize()
data = {"global_quality": serialized}
for extruder in sorted(stack.extruders.values(), key = lambda k: k.getMetaDataEntry("position")):
all_setting_keys = set(flat_global_container.getAllKeys())
for extruder in sorted(stack.extruders.values(), key = lambda k: int(k.getMetaDataEntry("position"))):
extruder_quality = extruder.qualityChanges
if extruder_quality.getId() == "empty_quality_changes":
Logger.log("w", "No extruder quality profile found, not writing quality for extruder %s to file!", extruder.getId())
continue
flat_extruder_quality = self._createFlattenedContainerInstance(extruder.getTop(), extruder_quality)
# Same story, if quality changes is empty, create a new one
quality_name = container_registry.uniqueName(stack.quality.getName())
extruder_quality = quality_manager._createQualityChanges(quality_type, quality_name, stack, None)
flat_extruder_quality = self._createFlattenedContainerInstance(extruder.userChanges, extruder_quality)
# If the quality changes is not set, we need to set type manually
if flat_extruder_quality.getMetaDataEntry("type", None) is None:
flat_extruder_quality.addMetaDataEntry("type", "quality_changes")
# Ensure that extruder is set. (Can happen if we have empty quality changes).
if flat_extruder_quality.getMetaDataEntry("extruder", None) is None:
flat_extruder_quality.addMetaDataEntry("extruder", extruder.getBottom().getId())
if flat_extruder_quality.getMetaDataEntry("position", None) is None:
flat_extruder_quality.addMetaDataEntry("position", extruder.getMetaDataEntry("position"))
# Ensure that quality_type is set. (Can happen if we have empty quality changes).
if flat_extruder_quality.getMetaDataEntry("quality_type", None) is None:
flat_extruder_quality.addMetaDataEntry("quality_type", extruder.quality.getMetaDataEntry("quality_type", "normal"))
# Change the default defintion
flat_extruder_quality.setMetaDataEntry("definition", default_machine_definition)
# Change the default definition
flat_extruder_quality.setMetaDataEntry("definition", machine_definition_id_for_quality)
extruder_serialized = flat_extruder_quality.serialize()
data.setdefault("extruder_quality", []).append(extruder_serialized)
all_setting_keys.update(set(flat_extruder_quality.getAllKeys()))
# Check if there is any profiles
if not all_setting_keys:
Logger.log("i", "No custom settings found, not writing settings to g-code.")
return ""
json_string = json.dumps(data)
# Escape characters that have a special meaning in g-code comments.
@ -169,5 +182,5 @@ class GCodeWriter(MeshWriter):
# Lines have 80 characters, so the payload of each line is 80 - prefix.
for pos in range(0, len(escaped_string), 80 - prefix_length):
result += prefix + escaped_string[pos : pos + 80 - prefix_length] + "\n"
result += prefix + escaped_string[pos: pos + 80 - prefix_length] + "\n"
return result

View File

@ -163,7 +163,16 @@ Item {
id: addedSettingsModel;
containerId: Cura.MachineManager.activeDefinitionId
expanded: [ "*" ]
exclude: {
filter:
{
if (printSequencePropertyProvider.properties.value == "one_at_a_time")
{
return {"settable_per_meshgroup": true};
}
return {"settable_per_mesh": true};
}
exclude:
{
var excluded_settings = [ "support_mesh", "anti_overhang_mesh", "cutting_mesh", "infill_mesh" ];
if(meshTypeSelection.model.get(meshTypeSelection.currentIndex).type == "support_mesh")
@ -375,7 +384,6 @@ Item {
title: catalog.i18nc("@title:window", "Select Settings to Customize for this model")
width: screenScaleFactor * 360
property string labelFilter: ""
property var additional_excluded_settings
onVisibilityChanged:
@ -386,11 +394,33 @@ Item {
// Set skip setting, it will prevent from resetting selected mesh_type
contents.model.visibilityHandler.addSkipResetSetting(meshTypeSelection.model.get(meshTypeSelection.currentIndex).type)
listview.model.forceUpdate()
updateFilter()
}
}
function updateFilter()
{
var new_filter = {};
if (printSequencePropertyProvider.properties.value == "one_at_a_time")
{
new_filter["settable_per_meshgroup"] = true;
}
else
{
new_filter["settable_per_mesh"] = true;
}
if(filterInput.text != "")
{
new_filter["i18n_label"] = "*" + filterInput.text;
}
listview.model.filter = new_filter;
}
TextField {
id: filter
id: filterInput
anchors {
top: parent.top
@ -401,17 +431,7 @@ Item {
placeholderText: catalog.i18nc("@label:textbox", "Filter...");
onTextChanged:
{
if(text != "")
{
listview.model.filter = {"settable_per_mesh": true, "i18n_label": "*" + text}
}
else
{
listview.model.filter = {"settable_per_mesh": true}
}
}
onTextChanged: settingPickDialog.updateFilter()
}
CheckBox
@ -437,7 +457,7 @@ Item {
anchors
{
top: filter.bottom;
top: filterInput.bottom;
left: parent.left;
right: parent.right;
bottom: parent.bottom;
@ -449,10 +469,6 @@ Item {
{
id: definitionsModel;
containerId: Cura.MachineManager.activeDefinitionId
filter:
{
"settable_per_mesh": true
}
visibilityHandler: UM.SettingPreferenceVisibilityHandler {}
expanded: [ "*" ]
exclude:
@ -484,6 +500,7 @@ Item {
}
}
}
Component.onCompleted: settingPickDialog.updateFilter()
}
}
@ -507,6 +524,16 @@ Item {
storeIndex: 0
}
UM.SettingPropertyProvider
{
id: printSequencePropertyProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "print_sequence"
watchedProperties: [ "value" ]
storeIndex: 0
}
SystemPalette { id: palette; }
Component

View File

@ -60,7 +60,7 @@ class RemovableDriveOutputDevice(OutputDevice):
if len(file_formats) == 0:
Logger.log("e", "There are no file formats available to write with!")
raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("There are no file formats available to write with!"))
raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("@info:status", "There are no file formats available to write with!"))
# Just take the first file format available.
if file_handler is not None:

View File

@ -13,6 +13,7 @@ class ClusterUM3PrinterOutputController(PrinterOutputController):
def __init__(self, output_device):
super().__init__(output_device)
self.can_pre_heat_bed = False
self.can_pre_heat_hotends = False
self.can_control_manually = False
def setJobState(self, job: "PrintJobOutputModel", state: str):

View File

@ -147,6 +147,10 @@ class DiscoverUM3Action(MachineAction):
return ""
@pyqtSlot(str, result = bool)
def existsKey(self, key) -> bool:
return Application.getInstance().getMachineManager().existNetworkInstances(network_key = key)
@pyqtSlot()
def loadConfigurationFromPrinter(self):
machine_manager = Application.getInstance().getMachineManager()

View File

@ -5,6 +5,7 @@ import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import QtQuick.Dialogs 1.2
Cura.MachineAction
{
@ -33,15 +34,34 @@ Cura.MachineAction
{
var printerKey = base.selectedDevice.key
var printerName = base.selectedDevice.name // TODO To change when the groups have a name
if(manager.getStoredKey() != printerKey)
if (manager.getStoredKey() != printerKey)
{
manager.setKey(printerKey)
manager.setGroupName(printerName) // TODO To change when the groups have a name
completed()
// Check if there is another instance with the same key
if (!manager.existsKey(printerKey))
{
manager.setKey(printerKey)
manager.setGroupName(printerName) // TODO To change when the groups have a name
completed()
}
else
{
existingConnectionDialog.open()
}
}
}
}
MessageDialog
{
id: existingConnectionDialog
title: catalog.i18nc("@window:title", "Existing Connection")
icon: StandardIcon.Information
text: catalog.i18nc("@message:text", "There is an instance already connected to this group")
detailedText: catalog.i18nc("@message:description", "You can't connect two instances to the same group. Please use the other instance or connect to another group.")
standardButtons: StandardButton.Ok
modality: Qt.ApplicationModal
}
Column
{
anchors.fill: parent;

View File

@ -82,6 +82,9 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
self._zero_conf_browser.cancel()
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_browser = ServiceBrowser(self._zero_conf, u'_ultimaker._tcp.local.',
[self._appendServiceChangedRequest])

View File

@ -1,68 +0,0 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
from PyQt5.QtCore import QTimer
MYPY = False
if MYPY:
from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
class USBPrinterOutputController(PrinterOutputController):
def __init__(self, output_device):
super().__init__(output_device)
self._preheat_bed_timer = QTimer()
self._preheat_bed_timer.setSingleShot(True)
self._preheat_bed_timer.timeout.connect(self._onPreheatBedTimerFinished)
self._preheat_printer = None
def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed):
self._output_device.sendCommand("G91")
self._output_device.sendCommand("G0 X%s Y%s Z%s F%s" % (x, y, z, speed))
self._output_device.sendCommand("G90")
def homeHead(self, printer):
self._output_device.sendCommand("G28 X")
self._output_device.sendCommand("G28 Y")
def homeBed(self, printer):
self._output_device.sendCommand("G28 Z")
def setJobState(self, job: "PrintJobOutputModel", state: str):
if state == "pause":
self._output_device.pausePrint()
job.updateState("paused")
elif state == "print":
self._output_device.resumePrint()
job.updateState("printing")
elif state == "abort":
self._output_device.cancelPrint()
pass
def preheatBed(self, printer: "PrinterOutputModel", temperature, duration):
try:
temperature = round(temperature) # The API doesn't allow floating point.
duration = round(duration)
except ValueError:
return # Got invalid values, can't pre-heat.
self.setTargetBedTemperature(printer, temperature=temperature)
self._preheat_bed_timer.setInterval(duration * 1000)
self._preheat_bed_timer.start()
self._preheat_printer = printer
printer.updateIsPreheating(True)
def cancelPreheatBed(self, printer: "PrinterOutputModel"):
self.preheatBed(printer, temperature=0, duration=0)
self._preheat_bed_timer.stop()
printer.updateIsPreheating(False)
def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int):
self._output_device.sendCommand("M140 S%s" % temperature)
def _onPreheatBedTimerFinished(self):
self.setTargetBedTemperature(self._preheat_printer, 0)
self._preheat_printer.updateIsPreheating(False)

View File

@ -10,9 +10,9 @@ from UM.PluginRegistry import PluginRegistry
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
from cura.PrinterOutput.GenericOutputController import GenericOutputController
from .AutoDetectBaudJob import AutoDetectBaudJob
from .USBPrinterOutputController import USBPrinterOutputController
from .avr_isp import stk500v2, intelHex
from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty
@ -240,7 +240,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
container_stack = Application.getInstance().getGlobalContainerStack()
num_extruders = container_stack.getProperty("machine_extruder_count", "value")
# Ensure that a printer is created.
self._printers = [PrinterOutputModel(output_controller=USBPrinterOutputController(self), number_of_extruders=num_extruders)]
self._printers = [PrinterOutputModel(output_controller=GenericOutputController(self), number_of_extruders=num_extruders)]
self._printers[0].updateName(container_stack.getName())
self.setConnectionState(ConnectionState.connected)
self._update_thread.start()
@ -372,7 +372,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
elapsed_time = int(time() - self._print_start_time)
print_job = self._printers[0].activePrintJob
if print_job is None:
print_job = PrintJobOutputModel(output_controller = USBPrinterOutputController(self), name= Application.getInstance().getPrintInformation().jobName)
print_job = PrintJobOutputModel(output_controller = GenericOutputController(self), name= Application.getInstance().getPrintInformation().jobName)
print_job.updateState("printing")
self._printers[0].updateActivePrintJob(print_job)

View File

@ -208,14 +208,9 @@ class XmlMaterialProfile(InstanceContainer):
machine_variant_map = {}
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.
material_group = material_manager.getMaterialGroup(root_material_id)
all_containers = []
for node in [material_group.root_material_node] + material_group.derived_material_node_list:
all_containers.append(node.getContainer())
all_containers = registry.findInstanceContainers(base_file = root_material_id)
for container in all_containers:
definition_id = container.getMetaDataEntry("definition")
@ -242,7 +237,7 @@ class XmlMaterialProfile(InstanceContainer):
for definition_id, container in machine_container_map.items():
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
for product_name, product_id_list in product_id_map.items():

View File

@ -6,7 +6,7 @@
"visible": true,
"manufacturer": "BQ",
"author": "BQ",
"file_formats": "text/x-code",
"file_formats": "text/x-gcode",
"platform": "bq_hephestos_platform.stl",
"platform_offset": [ 0, -82, 0]
},

View File

@ -25,6 +25,7 @@
"machine_nozzle_size": { "default_value": 0.5 },
"machine_shape": { "default_value": "elliptic" },
"machine_width": { "default_value": 290 },
"material_diameter": { "default_value": 1.75 },
"relative_extrusion": { "default_value": false },
"retraction_amount": { "default_value": 3.2 },
"retraction_combing": { "default_value": "off" },

View File

@ -25,6 +25,7 @@
"machine_nozzle_size": { "default_value": 0.5 },
"machine_shape": { "default_value": "elliptic" },
"machine_width": { "default_value": 265 },
"material_diameter": { "default_value": 1.75 },
"relative_extrusion": { "default_value": false },
"retraction_amount": { "default_value": 3.2 },
"retraction_combing": { "default_value": "off" },

View File

@ -110,9 +110,9 @@
"material_bed_temperature": { "maximum_value": "115" },
"material_bed_temperature_layer_0": { "maximum_value": "115" },
"material_standby_temperature": { "value": "100" },
"meshfix_maximum_resolution": { "value": "0.04" },
"meshfix_maximum_resolution": { "value": "0.04" },
"multiple_mesh_overlap": { "value": "0" },
"optimize_wall_printing_order": { "value": "True" },
"optimize_wall_printing_order": { "value": "True" },
"prime_tower_enable": { "default_value": true },
"raft_airgap": { "value": "0" },
"raft_base_thickness": { "value": "0.3" },

View File

@ -217,6 +217,7 @@ UM.MainWindow
text: catalog.i18nc("@action:inmenu", "Disable Extruder")
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false)
visible: Cura.MachineManager.getExtruder(model.index).isEnabled
enabled: Cura.MachineManager.numberExtrudersEnabled > 1
}
}

View File

@ -71,8 +71,8 @@ ToolButton
color: UM.Theme.getColor("sidebar_header_text_active")
text: control.text;
elide: Text.ElideRight;
anchors.left: isNetworkPrinter ? printerStatusIcon.right : parent.left;
anchors.leftMargin: isNetworkPrinter ? UM.Theme.getSize("sidebar_lining").width : UM.Theme.getSize("sidebar_margin").width
anchors.left: printerStatusIcon.visible ? printerStatusIcon.right : parent.left;
anchors.leftMargin: printerStatusIcon.visible ? UM.Theme.getSize("sidebar_lining").width : UM.Theme.getSize("sidebar_margin").width
anchors.right: downArrow.left;
anchors.rightMargin: control.rightMargin;
anchors.verticalCenter: parent.verticalCenter;

View File

@ -31,7 +31,7 @@ Menu
MenuItem {
text: "%1: %2 - %3".arg(model.name).arg(model.material).arg(model.variant)
visible: base.shouldShowExtruders
enabled: UM.Selection.hasSelection
enabled: UM.Selection.hasSelection && model.enabled
checkable: true
checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(model.id) != -1
onTriggered: CuraActions.setExtruderForSelection(model.id)

View File

@ -1,8 +1,8 @@
// 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 QtQuick 2.7
import QtQuick.Controls 1.4
import UM 1.2 as UM
import Cura 1.0 as Cura
@ -12,44 +12,26 @@ 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()
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
model: settingVisibilityPresetsModel
MenuItem
{
text: model.name
checkable: true
checked: model.id == Cura.SettingVisibilityPresetsModel.activePreset
checked: model.id == settingVisibilityPresetsModel.activePreset
exclusiveGroup: group
onTriggered:
{
Cura.SettingVisibilityPresetsModel.setActivePreset(model.id);
UM.Preferences.setValue("general/visible_settings", model.settings.join(";"));
settingVisibilityPresetsModel.setActivePreset(model.id);
showSettingVisibilityProfile();
}
}

View File

@ -364,6 +364,7 @@ Item
}
width: true ? (parent.width * 0.4) | 0 : parent.width
frameVisible: true
ListView
{

View File

@ -369,6 +369,7 @@ Item
}
width: true ? (parent.width * 0.4) | 0 : parent.width
frameVisible: true
ListView
{

View File

@ -13,6 +13,8 @@ UM.PreferencesPage
{
title: catalog.i18nc("@title:tab", "Setting Visibility");
property QtObject settingVisibilityPresetsModel: CuraApplication.getSettingVisibilityPresetsModel()
property int scrollToIndex: 0
signal scrollToSection( string key )
@ -27,8 +29,7 @@ UM.PreferencesPage
// After calling this function update Setting visibility preset combobox.
// Reset should set default setting preset ("Basic")
visibilityPreset.setDefaultPreset()
visibilityPreset.currentIndex = 1
}
resetEnabled: true;
@ -37,8 +38,6 @@ UM.PreferencesPage
id: base;
anchors.fill: parent;
property bool inhibitSwitchToCustom: false
CheckBox
{
id: toggleVisibleSettings
@ -112,11 +111,6 @@ UM.PreferencesPage
ComboBox
{
function setDefaultPreset()
{
visibilityPreset.currentIndex = 0
}
id: visibilityPreset
width: 150 * screenScaleFactor
anchors
@ -125,51 +119,25 @@ UM.PreferencesPage
right: parent.right
}
model: ListModel
{
id: visibilityPresetsModel
Component.onCompleted:
{
visibilityPresetsModel.append({text: catalog.i18nc("@action:inmenu", "Custom selection"), id: "custom"});
var presets = Cura.SettingVisibilityPresetsModel;
for(var i = 0; i < presets.rowCount(); i++)
{
visibilityPresetsModel.append({text: presets.getItem(i)["name"], id: presets.getItem(i)["id"]});
}
}
}
model: settingVisibilityPresetsModel
textRole: "name"
currentIndex:
{
// Load previously selected preset.
var index = Cura.SettingVisibilityPresetsModel.find("id", Cura.SettingVisibilityPresetsModel.activePreset);
if(index == -1)
var index = settingVisibilityPresetsModel.find("id", settingVisibilityPresetsModel.activePreset)
if (index == -1)
{
return 0;
return 0
}
return index + 1; // "Custom selection" entry is added in front, so index is off by 1
return index
}
onActivated:
{
base.inhibitSwitchToCustom = true;
var preset_id = visibilityPresetsModel.get(index).id;
Cura.SettingVisibilityPresetsModel.setActivePreset(preset_id);
UM.Preferences.setValue("cura/active_setting_visibility_preset", preset_id);
if (preset_id != "custom")
{
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;
var preset_id = settingVisibilityPresetsModel.getItem(index).id;
settingVisibilityPresetsModel.setActivePreset(preset_id);
}
}
@ -199,16 +167,7 @@ UM.PreferencesPage
exclude: ["machine_settings", "command_line_settings"]
showAncestors: true
expanded: ["*"]
visibilityHandler: UM.SettingPreferenceVisibilityHandler
{
onVisibilityChanged:
{
if(Cura.SettingVisibilityPresetsModel.activePreset != "" && !base.inhibitSwitchToCustom)
{
Cura.SettingVisibilityPresetsModel.setActivePreset("custom");
}
}
}
visibilityHandler: UM.SettingPreferenceVisibilityHandler {}
}
delegate: Loader

View File

@ -12,9 +12,20 @@ Item
property alias color: background.color
property var extruderModel
property var position: index
//width: index == machineExtruderCount.properties.value - 1 && index % 2 == 0 ? extrudersGrid.width : Math.floor(extrudersGrid.width / 2 - UM.Theme.getSize("sidebar_lining_thin").width / 2)
implicitWidth: parent.width
implicitHeight: UM.Theme.getSize("sidebar_extruder_box").height
UM.SettingPropertyProvider
{
id: extruderTemperature
containerStackId: Cura.ExtruderManager.extruderIds[position]
key: "material_print_temperature"
watchedProperties: ["value", "minimum_value", "maximum_value", "resolve"]
storeIndex: 0
property var resolve: Cura.MachineManager.activeStackId != Cura.MachineManager.activeMachineId ? properties.resolve : "None"
}
Rectangle
{
id: background
@ -34,12 +45,11 @@ Item
{
id: extruderTargetTemperature
text: Math.round(extruderModel.targetHotendTemperature) + "°C"
//text: (connectedPrinter != null && connectedPrinter.hotendIds[index] != null && connectedPrinter.targetHotendTemperatures[index] != null) ? Math.round(connectedPrinter.targetHotendTemperatures[index]) + "°C" : ""
font: UM.Theme.getFont("small")
color: UM.Theme.getColor("text_inactive")
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.bottom: extruderTemperature.bottom
anchors.bottom: extruderCurrentTemperature.bottom
MouseArea //For tooltip.
{
@ -52,7 +62,7 @@ Item
{
base.showTooltip(
base,
{x: 0, y: extruderTargetTemperature.mapToItem(base, 0, -parent.height / 4).y},
{x: 0, y: extruderTargetTemperature.mapToItem(base, 0, Math.floor(-parent.height / 4)).y},
catalog.i18nc("@tooltip", "The target temperature of the hotend. The hotend will heat up or cool down towards this temperature. If this is 0, the hotend heating is turned off.")
);
}
@ -65,9 +75,8 @@ Item
}
Label //Temperature indication.
{
id: extruderTemperature
id: extruderCurrentTemperature
text: Math.round(extruderModel.hotendTemperature) + "°C"
//text: (connectedPrinter != null && connectedPrinter.hotendIds[index] != null && connectedPrinter.hotendTemperatures[index] != null) ? Math.round(connectedPrinter.hotendTemperatures[index]) + "°C" : ""
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("large")
anchors.right: extruderTargetTemperature.left
@ -76,7 +85,7 @@ Item
MouseArea //For tooltip.
{
id: extruderTemperatureTooltipArea
id: extruderCurrentTemperatureTooltipArea
hoverEnabled: true
anchors.fill: parent
onHoveredChanged:
@ -85,8 +94,8 @@ Item
{
base.showTooltip(
base,
{x: 0, y: parent.mapToItem(base, 0, -parent.height / 4).y},
catalog.i18nc("@tooltip", "The current temperature of this extruder.")
{x: 0, y: parent.mapToItem(base, 0, Math.floor(-parent.height / 4)).y},
catalog.i18nc("@tooltip", "The current temperature of this hotend.")
);
}
else
@ -97,6 +106,272 @@ Item
}
}
Rectangle //Input field for pre-heat temperature.
{
id: preheatTemperatureControl
color: !enabled ? UM.Theme.getColor("setting_control_disabled") : showError ? UM.Theme.getColor("setting_validation_error_background") : UM.Theme.getColor("setting_validation_ok")
property var showError:
{
if(extruderTemperature.properties.maximum_value != "None" && extruderTemperature.properties.maximum_value < Math.floor(preheatTemperatureInput.text))
{
return true;
} else
{
return false;
}
}
enabled:
{
if (extruderModel == null)
{
return false; //Can't preheat if not connected.
}
if (!connectedPrinter.acceptsCommands)
{
return false; //Not allowed to do anything.
}
if (connectedPrinter.activePrinter && connectedPrinter.activePrinter.activePrintJob)
{
if((["printing", "pre_print", "resuming", "pausing", "paused", "error", "offline"]).indexOf(connectedPrinter.activePrinter.activePrintJob.state) != -1)
{
return false; //Printer is in a state where it can't react to pre-heating.
}
}
return true;
}
border.width: UM.Theme.getSize("default_lining").width
border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : preheatTemperatureInputMouseArea.containsMouse ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border")
anchors.right: preheatButton.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.bottom: parent.bottom
anchors.bottomMargin: UM.Theme.getSize("default_margin").height
width: UM.Theme.getSize("monitor_preheat_temperature_control").width
height: UM.Theme.getSize("monitor_preheat_temperature_control").height
visible: extruderModel != null ? enabled && extruderModel.canPreHeatHotends && !extruderModel.isPreheating : true
Rectangle //Highlight of input field.
{
anchors.fill: parent
anchors.margins: UM.Theme.getSize("default_lining").width
color: UM.Theme.getColor("setting_control_highlight")
opacity: preheatTemperatureControl.hovered ? 1.0 : 0
}
MouseArea //Change cursor on hovering.
{
id: preheatTemperatureInputMouseArea
hoverEnabled: true
anchors.fill: parent
cursorShape: Qt.IBeamCursor
onHoveredChanged:
{
if (containsMouse)
{
base.showTooltip(
base,
{x: 0, y: preheatTemperatureInputMouseArea.mapToItem(base, 0, 0).y},
catalog.i18nc("@tooltip of temperature input", "The temperature to pre-heat the hotend to.")
);
}
else
{
base.hideTooltip();
}
}
}
Label
{
id: unit
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("setting_unit_margin").width
anchors.verticalCenter: parent.verticalCenter
text: "°C";
color: UM.Theme.getColor("setting_unit")
font: UM.Theme.getFont("default")
}
TextInput
{
id: preheatTemperatureInput
font: UM.Theme.getFont("default")
color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text")
selectByMouse: true
maximumLength: 5
enabled: parent.enabled
validator: RegExpValidator { regExp: /^-?[0-9]{0,9}[.,]?[0-9]{0,10}$/ } //Floating point regex.
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width
anchors.right: unit.left
anchors.verticalCenter: parent.verticalCenter
renderType: Text.NativeRendering
Component.onCompleted:
{
if (!extruderTemperature.properties.value)
{
text = "";
}
else
{
text = extruderTemperature.properties.value;
}
}
}
}
Button //The pre-heat button.
{
id: preheatButton
height: UM.Theme.getSize("setting_control").height
visible: extruderModel != null ? extruderModel.canPreHeatHotends: true
enabled:
{
if (!preheatTemperatureControl.enabled)
{
return false; //Not connected, not authenticated or printer is busy.
}
if (extruderModel.isPreheating)
{
return true;
}
if (extruderTemperature.properties.minimum_value != "None" && Math.floor(preheatTemperatureInput.text) < Math.floor(extruderTemperature.properties.minimum_value))
{
return false; //Target temperature too low.
}
if (extruderTemperature.properties.maximum_value != "None" && Math.floor(preheatTemperatureInput.text) > Math.floor(extruderTemperature.properties.maximum_value))
{
return false; //Target temperature too high.
}
if (Math.floor(preheatTemperatureInput.text) == 0)
{
return false; //Setting the temperature to 0 is not allowed (since that cancels the pre-heating).
}
return true; //Preconditions are met.
}
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: UM.Theme.getSize("default_margin").width
style: ButtonStyle {
background: Rectangle
{
border.width: UM.Theme.getSize("default_lining").width
implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("default_margin").width * 2)
border.color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled_border");
}
else if(control.pressed)
{
return UM.Theme.getColor("action_button_active_border");
}
else if(control.hovered)
{
return UM.Theme.getColor("action_button_hovered_border");
}
else
{
return UM.Theme.getColor("action_button_border");
}
}
color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled");
}
else if(control.pressed)
{
return UM.Theme.getColor("action_button_active");
}
else if(control.hovered)
{
return UM.Theme.getColor("action_button_hovered");
}
else
{
return UM.Theme.getColor("action_button");
}
}
Behavior on color
{
ColorAnimation
{
duration: 50
}
}
Label
{
id: actualLabel
anchors.centerIn: parent
color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled_text");
}
else if(control.pressed)
{
return UM.Theme.getColor("action_button_active_text");
}
else if(control.hovered)
{
return UM.Theme.getColor("action_button_hovered_text");
}
else
{
return UM.Theme.getColor("action_button_text");
}
}
font: UM.Theme.getFont("action_button")
text:
{
if(extruderModel == null)
{
return ""
}
if(extruderModel.isPreheating )
{
return catalog.i18nc("@button Cancel pre-heating", "Cancel")
} else
{
return catalog.i18nc("@button", "Pre-heat")
}
}
}
}
}
onClicked:
{
if (!extruderModel.isPreheating)
{
extruderModel.preheatHotend(preheatTemperatureInput.text, 900);
}
else
{
extruderModel.cancelPreheatHotend();
}
}
onHoveredChanged:
{
if (hovered)
{
base.showTooltip(
base,
{x: 0, y: preheatButton.mapToItem(base, 0, 0).y},
catalog.i18nc("@tooltip of pre-heat", "Heat the hotend in advance before printing. You can continue adjusting your print while it is heating, and you won't have to wait for the hotend to heat up when you're ready to print.")
);
}
else
{
base.hideTooltip();
}
}
}
Rectangle //Material colour indication.
{
id: materialColor

View File

@ -114,21 +114,24 @@ Item
{
return false; //Not allowed to do anything.
}
if (connectedPrinter.jobState == "printing" || connectedPrinter.jobState == "pre_print" || connectedPrinter.jobState == "resuming" || connectedPrinter.jobState == "pausing" || connectedPrinter.jobState == "paused" || connectedPrinter.jobState == "error" || connectedPrinter.jobState == "offline")
if (connectedPrinter.activePrinter && connectedPrinter.activePrinter.activePrintJob)
{
return false; //Printer is in a state where it can't react to pre-heating.
if((["printing", "pre_print", "resuming", "pausing", "paused", "error", "offline"]).indexOf(connectedPrinter.activePrinter.activePrintJob.state) != -1)
{
return false; //Printer is in a state where it can't react to pre-heating.
}
}
return true;
}
border.width: UM.Theme.getSize("default_lining").width
border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : preheatTemperatureInputMouseArea.containsMouse ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border")
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.right: preheatButton.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.bottom: parent.bottom
anchors.bottomMargin: UM.Theme.getSize("default_margin").height
width: UM.Theme.getSize("setting_control").width
height: UM.Theme.getSize("setting_control").height
visible: printerModel != null ? printerModel.canPreHeatBed: true
width: UM.Theme.getSize("monitor_preheat_temperature_control").width
height: UM.Theme.getSize("monitor_preheat_temperature_control").height
visible: printerModel != null ? enabled && printerModel.canPreHeatBed && !printerModel.isPreheating : true
Rectangle //Highlight of input field.
{
anchors.fill: parent
@ -159,18 +162,29 @@ Item
}
}
}
Label
{
id: unit
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("setting_unit_margin").width
anchors.verticalCenter: parent.verticalCenter
text: "°C";
color: UM.Theme.getColor("setting_unit")
font: UM.Theme.getFont("default")
}
TextInput
{
id: preheatTemperatureInput
font: UM.Theme.getFont("default")
color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text")
selectByMouse: true
maximumLength: 10
maximumLength: 5
enabled: parent.enabled
validator: RegExpValidator { regExp: /^-?[0-9]{0,9}[.,]?[0-9]{0,10}$/ } //Floating point regex.
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width
anchors.right: parent.right
anchors.right: unit.left
anchors.verticalCenter: parent.verticalCenter
renderType: Text.NativeRendering

View File

@ -215,7 +215,8 @@ SettingItem
{
text: model.name
renderType: Text.NativeRendering
color: {
color:
{
if (model.enabled) {
UM.Theme.getColor("setting_control_text")
} else {

View File

@ -27,8 +27,19 @@ SettingItem
onActivated:
{
forceActiveFocus();
propertyProvider.setPropertyValue("value", model.getItem(index).index);
if (model.getItem(index).enabled)
{
forceActiveFocus();
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:
@ -192,7 +203,14 @@ SettingItem
{
text: model.name
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")
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter

View File

@ -15,6 +15,7 @@ Item
{
id: base;
property QtObject settingVisibilityPresetsModel: CuraApplication.getSettingVisibilityPresetsModel()
property Action configureSettings
property bool findingSettings
property bool showingAllSettings
@ -439,6 +440,7 @@ Item
key: model.key ? model.key : ""
watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ]
storeIndex: 0
removeUnusedValue: model.resolve == undefined
}
Connections
@ -562,9 +564,9 @@ Item
{
definitionsModel.hide(contextMenu.key);
// visible settings have changed, so we're no longer showing a preset
if (Cura.SettingVisibilityPresetsModel.activePreset != "" && !showingAllSettings)
if (settingVisibilityPresetsModel.activePreset != "" && !showingAllSettings)
{
Cura.SettingVisibilityPresetsModel.setActivePreset("custom");
settingVisibilityPresetsModel.setActivePreset("custom");
}
}
}
@ -594,16 +596,16 @@ Item
definitionsModel.show(contextMenu.key);
}
// visible settings have changed, so we're no longer showing a preset
if (Cura.SettingVisibilityPresetsModel.activePreset != "" && !showingAllSettings)
if (settingVisibilityPresetsModel.activePreset != "" && !showingAllSettings)
{
Cura.SettingVisibilityPresetsModel.setActivePreset("custom");
settingVisibilityPresetsModel.setActivePreset("custom");
}
}
}
MenuItem
{
//: 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);
}

View File

@ -178,6 +178,7 @@ Column
text: catalog.i18nc("@action:inmenu", "Disable Extruder")
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false)
visible: extruder_enabled
enabled: Cura.MachineManager.numberExtrudersEnabled > 1
}
}
@ -185,22 +186,34 @@ Column
{
background: Item
{
Rectangle
function buttonBackgroundColor(index)
{
anchors.fill: parent
border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width
border.color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_border") :
control.hovered ? UM.Theme.getColor("action_button_hovered_border") :
UM.Theme.getColor("action_button_border")
color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active") :
control.hovered ? UM.Theme.getColor("action_button_hovered") :
UM.Theme.getColor("action_button")
Behavior on color { ColorAnimation { duration: 50; } }
var extruder = Cura.MachineManager.getExtruder(index)
if (extruder.isEnabled) {
return (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active") :
control.hovered ? UM.Theme.getColor("action_button_hovered") :
UM.Theme.getColor("action_button")
} else {
return UM.Theme.getColor("action_button_disabled")
}
}
function buttonBorderColor(index)
{
var extruder = Cura.MachineManager.getExtruder(index)
if (extruder.isEnabled) {
return (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_border") :
control.hovered ? UM.Theme.getColor("action_button_hovered_border") :
UM.Theme.getColor("action_button_border")
} else {
return UM.Theme.getColor("action_button_disabled_border")
}
}
function buttonColor(index) {
var extruder = Cura.MachineManager.getExtruder(index);
if (extruder.isEnabled) {
if (extruder.isEnabled)
{
return (
control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") :
control.hovered ? UM.Theme.getColor("action_button_hovered_text") :
@ -210,10 +223,20 @@ Column
}
}
Rectangle
{
anchors.fill: parent
border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width
border.color: buttonBorderColor(index)
color: buttonBackgroundColor(index)
Behavior on color { ColorAnimation { duration: 50; } }
}
Item
{
id: extruderButtonFace
anchors.centerIn: parent
width: {
var extruderTextWidth = extruderStaticText.visible ? extruderStaticText.width : 0;
var iconWidth = extruderIconItem.width;

View File

@ -19,7 +19,7 @@ Item
property Action configureSettings;
property variant minimumPrintTime: PrintInformation.minimumPrintTime;
property variant maximumPrintTime: PrintInformation.maximumPrintTime;
property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || extrudersEnabledCount.properties.value == 1
property bool settingsEnabled: extrudersEnabledCount.properties.value == 1
Component.onCompleted: PrintInformation.enabled = true
Component.onDestruction: PrintInformation.enabled = false
@ -111,7 +111,6 @@ Item
// Set selected value
if (Cura.MachineManager.activeQualityType == qualityItem.quality_type) {
// set to -1 when switching to user created profile so all ticks are clickable
if (Cura.SimpleModeSettingsManager.isProfileUserCreated) {
qualityModel.qualitySliderActiveIndex = -1
@ -474,18 +473,7 @@ Item
onClicked:
{
// if the current profile is user-created, switch to a built-in quality
if (Cura.SimpleModeSettingsManager.isProfileUserCreated)
{
if (Cura.QualityProfilesDropDownMenuModel.rowCount() > 0)
{
var item = Cura.QualityProfilesDropDownMenuModel.getItem(0);
Cura.MachineManager.activeQualityGroup = item.quality_group;
}
}
if (Cura.SimpleModeSettingsManager.isProfileCustomized)
{
discardOrKeepProfileChangesDialog.show()
}
Cura.MachineManager.resetToUseDefaultQuality()
}
onEntered:
{
@ -594,7 +582,9 @@ Item
// Update value only if the Recomended mode is Active,
// Otherwise if I change the value in the Custom mode the Recomended view will try to repeat
// same operation
if (UM.Preferences.getValue("cura/active_mode") == 0) {
var active_mode = UM.Preferences.getValue("cura/active_mode")
if (active_mode == 0 || active_mode == "simple") {
Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue)
}
}

View File

@ -84,16 +84,16 @@
"tab_background": [39, 44, 48, 255],
"action_button": [39, 44, 48, 255],
"action_button_text": [255, 255, 255, 101],
"action_button_text": [255, 255, 255, 200],
"action_button_border": [255, 255, 255, 30],
"action_button_hovered": [39, 44, 48, 255],
"action_button_hovered_text": [255, 255, 255, 255],
"action_button_hovered_border": [255, 255, 255, 30],
"action_button_active": [39, 44, 48, 30],
"action_button_active_text": [255, 255, 255, 255],
"action_button_active_border": [255, 255, 255, 30],
"action_button_active_border": [255, 255, 255, 100],
"action_button_disabled": [39, 44, 48, 255],
"action_button_disabled_text": [255, 255, 255, 101],
"action_button_disabled_text": [255, 255, 255, 80],
"action_button_disabled_border": [255, 255, 255, 30],
"scrollbar_background": [39, 44, 48, 0],

View File

@ -411,6 +411,8 @@
"save_button_save_to_button": [0.3, 2.7],
"save_button_specs_icons": [1.4, 1.4],
"monitor_preheat_temperature_control": [4.5, 2.0],
"modal_window_minimum": [60.0, 45],
"license_window_minimum": [45, 45],
"wizard_progress": [10.0, 0.0],