Merge branch 'master' into headless_cura

This commit is contained in:
Mark 2017-11-01 13:25:09 +01:00
commit 3ba7db1420
388 changed files with 1957 additions and 1166 deletions

View File

@ -10,6 +10,6 @@ TryExec=@CMAKE_INSTALL_FULL_BINDIR@/cura
Icon=cura-icon Icon=cura-icon
Terminal=false Terminal=false
Type=Application Type=Application
MimeType=application/sla;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;image/bmp;image/gif;image/jpeg;image/png; MimeType=application/sla;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;image/bmp;image/gif;image/jpeg;image/png;model/x3d+xml;
Categories=Graphics; Categories=Graphics;
Keywords=3D;Printing; Keywords=3D;Printing;

View File

@ -12,8 +12,8 @@ class CameraAnimation(QVariantAnimation):
def __init__(self, parent = None): def __init__(self, parent = None):
super().__init__(parent) super().__init__(parent)
self._camera_tool = None self._camera_tool = None
self.setDuration(500) self.setDuration(300)
self.setEasingCurve(QEasingCurve.InOutQuad) self.setEasingCurve(QEasingCurve.OutQuad)
def setCameraTool(self, camera_tool): def setCameraTool(self, camera_tool):
self._camera_tool = camera_tool self._camera_tool = camera_tool

View File

@ -15,8 +15,9 @@ import urllib.request
import urllib.error import urllib.error
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, QCoreApplication from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, QCoreApplication
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit, QGroupBox, QPushButton from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit, QGroupBox
from UM.Application import Application
from UM.Logger import Logger from UM.Logger import Logger
from UM.View.GL.OpenGL import OpenGL from UM.View.GL.OpenGL import OpenGL
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
@ -44,14 +45,15 @@ fatal_exception_types = [
SystemError, SystemError,
] ]
class CrashHandler: class CrashHandler:
crash_url = "https://stats.ultimaker.com/api/cura" crash_url = "https://stats.ultimaker.com/api/cura"
def __init__(self, exception_type, value, tb): def __init__(self, exception_type, value, tb):
self.exception_type = exception_type self.exception_type = exception_type
self.value = value self.value = value
self.traceback = tb self.traceback = tb
self.dialog = QDialog()
# While we create the GUI, the information will be stored for sending afterwards # While we create the GUI, the information will be stored for sending afterwards
self.data = dict() self.data = dict()
@ -73,8 +75,6 @@ class CrashHandler:
## Creates a modal dialog. ## Creates a modal dialog.
def _createDialog(self): def _createDialog(self):
self.dialog = QDialog()
self.dialog.setMinimumWidth(640) self.dialog.setMinimumWidth(640)
self.dialog.setMinimumHeight(640) self.dialog.setMinimumHeight(640)
self.dialog.setWindowTitle(catalog.i18nc("@title:window", "Crash Report")) self.dialog.setWindowTitle(catalog.i18nc("@title:window", "Crash Report"))
@ -226,7 +226,6 @@ class CrashHandler:
return group return group
def _userDescriptionWidget(self): def _userDescriptionWidget(self):
group = QGroupBox() group = QGroupBox()
group.setTitle(catalog.i18nc("@title:groupbox", "User description")) group.setTitle(catalog.i18nc("@title:groupbox", "User description"))
@ -277,5 +276,9 @@ class CrashHandler:
os._exit(1) os._exit(1)
def show(self): def show(self):
# must run the GUI code on the Qt thread, otherwise the widgets on the dialog won't react correctly.
Application.getInstance().callLater(self._show)
def _show(self):
self.dialog.exec_() self.dialog.exec_()
os._exit(1) os._exit(1)

View File

@ -51,6 +51,7 @@ from cura.Settings.MaterialsModel import MaterialsModel
from cura.Settings.QualityAndUserProfilesModel import QualityAndUserProfilesModel from cura.Settings.QualityAndUserProfilesModel import QualityAndUserProfilesModel
from cura.Settings.SettingInheritanceManager import SettingInheritanceManager from cura.Settings.SettingInheritanceManager import SettingInheritanceManager
from cura.Settings.UserProfilesModel import UserProfilesModel from cura.Settings.UserProfilesModel import UserProfilesModel
from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager
from . import PlatformPhysics from . import PlatformPhysics
from . import BuildVolume from . import BuildVolume
@ -104,7 +105,7 @@ class CuraApplication(QtApplication):
# SettingVersion represents the set of settings available in the machine/extruder definitions. # SettingVersion represents the set of settings available in the machine/extruder definitions.
# You need to make sure that this version number needs to be increased if there is any non-backwards-compatible # You need to make sure that this version number needs to be increased if there is any non-backwards-compatible
# changes of the settings. # changes of the settings.
SettingVersion = 3 SettingVersion = 4
class ResourceTypes: class ResourceTypes:
QmlFiles = Resources.UserType + 1 QmlFiles = Resources.UserType + 1
@ -201,6 +202,7 @@ class CuraApplication(QtApplication):
self._machine_manager = None # This is initialized on demand. self._machine_manager = None # This is initialized on demand.
self._material_manager = None self._material_manager = None
self._setting_inheritance_manager = None self._setting_inheritance_manager = None
self._simple_mode_settings_manager = None
self._additional_components = {} # Components to add to certain areas in the interface self._additional_components = {} # Components to add to certain areas in the interface
@ -213,6 +215,7 @@ class CuraApplication(QtApplication):
self.setRequiredPlugins([ self.setRequiredPlugins([
"CuraEngineBackend", "CuraEngineBackend",
"UserAgreement",
"SolidView", "SolidView",
"LayerView", "LayerView",
"STLReader", "STLReader",
@ -268,8 +271,9 @@ class CuraApplication(QtApplication):
empty_quality_container = copy.deepcopy(empty_container) empty_quality_container = copy.deepcopy(empty_container)
empty_quality_container._id = "empty_quality" empty_quality_container._id = "empty_quality"
empty_quality_container.setName("Not Supported") empty_quality_container.setName("Not Supported")
empty_quality_container.addMetaDataEntry("quality_type", "normal") empty_quality_container.addMetaDataEntry("quality_type", "not_supported")
empty_quality_container.addMetaDataEntry("type", "quality") empty_quality_container.addMetaDataEntry("type", "quality")
empty_quality_container.addMetaDataEntry("supported", False)
ContainerRegistry.getInstance().addContainer(empty_quality_container) ContainerRegistry.getInstance().addContainer(empty_quality_container)
empty_quality_changes_container = copy.deepcopy(empty_container) empty_quality_changes_container = copy.deepcopy(empty_container)
empty_quality_changes_container._id = "empty_quality_changes" empty_quality_changes_container._id = "empty_quality_changes"
@ -301,6 +305,8 @@ class CuraApplication(QtApplication):
preferences.addPreference("view/invert_zoom", False) preferences.addPreference("view/invert_zoom", False)
self._need_to_show_user_agreement = not Preferences.getInstance().getValue("general/accepted_user_agreement")
for key in [ for key in [
"dialog_load_path", # dialog_save_path is in LocalFileOutputDevicePlugin "dialog_load_path", # dialog_save_path is in LocalFileOutputDevicePlugin
"dialog_profile_path", "dialog_profile_path",
@ -373,6 +379,14 @@ class CuraApplication(QtApplication):
def _onEngineCreated(self): def _onEngineCreated(self):
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider()) self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
@pyqtProperty(bool)
def needToShowUserAgreement(self):
return self._need_to_show_user_agreement
def setNeedToShowUserAgreement(self, set_value = True):
self._need_to_show_user_agreement = set_value
## The "Quit" button click event handler. ## The "Quit" button click event handler.
@pyqtSlot() @pyqtSlot()
def closeApplication(self): def closeApplication(self):
@ -391,6 +405,7 @@ class CuraApplication(QtApplication):
showDiscardOrKeepProfileChanges = pyqtSignal() showDiscardOrKeepProfileChanges = pyqtSignal()
def discardOrKeepProfileChanges(self): def discardOrKeepProfileChanges(self):
has_user_interaction = False
choice = Preferences.getInstance().getValue("cura/choice_on_profile_override") choice = Preferences.getInstance().getValue("cura/choice_on_profile_override")
if choice == "always_discard": if choice == "always_discard":
# don't show dialog and DISCARD the profile # don't show dialog and DISCARD the profile
@ -401,8 +416,10 @@ class CuraApplication(QtApplication):
else: else:
# ALWAYS ask whether to keep or discard the profile # ALWAYS ask whether to keep or discard the profile
self.showDiscardOrKeepProfileChanges.emit() self.showDiscardOrKeepProfileChanges.emit()
has_user_interaction = True
return has_user_interaction
sidebarSimpleDiscardOrKeepProfileChanges = pyqtSignal() onDiscardOrKeepProfileChangesClosed = pyqtSignal() # Used to notify other managers that the dialog was closed
@pyqtSlot(str) @pyqtSlot(str)
def discardOrKeepProfileChangesClosed(self, option): def discardOrKeepProfileChangesClosed(self, option):
@ -410,12 +427,24 @@ class CuraApplication(QtApplication):
global_stack = self.getGlobalContainerStack() global_stack = self.getGlobalContainerStack()
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()): for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
extruder.getTop().clear() extruder.getTop().clear()
global_stack.getTop().clear() global_stack.getTop().clear()
#event handler for SidebarSimple, which will update sliders view visibility (like:sliders..) # if the user decided to keep settings then the user settings should be re-calculated and validated for errors
if Preferences.getInstance().getValue("cura/active_mode") == 0: # before slicing. To ensure that slicer uses right settings values
self.sidebarSimpleDiscardOrKeepProfileChanges.emit() elif option == "keep":
global_stack = self.getGlobalContainerStack()
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
user_extruder_container = extruder.getTop()
if user_extruder_container:
user_extruder_container.update()
user_global_container = global_stack.getTop()
if user_global_container:
user_global_container.update()
# notify listeners that quality has changed (after user selected discard or keep)
self.onDiscardOrKeepProfileChangesClosed.emit()
self.getMachineManager().activeQualityChanged.emit()
@pyqtSlot(int) @pyqtSlot(int)
def messageBoxClosed(self, button): def messageBoxClosed(self, button):
@ -676,6 +705,8 @@ class CuraApplication(QtApplication):
qmlRegisterSingletonType(MaterialManager, "Cura", 1, 0, "MaterialManager", self.getMaterialManager) qmlRegisterSingletonType(MaterialManager, "Cura", 1, 0, "MaterialManager", self.getMaterialManager)
qmlRegisterSingletonType(SettingInheritanceManager, "Cura", 1, 0, "SettingInheritanceManager", qmlRegisterSingletonType(SettingInheritanceManager, "Cura", 1, 0, "SettingInheritanceManager",
self.getSettingInheritanceManager) self.getSettingInheritanceManager)
qmlRegisterSingletonType(SimpleModeSettingsManager, "Cura", 1, 2, "SimpleModeSettingsManager",
self.getSimpleModeSettingsManager)
qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager) qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager)
self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml"))
@ -718,6 +749,11 @@ class CuraApplication(QtApplication):
def getMachineActionManager(self, *args): def getMachineActionManager(self, *args):
return self._machine_action_manager return self._machine_action_manager
def getSimpleModeSettingsManager(self, *args):
if self._simple_mode_settings_manager is None:
self._simple_mode_settings_manager = SimpleModeSettingsManager()
return self._simple_mode_settings_manager
## Handle Qt events ## Handle Qt events
def event(self, event): def event(self, event):
if event.type() == QEvent.FileOpen: if event.type() == QEvent.FileOpen:

View File

@ -62,7 +62,7 @@ class CuraSplashScreen(QSplashScreen):
painter.setFont(font) painter.setFont(font)
painter.drawText(215, 66, 330 * self._scale, 230 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[0]) painter.drawText(215, 66, 330 * self._scale, 230 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[0])
if len(version) > 1: if len(version) > 1:
font.setPointSize(12) font.setPixelSize(16)
painter.setFont(font) painter.setFont(font)
painter.setPen(QColor(200, 200, 200, 255)) painter.setPen(QColor(200, 200, 200, 255))
painter.drawText(247, 105, 330 * self._scale, 255 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[1]) painter.drawText(247, 105, 330 * self._scale, 255 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[1])

View File

@ -313,7 +313,12 @@ class PrintInformation(QObject):
elif word.isdigit(): elif word.isdigit():
abbr_machine += word abbr_machine += word
else: else:
abbr_machine += self._stripAccents(word.strip("()[]{}#").upper())[0] stripped_word = self._stripAccents(word.strip("()[]{}#").upper())
# - use only the first character if the word is too long (> 3 characters)
# - use the whole word if it's not too long (<= 3 characters)
if len(stripped_word) > 3:
stripped_word = stripped_word[0]
abbr_machine += stripped_word
self._abbr_machine = abbr_machine self._abbr_machine = abbr_machine
@ -339,4 +344,3 @@ class PrintInformation(QObject):
temp_material_amounts = [0] temp_material_amounts = [0]
self._onPrintDurationMessage(temp_message, temp_material_amounts) self._onPrintDurationMessage(temp_message, temp_material_amounts)

View File

@ -87,7 +87,7 @@ class QualityManager:
qualities = set(quality_type_dict.values()) qualities = set(quality_type_dict.values())
for material_container in material_containers[1:]: for material_container in material_containers[1:]:
next_quality_type_dict = self.__fetchQualityTypeDictForMaterial(machine_definition, material_container) next_quality_type_dict = self.__fetchQualityTypeDictForMaterial(machine_definition, material_container)
qualities.update(set(next_quality_type_dict.values())) qualities.intersection_update(set(next_quality_type_dict.values()))
return list(qualities) return list(qualities)
@ -178,12 +178,25 @@ class QualityManager:
def findAllUsableQualitiesForMachineAndExtruders(self, global_container_stack: "GlobalStack", extruder_stacks: List["ExtruderStack"]) -> List[InstanceContainer]: def findAllUsableQualitiesForMachineAndExtruders(self, global_container_stack: "GlobalStack", extruder_stacks: List["ExtruderStack"]) -> List[InstanceContainer]:
global_machine_definition = global_container_stack.getBottom() global_machine_definition = global_container_stack.getBottom()
machine_manager = Application.getInstance().getMachineManager()
active_stack_id = machine_manager.activeStackId
materials = []
# TODO: fix this
if extruder_stacks: if extruder_stacks:
# Multi-extruder machine detected. # Multi-extruder machine detected
materials = [stack.material for stack in extruder_stacks] for stack in extruder_stacks:
if stack.getId() == active_stack_id and machine_manager.newMaterial:
materials.append(machine_manager.newMaterial)
else: else:
# Machine with one extruder. materials.append(stack.material)
materials = [global_container_stack.material] else:
# Machine with one extruder
if global_container_stack.getId() == active_stack_id and machine_manager.newMaterial:
materials.append(machine_manager.newMaterial)
else:
materials.append(global_container_stack.material)
quality_types = self.findAllQualityTypesForMachineAndMaterials(global_machine_definition, materials) quality_types = self.findAllQualityTypesForMachineAndMaterials(global_machine_definition, materials)

View File

@ -303,6 +303,9 @@ class CuraContainerRegistry(ContainerRegistry):
if "material" in quality_type_criteria: if "material" in quality_type_criteria:
materials = ContainerRegistry.getInstance().findInstanceContainers(id = quality_type_criteria["material"]) materials = ContainerRegistry.getInstance().findInstanceContainers(id = quality_type_criteria["material"])
del quality_type_criteria["material"] del quality_type_criteria["material"]
# Do not filter quality containers here with materials because we are trying to import a profile, so it should
# NOT be restricted by the active materials on the current machine.
materials = None
# Check to make sure the imported profile actually makes sense in context of the current configuration. # Check to make sure the imported profile actually makes sense in context of the current configuration.
# This prevents issues where importing a "draft" profile for a machine without "draft" qualities would report as # This prevents issues where importing a "draft" profile for a machine without "draft" qualities would report as

View File

@ -39,8 +39,6 @@ if TYPE_CHECKING:
from cura.Settings.CuraContainerStack import CuraContainerStack from cura.Settings.CuraContainerStack import CuraContainerStack
from cura.Settings.GlobalStack import GlobalStack from cura.Settings.GlobalStack import GlobalStack
import os
class MachineManager(QObject): class MachineManager(QObject):
def __init__(self, parent = None): def __init__(self, parent = None):
@ -49,6 +47,11 @@ class MachineManager(QObject):
self._active_container_stack = None # type: CuraContainerStack self._active_container_stack = None # type: CuraContainerStack
self._global_container_stack = None # type: GlobalStack self._global_container_stack = None # type: GlobalStack
# Used to store the new containers until after confirming the dialog
self._new_variant_container = None
self._new_material_container = None
self._new_quality_containers = []
self._error_check_timer = QTimer() self._error_check_timer = QTimer()
self._error_check_timer.setInterval(250) self._error_check_timer.setInterval(250)
self._error_check_timer.setSingleShot(True) self._error_check_timer.setSingleShot(True)
@ -60,6 +63,7 @@ class MachineManager(QObject):
self._instance_container_timer.timeout.connect(self.__onInstanceContainersChanged) self._instance_container_timer.timeout.connect(self.__onInstanceContainersChanged)
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged) Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
## When the global container is changed, active material probably needs to be updated. ## When the global container is changed, active material probably needs to be updated.
self.globalContainerChanged.connect(self.activeMaterialChanged) self.globalContainerChanged.connect(self.activeMaterialChanged)
self.globalContainerChanged.connect(self.activeVariantChanged) self.globalContainerChanged.connect(self.activeVariantChanged)
@ -67,10 +71,10 @@ class MachineManager(QObject):
self._stacks_have_errors = None self._stacks_have_errors = None
self._empty_variant_container = ContainerRegistry.getInstance().getEmptyInstanceContainer() self._empty_variant_container = ContainerRegistry.getInstance().findContainers(id = "empty_variant")[0]
self._empty_material_container = ContainerRegistry.getInstance().getEmptyInstanceContainer() self._empty_material_container = ContainerRegistry.getInstance().findContainers(id = "empty_material")[0]
self._empty_quality_container = ContainerRegistry.getInstance().getEmptyInstanceContainer() self._empty_quality_container = ContainerRegistry.getInstance().findContainers(id = "empty_quality")[0]
self._empty_quality_changes_container = ContainerRegistry.getInstance().getEmptyInstanceContainer() self._empty_quality_changes_container = ContainerRegistry.getInstance().findContainers(id = "empty_quality_changes")[0]
self._onGlobalContainerChanged() self._onGlobalContainerChanged()
@ -86,6 +90,9 @@ class MachineManager(QObject):
ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeStackChanged) ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeStackChanged)
self.activeStackChanged.connect(self.activeStackValueChanged) self.activeStackChanged.connect(self.activeStackValueChanged)
# when a user closed dialog check if any delayed material or variant changes need to be applied
Application.getInstance().onDiscardOrKeepProfileChangesClosed.connect(self._executeDelayedActiveContainerStackChanges)
Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_machine", "")
self._global_event_keys = set() self._global_event_keys = set()
@ -141,6 +148,14 @@ class MachineManager(QObject):
self.outputDevicesChanged.emit() self.outputDevicesChanged.emit()
@property
def newVariant(self):
return self._new_variant_container
@property
def newMaterial(self):
return self._new_material_container
@pyqtProperty("QVariantList", notify = outputDevicesChanged) @pyqtProperty("QVariantList", notify = outputDevicesChanged)
def printerOutputDevices(self): def printerOutputDevices(self):
return self._printer_output_devices return self._printer_output_devices
@ -335,6 +350,7 @@ class MachineManager(QObject):
self.activeQualityChanged.emit() self.activeQualityChanged.emit()
self.activeVariantChanged.emit() self.activeVariantChanged.emit()
self.activeMaterialChanged.emit() self.activeMaterialChanged.emit()
self._updateStacksHaveErrors() # Prevents unwanted re-slices after changing machine
self._error_check_timer.start() self._error_check_timer.start()
def _onInstanceContainersChanged(self, container): def _onInstanceContainersChanged(self, container):
@ -351,6 +367,8 @@ class MachineManager(QObject):
@pyqtSlot(str) @pyqtSlot(str)
def setActiveMachine(self, stack_id: str) -> None: def setActiveMachine(self, stack_id: str) -> None:
self.blurSettings.emit() # Ensure no-one has focus. self.blurSettings.emit() # Ensure no-one has focus.
self._cancelDelayedActiveContainerStackChanges()
containers = ContainerRegistry.getInstance().findContainerStacks(id = stack_id) containers = ContainerRegistry.getInstance().findContainerStacks(id = stack_id)
if containers: if containers:
Application.getInstance().setGlobalContainerStack(containers[0]) Application.getInstance().setGlobalContainerStack(containers[0])
@ -413,42 +431,6 @@ class MachineManager(QObject):
return False return False
## Check whether user containers have adjusted settings or not
# \param skip_keys \type{list} List of setting keys which will be not taken into account ("support_enable" , "infill_sparse_density"...)
# \return \type{boole} Return true if user containers have any of adjusted settings
@pyqtSlot("QVariantList", result = bool)
def hasUserCustomSettings(self, skip_keys = []) -> bool:
user_setting_keys = []
try:
if not self._global_container_stack:
return False
allContainers = self._global_container_stack.getContainers()
for container in allContainers:
meta = container.getMetaData()
if meta and meta["type"] and meta["type"] == "user":
user_setting_keys.extend(container.getAllKeys())
stacks = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
for stack in stacks:
for container in stack.getContainers():
meta = container.getMetaData()
if meta and meta["type"] and meta["type"] == "user":
user_setting_keys.extend(container.getAllKeys())
for skip_key in skip_keys:
if skip_key in user_setting_keys:
user_setting_keys.remove(skip_key)
except:
Logger.log("e", "While checking user custom settings occured error. skip_keys: %s", skip_keys )
return False
return len(user_setting_keys) > 0
@pyqtProperty(int, notify = activeStackValueChanged) @pyqtProperty(int, notify = activeStackValueChanged)
def numUserSettings(self) -> int: def numUserSettings(self) -> int:
if not self._global_container_stack: if not self._global_container_stack:
@ -785,7 +767,7 @@ class MachineManager(QObject):
self.blurSettings.emit() self.blurSettings.emit()
old_material.nameChanged.disconnect(self._onMaterialNameChanged) old_material.nameChanged.disconnect(self._onMaterialNameChanged)
self._active_container_stack.material = material_container self._new_material_container = material_container # self._active_container_stack will be updated with a delay
Logger.log("d", "Active material changed") Logger.log("d", "Active material changed")
material_container.nameChanged.connect(self._onMaterialNameChanged) material_container.nameChanged.connect(self._onMaterialNameChanged)
@ -839,13 +821,13 @@ class MachineManager(QObject):
old_material = self._active_container_stack.material old_material = self._active_container_stack.material
if old_variant: if old_variant:
self.blurSettings.emit() self.blurSettings.emit()
self._active_container_stack.variant = containers[0] self._new_variant_container = containers[0] # self._active_container_stack will be updated with a delay
Logger.log("d", "Active variant changed to {active_variant_id}".format(active_variant_id = containers[0].getId())) Logger.log("d", "Active variant changed to {active_variant_id}".format(active_variant_id = containers[0].getId()))
preferred_material_name = None preferred_material_name = None
if old_material: if old_material:
preferred_material_name = old_material.getName() preferred_material_name = old_material.getName()
preferred_material_id = self._updateMaterialContainer(self._global_container_stack.getBottom(), self._global_container_stack, containers[0], preferred_material_name).id
self.setActiveMaterial(self._updateMaterialContainer(self._global_container_stack.getBottom(), self._global_container_stack, containers[0], preferred_material_name).id) self.setActiveMaterial(preferred_material_id)
else: else:
Logger.log("w", "While trying to set the active variant, no variant was found to replace.") Logger.log("w", "While trying to set the active variant, no variant was found to replace.")
@ -860,8 +842,6 @@ class MachineManager(QObject):
if not containers or not self._global_container_stack: if not containers or not self._global_container_stack:
return return
Logger.log("d", "Attempting to change the active quality to %s", quality_id)
# Quality profile come in two flavours: type=quality and type=quality_changes # Quality profile come in two flavours: type=quality and type=quality_changes
# If we found a quality_changes profile then look up its parent quality profile. # If we found a quality_changes profile then look up its parent quality profile.
container_type = containers[0].getMetaDataEntry("type") container_type = containers[0].getMetaDataEntry("type")
@ -881,30 +861,79 @@ class MachineManager(QObject):
if new_quality_settings_list is None: if new_quality_settings_list is None:
return return
name_changed_connect_stacks = [] # Connect these stacks to the name changed callback # check if any of the stacks have a not supported profile
# if that is the case, all stacks should have a not supported state (otherwise it will show quality_type normal)
has_not_supported_quality = False
# check all stacks for not supported
for setting_info in new_quality_settings_list:
if setting_info["quality"].getMetaDataEntry("quality_type") == "not_supported":
has_not_supported_quality = True
break
# set all stacks to not supported if that's the case
if has_not_supported_quality:
for setting_info in new_quality_settings_list:
setting_info["quality"] = self._empty_quality_container
self._new_quality_containers.clear()
# store the upcoming quality profile changes per stack for later execution
# this prevents re-slicing before the user has made a choice in the discard or keep dialog
# (see _executeDelayedActiveContainerStackChanges)
for setting_info in new_quality_settings_list: for setting_info in new_quality_settings_list:
stack = setting_info["stack"] stack = setting_info["stack"]
stack_quality = setting_info["quality"] stack_quality = setting_info["quality"]
stack_quality_changes = setting_info["quality_changes"] stack_quality_changes = setting_info["quality_changes"]
name_changed_connect_stacks.append(stack_quality) self._new_quality_containers.append({
name_changed_connect_stacks.append(stack_quality_changes) "stack": stack,
self._replaceQualityOrQualityChangesInStack(stack, stack_quality, postpone_emit=True) "quality": stack_quality,
self._replaceQualityOrQualityChangesInStack(stack, stack_quality_changes, postpone_emit=True) "quality_changes": stack_quality_changes
})
# Send emits that are postponed in replaceContainer. has_user_interaction = False
# Here the stacks are finished replacing and every value can be resolved based on the current state.
for setting_info in new_quality_settings_list:
setting_info["stack"].sendPostponedEmits()
# Connect to onQualityNameChanged
for stack in name_changed_connect_stacks:
stack.nameChanged.connect(self._onQualityNameChanged)
if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1: if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1:
self._askUserToKeepOrClearCurrentSettings() # Show the keep/discard user settings dialog
has_user_interaction = Application.getInstance().discardOrKeepProfileChanges()
self.activeQualityChanged.emit() # If there is no interaction with the user (it means the dialog showing "keep" or "discard" was not shown)
# because either there are not user changes or because the used already decided to always keep or discard,
# then the quality instance container is replaced, in which case, the activeQualityChanged signal is emitted.
if not has_user_interaction:
self._executeDelayedActiveContainerStackChanges()
## Used to update material and variant in the active container stack with a delay.
# This delay prevents the stack from triggering a lot of signals (eventually resulting in slicing)
# before the user decided to keep or discard any of their changes using the dialog.
# The Application.onDiscardOrKeepProfileChangesClosed signal triggers this method.
def _executeDelayedActiveContainerStackChanges(self):
if self._new_variant_container is not None:
self._active_container_stack.variant = self._new_variant_container
self._new_variant_container = None
if self._new_material_container is not None:
self._active_container_stack.material = self._new_material_container
self._new_material_container = None
# apply the new quality to all stacks
if self._new_quality_containers:
for new_quality in self._new_quality_containers:
self._replaceQualityOrQualityChangesInStack(new_quality["stack"], new_quality["quality"], postpone_emit = True)
self._replaceQualityOrQualityChangesInStack(new_quality["stack"], new_quality["quality_changes"], postpone_emit = True)
for new_quality in self._new_quality_containers:
new_quality["stack"].nameChanged.connect(self._onQualityNameChanged)
new_quality["stack"].sendPostponedEmits() # Send the signals that were postponed in _replaceQualityOrQualityChangesInStack
self._new_quality_containers.clear()
## Cancel set changes for material and variant in the active container stack.
# Used for ignoring any changes when switching between printers (setActiveMachine)
def _cancelDelayedActiveContainerStackChanges(self):
self._new_material_container = None
self._new_variant_container = None
## Determine the quality and quality changes settings for the current machine for a quality name. ## Determine the quality and quality changes settings for the current machine for a quality name.
# #
@ -928,8 +957,14 @@ class MachineManager(QObject):
for stack in stacks: for stack in stacks:
material = stack.material material = stack.material
# TODO: fix this
if self._new_material_container and stack.getId() == self._active_container_stack.getId():
material = self._new_material_container
quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material]) quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])
if not quality: #No quality profile is found for this quality type. if not quality:
# No quality profile is found for this quality type.
quality = self._empty_quality_container quality = self._empty_quality_container
result.append({"stack": stack, "quality": quality, "quality_changes": empty_quality_changes}) result.append({"stack": stack, "quality": quality, "quality_changes": empty_quality_changes})
@ -964,8 +999,12 @@ class MachineManager(QObject):
else: else:
Logger.log("e", "Could not find the global quality changes container with name %s", quality_changes_name) Logger.log("e", "Could not find the global quality changes container with name %s", quality_changes_name)
return None return None
material = global_container_stack.material material = global_container_stack.material
if self._new_material_container and self._active_container_stack.getId() == global_container_stack.getId():
material = self._new_material_container
# For the global stack, find a quality which matches the quality_type in # For the global stack, find a quality which matches the quality_type in
# the quality changes profile and also satisfies any material constraints. # the quality changes profile and also satisfies any material constraints.
quality_type = global_quality_changes.getMetaDataEntry("quality_type") quality_type = global_quality_changes.getMetaDataEntry("quality_type")
@ -992,6 +1031,10 @@ class MachineManager(QObject):
quality_changes = self._empty_quality_changes_container quality_changes = self._empty_quality_changes_container
material = stack.material material = stack.material
if self._new_material_container and self._active_container_stack.getId() == stack.getId():
material = self._new_material_container
quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material]) quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])
if not quality: #No quality profile found for this quality type. if not quality: #No quality profile found for this quality type.
quality = self._empty_quality_container quality = self._empty_quality_container
@ -1023,9 +1066,6 @@ class MachineManager(QObject):
stack.qualityChanges.nameChanged.connect(self._onQualityNameChanged) stack.qualityChanges.nameChanged.connect(self._onQualityNameChanged)
self._onQualityNameChanged() self._onQualityNameChanged()
def _askUserToKeepOrClearCurrentSettings(self):
Application.getInstance().discardOrKeepProfileChanges()
@pyqtProperty(str, notify = activeVariantChanged) @pyqtProperty(str, notify = activeVariantChanged)
def activeVariantName(self) -> str: def activeVariantName(self) -> str:
if self._active_container_stack: if self._active_container_stack:

View File

@ -61,6 +61,7 @@ class ProfilesModel(InstanceContainersModel):
active_extruder = extruder_manager.getActiveExtruderStack() active_extruder = extruder_manager.getActiveExtruderStack()
extruder_stacks = extruder_manager.getActiveExtruderStacks() extruder_stacks = extruder_manager.getActiveExtruderStacks()
materials = [global_container_stack.material] materials = [global_container_stack.material]
if active_extruder in extruder_stacks: if active_extruder in extruder_stacks:
extruder_stacks.remove(active_extruder) extruder_stacks.remove(active_extruder)
extruder_stacks = [active_extruder] + extruder_stacks extruder_stacks = [active_extruder] + extruder_stacks
@ -83,21 +84,30 @@ class ProfilesModel(InstanceContainersModel):
if quality.getMetaDataEntry("quality_type") not in quality_type_set: if quality.getMetaDataEntry("quality_type") not in quality_type_set:
result.append(quality) result.append(quality)
# if still profiles are found, add a single empty_quality ("Not supported") instance to the drop down list
if len(result) == 0:
# If not qualities are found we dynamically create a not supported container for this machine + material combination
not_supported_container = ContainerRegistry.getInstance().findContainers(id = "empty_quality")[0]
result.append(not_supported_container)
return result return result
## Re-computes the items in this model, and adds the layer height role. ## Re-computes the items in this model, and adds the layer height role.
def _recomputeItems(self): def _recomputeItems(self):
#Some globals that we can re-use.
# Some globals that we can re-use.
global_container_stack = Application.getInstance().getGlobalContainerStack() global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack is None: if global_container_stack is None:
return return
# Detecting if the machine has multiple extrusion # Detecting if the machine has multiple extrusion
multiple_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1 multiple_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
# Get the list of extruders and place the selected extruder at the front of the list. # Get the list of extruders and place the selected extruder at the front of the list.
extruder_manager = ExtruderManager.getInstance() extruder_manager = ExtruderManager.getInstance()
active_extruder = extruder_manager.getActiveExtruderStack() active_extruder = extruder_manager.getActiveExtruderStack()
extruder_stacks = extruder_manager.getActiveExtruderStacks() extruder_stacks = extruder_manager.getActiveExtruderStacks()
if multiple_extrusion: if multiple_extrusion:
# Place the active extruder at the front of the list. # Place the active extruder at the front of the list.
# This is a workaround checking if there is an active_extruder or not before moving it to the front of the list. # This is a workaround checking if there is an active_extruder or not before moving it to the front of the list.
@ -111,8 +121,7 @@ class ProfilesModel(InstanceContainersModel):
extruder_stacks = new_extruder_stacks + extruder_stacks extruder_stacks = new_extruder_stacks + extruder_stacks
# Get a list of usable/available qualities for this machine and material # Get a list of usable/available qualities for this machine and material
qualities = QualityManager.getInstance().findAllUsableQualitiesForMachineAndExtruders(global_container_stack, qualities = QualityManager.getInstance().findAllUsableQualitiesForMachineAndExtruders(global_container_stack, extruder_stacks)
extruder_stacks)
container_registry = ContainerRegistry.getInstance() container_registry = ContainerRegistry.getInstance()
machine_manager = Application.getInstance().getMachineManager() machine_manager = Application.getInstance().getMachineManager()
@ -155,14 +164,24 @@ class ProfilesModel(InstanceContainersModel):
# Now all the containers are set # Now all the containers are set
for item in containers: for item in containers:
profile = container_registry.findContainers(id=item["id"]) profile = container_registry.findContainers(id = item["id"])
# When for some reason there is no profile container in the registry
if not profile: if not profile:
self._setItemLayerHeight(item, "", unit) self._setItemLayerHeight(item, "", "")
item["available"] = False item["available"] = False
yield item yield item
continue continue
profile = profile[0] profile = profile[0]
# When there is a profile but it's an empty quality should. It's shown in the list (they are "Not Supported" profiles)
if profile.getId() == "empty_quality":
self._setItemLayerHeight(item, "", "")
item["available"] = True
yield item
continue
item["available"] = profile in qualities item["available"] = profile in qualities
# Easy case: This profile defines its own layer height. # Easy case: This profile defines its own layer height.
@ -179,9 +198,10 @@ class ProfilesModel(InstanceContainersModel):
if quality_result["stack"] is global_container_stack: if quality_result["stack"] is global_container_stack:
quality = quality_result["quality"] quality = quality_result["quality"]
break break
else: #No global container stack in the results: else:
# No global container stack in the results:
if quality_results: if quality_results:
quality = quality_results[0]["quality"] #Take any of the extruders. quality = quality_results[0]["quality"] # Take any of the extruders.
else: else:
quality = None quality = None
if quality and quality.hasProperty("layer_height", "value"): if quality and quality.hasProperty("layer_height", "value"):
@ -189,7 +209,7 @@ class ProfilesModel(InstanceContainersModel):
yield item yield item
continue continue
#Quality has no value for layer height either. Get the layer height from somewhere lower in the stack. # Quality has no value for layer height either. Get the layer height from somewhere lower in the stack.
skip_until_container = global_container_stack.material skip_until_container = global_container_stack.material
if not skip_until_container or skip_until_container == ContainerRegistry.getInstance().getEmptyInstanceContainer(): #No material in stack. if not skip_until_container or skip_until_container == ContainerRegistry.getInstance().getEmptyInstanceContainer(): #No material in stack.
skip_until_container = global_container_stack.variant skip_until_container = global_container_stack.variant

View File

@ -58,8 +58,8 @@ class QualityAndUserProfilesModel(ProfilesModel):
# If the printer has multiple extruders then quality changes related to the current extruder are kept # If the printer has multiple extruders then quality changes related to the current extruder are kept
filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and
qc.getMetaDataEntry("extruder") is not None and qc.getMetaDataEntry("extruder") is not None and
qc.getMetaDataEntry("extruder") == active_extruder.definition.getMetaDataEntry("quality_definition") or (qc.getMetaDataEntry("extruder") == active_extruder.definition.getMetaDataEntry("quality_definition") or
qc.getMetaDataEntry("extruder") == active_extruder.definition.getId()] qc.getMetaDataEntry("extruder") == active_extruder.definition.getId())]
else: else:
# If not, the quality changes of the global stack are selected # If not, the quality changes of the global stack are selected
filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and

View File

@ -0,0 +1,92 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty
from UM.Application import Application
class SimpleModeSettingsManager(QObject):
def __init__(self, parent = None):
super().__init__(parent)
self._machine_manager = Application.getInstance().getMachineManager()
self._is_profile_customized = False # True when default profile has user changes
self._is_profile_user_created = False # True when profile was custom created by user
self._machine_manager.activeStackValueChanged.connect(self._updateIsProfileCustomized)
self._machine_manager.activeQualityChanged.connect(self._updateIsProfileUserCreated)
# update on create as the activeQualityChanged signal is emitted before this manager is created when Cura starts
self._updateIsProfileCustomized()
self._updateIsProfileUserCreated()
isProfileCustomizedChanged = pyqtSignal()
isProfileUserCreatedChanged = pyqtSignal()
@pyqtProperty(bool, notify = isProfileCustomizedChanged)
def isProfileCustomized(self):
return self._is_profile_customized
def _updateIsProfileCustomized(self):
user_setting_keys = set()
if not self._machine_manager.activeMachine:
return False
global_stack = self._machine_manager.activeMachine
# check user settings in the global stack
user_setting_keys.update(set(global_stack.userChanges.getAllKeys()))
# check user settings in the extruder stacks
if global_stack.extruders:
for extruder_stack in global_stack.extruders.values():
user_setting_keys.update(set(extruder_stack.userChanges.getAllKeys()))
# remove settings that are visible in recommended (we don't show the reset button for those)
for skip_key in self.__ignored_custom_setting_keys:
if skip_key in user_setting_keys:
user_setting_keys.remove(skip_key)
has_customized_user_settings = len(user_setting_keys) > 0
if has_customized_user_settings != self._is_profile_customized:
self._is_profile_customized = has_customized_user_settings
self.isProfileCustomizedChanged.emit()
@pyqtProperty(bool, notify = isProfileUserCreatedChanged)
def isProfileUserCreated(self):
return self._is_profile_user_created
def _updateIsProfileUserCreated(self):
quality_changes_keys = set()
if not self._machine_manager.activeMachine:
return False
global_stack = self._machine_manager.activeMachine
# check quality changes settings in the global stack
quality_changes_keys.update(set(global_stack.qualityChanges.getAllKeys()))
# check quality changes settings in the extruder stacks
if global_stack.extruders:
for extruder_stack in global_stack.extruders.values():
quality_changes_keys.update(set(extruder_stack.qualityChanges.getAllKeys()))
# check if the qualityChanges container is not empty (meaning it is a user created profile)
has_quality_changes = len(quality_changes_keys) > 0
if has_quality_changes != self._is_profile_user_created:
self._is_profile_user_created = has_quality_changes
self.isProfileUserCreatedChanged.emit()
# These are the settings included in the Simple ("Recommended") Mode, so only when the other settings have been
# changed, we consider it as a user customized profile in the Simple ("Recommended") Mode.
__ignored_custom_setting_keys = ["support_enable",
"infill_sparse_density",
"gradual_infill_steps",
"adhesion_type",
"support_extruder_nr"]

View File

@ -21,6 +21,8 @@ from cura.Settings.CuraStackBuilder import CuraStackBuilder
from cura.Settings.ExtruderManager import ExtruderManager from cura.Settings.ExtruderManager import ExtruderManager
from cura.Settings.ExtruderStack import ExtruderStack from cura.Settings.ExtruderStack import ExtruderStack
from cura.Settings.GlobalStack import GlobalStack from cura.Settings.GlobalStack import GlobalStack
from cura.Settings.CuraContainerStack import _ContainerIndexes
from cura.QualityManager import QualityManager
from configparser import ConfigParser from configparser import ConfigParser
import zipfile import zipfile
@ -757,13 +759,37 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._container_registry.removeContainer(container.getId()) self._container_registry.removeContainer(container.getId())
return return
# Check quality profiles to make sure that if one stack has the "not supported" quality profile,
# all others should have the same.
#
# This block code tries to fix the following problems in Cura 3.0 and earlier:
# 1. The upgrade script can rename all "Not Supported" quality profiles to "empty_quality", but it cannot fix
# the problem that the global stack the extruder stacks may have different quality profiles. The code
# below loops over all stacks and make sure that if there is one stack with "Not Supported" profile, the
# rest should also use the "Not Supported" profile.
# 2. In earlier versions (at least 2.7 and 3.0), a wrong quality profile could be assigned to a stack. For
# example, a UM3 can have a BB 0.8 variant with "aa04_pla_fast" quality profile enabled. To fix this,
# in the code below we also check the actual available quality profiles for the machine.
#
has_not_supported = False
for stack in [global_stack] + extruder_stacks:
if stack.quality.getId() == "empty_quality":
has_not_supported = True
break
if not has_not_supported:
available_quality = QualityManager.getInstance().findAllUsableQualitiesForMachineAndExtruders(global_stack, extruder_stacks)
has_not_supported = not available_quality
if has_not_supported:
empty_quality_container = self._container_registry.findInstanceContainers(id = "empty_quality")[0]
for stack in [global_stack] + extruder_stacks:
stack.replaceContainer(_ContainerIndexes.Quality, empty_quality_container)
# #
# Replacing the old containers if resolve is "new". # Replacing the old containers if resolve is "new".
# When resolve is "new", some containers will get renamed, so all the other containers that reference to those # When resolve is "new", some containers will get renamed, so all the other containers that reference to those
# MUST get updated too. # MUST get updated too.
# #
if self._resolve_strategies["machine"] == "new": if self._resolve_strategies["machine"] == "new":
# A new machine was made, but it was serialized with the wrong user container. Fix that now. # A new machine was made, but it was serialized with the wrong user container. Fix that now.
for container in user_instance_containers: for container in user_instance_containers:
# replacing the container ID for user instance containers for the extruders # replacing the container ID for user instance containers for the extruders

View File

@ -8,7 +8,6 @@ from UM.Application import Application
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from UM.Version import Version from UM.Version import Version
from PyQt5.QtQuick import QQuickView
from PyQt5.QtQml import QQmlComponent, QQmlContext from PyQt5.QtQml import QQmlComponent, QQmlContext
from PyQt5.QtCore import QUrl, pyqtSlot, QObject from PyQt5.QtCore import QUrl, pyqtSlot, QObject

View File

@ -1,3 +1,13 @@
[3.0.4]
*Bug fixes
- Fixed OpenGL issue that prevents Cura from starting.
*License agreement on the first startup has been added
[3.0.3]
*Bug fixes
- Add missing libraries for the MakePrintable plugin.
[3.0.0] [3.0.0]
*Faster start-up *Faster start-up
Start-up speed has been cut in half compared to the previous version. Start-up speed has been cut in half compared to the previous version.

View File

@ -240,3 +240,4 @@ class ProcessSlicedLayersJob(Job):
else: else:
if self._progress_message: if self._progress_message:
self._progress_message.hide() self._progress_message.hide()

View File

@ -48,7 +48,7 @@ UM.PointingRectangle {
anchors { anchors {
left: parent.left left: parent.left
leftMargin: UM.Theme.getSize("default_margin").width / 2 leftMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2)
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
@ -90,7 +90,7 @@ UM.PointingRectangle {
anchors { anchors {
left: parent.right left: parent.right
leftMargin: UM.Theme.getSize("default_margin").width / 2 leftMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2)
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }

View File

@ -147,6 +147,7 @@ class MachineSettingsAction(MachineAction):
for setting_instance in extruder_user_container.findInstances(): for setting_instance in extruder_user_container.findInstances():
setting_key = setting_instance.definition.key setting_key = setting_instance.definition.key
settable_per_extruder = self._global_container_stack.getProperty(setting_key, "settable_per_extruder") settable_per_extruder = self._global_container_stack.getProperty(setting_key, "settable_per_extruder")
if settable_per_extruder: if settable_per_extruder:
limit_to_extruder = self._global_container_stack.getProperty(setting_key, "limit_to_extruder") limit_to_extruder = self._global_container_stack.getProperty(setting_key, "limit_to_extruder")
@ -154,11 +155,16 @@ class MachineSettingsAction(MachineAction):
global_user_container.setProperty(setting_key, "value", extruder_user_container.getProperty(setting_key, "value")) global_user_container.setProperty(setting_key, "value", extruder_user_container.getProperty(setting_key, "value"))
extruder_user_container.removeInstance(setting_key) extruder_user_container.removeInstance(setting_key)
# Check to see if any features are set to print with an extruder that will no longer exist # reset all extruder number settings whose value is no longer valid
for setting_key in ["adhesion_extruder_nr", "support_extruder_nr", "support_extruder_nr_layer_0", "support_infill_extruder_nr", "support_interface_extruder_nr"]: for setting_instance in self._global_container_stack.userChanges.findInstances():
if int(self._global_container_stack.getProperty(setting_key, "value")) > extruder_count - 1: setting_key = setting_instance.definition.key
Logger.log("i", "Lowering %s setting to match number of extruders", setting_key) if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"):
self._global_container_stack.getTop().setProperty(setting_key, "value", extruder_count - 1) continue
old_value = int(self._global_container_stack.userChanges.getProperty(setting_key, "value"))
if old_value >= extruder_count:
self._global_container_stack.userChanges.removeInstance(setting_key)
Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid ", setting_key, old_value)
# Check to see if any objects are set to print with an extruder that will no longer exist # Check to see if any objects are set to print with an extruder that will no longer exist
root_node = Application.getInstance().getController().getScene().getRoot() root_node = Application.getInstance().getController().getScene().getRoot()

View File

@ -26,7 +26,7 @@ class PluginBrowser(QObject, Extension):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self._api_version = 1 self._api_version = 2
self._api_url = "http://software.ultimaker.com/cura/v%s/" % self._api_version self._api_url = "http://software.ultimaker.com/cura/v%s/" % self._api_version
self._plugin_list_request = None self._plugin_list_request = None

View File

@ -114,7 +114,7 @@ UM.Dialog
anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.rightMargin: UM.Theme.getSize("default_margin").width
Label Label
{ {
text: "<b>" + model.name + "</b> - " + model.author text: "<b>" + model.name + "</b>" + ((model.author !== "") ? (" - " + model.author) : "")
width: contentWidth width: contentWidth
height: contentHeight + UM.Theme.getSize("default_margin").height height: contentHeight + UM.Theme.getSize("default_margin").height
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter

View File

@ -83,8 +83,7 @@ Component
anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.rightMargin: UM.Theme.getSize("default_margin").width
//TODO; It's probably nicer to do this with a dynamic data model instead of hardcoding this.
//But you know the drill; time constraints don't result in elegant code.
Item Item
{ {
width: parent.width width: parent.width

View File

@ -114,7 +114,7 @@ Cura.MachineAction
Column Column
{ {
width: (parent.width * 0.5) | 0 width: Math.floor(parent.width * 0.5)
spacing: UM.Theme.getSize("default_margin").height spacing: UM.Theme.getSize("default_margin").height
ScrollView ScrollView
@ -191,8 +191,6 @@ Cura.MachineAction
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
//: Tips label
//TODO: get actual link from webteam
text: catalog.i18nc("@label", "If your printer is not listed, read the <a href='%1'>network printing troubleshooting guide</a>").arg("https://ultimaker.com/en/troubleshooting"); text: catalog.i18nc("@label", "If your printer is not listed, read the <a href='%1'>network printing troubleshooting guide</a>").arg("https://ultimaker.com/en/troubleshooting");
onLinkActivated: Qt.openUrlExternally(link) onLinkActivated: Qt.openUrlExternally(link)
} }
@ -200,7 +198,7 @@ Cura.MachineAction
} }
Column Column
{ {
width: (parent.width * 0.5) | 0 width: Math.floor(parent.width * 0.5)
visible: base.selectedPrinter ? true : false visible: base.selectedPrinter ? true : false
spacing: UM.Theme.getSize("default_margin").height spacing: UM.Theme.getSize("default_margin").height
Label Label
@ -218,13 +216,13 @@ Cura.MachineAction
columns: 2 columns: 2
Label Label
{ {
width: (parent.width * 0.5) | 0 width: Math.floor(parent.width * 0.5)
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "Type") text: catalog.i18nc("@label", "Type")
} }
Label Label
{ {
width: (parent.width * 0.5) | 0 width: Math.floor(parent.width * 0.5)
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: text:
{ {
@ -249,25 +247,25 @@ Cura.MachineAction
} }
Label Label
{ {
width: (parent.width * 0.5) | 0 width: Math.floor(parent.width * 0.5)
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "Firmware version") text: catalog.i18nc("@label", "Firmware version")
} }
Label Label
{ {
width: (parent.width * 0.5) | 0 width: Math.floor(parent.width * 0.5)
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: base.selectedPrinter ? base.selectedPrinter.firmwareVersion : "" text: base.selectedPrinter ? base.selectedPrinter.firmwareVersion : ""
} }
Label Label
{ {
width: (parent.width * 0.5) | 0 width: Math.floor(parent.width * 0.5)
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "Address") text: catalog.i18nc("@label", "Address")
} }
Label Label
{ {
width: (parent.width * 0.5) | 0 width: Math.floor(parent.width * 0.5)
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: base.selectedPrinter ? base.selectedPrinter.ipAddress : "" text: base.selectedPrinter ? base.selectedPrinter.ipAddress : ""
} }

View File

@ -17,10 +17,10 @@ Component
} }
return (sourceSize.width / sourceSize.height) > (maximumWidth / maximumHeight); return (sourceSize.width / sourceSize.height) > (maximumWidth / maximumHeight);
} }
property real _width: Math.min(maximumWidth, sourceSize.width) property real _width: Math.floor(Math.min(maximumWidth, sourceSize.width))
property real _height: Math.min(maximumHeight, sourceSize.height) property real _height: Math.floor(Math.min(maximumHeight, sourceSize.height))
width: proportionalHeight ? _width : sourceSize.width * _height / sourceSize.height width: proportionalHeight ? _width : Math.floor(sourceSize.width * _height / sourceSize.height)
height: !proportionalHeight ? _height : sourceSize.height * _width / sourceSize.width height: !proportionalHeight ? _height : Math.floor(sourceSize.height * _width / sourceSize.width)
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
onVisibleChanged: onVisibleChanged:

View File

@ -220,7 +220,9 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
self.setPrinters(json_data) self.setPrinters(json_data)
def materialHotendChangedMessage(self, callback): def materialHotendChangedMessage(self, callback):
pass # Do nothing. # When there is just one printer, the activate configuration option is enabled
if (self._cluster_size == 1):
super().materialHotendChangedMessage(callback = callback)
def _startCameraStream(self): def _startCameraStream(self):
## Request new image ## Request new image

View File

@ -1,19 +1,18 @@
# Copyright (c) 2017 Ultimaker B.V. # Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import os
import time import time
import json import json
from queue import Queue
from threading import Event, Thread
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot from PyQt5.QtCore import QObject, pyqtSlot
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QDesktopServices from PyQt5.QtGui import QDesktopServices
from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager, QNetworkReply from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager
from PyQt5.QtQml import QQmlComponent, QQmlContext
from UM.Application import Application from UM.Application import Application
from UM.Logger import Logger from UM.Logger import Logger
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from UM.PluginRegistry import PluginRegistry
from UM.Preferences import Preferences from UM.Preferences import Preferences
from UM.Signal import Signal, signalemitter from UM.Signal import Signal, signalemitter
from zeroconf import Zeroconf, ServiceBrowser, ServiceStateChange, ServiceInfo # type: ignore from zeroconf import Zeroconf, ServiceBrowser, ServiceStateChange, ServiceInfo # type: ignore
@ -57,6 +56,16 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
self._network_requests_buffer = {} # store api responses until data is complete self._network_requests_buffer = {} # store api responses until data is complete
# The zeroconf service changed requests are handled in a separate thread, so we can re-schedule the requests
# which fail to get detailed service info.
# Any new or re-scheduled requests will be appended to the request queue, and the handling thread will pick
# them up and process them.
self._service_changed_request_queue = Queue()
self._service_changed_request_event = Event()
self._service_changed_request_thread = Thread(target = self._handleOnServiceChangedRequests,
daemon = True)
self._service_changed_request_thread.start()
addPrinterSignal = Signal() addPrinterSignal = Signal()
removePrinterSignal = Signal() removePrinterSignal = Signal()
printerListChanged = Signal() printerListChanged = Signal()
@ -76,7 +85,7 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
# After network switching, one must make a new instance of Zeroconf # After network switching, one must make a new instance of Zeroconf
# On windows, the instance creation is very fast (unnoticable). Other platforms? # On windows, the instance creation is very fast (unnoticable). Other platforms?
self._zero_conf = Zeroconf() self._zero_conf = Zeroconf()
self._browser = ServiceBrowser(self._zero_conf, u'_ultimaker._tcp.local.', [self._onServiceChanged]) self._browser = ServiceBrowser(self._zero_conf, u'_ultimaker._tcp.local.', [self._appendServiceChangedRequest])
# Look for manual instances from preference # Look for manual instances from preference
for address in self._manual_instances: for address in self._manual_instances:
@ -265,7 +274,8 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
else: else:
self.getOutputDeviceManager().removeOutputDevice(key) self.getOutputDeviceManager().removeOutputDevice(key)
## Handler for zeroConf detection ## Handler for zeroConf detection.
# Return True or False indicating if the process succeeded.
def _onServiceChanged(self, zeroconf, service_type, name, state_change): def _onServiceChanged(self, zeroconf, service_type, name, state_change):
if state_change == ServiceStateChange.Added: if state_change == ServiceStateChange.Added:
Logger.log("d", "Bonjour service added: %s" % name) Logger.log("d", "Bonjour service added: %s" % name)
@ -295,11 +305,50 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
Logger.log("w", "The type of the found device is '%s', not 'printer'! Ignoring.." % type_of_device ) Logger.log("w", "The type of the found device is '%s', not 'printer'! Ignoring.." % type_of_device )
else: else:
Logger.log("w", "Could not get information about %s" % name) Logger.log("w", "Could not get information about %s" % name)
return False
elif state_change == ServiceStateChange.Removed: elif state_change == ServiceStateChange.Removed:
Logger.log("d", "Bonjour service removed: %s" % name) Logger.log("d", "Bonjour service removed: %s" % name)
self.removePrinterSignal.emit(str(name)) self.removePrinterSignal.emit(str(name))
return True
## Appends a service changed request so later the handling thread will pick it up and processes it.
def _appendServiceChangedRequest(self, zeroconf, service_type, name, state_change):
# append the request and set the event so the event handling thread can pick it up
item = (zeroconf, service_type, name, state_change)
self._service_changed_request_queue.put(item)
self._service_changed_request_event.set()
def _handleOnServiceChangedRequests(self):
while True:
# wait for the event to be set
self._service_changed_request_event.wait(timeout = 5.0)
# stop if the application is shutting down
if Application.getInstance().isShuttingDown():
return
self._service_changed_request_event.clear()
# handle all pending requests
reschedule_requests = [] # a list of requests that have failed so later they will get re-scheduled
while not self._service_changed_request_queue.empty():
request = self._service_changed_request_queue.get()
zeroconf, service_type, name, state_change = request
try:
result = self._onServiceChanged(zeroconf, service_type, name, state_change)
if not result:
reschedule_requests.append(request)
except Exception:
Logger.logException("e", "Failed to get service info for [%s] [%s], the request will be rescheduled",
service_type, name)
reschedule_requests.append(request)
# re-schedule the failed requests if any
if reschedule_requests:
for request in reschedule_requests:
self._service_changed_request_queue.put(request)
@pyqtSlot() @pyqtSlot()
def openControlPanel(self): def openControlPanel(self):
Logger.log("d", "Opening print jobs web UI...") Logger.log("d", "Opening print jobs web UI...")

View File

@ -10,7 +10,7 @@ Item
id: extruderInfo id: extruderInfo
property var printCoreConfiguration property var printCoreConfiguration
width: parent.width / 2 width: Math.floor(parent.width / 2)
height: childrenRect.height height: childrenRect.height
Label Label
{ {

View File

@ -86,7 +86,7 @@ Rectangle
Rectangle Rectangle
{ {
width: parent.width / 3 width: Math.floor(parent.width / 3)
height: parent.height height: parent.height
Label // Print job name Label // Print job name
@ -131,7 +131,7 @@ Rectangle
Rectangle Rectangle
{ {
width: parent.width / 3 * 2 width: Math.floor(parent.width / 3 * 2)
height: parent.height height: parent.height
Label // Friendly machine name Label // Friendly machine name
@ -139,7 +139,7 @@ Rectangle
id: printerNameLabel id: printerNameLabel
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
width: parent.width / 2 - UM.Theme.getSize("default_margin").width - showCameraIcon.width width: Math.floor(parent.width / 2 - UM.Theme.getSize("default_margin").width - showCameraIcon.width)
text: printer.friendly_name text: printer.friendly_name
font: UM.Theme.getFont("default_bold") font: UM.Theme.getFont("default_bold")
elide: Text.ElideRight elide: Text.ElideRight
@ -149,7 +149,7 @@ Rectangle
{ {
id: printerTypeLabel id: printerTypeLabel
anchors.top: printerNameLabel.bottom anchors.top: printerNameLabel.bottom
width: parent.width / 2 - UM.Theme.getSize("default_margin").width width: Math.floor(parent.width / 2 - UM.Theme.getSize("default_margin").width)
text: printer.machine_variant text: printer.machine_variant
anchors.left: parent.left anchors.left: parent.left
elide: Text.ElideRight elide: Text.ElideRight
@ -183,7 +183,7 @@ Rectangle
id: extruderInfo id: extruderInfo
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
width: parent.width / 2 - UM.Theme.getSize("default_margin").width width: Math.floor(parent.width / 2 - UM.Theme.getSize("default_margin").width)
height: childrenRect.height height: childrenRect.height
spacing: UM.Theme.getSize("default_margin").width spacing: UM.Theme.getSize("default_margin").width
@ -217,7 +217,7 @@ Rectangle
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
height: showExtended ? parent.height: printProgressTitleBar.height height: showExtended ? parent.height: printProgressTitleBar.height
width: parent.width / 2 - UM.Theme.getSize("default_margin").width width: Math.floor(parent.width / 2 - UM.Theme.getSize("default_margin").width)
border.width: UM.Theme.getSize("default_lining").width border.width: UM.Theme.getSize("default_lining").width
border.color: lineColor border.color: lineColor
radius: cornerRadius radius: cornerRadius

View File

@ -57,7 +57,7 @@ Item
{ {
id: cameraImage id: cameraImage
width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth) width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth)
height: (sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width height: Math.floor((sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width)
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
z: 1 z: 1

View File

@ -115,8 +115,22 @@ Item
{ {
tooltip: catalog.i18nc("@info:tooltip", "Load the configuration of the printer into Cura") tooltip: catalog.i18nc("@info:tooltip", "Load the configuration of the printer into Cura")
text: catalog.i18nc("@action:button", "Activate Configuration") text: catalog.i18nc("@action:button", "Activate Configuration")
visible: printerConnected visible: printerConnected && !isClusterPrinter()
onClicked: manager.loadConfigurationFromPrinter() onClicked: manager.loadConfigurationFromPrinter()
function isClusterPrinter() {
if(Cura.MachineManager.printerOutputDevices.length == 0)
{
return false;
}
var clusterSize = Cura.MachineManager.printerOutputDevices[0].clusterSize;
// This is not a cluster printer or the cluster it is just one printer
if(clusterSize == undefined || clusterSize == 1)
{
return false;
}
return true;
}
} }
} }

View File

@ -0,0 +1,53 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from UM.Extension import Extension
from UM.Preferences import Preferences
from UM.Application import Application
from UM.PluginRegistry import PluginRegistry
from UM.Logger import Logger
from cura.CuraApplication import CuraApplication
from PyQt5.QtQml import QQmlComponent, QQmlContext
from PyQt5.QtCore import QUrl, QObject, pyqtSlot
import os.path
class UserAgreement(QObject, Extension):
def __init__(self, parent = None):
super(UserAgreement, self).__init__()
self._user_agreement_window = None
self._user_agreement_context = None
Application.getInstance().engineCreatedSignal.connect(self._onEngineCreated)
Preferences.getInstance().addPreference("general/accepted_user_agreement", False)
def _onEngineCreated(self):
if not Preferences.getInstance().getValue("general/accepted_user_agreement"):
self.showUserAgreement()
def showUserAgreement(self):
if not self._user_agreement_window:
self.createUserAgreementWindow()
self._user_agreement_window.show()
@pyqtSlot(bool)
def didAgree(self, userChoice):
if userChoice:
Logger.log("i", "User agreed to the user agreement")
Preferences.getInstance().setValue("general/accepted_user_agreement", True)
self._user_agreement_window.hide()
else:
Logger.log("i", "User did NOT agree to the user agreement")
Preferences.getInstance().setValue("general/accepted_user_agreement", False)
CuraApplication.getInstance().quit()
CuraApplication.getInstance().setNeedToShowUserAgreement(False)
def createUserAgreementWindow(self):
path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "UserAgreement.qml"))
component = QQmlComponent(Application.getInstance()._engine, path)
self._user_agreement_context = QQmlContext(Application.getInstance()._engine.rootContext())
self._user_agreement_context.setContextProperty("manager", self)
self._user_agreement_window = component.create(self._user_agreement_context)

View File

@ -0,0 +1,64 @@
// Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.4
import UM 1.3 as UM
UM.Dialog
{
id: baseDialog
minimumWidth: Math.floor(UM.Theme.getSize("modal_window_minimum").width * 0.75)
minimumHeight: Math.floor(UM.Theme.getSize("modal_window_minimum").height * 0.5)
width: minimumWidth
height: minimumHeight
title: catalog.i18nc("@title:window", "User Agreement")
TextArea
{
anchors.top: parent.top
width: parent.width
anchors.bottom: buttonRow.top
text: ' <center><h3>DISCLAIMER BY ULTIMAKER</h3></center>
<p>PLEASE READ THIS DISCLAIMER CAREFULLY.</p>
<p>EXCEPT WHEN OTHERWISE STATED IN WRITING, ULTIMAKER PROVIDES ANY ULTIMAKER SOFTWARE OR THIRD PARTY SOFTWARE AS IS WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF ULTIMAKER SOFTWARE IS WITH YOU.</p>
<p>UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, IN NO EVENT WILL ULTIMAKER BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE ANY ULTIMAKER SOFTWARE OR THIRD PARTY SOFTWARE.</p>
'
readOnly: true;
textFormat: TextEdit.RichText
}
Item
{
id: buttonRow
anchors.bottom: parent.bottom
width: parent.width
anchors.bottomMargin: UM.Theme.getSize("default_margin").height
UM.I18nCatalog { id: catalog; name:"cura" }
Button
{
anchors.right: parent.right
text: catalog.i18nc("@action:button", "I understand and agree")
onClicked: {
manager.didAgree(true)
}
}
Button
{
anchors.left: parent.left
text: catalog.i18nc("@action:button", "I don't agree")
onClicked: {
manager.didAgree(false)
}
}
}
onClosing: {
manager.didAgree(false)
}
}

View File

@ -0,0 +1,10 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from . import UserAgreement
def getMetaData():
return {}
def register(app):
return {"extension": UserAgreement.UserAgreement()}

View File

@ -0,0 +1,8 @@
{
"name": "UserAgreement",
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Ask the user once if he/she agrees with our license",
"api": 4,
"i18n-catalog": "cura"
}

View File

@ -128,8 +128,8 @@ class VersionUpgrade27to30(VersionUpgrade):
# set machine definition to "ultimaker2" for the custom quality profiles that can be for the ultimaker 2 family # set machine definition to "ultimaker2" for the custom quality profiles that can be for the ultimaker 2 family
file_base_name = os.path.basename(filename) file_base_name = os.path.basename(filename)
is_ultimaker2_family = not any(file_base_name.startswith(ep) for ep in exclude_prefix_list) is_ultimaker2_family = False
if not is_ultimaker2_family: if not any(file_base_name.startswith(ep) for ep in exclude_prefix_list):
is_ultimaker2_family = any(file_base_name.startswith(ep) for ep in ultimaker2_prefix_list) is_ultimaker2_family = any(file_base_name.startswith(ep) for ep in ultimaker2_prefix_list)
# ultimaker2 family quality profiles used to set as "fdmprinter" profiles # ultimaker2 family quality profiles used to set as "fdmprinter" profiles

View File

@ -0,0 +1,141 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import configparser #To parse preference files.
import io #To serialise the preference files afterwards.
from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this.
# a list of all legacy "Not Supported" quality profiles
_OLD_NOT_SUPPORTED_PROFILES = [
"um2p_pp_0.25_normal",
"um2p_tpu_0.8_normal",
"um3_bb0.4_ABS_Fast_Print",
"um3_bb0.4_ABS_Superdraft_Print",
"um3_bb0.4_CPEP_Fast_Print",
"um3_bb0.4_CPEP_Superdraft_Print",
"um3_bb0.4_CPE_Fast_Print",
"um3_bb0.4_CPE_Superdraft_Print",
"um3_bb0.4_Nylon_Fast_Print",
"um3_bb0.4_Nylon_Superdraft_Print",
"um3_bb0.4_PC_Fast_Print",
"um3_bb0.4_PLA_Fast_Print",
"um3_bb0.4_PLA_Superdraft_Print",
"um3_bb0.4_PP_Fast_Print",
"um3_bb0.4_PP_Superdraft_Print",
"um3_bb0.4_TPU_Fast_Print",
"um3_bb0.4_TPU_Superdraft_Print",
"um3_bb0.8_ABS_Fast_Print",
"um3_bb0.8_ABS_Superdraft_Print",
"um3_bb0.8_CPEP_Fast_Print",
"um3_bb0.8_CPEP_Superdraft_Print",
"um3_bb0.8_CPE_Fast_Print",
"um3_bb0.8_CPE_Superdraft_Print",
"um3_bb0.8_Nylon_Fast_Print",
"um3_bb0.8_Nylon_Superdraft_Print",
"um3_bb0.8_PC_Fast_Print",
"um3_bb0.8_PC_Superdraft_Print",
"um3_bb0.8_PLA_Fast_Print",
"um3_bb0.8_PLA_Superdraft_Print",
"um3_bb0.8_PP_Fast_Print",
"um3_bb0.8_PP_Superdraft_Print",
"um3_bb0.8_TPU_Fast_print",
"um3_bb0.8_TPU_Superdraft_Print",
]
class VersionUpgrade30to31(VersionUpgrade):
## Gets the version number from a CFG file in Uranium's 3.0 format.
#
# Since the format may change, this is implemented for the 3.0 format only
# and needs to be included in the version upgrade system rather than
# globally in Uranium.
#
# \param serialised The serialised form of a CFG file.
# \return The version number stored in the CFG file.
# \raises ValueError The format of the version number in the file is
# incorrect.
# \raises KeyError The format of the file is incorrect.
def getCfgVersion(self, serialised):
parser = configparser.ConfigParser(interpolation = None)
parser.read_string(serialised)
format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised.
setting_version = int(parser.get("metadata", "setting_version", fallback = 0))
return format_version * 1000000 + setting_version
## Upgrades a preferences file from version 3.0 to 3.1.
#
# \param serialised The serialised form of a preferences file.
# \param filename The name of the file to upgrade.
def upgradePreferences(self, serialised, filename):
parser = configparser.ConfigParser(interpolation=None)
parser.read_string(serialised)
# Update version numbers
if "general" not in parser:
parser["general"] = {}
parser["general"]["version"] = "5"
if "metadata" not in parser:
parser["metadata"] = {}
parser["metadata"]["setting_version"] = "4"
# Re-serialise the file.
output = io.StringIO()
parser.write(output)
return [filename], [output.getvalue()]
## Upgrades the given instance container file from version 3.0 to 3.1.
#
# \param serialised The serialised form of the container file.
# \param filename The name of the file to upgrade.
def upgradeInstanceContainer(self, serialised, filename):
parser = configparser.ConfigParser(interpolation=None)
parser.read_string(serialised)
for each_section in ("general", "metadata"):
if not parser.has_section(each_section):
parser.add_section(each_section)
# Update version numbers
parser["general"]["version"] = "2"
parser["metadata"]["setting_version"] = "4"
# Re-serialise the file.
output = io.StringIO()
parser.write(output)
return [filename], [output.getvalue()]
## Upgrades a container stack from version 3.0 to 3.1.
#
# \param serialised The serialised form of a container stack.
# \param filename The name of the file to upgrade.
def upgradeStack(self, serialised, filename):
parser = configparser.ConfigParser(interpolation=None)
parser.read_string(serialised)
for each_section in ("general", "metadata"):
if not parser.has_section(each_section):
parser.add_section(each_section)
# change "not supported" quality profiles to empty because they no longer exist
if parser.has_section("containers"):
if parser.has_option("containers", "2"):
quality_profile_id = parser["containers"]["2"]
if quality_profile_id in _OLD_NOT_SUPPORTED_PROFILES:
parser["containers"]["2"] = "empty_quality"
# Update version numbers
if "general" not in parser:
parser["general"] = {}
parser["general"]["version"] = "3"
if "metadata" not in parser:
parser["metadata"] = {}
parser["metadata"]["setting_version"] = "4"
# Re-serialise the file.
output = io.StringIO()
parser.write(output)
return [filename], [output.getvalue()]

View File

@ -0,0 +1,56 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from . import VersionUpgrade30to31
upgrade = VersionUpgrade30to31.VersionUpgrade30to31()
def getMetaData():
return {
"version_upgrade": {
# From To Upgrade function
("preferences", 5000003): ("preferences", 5000004, upgrade.upgradePreferences),
("machine_stack", 3000003): ("machine_stack", 3000004, upgrade.upgradeStack),
("extruder_train", 3000003): ("extruder_train", 3000004, upgrade.upgradeStack),
("quality_changes", 2000003): ("quality_changes", 2000004, upgrade.upgradeInstanceContainer),
("user", 2000003): ("user", 2000004, upgrade.upgradeInstanceContainer),
("quality", 2000003): ("quality", 2000004, upgrade.upgradeInstanceContainer),
("definition_changes", 2000003): ("definition_changes", 2000004, upgrade.upgradeInstanceContainer),
("variant", 2000003): ("variant", 2000004, upgrade.upgradeInstanceContainer)
},
"sources": {
"preferences": {
"get_version": upgrade.getCfgVersion,
"location": {"."}
},
"machine_stack": {
"get_version": upgrade.getCfgVersion,
"location": {"./machine_instances"}
},
"extruder_train": {
"get_version": upgrade.getCfgVersion,
"location": {"./extruders"}
},
"quality_changes": {
"get_version": upgrade.getCfgVersion,
"location": {"./quality"}
},
"user": {
"get_version": upgrade.getCfgVersion,
"location": {"./user"}
},
"definition_changes": {
"get_version": upgrade.getCfgVersion,
"location": {"./definition_changes"}
},
"variant": {
"get_version": upgrade.getCfgVersion,
"location": {"./variants"}
}
}
}
def register(app):
return { "version_upgrade": upgrade }

View File

@ -0,0 +1,8 @@
{
"name": "Version Upgrade 3.0 to 3.1",
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Upgrades configurations from Cura 3.0 to Cura 3.1.",
"api": 4,
"i18n-catalog": "cura"
}

View File

@ -35,7 +35,7 @@ class XmlMaterialProfile(InstanceContainer):
# \return The corresponding setting_version. # \return The corresponding setting_version.
def xmlVersionToSettingVersion(self, xml_version: str) -> int: def xmlVersionToSettingVersion(self, xml_version: str) -> int:
if xml_version == "1.3": if xml_version == "1.3":
return 3 return 4
return 0 #Older than 1.3. return 0 #Older than 1.3.
def getInheritedFiles(self): def getInheritedFiles(self):
@ -509,8 +509,6 @@ class XmlMaterialProfile(InstanceContainer):
elif key in self.__unmapped_settings: elif key in self.__unmapped_settings:
if key == "hardware compatible": if key == "hardware compatible":
common_compatibility = self._parseCompatibleValue(entry.text) common_compatibility = self._parseCompatibleValue(entry.text)
else:
Logger.log("d", "Unsupported material setting %s", key)
self._cached_values = common_setting_values # from InstanceContainer ancestor self._cached_values = common_setting_values # from InstanceContainer ancestor
meta_data["compatible"] = common_compatibility meta_data["compatible"] = common_compatibility
@ -676,7 +674,9 @@ class XmlMaterialProfile(InstanceContainer):
"processing temperature graph": "material_flow_temp_graph", "processing temperature graph": "material_flow_temp_graph",
"print cooling": "cool_fan_speed", "print cooling": "cool_fan_speed",
"retraction amount": "retraction_amount", "retraction amount": "retraction_amount",
"retraction speed": "retraction_speed" "retraction speed": "retraction_speed",
"adhesion tendency": "material_adhesion_tendency",
"surface energy": "material_surface_energy"
} }
__unmapped_settings = [ __unmapped_settings = [
"hardware compatible" "hardware compatible"

View File

@ -0,0 +1,117 @@
{
"id": "builder_premium_large",
"version": 2,
"name": "Builder Premium Large",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Builder SZ",
"manufacturer": "Builder",
"category": "Other",
"quality_definition": "builder_premium_small",
"file_formats": "text/x-gcode",
"platform": "builder_premium_platform.stl",
"platform_offset": [-126, -36, 117],
"has_machine_quality": true,
"preferred_quality": "*Normal*",
"machine_extruder_trains":
{
"0": "builder_premium_large_rear",
"1": "builder_premium_large_front"
}
},
"overrides": {
"machine_name": { "default_value": "Builder Premium Large" },
"machine_heated_bed": { "default_value": true },
"machine_width": { "default_value": 215 },
"machine_height": { "default_value": 600 },
"machine_depth": { "default_value": 205 },
"material_diameter": { "default_value": 1.75 },
"infill_pattern": {"value": "'triangles'" },
"infill_before_walls": {"value": false },
"default_material_print_temperature": { "value": "215" },
"material_print_temperature_layer_0": { "value": "material_print_temperature + 5" },
"material_standby_temperature": { "value": "material_print_temperature" },
"switch_extruder_retraction_speeds": {"default_value": 15 },
"switch_extruder_retraction_speed": {"default_value": 15 },
"switch_extruder_prime_speed": {"default_value": 15 },
"switch_extruder_retraction_amount": {"value": 1 },
"speed_travel": { "value": "100" },
"speed_layer_0": { "value": "20" },
"speed_prime_tower": { "value": "speed_topbottom" },
"speed_print": { "value": "40" },
"speed_support": { "value": "speed_wall_0" },
"speed_support_interface": { "value": "speed_topbottom" },
"speed_topbottom": { "value": "math.ceil(speed_print * 20 / 35)" },
"speed_wall": { "value": "math.ceil(speed_print * 30 / 40)" },
"speed_wall_0": { "value": "math.ceil(speed_wall * 20 / 25)" },
"speed_wall_x": { "value": "speed_wall" },
"prime_tower_position_x": { "default_value": 175 },
"prime_tower_position_y": { "default_value": 178 },
"prime_tower_wipe_enabled": { "default_value": false },
"prime_tower_min_volume": { "default_value": 50 },
"dual_pre_wipe": { "default_value": false },
"prime_blob_enable": { "enabled": true },
"acceleration_enabled": { "value": "True" },
"acceleration_layer_0": { "value": "acceleration_topbottom" },
"acceleration_prime_tower": { "value": "math.ceil(acceleration_print * 2000 / 4000)" },
"acceleration_print": { "value": "3000" },
"acceleration_support": { "value": "math.ceil(acceleration_print * 2000 / 4000)" },
"acceleration_support_interface": { "value": "acceleration_topbottom" },
"acceleration_topbottom": { "value": "math.ceil(acceleration_print * 1000 / 3000)" },
"acceleration_travel": { "value": "acceleration_print" },
"acceleration_wall": { "value": "math.ceil(acceleration_print * 1000 / 3000)" },
"acceleration_wall_0": { "value": "math.ceil(acceleration_wall * 1000 / 1000)" },
"cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" },
"cool_min_layer_time": { "default_value": 10 },
"jerk_enabled": { "value": "True" },
"jerk_layer_0": { "value": "jerk_topbottom" },
"jerk_prime_tower": { "value": "math.ceil(jerk_print * 15 / 25)" },
"jerk_print": { "value": "25" },
"jerk_support": { "value": "math.ceil(jerk_print * 15 / 25)" },
"jerk_support_interface": { "value": "jerk_topbottom" },
"jerk_topbottom": { "value": "math.ceil(jerk_print * 5 / 25)" },
"jerk_wall": { "value": "math.ceil(jerk_print * 10 / 25)" },
"jerk_wall_0": { "value": "math.ceil(jerk_wall * 5 / 10)" },
"wall_thickness": { "value": "1.2" },
"retraction_amount": { "default_value": 3 },
"retraction_speed": { "default_value": 15 },
"retraction_retract_speed": { "default_value": 15 },
"retraction_prime_speed": { "default_value": 15 },
"travel_retract_before_outer_wall": { "default_value": true },
"skin_overlap": { "value": "15" },
"adhesion_type": { "default_value": "skirt" },
"machine_nozzle_heat_up_speed": { "default_value": 2 },
"machine_nozzle_cool_down_speed": { "default_value": 2 },
"machine_head_polygon": { "default_value": [[-75, -18],[-75, 35],[18, 35],[18, -18]] },
"gantry_height": { "default_value": 55 },
"machine_max_feedrate_x": { "default_value": 300 },
"machine_max_feedrate_y": { "default_value": 300 },
"machine_max_feedrate_z": { "default_value": 40 },
"machine_max_acceleration_z": { "default_value": 500 },
"machine_acceleration": { "default_value": 1000 },
"machine_max_jerk_xy": { "default_value": 10 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": {
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E15 ;extrude 15mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\nT0 ;Start with Rear Extruder\n;Put printing message on LCD screen\nM117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
},
"machine_extruder_count": { "default_value": 2 }
}
}

View File

@ -0,0 +1,117 @@
{
"id": "builder_premium_medium",
"version": 2,
"name": "Builder Premium Medium",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Builder SZ",
"manufacturer": "Builder",
"category": "Other",
"quality_definition": "builder_premium_small",
"file_formats": "text/x-gcode",
"platform": "builder_premium_platform.stl",
"platform_offset": [-126, -36, 117],
"has_machine_quality": true,
"preferred_quality": "*Normal*",
"machine_extruder_trains":
{
"0": "builder_premium_medium_rear",
"1": "builder_premium_medium_front"
}
},
"overrides": {
"machine_name": { "default_value": "Builder Premium Medium" },
"machine_heated_bed": { "default_value": true },
"machine_width": { "default_value": 215 },
"machine_height": { "default_value": 400 },
"machine_depth": { "default_value": 205 },
"material_diameter": { "default_value": 1.75 },
"infill_pattern": {"value": "'triangles'" },
"infill_before_walls": {"value": false },
"default_material_print_temperature": { "value": "215" },
"material_print_temperature_layer_0": { "value": "material_print_temperature + 5" },
"material_standby_temperature": { "value": "material_print_temperature" },
"switch_extruder_retraction_speeds": {"default_value": 15 },
"switch_extruder_retraction_speed": {"default_value": 15 },
"switch_extruder_prime_speed": {"default_value": 15 },
"switch_extruder_retraction_amount": {"value": 1 },
"speed_travel": { "value": "100" },
"speed_layer_0": { "value": "20" },
"speed_prime_tower": { "value": "speed_topbottom" },
"speed_print": { "value": "40" },
"speed_support": { "value": "speed_wall_0" },
"speed_support_interface": { "value": "speed_topbottom" },
"speed_topbottom": { "value": "math.ceil(speed_print * 20 / 35)" },
"speed_wall": { "value": "math.ceil(speed_print * 30 / 40)" },
"speed_wall_0": { "value": "math.ceil(speed_wall * 20 / 25)" },
"speed_wall_x": { "value": "speed_wall" },
"prime_tower_position_x": { "default_value": 175 },
"prime_tower_position_y": { "default_value": 178 },
"prime_tower_wipe_enabled": { "default_value": false },
"prime_tower_min_volume": { "default_value": 50 },
"dual_pre_wipe": { "default_value": false },
"prime_blob_enable": { "enabled": true },
"acceleration_enabled": { "value": "True" },
"acceleration_layer_0": { "value": "acceleration_topbottom" },
"acceleration_prime_tower": { "value": "math.ceil(acceleration_print * 2000 / 4000)" },
"acceleration_print": { "value": "3000" },
"acceleration_support": { "value": "math.ceil(acceleration_print * 2000 / 4000)" },
"acceleration_support_interface": { "value": "acceleration_topbottom" },
"acceleration_topbottom": { "value": "math.ceil(acceleration_print * 1000 / 3000)" },
"acceleration_travel": { "value": "acceleration_print" },
"acceleration_wall": { "value": "math.ceil(acceleration_print * 1000 / 3000)" },
"acceleration_wall_0": { "value": "math.ceil(acceleration_wall * 1000 / 1000)" },
"cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" },
"cool_min_layer_time": { "default_value": 10 },
"jerk_enabled": { "value": "True" },
"jerk_layer_0": { "value": "jerk_topbottom" },
"jerk_prime_tower": { "value": "math.ceil(jerk_print * 15 / 25)" },
"jerk_print": { "value": "25" },
"jerk_support": { "value": "math.ceil(jerk_print * 15 / 25)" },
"jerk_support_interface": { "value": "jerk_topbottom" },
"jerk_topbottom": { "value": "math.ceil(jerk_print * 5 / 25)" },
"jerk_wall": { "value": "math.ceil(jerk_print * 10 / 25)" },
"jerk_wall_0": { "value": "math.ceil(jerk_wall * 5 / 10)" },
"wall_thickness": { "value": "1.2" },
"retraction_amount": { "default_value": 3 },
"retraction_speed": { "default_value": 15 },
"retraction_retract_speed": { "default_value": 15 },
"retraction_prime_speed": { "default_value": 15 },
"travel_retract_before_outer_wall": { "default_value": true },
"skin_overlap": { "value": "15" },
"adhesion_type": { "default_value": "skirt" },
"machine_nozzle_heat_up_speed": { "default_value": 2 },
"machine_nozzle_cool_down_speed": { "default_value": 2 },
"machine_head_polygon": { "default_value": [[-75, -18],[-75, 35],[18, 35],[18, -18]] },
"gantry_height": { "default_value": 55 },
"machine_max_feedrate_x": { "default_value": 300 },
"machine_max_feedrate_y": { "default_value": 300 },
"machine_max_feedrate_z": { "default_value": 40 },
"machine_max_acceleration_z": { "default_value": 500 },
"machine_acceleration": { "default_value": 1000 },
"machine_max_jerk_xy": { "default_value": 10 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": {
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E15 ;extrude 15mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\nT0 ;Start with Rear Extruder\n;Put printing message on LCD screen\nM117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
},
"machine_extruder_count": { "default_value": 2 }
}
}

View File

@ -0,0 +1,116 @@
{
"id": "builder_premium_small",
"version": 2,
"name": "Builder Premium Small",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Builder SZ",
"manufacturer": "Builder",
"category": "Other",
"file_formats": "text/x-gcode",
"platform": "builder_premium_platform.stl",
"platform_offset": [-126, -36, 117],
"has_machine_quality": true,
"preferred_quality": "*Normal*",
"machine_extruder_trains":
{
"0": "builder_premium_small_rear",
"1": "builder_premium_small_front"
}
},
"overrides": {
"machine_name": { "default_value": "Builder Premium Small" },
"machine_heated_bed": { "default_value": true },
"machine_width": { "default_value": 215 },
"machine_height": { "default_value": 200 },
"machine_depth": { "default_value": 205 },
"material_diameter": { "default_value": 1.75 },
"infill_pattern": {"value": "'triangles'" },
"infill_before_walls": {"value": false },
"default_material_print_temperature": { "value": "215" },
"material_print_temperature_layer_0": { "value": "material_print_temperature + 5" },
"material_standby_temperature": { "value": "material_print_temperature" },
"switch_extruder_retraction_speeds": {"default_value": 15 },
"switch_extruder_retraction_speed": {"default_value": 15 },
"switch_extruder_prime_speed": {"default_value": 15 },
"switch_extruder_retraction_amount": {"value": 1 },
"speed_travel": { "value": "100" },
"speed_layer_0": { "value": "20" },
"speed_prime_tower": { "value": "speed_topbottom" },
"speed_print": { "value": "40" },
"speed_support": { "value": "speed_wall_0" },
"speed_support_interface": { "value": "speed_topbottom" },
"speed_topbottom": { "value": "math.ceil(speed_print * 20 / 35)" },
"speed_wall": { "value": "math.ceil(speed_print * 30 / 40)" },
"speed_wall_0": { "value": "math.ceil(speed_wall * 20 / 25)" },
"speed_wall_x": { "value": "speed_wall" },
"prime_tower_position_x": { "default_value": 175 },
"prime_tower_position_y": { "default_value": 178 },
"prime_tower_wipe_enabled": { "default_value": false },
"prime_tower_min_volume": { "default_value": 50 },
"dual_pre_wipe": { "default_value": false },
"prime_blob_enable": { "enabled": true },
"acceleration_enabled": { "value": "True" },
"acceleration_layer_0": { "value": "acceleration_topbottom" },
"acceleration_prime_tower": { "value": "math.ceil(acceleration_print * 2000 / 4000)" },
"acceleration_print": { "value": "3000" },
"acceleration_support": { "value": "math.ceil(acceleration_print * 2000 / 4000)" },
"acceleration_support_interface": { "value": "acceleration_topbottom" },
"acceleration_topbottom": { "value": "math.ceil(acceleration_print * 1000 / 3000)" },
"acceleration_travel": { "value": "acceleration_print" },
"acceleration_wall": { "value": "math.ceil(acceleration_print * 1000 / 3000)" },
"acceleration_wall_0": { "value": "math.ceil(acceleration_wall * 1000 / 1000)" },
"cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" },
"cool_min_layer_time": { "default_value": 10 },
"jerk_enabled": { "value": "True" },
"jerk_layer_0": { "value": "jerk_topbottom" },
"jerk_prime_tower": { "value": "math.ceil(jerk_print * 15 / 25)" },
"jerk_print": { "value": "25" },
"jerk_support": { "value": "math.ceil(jerk_print * 15 / 25)" },
"jerk_support_interface": { "value": "jerk_topbottom" },
"jerk_topbottom": { "value": "math.ceil(jerk_print * 5 / 25)" },
"jerk_wall": { "value": "math.ceil(jerk_print * 10 / 25)" },
"jerk_wall_0": { "value": "math.ceil(jerk_wall * 5 / 10)" },
"wall_thickness": { "value": "1.2" },
"retraction_amount": { "default_value": 3 },
"retraction_speed": { "default_value": 15 },
"retraction_retract_speed": { "default_value": 15 },
"retraction_prime_speed": { "default_value": 15 },
"travel_retract_before_outer_wall": { "default_value": true },
"skin_overlap": { "value": "15" },
"adhesion_type": { "default_value": "skirt" },
"machine_nozzle_heat_up_speed": { "default_value": 2 },
"machine_nozzle_cool_down_speed": { "default_value": 2 },
"machine_head_polygon": { "default_value": [[-75, -18],[-75, 35],[18, 35],[18, -18]] },
"gantry_height": { "default_value": 55 },
"machine_max_feedrate_x": { "default_value": 300 },
"machine_max_feedrate_y": { "default_value": 300 },
"machine_max_feedrate_z": { "default_value": 40 },
"machine_max_acceleration_z": { "default_value": 500 },
"machine_acceleration": { "default_value": 1000 },
"machine_max_jerk_xy": { "default_value": 10 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": {
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E15 ;extrude 15mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\nT0 ;Start with Rear Extruder\n;Put printing message on LCD screen\nM117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
},
"machine_extruder_count": { "default_value": 2 }
}
}

View File

@ -7,7 +7,8 @@
"visible": true, "visible": true,
"author": "Michael Wildermuth", "author": "Michael Wildermuth",
"manufacturer": "Creality3D", "manufacturer": "Creality3D",
"file_formats": "text/x-gcode" "file_formats": "text/x-gcode",
"preferred_quality": "*Draft*"
}, },
"overrides": { "overrides": {
"machine_width": { "machine_width": {
@ -25,9 +26,6 @@
"machine_nozzle_size": { "machine_nozzle_size": {
"default_value": 0.4 "default_value": 0.4
}, },
"layer_height": {
"default_value": 0.2
},
"layer_height_0": { "layer_height_0": {
"default_value": 0.2 "default_value": 0.2
}, },
@ -61,9 +59,6 @@
"skirt_gap": { "skirt_gap": {
"default_value": 5 "default_value": 5
}, },
"machine_start_gcode": {
"default_value": "G21 ;metric values\nG90 ;absolute Positioning\nG28 ; home all axes\nG1 Z5 F3000 ; lift\nG1 X20 Y2 F1500 ; avoid binder clips\nG1 Z0.2 F3000 ; get ready to prime\nG92 E0 ; reset extrusion distance\nG1 X120 E10 F600 ; prime nozzle\nG1 X150 F5000 ; quick wipe"
},
"machine_end_gcode": { "machine_end_gcode": {
"default_value": "G91\nG1 F1800 E-3\nG1 F3000 Z10\nG90\nG28 X0 Y0 ; home x and y axis\nM106 S0 ; turn off cooling fan\nM104 S0 ; turn off extruder\nM140 S0 ; turn off bed\nM84 ; disable motors" "default_value": "G91\nG1 F1800 E-3\nG1 F3000 Z10\nG90\nG28 X0 Y0 ; home x and y axis\nM106 S0 ; turn off cooling fan\nM104 S0 ; turn off extruder\nM140 S0 ; turn off bed\nM84 ; disable motors"
}, },

0
resources/definitions/dagoma_discoeasy200.def.json Executable file → Normal file
View File

71
resources/definitions/fdmprinter.def.json Executable file → Normal file
View File

@ -643,6 +643,20 @@
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false "settable_per_extruder": false
}, },
"slicing_tolerance":
{
"label": "Slicing Tolerance",
"description": "How to slice layers with diagonal surfaces. The areas of a layer can be generated based on where the middle of the layer intersects the surface (Middle). Alternatively each layer can have the areas which fall inside of the volume throughout the height of the layer (Exclusive) or a layer has the areas which fall inside anywhere within the layer (Inclusive). Exclusive retains the most details, Inclusive makes for the best fit and Middle takes the least time to process.",
"type": "enum",
"options":
{
"middle": "Middle",
"exclusive": "Exclusive",
"inclusive": "Inclusive"
},
"default_value": "middle",
"settable_per_mesh": true
},
"line_width": "line_width":
{ {
"label": "Line Width", "label": "Line Width",
@ -668,6 +682,7 @@
"value": "line_width", "value": "line_width",
"default_value": 0.4, "default_value": 0.4,
"type": "float", "type": "float",
"limit_to_extruder": "wall_0_extruder_nr if wall_x_extruder_nr == wall_0_extruder_nr else -1",
"settable_per_mesh": true, "settable_per_mesh": true,
"children": "children":
{ {
@ -866,11 +881,24 @@
"type": "category", "type": "category",
"children": "children":
{ {
"wall_extruder_nr":
{
"label": "Wall Extruder",
"description": "The extruder train used for printing the walls. This is used in multi-extrusion.",
"type": "optional_extruder",
"default_value": "-1",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": true,
"settable_globally": true,
"enabled": "machine_extruder_count > 1",
"children": {
"wall_0_extruder_nr": "wall_0_extruder_nr":
{ {
"label": "Outer Wall Extruder", "label": "Outer Wall Extruder",
"description": "The extruder train used for printing the outer wall. This is used in multi-extrusion.", "description": "The extruder train used for printing the outer wall. This is used in multi-extrusion.",
"type": "optional_extruder", "type": "optional_extruder",
"value": "wall_extruder_nr",
"default_value": "-1", "default_value": "-1",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false, "settable_per_extruder": false,
@ -880,15 +908,18 @@
}, },
"wall_x_extruder_nr": "wall_x_extruder_nr":
{ {
"label": "Inner Walls Extruder", "label": "Inner Wall Extruder",
"description": "The extruder train used for printing the inner walls. This is used in multi-extrusion.", "description": "The extruder train used for printing the inner walls. This is used in multi-extrusion.",
"type": "optional_extruder", "type": "optional_extruder",
"value": "wall_extruder_nr",
"default_value": "-1", "default_value": "-1",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false, "settable_per_extruder": false,
"settable_per_meshgroup": true, "settable_per_meshgroup": true,
"settable_globally": true, "settable_globally": true,
"enabled": "machine_extruder_count > 1" "enabled": "machine_extruder_count > 1"
}
}
}, },
"wall_thickness": "wall_thickness":
{ {
@ -1354,7 +1385,7 @@
"default_value": 2, "default_value": 2,
"minimum_value": "0", "minimum_value": "0",
"minimum_value_warning": "infill_line_width", "minimum_value_warning": "infill_line_width",
"value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == 'grid' else (3 if infill_pattern == 'triangles' or infill_pattern == 'cubic' or infill_pattern == 'cubicsubdiv' else (2 if infill_pattern == 'tetrahedral' or infill_pattern == 'quarter_cubic' else (1 if infill_pattern == 'cross' or infill_pattern == 'cross_3d' else 1))))", "value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == 'grid' else (3 if infill_pattern == 'triangles' or infill_pattern == 'trihexagon' or infill_pattern == 'cubic' or infill_pattern == 'cubicsubdiv' else (2 if infill_pattern == 'tetrahedral' or infill_pattern == 'quarter_cubic' else (1 if infill_pattern == 'cross' or infill_pattern == 'cross_3d' else 1))))",
"limit_to_extruder": "infill_extruder_nr", "limit_to_extruder": "infill_extruder_nr",
"settable_per_mesh": true "settable_per_mesh": true
} }
@ -1370,6 +1401,7 @@
"grid": "Grid", "grid": "Grid",
"lines": "Lines", "lines": "Lines",
"triangles": "Triangles", "triangles": "Triangles",
"trihexagon": "Tri-Hexagon",
"cubic": "Cubic", "cubic": "Cubic",
"cubicsubdiv": "Cubic Subdivision", "cubicsubdiv": "Cubic Subdivision",
"tetrahedral": "Octet", "tetrahedral": "Octet",
@ -1850,6 +1882,31 @@
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
"material_adhesion_tendency":
{
"label": "Adhesion Tendency",
"description": "Surface adhesion tendency.",
"type": "int",
"default_value": 10,
"minimum_value": "0",
"maximum_value": "10",
"enabled": false,
"settable_per_mesh": false,
"settable_per_extruder": true
},
"material_surface_energy":
{
"label": "Surface Energy",
"description": "Surface energy.",
"unit": "%",
"type": "int",
"default_value": 100,
"minimum_value": "0",
"maximum_value": "100",
"enabled": false,
"settable_per_mesh": false,
"settable_per_extruder": true
},
"material_flow": "material_flow":
{ {
"label": "Flow", "label": "Flow",
@ -3917,6 +3974,16 @@
"limit_to_extruder": "support_infill_extruder_nr", "limit_to_extruder": "support_infill_extruder_nr",
"enabled": "support_enable and support_use_towers", "enabled": "support_enable and support_use_towers",
"settable_per_mesh": true "settable_per_mesh": true
},
"remove_empty_first_layers":
{
"label": "Remove Empty First Layers",
"description": "Remove empty layers beneath the first printed layer if they are present.",
"type": "bool",
"default_value": true,
"enabled": "not support_enable",
"settable_per_mesh": false,
"settable_per_extruder": false
} }
} }
}, },

0
resources/definitions/helloBEEprusa.def.json Executable file → Normal file
View File

View File

@ -5,7 +5,7 @@
"inherits": "fdmprinter", "inherits": "fdmprinter",
"metadata": { "metadata": {
"visible": true, "visible": true,
"author": "Apsu", "author": "Apsu, Nounours2099",
"manufacturer": "Prusa Research", "manufacturer": "Prusa Research",
"file_formats": "text/x-gcode", "file_formats": "text/x-gcode",
"icon": "icon_ultimaker2", "icon": "icon_ultimaker2",
@ -41,7 +41,7 @@
"machine_max_jerk_e": { "default_value": 2.5 }, "machine_max_jerk_e": { "default_value": 2.5 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" }, "machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": { "machine_start_gcode": {
"default_value": "G21 ; set units to millimeters\nG90 ; use absolute positioning\nM82 ; absolute extrusion mode\nM104 S{material_print_temperature} ; set extruder temp\nM140 S{material_bed_temperature} ; set bed temp\nM190 S{material_bed_temperature} ; wait for bed temp\nM109 S{material_print_temperature} ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG92 E0.0 ; reset extruder distance position\nG1 Y-3.0 F1000.0 ; go outside print area\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E21.5 F1000.0 ; intro line\nG92 E0.0 ; reset extruder distance position" "default_value": "G21 ; set units to millimeters\nG90 ; use absolute positioning\nM82 ; absolute extrusion mode\nM104 S{material_print_temperature_layer_0} ; set extruder temp\nM140 S{material_bed_temperature_layer_0} ; set bed temp\nM190 S{material_bed_temperature_layer_0} ; wait for bed temp\nM109 S{material_print_temperature_layer_0} ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG92 E0.0 ; reset extruder distance position\nG1 Y-3.0 F1000.0 ; go outside print area\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E21.5 F1000.0 ; intro line\nG92 E0.0 ; reset extruder distance position"
}, },
"machine_end_gcode": { "machine_end_gcode": {
"default_value": "M104 S0 ; turn off extruder\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y210; home X axis and push Y forward\nM84 ; disable motors" "default_value": "M104 S0 ; turn off extruder\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y210; home X axis and push Y forward\nM84 ; disable motors"

View File

@ -150,7 +150,7 @@
"top_bottom_thickness": { "value": "1" }, "top_bottom_thickness": { "value": "1" },
"travel_avoid_distance": { "value": "3" }, "travel_avoid_distance": { "value": "3" },
"wall_0_inset": { "value": "0" }, "wall_0_inset": { "value": "0" },
"wall_line_width_x": { "value": "round(line_width * 0.3 / 0.35, 2)" }, "wall_line_width_x": { "value": "round(wall_line_width * 0.3 / 0.35, 2)" },
"wall_thickness": { "value": "1" } "wall_thickness": { "value": "1" }
} }
} }

View File

@ -0,0 +1,27 @@
{
"id": "builder_premium_large_front",
"version": 2,
"name": "Front Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "builder_premium_large",
"position": "1"
},
"overrides": {
"extruder_nr": {
"default_value": 1,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
"machine_extruder_end_pos_abs": { "default_value": true },
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" },
"extruder_prime_pos_abs": { "default_value": true }
}
}

View File

@ -0,0 +1,27 @@
{
"id": "builder_premium_large_rear",
"version": 2,
"name": "Rear Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "builder_premium_large",
"position": "0"
},
"overrides": {
"extruder_nr": {
"default_value": 0,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
"machine_extruder_end_pos_abs": { "default_value": true },
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" },
"extruder_prime_pos_abs": { "default_value": true }
}
}

View File

@ -0,0 +1,27 @@
{
"id": "builder_premium_medium_front",
"version": 2,
"name": "Front Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "builder_premium_medium",
"position": "1"
},
"overrides": {
"extruder_nr": {
"default_value": 1,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
"machine_extruder_end_pos_abs": { "default_value": true },
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" },
"extruder_prime_pos_abs": { "default_value": true }
}
}

View File

@ -0,0 +1,27 @@
{
"id": "builder_premium_medium_rear",
"version": 2,
"name": "Rear Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "builder_premium_medium",
"position": "0"
},
"overrides": {
"extruder_nr": {
"default_value": 0,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
"machine_extruder_end_pos_abs": { "default_value": true },
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" },
"extruder_prime_pos_abs": { "default_value": true }
}
}

View File

@ -0,0 +1,27 @@
{
"id": "builder_premium_small_front",
"version": 2,
"name": "Front Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "builder_premium_small",
"position": "1"
},
"overrides": {
"extruder_nr": {
"default_value": 1,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
"machine_extruder_end_pos_abs": { "default_value": true },
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" },
"extruder_prime_pos_abs": { "default_value": true }
}
}

View File

@ -0,0 +1,27 @@
{
"id": "builder_premium_small_rear",
"version": 2,
"name": "Rear Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "builder_premium_small",
"position": "0"
},
"overrides": {
"extruder_nr": {
"default_value": 0,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
"machine_extruder_end_pos_abs": { "default_value": true },
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" },
"extruder_prime_pos_abs": { "default_value": true }
}
}

0
resources/extruders/hBp_extruder_left.def.json Executable file → Normal file
View File

0
resources/extruders/hBp_extruder_right.def.json Executable file → Normal file
View File

View File

@ -18,6 +18,21 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
#Manually added for plugins/UserAgreementPlugin/UserAgreement.qml
msgctxt "@title:window"
msgid "User Agreement"
msgstr ""
#Manually added for plugins/UserAgreementPlugin/UserAgreement.qml
msgctxt "@action:button"
msgid "I understand and agree"
msgstr ""
#Manually added for plugins/UserAgreementPlugin/UserAgreement.qml
msgctxt "@action:button"
msgid "I don't agree"
msgstr ""
#: Manually added for plugins/UM3NetworkPrinting/PrinterInfoBlock.qml #: Manually added for plugins/UM3NetworkPrinting/PrinterInfoBlock.qml
msgctxt "@label:status" msgctxt "@label:status"
msgid "Print aborted" msgid "Print aborted"

View File

@ -2519,7 +2519,7 @@ msgstr "Sichtbarkeit einstellen"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/SettingVisibilityPage.qml:44 #: /home/ruben/Projects/Cura/resources/qml/Preferences/SettingVisibilityPage.qml:44
msgctxt "@label:textbox" msgctxt "@label:textbox"
msgid "Check all" msgid "Check all"
msgstr "Alle prüfen" msgstr "Alles wählen"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/ProfileTab.qml:40 #: /home/ruben/Projects/Cura/resources/qml/Preferences/ProfileTab.qml:40
msgctxt "@info:status" msgctxt "@info:status"

0
resources/meshes/BEEVERYCREATIVE-helloBEEprusa.stl Executable file → Normal file
View File

Binary file not shown.

View File

@ -132,6 +132,7 @@ UM.Dialog
projectsModel.append({ name:"PySerial", description: catalog.i18nc("@label", "Serial communication library"), license: "Python", url: "http://pyserial.sourceforge.net/" }); projectsModel.append({ name:"PySerial", description: catalog.i18nc("@label", "Serial communication library"), license: "Python", url: "http://pyserial.sourceforge.net/" });
projectsModel.append({ name:"python-zeroconf", description: catalog.i18nc("@label", "ZeroConf discovery library"), license: "LGPL", url: "https://github.com/jstasiak/python-zeroconf" }); projectsModel.append({ name:"python-zeroconf", description: catalog.i18nc("@label", "ZeroConf discovery library"), license: "LGPL", url: "https://github.com/jstasiak/python-zeroconf" });
projectsModel.append({ name:"Clipper", description: catalog.i18nc("@label", "Polygon clipping library"), license: "Boost", url: "http://www.angusj.com/delphi/clipper.php" }); projectsModel.append({ name:"Clipper", description: catalog.i18nc("@label", "Polygon clipping library"), license: "Boost", url: "http://www.angusj.com/delphi/clipper.php" });
projectsModel.append({ name:"Requests", description: catalog.i18nc("@Label", "Python HTTP library"), license: "GPL", url: "http://docs.python-requests.org" });
projectsModel.append({ name:"Open Sans", description: catalog.i18nc("@label", "Font"), license: "Apache 2.0", url: "https://fonts.google.com/specimen/Open+Sans" }); projectsModel.append({ name:"Open Sans", description: catalog.i18nc("@label", "Font"), license: "Apache 2.0", url: "https://fonts.google.com/specimen/Open+Sans" });
projectsModel.append({ name:"Font-Awesome-SVG-PNG", description: catalog.i18nc("@label", "SVG icons"), license: "SIL OFL 1.1", url: "https://github.com/encharm/Font-Awesome-SVG-PNG" }); projectsModel.append({ name:"Font-Awesome-SVG-PNG", description: catalog.i18nc("@label", "SVG icons"), license: "SIL OFL 1.1", url: "https://github.com/encharm/Font-Awesome-SVG-PNG" });

0
resources/qml/Actions.qml Executable file → Normal file
View File

View File

@ -63,11 +63,12 @@ UM.Dialog
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 20 * screenScaleFactor anchors.leftMargin: 20 * screenScaleFactor
anchors.rightMargin: 20 * screenScaleFactor anchors.rightMargin: 20 * screenScaleFactor
anchors.bottomMargin: 20 * screenScaleFactor anchors.bottomMargin: 10 * screenScaleFactor
spacing: 10 * screenScaleFactor spacing: 10 * screenScaleFactor
Label Label
{ {
id: questionText
text: catalog.i18nc("@text:window", "This is a Cura project file. Would you like to open it as a project or import the models from it?") text: catalog.i18nc("@text:window", "This is a Cura project file. Would you like to open it as a project or import the models from it?")
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@ -80,11 +81,18 @@ UM.Dialog
id: rememberChoiceCheckBox id: rememberChoiceCheckBox
text: catalog.i18nc("@text:window", "Remember my choice") text: catalog.i18nc("@text:window", "Remember my choice")
checked: UM.Preferences.getValue("cura/choice_on_open_project") != "always_ask" checked: UM.Preferences.getValue("cura/choice_on_open_project") != "always_ask"
style: CheckBoxStyle {
label: Label {
text: control.text
font: UM.Theme.getFont("default")
}
}
} }
// Buttons // Buttons
Item Item
{ {
id: buttonBar
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
height: childrenRect.height height: childrenRect.height

5
resources/qml/Cura.qml Executable file → Normal file
View File

@ -894,6 +894,11 @@ UM.MainWindow
if(!base.visible) if(!base.visible)
{ {
base.visible = true; base.visible = true;
}
// check later if the user agreement dialog has been closed
if (CuraApplication.needToShowUserAgreement)
{
restart(); restart();
} }
else if(Cura.MachineManager.activeMachineId == null || Cura.MachineManager.activeMachineId == "") else if(Cura.MachineManager.activeMachineId == null || Cura.MachineManager.activeMachineId == "")

View File

@ -95,7 +95,7 @@ Item {
{ {
id: printJobTextfield id: printJobTextfield
anchors.right: printJobPencilIcon.left anchors.right: printJobPencilIcon.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width/2 anchors.rightMargin: Math.floor(UM.Theme.getSize("default_margin").width/2)
height: UM.Theme.getSize("jobspecs_line").height height: UM.Theme.getSize("jobspecs_line").height
width: Math.max(__contentWidth + UM.Theme.getSize("default_margin").width, 50) width: Math.max(__contentWidth + UM.Theme.getSize("default_margin").width, 50)
maximumLength: 120 maximumLength: 120

0
resources/qml/Menus/ContextMenu.qml Executable file → Normal file
View File

View File

@ -14,6 +14,20 @@ Menu
property int extruderIndex: 0 property int extruderIndex: 0
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
property bool isClusterPrinter:
{
if(Cura.MachineManager.printerOutputDevices.length == 0)
{
return false;
}
var clusterSize = Cura.MachineManager.printerOutputDevices[0].clusterSize;
// This is not a cluster printer or the cluster it is just one printer
if(clusterSize == undefined || clusterSize == 1)
{
return false;
}
return true;
}
UM.SettingPropertyProvider UM.SettingPropertyProvider
{ {
@ -29,14 +43,14 @@ Menu
id: automaticMaterial id: automaticMaterial
text: text:
{ {
if(printerConnected && Cura.MachineManager.printerOutputDevices[0].materialNames.length > extruderIndex) if(printerConnected && Cura.MachineManager.printerOutputDevices[0].materialNames.length > extruderIndex && !isClusterPrinter)
{ {
var materialName = Cura.MachineManager.printerOutputDevices[0].materialNames[extruderIndex]; var materialName = Cura.MachineManager.printerOutputDevices[0].materialNames[extruderIndex];
return catalog.i18nc("@title:menuitem %1 is the automatically selected material", "Automatic: %1").arg(materialName); return catalog.i18nc("@title:menuitem %1 is the automatically selected material", "Automatic: %1").arg(materialName);
} }
return ""; return "";
} }
visible: printerConnected && Cura.MachineManager.printerOutputDevices[0].materialNames.length > extruderIndex visible: printerConnected && Cura.MachineManager.printerOutputDevices[0].materialNames.length > extruderIndex && !isClusterPrinter
onTriggered: onTriggered:
{ {
var materialId = Cura.MachineManager.printerOutputDevices[0].materialIds[extruderIndex]; var materialId = Cura.MachineManager.printerOutputDevices[0].materialIds[extruderIndex];

View File

@ -14,20 +14,34 @@ Menu
property int extruderIndex: 0 property int extruderIndex: 0
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
property bool isClusterPrinter:
{
if(Cura.MachineManager.printerOutputDevices.length == 0)
{
return false;
}
var clusterSize = Cura.MachineManager.printerOutputDevices[0].clusterSize;
// This is not a cluster printer or the cluster it is just one printer
if(clusterSize == undefined || clusterSize == 1)
{
return false;
}
return true;
}
MenuItem MenuItem
{ {
id: automaticNozzle id: automaticNozzle
text: text:
{ {
if(printerConnected && Cura.MachineManager.printerOutputDevices[0].hotendIds.length > extruderIndex) if(printerConnected && Cura.MachineManager.printerOutputDevices[0].hotendIds.length > extruderIndex && !isClusterPrinter)
{ {
var nozzleName = Cura.MachineManager.printerOutputDevices[0].hotendIds[extruderIndex]; var nozzleName = Cura.MachineManager.printerOutputDevices[0].hotendIds[extruderIndex];
return catalog.i18nc("@title:menuitem %1 is the nozzle currently loaded in the printer", "Automatic: %1").arg(nozzleName); return catalog.i18nc("@title:menuitem %1 is the nozzle currently loaded in the printer", "Automatic: %1").arg(nozzleName);
} }
return ""; return "";
} }
visible: printerConnected && Cura.MachineManager.printerOutputDevices[0].hotendIds.length > extruderIndex visible: printerConnected && Cura.MachineManager.printerOutputDevices[0].hotendIds.length > extruderIndex && !isClusterPrinter
onTriggered: onTriggered:
{ {
var activeExtruderIndex = ExtruderManager.activeExtruderIndex; var activeExtruderIndex = ExtruderManager.activeExtruderIndex;

View File

@ -17,9 +17,9 @@ Menu
MenuItem MenuItem
{ {
text: model.name + " - " + model.layer_height text: (model.layer_height != "") ? model.name + " - " + model.layer_height : model.name
checkable: true checkable: true
checked: Cura.MachineManager.activeQualityChangesId == "" && Cura.MachineManager.activeQualityType == model.metadata.quality_type checked: Cura.MachineManager.activeQualityId == model.id
exclusiveGroup: group exclusiveGroup: group
onTriggered: Cura.MachineManager.setActiveQuality(model.id) onTriggered: Cura.MachineManager.setActiveQuality(model.id)
visible: model.available visible: model.available

0
resources/qml/Preferences/GeneralPage.qml Executable file → Normal file
View File

View File

@ -91,8 +91,8 @@ Item {
id: saveRow id: saveRow
width: base.width width: base.width
height: saveToButton.height height: saveToButton.height
anchors.top: progressBar.bottom anchors.bottom: parent.bottom
anchors.topMargin: UM.Theme.getSize("sidebar_margin").height anchors.bottomMargin: UM.Theme.getSize("sidebar_margin").height
anchors.left: parent.left anchors.left: parent.left
Row { Row {

View File

@ -11,6 +11,14 @@ SettingItem
id: base id: base
property var focusItem: input property var focusItem: input
property string textBeforeEdit
property bool textHasChanged
onFocusReceived:
{
textHasChanged = false;
textBeforeEdit = focusItem.text;
}
contents: Rectangle contents: Rectangle
{ {
id: control id: control
@ -114,14 +122,24 @@ SettingItem
} }
Keys.onReleased: Keys.onReleased:
{
if (text != textBeforeEdit)
{
textHasChanged = true;
}
if (textHasChanged)
{ {
propertyProvider.setPropertyValue("value", text) propertyProvider.setPropertyValue("value", text)
} }
}
onEditingFinished: onEditingFinished:
{
if (textHasChanged)
{ {
propertyProvider.setPropertyValue("value", text) propertyProvider.setPropertyValue("value", text)
} }
}
onActiveFocusChanged: onActiveFocusChanged:
{ {

View File

@ -51,27 +51,34 @@ Item
{ {
id: globalProfileSelection id: globalProfileSelection
text: { text: generateActiveQualityText()
var result = Cura.MachineManager.activeQualityName;
if (Cura.MachineManager.activeQualityLayerHeight > 0) {
result += " <font color=\"" + UM.Theme.getColor("text_detail") + "\">";
result += " - ";
result += Cura.MachineManager.activeQualityLayerHeight + "mm";
result += "</font>";
}
return result;
}
enabled: !header.currentExtruderVisible || header.currentExtruderIndex > -1 enabled: !header.currentExtruderVisible || header.currentExtruderIndex > -1
width: Math.floor(parent.width * 0.55) width: Math.floor(parent.width * 0.55)
height: UM.Theme.getSize("setting_control").height height: UM.Theme.getSize("setting_control").height
anchors.left: globalProfileLabel.right anchors.left: globalProfileLabel.right
anchors.right: parent.right anchors.right: parent.right
tooltip: Cura.MachineManager.activeQualityName tooltip: Cura.MachineManager.activeQualityName
style: UM.Theme.styles.sidebar_header_button style: UM.Theme.styles.sidebar_header_button
activeFocusOnPress: true; activeFocusOnPress: true
menu: ProfileMenu { } menu: ProfileMenu { }
function generateActiveQualityText () {
var result = catalog.i18nc("@", "No Profile Available") // default text
if (Cura.MachineManager.isActiveQualitySupported ) {
result = Cura.MachineManager.activeQualityName
if (Cura.MachineManager.activeQualityLayerHeight > 0) {
result += " <font color=\"" + UM.Theme.getColor("text_detail") + "\">"
result += " - "
result += Cura.MachineManager.activeQualityLayerHeight + "mm"
result += "</font>"
}
}
return result
}
UM.SimpleButton UM.SimpleButton
{ {
id: customisedSettings id: customisedSettings

0
resources/qml/Sidebar.qml Executable file → Normal file
View File

View File

@ -34,20 +34,6 @@ Column
width: height width: height
} }
Item
{
anchors
{
left: parent.left
leftMargin: UM.Theme.getSize("sidebar_margin").width
right: parent.right
rightMargin: UM.Theme.getSize("sidebar_margin").width
}
visible: extruderSelectionRow.visible
height: UM.Theme.getSize("default_lining").hieght
width: height
}
Item Item
{ {
id: extruderSelectionRow id: extruderSelectionRow
@ -259,42 +245,36 @@ Column
color: UM.Theme.getColor("text"); color: UM.Theme.getColor("text");
} }
ToolButton { ToolButton
{
id: materialSelection id: materialSelection
text: Cura.MachineManager.activeMaterialName text: Cura.MachineManager.activeMaterialName
tooltip: Cura.MachineManager.activeMaterialName tooltip: Cura.MachineManager.activeMaterialName
visible: Cura.MachineManager.hasMaterials visible: Cura.MachineManager.hasMaterials
property var valueError:
{
var data = Cura.ContainerManager.getContainerMetaDataEntry(Cura.MachineManager.activeMaterialId, "compatible")
if(data == "False")
{
return true
}
else
{
return false
}
}
property var valueWarning: ! Cura.MachineManager.isActiveQualitySupported
enabled: !extrudersList.visible || base.currentExtruderIndex > -1 enabled: !extrudersList.visible || base.currentExtruderIndex > -1
height: UM.Theme.getSize("setting_control").height height: UM.Theme.getSize("setting_control").height
width: parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width width: parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width
anchors.right: parent.right anchors.right: parent.right
style: UM.Theme.styles.sidebar_header_button style: UM.Theme.styles.sidebar_header_button
activeFocusOnPress: true; activeFocusOnPress: true;
menu: MaterialMenu {
extruderIndex: base.currentExtruderIndex
}
menu: MaterialMenu { extruderIndex: base.currentExtruderIndex } property var valueError: !isMaterialSupported()
property var valueWarning: ! Cura.MachineManager.isActiveQualitySupported
function isMaterialSupported () {
return Cura.ContainerManager.getContainerMetaDataEntry(Cura.MachineManager.activeMaterialId, "compatible") == "True"
}
} }
} }
// Print core row //Variant row
Item Item
{ {
id: printCoreRow id: variantRow
height: UM.Theme.getSize("sidebar_setup").height height: UM.Theme.getSize("sidebar_setup").height
visible: Cura.MachineManager.hasVariants && !sidebar.monitoringPrint && !sidebar.hideSettings visible: Cura.MachineManager.hasVariants && !sidebar.monitoringPrint && !sidebar.hideSettings
@ -308,7 +288,7 @@ Column
Label Label
{ {
id: printCoreLabel id: variantLabel
text: Cura.MachineManager.activeDefinitionVariantsName; text: Cura.MachineManager.activeDefinitionVariantsName;
width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("default_margin").width)
font: UM.Theme.getFont("default"); font: UM.Theme.getFont("default");
@ -316,7 +296,7 @@ Column
} }
ToolButton { ToolButton {
id: printCoreSelection id: variantSelection
text: Cura.MachineManager.activeVariantName text: Cura.MachineManager.activeVariantName
tooltip: Cura.MachineManager.activeVariantName; tooltip: Cura.MachineManager.activeVariantName;
visible: Cura.MachineManager.hasVariants visible: Cura.MachineManager.hasVariants

View File

@ -7,7 +7,7 @@ import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.2 as Cura
Item Item
{ {
@ -20,40 +20,11 @@ Item
property variant minimumPrintTime: PrintInformation.minimumPrintTime; property variant minimumPrintTime: PrintInformation.minimumPrintTime;
property variant maximumPrintTime: PrintInformation.maximumPrintTime; property variant maximumPrintTime: PrintInformation.maximumPrintTime;
property bool settingsEnabled: ExtruderManager.activeExtruderStackId || machineExtruderCount.properties.value == 1 property bool settingsEnabled: ExtruderManager.activeExtruderStackId || machineExtruderCount.properties.value == 1
property bool hasUserSettings;
Component.onCompleted: PrintInformation.enabled = true Component.onCompleted: PrintInformation.enabled = true
Component.onDestruction: PrintInformation.enabled = false Component.onDestruction: PrintInformation.enabled = false
UM.I18nCatalog { id: catalog; name: "cura" } UM.I18nCatalog { id: catalog; name: "cura" }
onVisibleChanged:
{
if (visible)
{
base.checkUserSettings()
}
}
Connections
{
target: CuraApplication
onSidebarSimpleDiscardOrKeepProfileChanges:
{
base.hasUserSettings = false
}
}
function checkUserSettings(){
var skip_keys = ["support_enable" ,
"infill_sparse_density",
"gradual_infill_steps",
"adhesion_type",
"support_extruder_nr"]
base.hasUserSettings = Cura.MachineManager.hasUserCustomSettings(skip_keys)
}
ScrollView ScrollView
{ {
visible: Cura.MachineManager.activeMachineName != "" // If no printers added then the view is invisible visible: Cura.MachineManager.activeMachineName != "" // If no printers added then the view is invisible
@ -105,12 +76,13 @@ Item
property var totalTicks: 0 property var totalTicks: 0
property var availableTotalTicks: 0 property var availableTotalTicks: 0
property var activeQualityIndex: 0 property var existingQualityProfile: 0
property var qualitySliderActiveIndex: 0
property var qualitySliderStepWidth: 0 property var qualitySliderStepWidth: 0
property var qualitySliderAvailableMin : 0 property var qualitySliderAvailableMin: 0
property var qualitySliderAvailableMax : 0 property var qualitySliderAvailableMax: 0
property var qualitySliderMarginRight : 0 property var qualitySliderMarginRight: 0
function update () { function update () {
reset() reset()
@ -118,15 +90,23 @@ Item
var availableMin = -1 var availableMin = -1
var availableMax = -1 var availableMax = -1
for (var i = 0; i <= Cura.ProfilesModel.rowCount(); i++) { for (var i = 0; i < Cura.ProfilesModel.rowCount(); i++) {
var qualityItem = Cura.ProfilesModel.getItem(i) var qualityItem = Cura.ProfilesModel.getItem(i)
// Add each quality item to the UI quality model // Add each quality item to the UI quality model
qualityModel.append(qualityItem) qualityModel.append(qualityItem)
// Set selected value // Set selected value
if (Cura.MachineManager.activeQualityId == qualityItem.id) { if (Cura.MachineManager.activeQualityType == qualityItem.metadata.quality_type) {
qualityModel.activeQualityIndex = i
// set to -1 when switching to user created profile so all ticks are clickable
if (Cura.SimpleModeSettingsManager.isProfileUserCreated) {
qualityModel.qualitySliderActiveIndex = -1
} else {
qualityModel.qualitySliderActiveIndex = i
}
qualityModel.existingQualityProfile = 1
} }
// Set min available // Set min available
@ -170,16 +150,10 @@ Item
function reset () { function reset () {
qualityModel.clear() qualityModel.clear()
qualityModel.availableTotalTicks = -1 qualityModel.availableTotalTicks = -1
qualityModel.existingQualityProfile = 0
// check, the ticks count cannot be less than zero // check, the ticks count cannot be less than zero
if(Cura.ProfilesModel.rowCount() != 0) qualityModel.totalTicks = Math.max(0, Cura.ProfilesModel.rowCount() - 1)
{
qualityModel.totalTicks = Cura.ProfilesModel.rowCount() - 1 // minus one, because slider starts from 0
}
else
{
qualityModel.totalTicks = 0
}
} }
} }
@ -204,7 +178,7 @@ Item
{ {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height / 2) anchors.topMargin: parseInt(UM.Theme.getSize("sidebar_margin").height / 2)
color: (Cura.MachineManager.activeMachine != null && Cura.ProfilesModel.getItem(index).available) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") color: (Cura.MachineManager.activeMachine != null && Cura.ProfilesModel.getItem(index).available) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
text: text:
{ {
@ -223,13 +197,13 @@ Item
// Make sure the text aligns correctly with each tick // Make sure the text aligns correctly with each tick
if (qualityModel.totalTicks == 0) { if (qualityModel.totalTicks == 0) {
// If there is only one tick, align it centrally // If there is only one tick, align it centrally
return Math.floor(((base.width * 0.55) - width) / 2) return parseInt(((base.width * 0.55) - width) / 2)
} else if (index == 0) { } else if (index == 0) {
return (base.width * 0.55 / qualityModel.totalTicks) * index return (base.width * 0.55 / qualityModel.totalTicks) * index
} else if (index == qualityModel.totalTicks) { } else if (index == qualityModel.totalTicks) {
return (base.width * 0.55 / qualityModel.totalTicks) * index - width return (base.width * 0.55 / qualityModel.totalTicks) * index - width
} else { } else {
return Math.floor((base.width * 0.55 / qualityModel.totalTicks) * index - (width / 2)) return parseInt((base.width * 0.55 / qualityModel.totalTicks) * index - (width / 2))
} }
} }
} }
@ -289,7 +263,7 @@ Item
id: qualitySlider id: qualitySlider
height: UM.Theme.getSize("sidebar_margin").height height: UM.Theme.getSize("sidebar_margin").height
anchors.bottom: speedSlider.bottom anchors.bottom: speedSlider.bottom
enabled: qualityModel.availableTotalTicks > 0 enabled: qualityModel.availableTotalTicks > 0 && !Cura.SimpleModeSettingsManager.isProfileCustomized
visible: qualityModel.totalTicks > 0 visible: qualityModel.totalTicks > 0
updateValueWhileDragging : false updateValueWhileDragging : false
@ -297,7 +271,7 @@ Item
maximumValue: qualityModel.qualitySliderAvailableMax >= 0 ? qualityModel.qualitySliderAvailableMax : 0 maximumValue: qualityModel.qualitySliderAvailableMax >= 0 ? qualityModel.qualitySliderAvailableMax : 0
stepSize: 1 stepSize: 1
value: qualityModel.activeQualityIndex value: qualityModel.qualitySliderActiveIndex
width: qualityModel.qualitySliderStepWidth * qualityModel.availableTotalTicks width: qualityModel.qualitySliderStepWidth * qualityModel.availableTotalTicks
@ -320,50 +294,39 @@ Item
implicitWidth: 10 * screenScaleFactor implicitWidth: 10 * screenScaleFactor
implicitHeight: implicitWidth implicitHeight: implicitWidth
radius: implicitWidth / 2 radius: implicitWidth / 2
visible: !hasUserSettings; visible: !Cura.SimpleModeSettingsManager.isProfileCustomized && !Cura.SimpleModeSettingsManager.isProfileUserCreated && qualityModel.existingQualityProfile
} }
} }
} }
onValueChanged: { onValueChanged: {
// Only change if an active machine is set and the slider is visible at all. // only change if an active machine is set and the slider is visible at all.
if(Cura.MachineManager.activeMachine != null && visible) if (Cura.MachineManager.activeMachine != null && visible) {
// prevent updating during view initializing. Trigger only if the value changed by user
if (qualitySlider.value != qualityModel.qualitySliderActiveIndex) {
// start updating with short delay
qualitySliderChangeTimer.start()
}
}
}
}
MouseArea
{ {
//Prevent updating during view initializing. Trigger only if the value changed by user id: speedSliderMouseArea
if(qualitySlider.value != qualityModel.activeQualityIndex)
{
//start updating with short delay
qualitySliderChangeTimer.start();
}
}
}
}
//If any of settings were changed in custom mode then the Rectangle will
//overlap quality slider area. It is used to catch mouse click
Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.right: extrudersModelCheckBox.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
width: qualitySlider.width
height: qualitySlider.height * 1.5
//border.width: UM.Theme.getSize("default_lining").width // dispay overlap zone
//border.color: UM.Theme.getColor("lining")
color: "transparent"
visible: hasUserSettings
enabled: hasUserSettings
MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { hoverEnabled: true
discardOrKeepProfileChangesDialog.show() enabled: Cura.SimpleModeSettingsManager.isProfileUserCreated
}
}
onEntered:
{
var content = catalog.i18nc("@tooltip","A custom profile is currently active. To enable the quality slider, choose a default quality profile in Custom tab")
base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, customisedSettings.height), content)
}
onExited:
{
base.hideTooltip();
}
} }
} }
@ -373,13 +336,10 @@ Item
anchors.top: speedSlider.bottom anchors.top: speedSlider.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: speedSlider.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@label", "Print Speed") text: catalog.i18nc("@label", "Print Speed")
font: UM.Theme.getFont("default") font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")
elide: Text.ElideRight
} }
Label Label
@ -408,7 +368,7 @@ Item
{ {
id: customisedSettings id: customisedSettings
visible: hasUserSettings visible: Cura.SimpleModeSettingsManager.isProfileCustomized
height: speedSlider.height * 0.8 height: speedSlider.height * 0.8
width: speedSlider.height * 0.8 width: speedSlider.height * 0.8
@ -425,7 +385,7 @@ Item
} }
onEntered: onEntered:
{ {
var content = catalog.i18nc("@tooltip","You have selected a custom profile. If you want to change it, go to custom mode.") var content = catalog.i18nc("@tooltip","You have modified some profile settings. If you want to change these go to custom mode.")
base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, customisedSettings.height), content) base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, customisedSettings.height), content)
} }
onExited: base.hideTooltip() onExited: base.hideTooltip()
@ -445,7 +405,7 @@ Item
anchors.topMargin: UM.Theme.getSize("sidebar_margin").height * 2 anchors.topMargin: UM.Theme.getSize("sidebar_margin").height * 2
anchors.left: parent.left anchors.left: parent.left
width: Math.floor(UM.Theme.getSize("sidebar").width * .45 - UM.Theme.getSize("sidebar_margin").width) width: parseInt(UM.Theme.getSize("sidebar").width * .45 - UM.Theme.getSize("sidebar_margin").width)
Label Label
{ {
@ -455,7 +415,7 @@ Item
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height * 1.7) anchors.topMargin: parseInt(UM.Theme.getSize("sidebar_margin").height * 1.7)
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width
} }
@ -466,7 +426,7 @@ Item
id: infillCellRight id: infillCellRight
height: infillSlider.height + UM.Theme.getSize("sidebar_margin").height + enableGradualInfillCheckBox.visible * (enableGradualInfillCheckBox.height + UM.Theme.getSize("sidebar_margin").height) height: infillSlider.height + UM.Theme.getSize("sidebar_margin").height + enableGradualInfillCheckBox.visible * (enableGradualInfillCheckBox.height + UM.Theme.getSize("sidebar_margin").height)
width: Math.floor(UM.Theme.getSize("sidebar").width * .55) width: parseInt(UM.Theme.getSize("sidebar").width * .55)
anchors.left: infillCellLeft.right anchors.left: infillCellLeft.right
anchors.top: infillCellLeft.top anchors.top: infillCellLeft.top
@ -477,10 +437,10 @@ Item
//anchors.top: parent.top //anchors.top: parent.top
anchors.left: infillSlider.left anchors.left: infillSlider.left
anchors.leftMargin: Math.floor((infillSlider.value / infillSlider.stepSize) * (infillSlider.width / (infillSlider.maximumValue / infillSlider.stepSize)) - 10 * screenScaleFactor) anchors.leftMargin: parseInt((infillSlider.value / infillSlider.stepSize) * (infillSlider.width / (infillSlider.maximumValue / infillSlider.stepSize)) - 10 * screenScaleFactor)
anchors.right: parent.right anchors.right: parent.right
text: Math.floor(infillDensity.properties.value) + "%" text: parseInt(infillDensity.properties.value) + "%"
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
color: infillSlider.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") color: infillSlider.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
@ -490,7 +450,7 @@ Item
Binding { Binding {
target: infillSlider target: infillSlider
property: "value" property: "value"
value: Math.floor(infillDensity.properties.value) value: parseInt(infillDensity.properties.value)
} }
Slider Slider
@ -503,7 +463,7 @@ Item
anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width
height: UM.Theme.getSize("sidebar_margin").height height: UM.Theme.getSize("sidebar_margin").height
width: Math.floor(infillCellRight.width - UM.Theme.getSize("sidebar_margin").width - style.handleWidth) width: parseInt(infillCellRight.width - UM.Theme.getSize("sidebar_margin").width - style.handleWidth)
minimumValue: 0 minimumValue: 0
maximumValue: 100 maximumValue: 100
@ -511,15 +471,15 @@ Item
tickmarksEnabled: true tickmarksEnabled: true
// disable slider when gradual support is enabled // disable slider when gradual support is enabled
enabled: Math.floor(infillSteps.properties.value) == 0 enabled: parseInt(infillSteps.properties.value) == 0
// set initial value from stack // set initial value from stack
value: Math.floor(infillDensity.properties.value) value: parseInt(infillDensity.properties.value)
onValueChanged: { onValueChanged: {
// Don't round the value if it's already the same // Don't round the value if it's already the same
if (Math.floor(infillDensity.properties.value) == infillSlider.value) { if (parseInt(infillDensity.properties.value) == infillSlider.value) {
return return
} }
@ -588,7 +548,7 @@ Item
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height / 2) anchors.topMargin: parseInt(UM.Theme.getSize("sidebar_margin").height / 2)
// we loop over all density icons and only show the one that has the current density and steps // we loop over all density icons and only show the one that has the current density and steps
Repeater Repeater
@ -599,8 +559,8 @@ Item
property int activeIndex: { property int activeIndex: {
for (var i = 0; i < infillModel.count; i++) { for (var i = 0; i < infillModel.count; i++) {
var density = Math.floor(infillDensity.properties.value) var density = parseInt(infillDensity.properties.value)
var steps = Math.floor(infillSteps.properties.value) var steps = parseInt(infillSteps.properties.value)
var infillModelItem = infillModel.get(i) var infillModelItem = infillModel.get(i)
if (density >= infillModelItem.percentageMin if (density >= infillModelItem.percentageMin
@ -639,13 +599,13 @@ Item
property alias _hovered: enableGradualInfillMouseArea.containsMouse property alias _hovered: enableGradualInfillMouseArea.containsMouse
anchors.top: infillSlider.bottom anchors.top: infillSlider.bottom
anchors.topMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height / 2) // closer to slider since it belongs to the same category anchors.topMargin: parseInt(UM.Theme.getSize("sidebar_margin").height / 2) // closer to slider since it belongs to the same category
anchors.left: infillCellRight.left anchors.left: infillCellRight.left
style: UM.Theme.styles.checkbox style: UM.Theme.styles.checkbox
enabled: base.settingsEnabled enabled: base.settingsEnabled
visible: infillSteps.properties.enabled == "True" visible: infillSteps.properties.enabled == "True"
checked: Math.floor(infillSteps.properties.value) > 0 checked: parseInt(infillSteps.properties.value) > 0
MouseArea { MouseArea {
id: enableGradualInfillMouseArea id: enableGradualInfillMouseArea
@ -654,18 +614,18 @@ Item
hoverEnabled: true hoverEnabled: true
enabled: true enabled: true
property var previousInfillDensity: Math.floor(infillDensity.properties.value) property var previousInfillDensity: parseInt(infillDensity.properties.value)
onClicked: { onClicked: {
// Set to 90% only when enabling gradual infill // Set to 90% only when enabling gradual infill
if (Math.floor(infillSteps.properties.value) == 0) { if (parseInt(infillSteps.properties.value) == 0) {
previousInfillDensity = Math.floor(infillDensity.properties.value) previousInfillDensity = parseInt(infillDensity.properties.value)
infillDensity.setPropertyValue("value", String(90)) infillDensity.setPropertyValue("value", String(90))
} else { } else {
infillDensity.setPropertyValue("value", String(previousInfillDensity)) infillDensity.setPropertyValue("value", String(previousInfillDensity))
} }
infillSteps.setPropertyValue("value", (Math.floor(infillSteps.properties.value) == 0) ? 5 : 0) infillSteps.setPropertyValue("value", (parseInt(infillSteps.properties.value) == 0) ? 5 : 0)
} }
onEntered: { onEntered: {
@ -681,7 +641,7 @@ Item
Label { Label {
id: gradualInfillLabel id: gradualInfillLabel
anchors.left: enableGradualInfillCheckBox.right anchors.left: enableGradualInfillCheckBox.right
anchors.leftMargin: Math.floor(UM.Theme.getSize("sidebar_margin").width / 2) anchors.leftMargin: parseInt(UM.Theme.getSize("sidebar_margin").width / 2)
text: catalog.i18nc("@label", "Enable gradual") text: catalog.i18nc("@label", "Enable gradual")
font: UM.Theme.getFont("default") font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")
@ -742,7 +702,7 @@ Item
visible: enableSupportCheckBox.visible visible: enableSupportCheckBox.visible
anchors.top: infillCellRight.bottom anchors.top: infillCellRight.bottom
anchors.topMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height * 1.5) anchors.topMargin: parseInt(UM.Theme.getSize("sidebar_margin").height * 1.5)
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width
anchors.right: infillCellLeft.right anchors.right: infillCellLeft.right
@ -957,7 +917,7 @@ Item
{ {
id: tipsCell id: tipsCell
anchors.top: adhesionCheckBox.visible ? adhesionCheckBox.bottom : (enableSupportCheckBox.visible ? supportExtruderCombobox.bottom : infillCellRight.bottom) anchors.top: adhesionCheckBox.visible ? adhesionCheckBox.bottom : (enableSupportCheckBox.visible ? supportExtruderCombobox.bottom : infillCellRight.bottom)
anchors.topMargin: Math.floor(UM.Theme.getSize("sidebar_margin").height * 2) anchors.topMargin: parseInt(UM.Theme.getSize("sidebar_margin").height * 2)
anchors.left: parent.left anchors.left: parent.left
width: parent.width width: parent.width
height: tipsText.contentHeight * tipsText.lineCount height: tipsText.contentHeight * tipsText.lineCount
@ -988,35 +948,6 @@ Item
storeIndex: 0 storeIndex: 0
} }
Binding
{
target: infillDensity
property: "containerStackId"
value: {
// not settable per extruder or there only is global, so we must pick global
if (machineExtruderCount.properties.value == 1) {
return Cura.MachineManager.activeStackId
}
// return the ID of the extruder when the infill is limited to an extruder
if (infillInheritStackProvider.properties.limit_to_extruder != null && infillInheritStackProvider.properties.limit_to_extruder >= 0) {
return ExtruderManager.extruderIds[String(infillInheritStackProvider.properties.limit_to_extruder)]
}
// default to the global stack
return Cura.MachineManager.activeStackId
}
}
UM.SettingPropertyProvider
{
id: infillInheritStackProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "infill_sparse_density"
watchedProperties: [ "limit_to_extruder" ]
}
UM.SettingPropertyProvider UM.SettingPropertyProvider
{ {
id: infillDensity id: infillDensity

View File

@ -8,7 +8,7 @@ type = quality
material = generic_pla material = generic_pla
weight = -1 weight = -1
quality_type = normal quality_type = normal
setting_version = 3 setting_version = 4
[values] [values]
layer_height = 0.2 layer_height = 0.2

View File

@ -8,7 +8,7 @@ type = quality
material = generic_pla material = generic_pla
weight = 1 weight = 1
quality_type = high quality_type = high
setting_version = 3 setting_version = 4
[values] [values]
layer_height = 0.1 layer_height = 0.1

View File

@ -8,7 +8,7 @@ type = quality
material = generic_pla material = generic_pla
weight = 0 weight = 0
quality_type = normal quality_type = normal
setting_version = 3 setting_version = 4
[values] [values]
layer_height = 0.2 layer_height = 0.2

View File

@ -8,7 +8,7 @@ type = quality
material = generic_pla material = generic_pla
weight = -1 weight = -1
quality_type = normal quality_type = normal
setting_version = 3 setting_version = 4
[values] [values]
layer_height = 0.2 layer_height = 0.2

View File

@ -8,7 +8,7 @@ type = quality
material = generic_pla material = generic_pla
weight = 1 weight = 1
quality_type = high quality_type = high
setting_version = 3 setting_version = 4
[values] [values]
layer_height = 0.1 layer_height = 0.1

View File

@ -8,7 +8,7 @@ type = quality
material = generic_pla material = generic_pla
weight = 0 weight = 0
quality_type = normal quality_type = normal
setting_version = 3 setting_version = 4
[values] [values]
layer_height = 0.2 layer_height = 0.2

View File

@ -8,7 +8,7 @@ type = quality
material = generic_pla material = generic_pla
weight = -1 weight = -1
quality_type = normal quality_type = normal
setting_version = 3 setting_version = 4
[values] [values]
layer_height = 0.2 layer_height = 0.2

View File

@ -7,7 +7,7 @@ type = quality
material = generic_pla material = generic_pla
weight = 1 weight = 1
quality_type = high quality_type = high
setting_version = 3 setting_version = 4
[values] [values]
layer_height = 0.1 layer_height = 0.1

View File

@ -8,7 +8,7 @@ type = quality
material = generic_pla material = generic_pla
weight = 0 weight = 0
quality_type = normal quality_type = normal
setting_version = 3 setting_version = 4
[values] [values]
layer_height = 0.2 layer_height = 0.2

View File

@ -0,0 +1,25 @@
[general]
version = 2
name = Coarse
definition = builder_premium_small
[metadata]
type = quality
quality_type = coarse
material = generic_pla_175
setting_version = 4
weight = -1
global_quality = True
[values]
material_print_temperature = =default_material_print_temperature + 15
material_standby_temperature = =material_print_temperature
material_initial_print_temperature= =material_print_temperature
material_final_print_temperature= =material_print_temperature
material_bed_temperature = 45
material_bed_temperature_layer_0= =material_bed_temperature
layer_height = 0.3
top_thickness = =layer_height * 5
bottom_thickness = =layer_height * 3
speed_print = 60

View File

@ -0,0 +1,26 @@
[general]
version = 2
name = High Quality
definition = builder_premium_small
[metadata]
type = quality
quality_type = high
material = generic_pla_175
setting_version = 4
weight = 1
global_quality = True
[values]
acceleration_print = 2000
material_print_temperature = =default_material_print_temperature + 15
material_standby_temperature = =material_print_temperature
material_initial_print_temperature= =material_print_temperature
material_final_print_temperature= =material_print_temperature
material_bed_temperature = 45
material_bed_temperature_layer_0= =material_bed_temperature
layer_height = 0.1
top_thickness = =layer_height * 7
bottom_thickness = =layer_height * 5
speed_print = 40
layer_height_0 = 0.2

View File

@ -0,0 +1,24 @@
[general]
version = 2
name = Normal
definition = builder_premium_small
[metadata]
type = quality
quality_type = normal
material = generic_pla_175
setting_version = 4
weight = 0
global_quality = True
[values]
material_print_temperature = =default_material_print_temperature + 15
material_standby_temperature = =material_print_temperature
material_initial_print_temperature= =material_print_temperature
material_final_print_temperature= =material_print_temperature
material_bed_temperature = 45
material_bed_temperature_layer_0= =material_bed_temperature
layer_height = 0.2
top_thickness = =layer_height * 5
bottom_thickness = =layer_height * 3
speed_print = 50

View File

@ -8,7 +8,7 @@ type = quality
quality_type = high quality_type = high
material = generic_abs_175_cartesio_0.25_mm material = generic_abs_175_cartesio_0.25_mm
weight = 1 weight = 1
setting_version = 3 setting_version = 4
[values] [values]
infill_line_width = 0.3 infill_line_width = 0.3

View File

@ -8,7 +8,7 @@ type = quality
quality_type = normal quality_type = normal
material = generic_abs_175_cartesio_0.25_mm material = generic_abs_175_cartesio_0.25_mm
weight = 2 weight = 2
setting_version = 3 setting_version = 4
[values] [values]
infill_line_width = 0.3 infill_line_width = 0.3

View File

@ -8,7 +8,7 @@ type = quality
quality_type = high quality_type = high
material = generic_abs_175_cartesio_0.4_mm material = generic_abs_175_cartesio_0.4_mm
weight = 1 weight = 1
setting_version = 3 setting_version = 4
[values] [values]
infill_line_width = 0.5 infill_line_width = 0.5

View File

@ -8,7 +8,7 @@ type = quality
quality_type = normal quality_type = normal
material = generic_abs_175_cartesio_0.4_mm material = generic_abs_175_cartesio_0.4_mm
weight = 2 weight = 2
setting_version = 3 setting_version = 4
[values] [values]
infill_line_width = 0.5 infill_line_width = 0.5

View File

@ -8,7 +8,7 @@ type = quality
quality_type = coarse quality_type = coarse
material = generic_abs_175_cartesio_0.8_mm material = generic_abs_175_cartesio_0.8_mm
weight = 3 weight = 3
setting_version = 3 setting_version = 4
[values] [values]
infill_line_width = 0.9 infill_line_width = 0.9

View File

@ -8,7 +8,7 @@ type = quality
quality_type = extra coarse quality_type = extra coarse
material = generic_abs_175_cartesio_0.8_mm material = generic_abs_175_cartesio_0.8_mm
weight = 4 weight = 4
setting_version = 3 setting_version = 4
[values] [values]
infill_line_width = 0.9 infill_line_width = 0.9

View File

@ -8,7 +8,7 @@ type = quality
quality_type = high quality_type = high
material = generic_abs_175_cartesio_0.8_mm material = generic_abs_175_cartesio_0.8_mm
weight = 1 weight = 1
setting_version = 3 setting_version = 4
[values] [values]
infill_line_width = 0.9 infill_line_width = 0.9

View File

@ -8,7 +8,7 @@ type = quality
quality_type = normal quality_type = normal
material = generic_abs_175_cartesio_0.8_mm material = generic_abs_175_cartesio_0.8_mm
weight = 2 weight = 2
setting_version = 3 setting_version = 4
[values] [values]
infill_line_width = 0.9 infill_line_width = 0.9

View File

@ -8,7 +8,7 @@ type = quality
quality_type = high quality_type = high
material = dsm_arnitel2045_175_cartesio_0.4_mm material = dsm_arnitel2045_175_cartesio_0.4_mm
weight = 1 weight = 1
setting_version = 3 setting_version = 4
[values] [values]
infill_line_width = 0.5 infill_line_width = 0.5

View File

@ -8,7 +8,7 @@ type = quality
quality_type = normal quality_type = normal
material = dsm_arnitel2045_175_cartesio_0.4_mm material = dsm_arnitel2045_175_cartesio_0.4_mm
weight = 2 weight = 2
setting_version = 3 setting_version = 4
[values] [values]
infill_line_width = 0.5 infill_line_width = 0.5

View File

@ -8,7 +8,7 @@ type = quality
quality_type = coarse quality_type = coarse
global_quality = True global_quality = True
weight = -3 weight = -3
setting_version = 3 setting_version = 4
[values] [values]
layer_height = 0.4 layer_height = 0.4

View File

@ -8,7 +8,7 @@ type = quality
quality_type = extra coarse quality_type = extra coarse
global_quality = True global_quality = True
weight = -4 weight = -4
setting_version = 3 setting_version = 4
[values] [values]
layer_height = 0.6 layer_height = 0.6

View File

@ -8,7 +8,7 @@ type = quality
quality_type = high quality_type = high
global_quality = True global_quality = True
weight = 1 weight = 1
setting_version = 3 setting_version = 4
[values] [values]
layer_height = 0.1 layer_height = 0.1

Some files were not shown because too many files have changed in this diff Show More