Merge master. CURA-2006

This commit is contained in:
Jack Ha 2016-08-16 15:08:25 +02:00
commit 8c0837d75d
58 changed files with 11611 additions and 530 deletions

View File

@ -14,6 +14,7 @@ add_custom_command(TARGET tests POST_BUILD COMMAND "PYTHONPATH=${CMAKE_SOURCE_DI
set(CURA_VERSION "master" CACHE STRING "Version name of Cura") set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'") set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'")
configure_file(${CMAKE_SOURCE_DIR}/cura.desktop.in ${CMAKE_BINARY_DIR}/cura.desktop @ONLY)
configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY) configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY)
# Macro needed to list all sub-directory of a directory. # Macro needed to list all sub-directory of a directory.
@ -76,7 +77,7 @@ if(NOT APPLE AND NOT WIN32)
FILES_MATCHING PATTERN *.py) FILES_MATCHING PATTERN *.py)
install(FILES ${CMAKE_BINARY_DIR}/CuraVersion.py install(FILES ${CMAKE_BINARY_DIR}/CuraVersion.py
DESTINATION lib/python${PYTHON_VERSION_MAJOR}/dist-packages/cura) DESTINATION lib/python${PYTHON_VERSION_MAJOR}/dist-packages/cura)
install(FILES cura.desktop install(FILES ${CMAKE_BINARY_DIR}/cura.desktop
DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
install(FILES cura.sharedmimeinfo install(FILES cura.sharedmimeinfo
DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages/ DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages/

View File

@ -5,9 +5,9 @@ Name[de]=Cura
GenericName=3D Printing Software GenericName=3D Printing Software
GenericName[de]=3D-Druck-Software GenericName[de]=3D-Druck-Software
Comment=Cura converts 3D models into paths for a 3D printer. It prepares your print for maximum accuracy, minimum printing time and good reliability with many extra features that make your print come out great. Comment=Cura converts 3D models into paths for a 3D printer. It prepares your print for maximum accuracy, minimum printing time and good reliability with many extra features that make your print come out great.
Exec=/usr/bin/cura %F Exec=@CMAKE_INSTALL_FULL_BINDIR@/cura %F
TryExec=/usr/bin/cura TryExec=@CMAKE_INSTALL_FULL_BINDIR@/cura
Icon=/usr/share/cura/resources/images/cura-icon.png Icon=@CMAKE_INSTALL_FULL_DATADIR@/cura/resources/images/cura-icon.png
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

View File

@ -208,7 +208,7 @@ class BuildVolume(SceneNode):
"@info:status", "@info:status",
"The build volume height has been reduced due to the value of the" "The build volume height has been reduced due to the value of the"
" \"Print Sequence\" setting to prevent the gantry from colliding" " \"Print Sequence\" setting to prevent the gantry from colliding"
" with printed objects."), lifetime=10).show() " with printed models."), lifetime=10).show()
def getRaftThickness(self): def getRaftThickness(self):
return self._raft_thickness return self._raft_thickness
@ -265,7 +265,7 @@ class BuildVolume(SceneNode):
self._height = self._active_container_stack.getProperty("machine_height", "value") self._height = self._active_container_stack.getProperty("machine_height", "value")
rebuild_me = True rebuild_me = True
if setting_key in self._skirt_settings: if setting_key in self._skirt_settings or setting_key in self._prime_settings or setting_key in self._tower_settings:
self._updateDisallowedAreas() self._updateDisallowedAreas()
rebuild_me = True rebuild_me = True
@ -284,12 +284,26 @@ class BuildVolume(SceneNode):
self._active_container_stack.getProperty("machine_disallowed_areas", "value")) self._active_container_stack.getProperty("machine_disallowed_areas", "value"))
areas = [] areas = []
machine_width = self._active_container_stack.getProperty("machine_width", "value")
machine_depth = self._active_container_stack.getProperty("machine_depth", "value")
# Add prima tower location as disallowed area.
if self._active_container_stack.getProperty("prime_tower_enable", "value"):
half_prime_tower_size = self._active_container_stack.getProperty("prime_tower_size", "value") / 2
prime_tower_x = self._active_container_stack.getProperty("prime_tower_position_x", "value") - machine_width / 2
prime_tower_y = - self._active_container_stack.getProperty("prime_tower_position_y", "value") + machine_depth / 2
disallowed_areas.append([
[prime_tower_x - half_prime_tower_size, prime_tower_y - half_prime_tower_size],
[prime_tower_x + half_prime_tower_size, prime_tower_y - half_prime_tower_size],
[prime_tower_x + half_prime_tower_size, prime_tower_y + half_prime_tower_size],
[prime_tower_x - half_prime_tower_size, prime_tower_y + half_prime_tower_size],
])
# Add extruder prime locations as disallowed areas. # Add extruder prime locations as disallowed areas.
# Probably needs some rework after coordinate system change. # Probably needs some rework after coordinate system change.
extruder_manager = ExtruderManager.getInstance() extruder_manager = ExtruderManager.getInstance()
extruders = extruder_manager.getMachineExtruders(self._active_container_stack.getId()) extruders = extruder_manager.getMachineExtruders(self._active_container_stack.getId())
machine_width = self._active_container_stack.getProperty("machine_width", "value")
machine_depth = self._active_container_stack.getProperty("machine_depth", "value")
for single_extruder in extruders: for single_extruder in extruders:
extruder_prime_pos_x = single_extruder.getProperty("extruder_prime_pos_x", "value") extruder_prime_pos_x = single_extruder.getProperty("extruder_prime_pos_x", "value")
extruder_prime_pos_y = single_extruder.getProperty("extruder_prime_pos_y", "value") extruder_prime_pos_y = single_extruder.getProperty("extruder_prime_pos_y", "value")
@ -377,3 +391,5 @@ class BuildVolume(SceneNode):
_skirt_settings = ["adhesion_type", "skirt_gap", "skirt_line_count", "skirt_brim_line_width", "brim_width", "brim_line_count", "raft_margin", "draft_shield_enabled", "draft_shield_dist", "xy_offset"] _skirt_settings = ["adhesion_type", "skirt_gap", "skirt_line_count", "skirt_brim_line_width", "brim_width", "brim_line_count", "raft_margin", "draft_shield_enabled", "draft_shield_dist", "xy_offset"]
_raft_settings = ["adhesion_type", "raft_base_thickness", "raft_interface_thickness", "raft_surface_layers", "raft_surface_thickness", "raft_airgap"] _raft_settings = ["adhesion_type", "raft_base_thickness", "raft_interface_thickness", "raft_surface_layers", "raft_surface_thickness", "raft_airgap"]
_prime_settings = ["extruder_prime_pos_x", "extruder_prime_pos_y", "extruder_prime_pos_z"]
_tower_settings = ["prime_tower_enable", "prime_tower_size", "prime_tower_position_x", "prime_tower_position_y"]

View File

@ -58,14 +58,6 @@ import copy
import urllib import urllib
numpy.seterr(all="ignore") numpy.seterr(all="ignore")
#WORKAROUND: GITHUB-88 GITHUB-385 GITHUB-612
if Platform.isLinux(): # Needed for platform.linux_distribution, which is not available on Windows and OSX
# For Ubuntu: https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826
if platform.linux_distribution()[0] in ("Ubuntu", ): # TODO: Needs a "if X11_GFX == 'nvidia'" here. The workaround is only needed on Ubuntu+NVidia drivers. Other drivers are not affected, but fine with this fix.
import ctypes
from ctypes.util import find_library
ctypes.CDLL(find_library('GL'), ctypes.RTLD_GLOBAL)
try: try:
from cura.CuraVersion import CuraVersion, CuraBuildType from cura.CuraVersion import CuraVersion, CuraBuildType
except ImportError: except ImportError:
@ -242,13 +234,20 @@ class CuraApplication(QtApplication):
support support
support_enable support_enable
support_type support_type
support_roof_density support_interface_density
platform_adhesion platform_adhesion
adhesion_type adhesion_type
brim_width brim_width
raft_airgap raft_airgap
layer_0_z_overlap layer_0_z_overlap
raft_surface_layers raft_surface_layers
dual
adhesion_extruder_nr
support_extruder_nr
prime_tower_enable
prime_tower_size
prime_tower_position_x
prime_tower_position_y
meshfix meshfix
blackmagic blackmagic
print_sequence print_sequence

View File

@ -31,10 +31,13 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._head_y = 0 self._head_y = 0
self._head_z = 0 self._head_z = 0
self._connection_state = ConnectionState.closed self._connection_state = ConnectionState.closed
self._connection_text = ""
self._time_elapsed = 0 self._time_elapsed = 0
self._time_total = 0 self._time_total = 0
self._job_state = "" self._job_state = ""
self._job_name = "" self._job_name = ""
self._error_text = ""
self._accepts_commands = True
def requestWrite(self, node, file_name = None, filter_by_machine = False): def requestWrite(self, node, file_name = None, filter_by_machine = False):
raise NotImplementedError("requestWrite needs to be implemented") raise NotImplementedError("requestWrite needs to be implemented")
@ -69,6 +72,8 @@ class PrinterOutputDevice(QObject, OutputDevice):
# it also sends it's own device_id (for convenience sake) # it also sends it's own device_id (for convenience sake)
connectionStateChanged = pyqtSignal(str) connectionStateChanged = pyqtSignal(str)
connectionTextChanged = pyqtSignal()
timeElapsedChanged = pyqtSignal() timeElapsedChanged = pyqtSignal()
timeTotalChanged = pyqtSignal() timeTotalChanged = pyqtSignal()
@ -77,6 +82,10 @@ class PrinterOutputDevice(QObject, OutputDevice):
jobNameChanged = pyqtSignal() jobNameChanged = pyqtSignal()
errorTextChanged = pyqtSignal()
acceptsCommandsChanged = pyqtSignal()
@pyqtProperty(str, notify = jobStateChanged) @pyqtProperty(str, notify = jobStateChanged)
def jobState(self): def jobState(self):
return self._job_state return self._job_state
@ -102,6 +111,26 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._job_name = name self._job_name = name
self.jobNameChanged.emit() self.jobNameChanged.emit()
@pyqtProperty(str, notify = errorTextChanged)
def errorText(self):
return self._error_text
## Set the error-text that is shown in the print monitor in case of an error
def setErrorText(self, error_text):
if self._error_text != error_text:
self._error_text = error_text
self.errorTextChanged.emit()
@pyqtProperty(bool, notify = acceptsCommandsChanged)
def acceptsCommands(self):
return self._accepts_commands
## Set a flag to signal the UI that the printer is not (yet) ready to receive commands
def setAcceptsCommands(self, accepts_commands):
if self._accepts_commands != accepts_commands:
self._accepts_commands = accepts_commands
self.acceptsCommandsChanged.emit()
## Get the bed temperature of the bed (if any) ## Get the bed temperature of the bed (if any)
# This function is "final" (do not re-implement) # This function is "final" (do not re-implement)
# /sa _getBedTemperature implementation function # /sa _getBedTemperature implementation function
@ -266,6 +295,16 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._connection_state = connection_state self._connection_state = connection_state
self.connectionStateChanged.emit(self._id) self.connectionStateChanged.emit(self._id)
@pyqtProperty(str, notify = connectionTextChanged)
def connectionText(self):
return self._connection_text
## Set a text that is shown on top of the print monitor tab
def setConnectionText(self, connection_text):
if self._connection_text != connection_text:
self._connection_text = connection_text
self.connectionTextChanged.emit()
## Ensure that close gets called when object is destroyed ## Ensure that close gets called when object is destroyed
def __del__(self): def __del__(self):
self.close() self.close()

View File

@ -41,7 +41,6 @@ class ContainerSettingsModel(ListModel):
keys = keys + list(container.getAllKeys()) keys = keys + list(container.getAllKeys())
keys = list(set(keys)) # remove duplicate keys keys = list(set(keys)) # remove duplicate keys
keys.sort()
for key in keys: for key in keys:
definition = None definition = None
@ -72,6 +71,7 @@ class ContainerSettingsModel(ListModel):
"unit": definition.unit, "unit": definition.unit,
"category": category.label "category": category.label
}) })
self.sort(lambda k: (k["category"], k["key"]))
## Set the ids of the containers which have the settings this model should list. ## Set the ids of the containers which have the settings this model should list.
# Also makes sure the model updates when the containers have property changes # Also makes sure the model updates when the containers have property changes

View File

@ -315,7 +315,7 @@ class ExtruderManager(QObject):
result = [] result = []
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()): for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
value = extruder.getRawProperty(key, "value", use_next = False) value = extruder.getRawProperty(key, "value")
if not value: if not value:
continue continue
@ -337,16 +337,17 @@ class ExtruderManager(QObject):
# \param extruder_index The index of the extruder to get the value from. # \param extruder_index The index of the extruder to get the value from.
# \param key The key of the setting to get the value of. # \param key The key of the setting to get the value of.
# #
# \return The value of the setting for the specified extruder or None if not found. # \return The value of the setting for the specified extruder or for the
# global stack if not found.
@staticmethod @staticmethod
def getExtruderValue(extruder_index, key): def getExtruderValue(extruder_index, key):
extruder = ExtruderManager.getInstance().getExtruderStack(extruder_index) extruder = ExtruderManager.getInstance().getExtruderStack(extruder_index)
value = None
if extruder: if extruder:
value = extruder.getRawProperty(key, "value", use_next = False) value = extruder.getRawProperty(key, "value")
if isinstance(value, UM.Settings.SettingFunction):
if isinstance(value, UM.Settings.SettingFunction): value = value(extruder)
value = value(extruder) else: #Just a value from global.
value = UM.Application.getInstance().getGlobalContainerStack().getProperty(key, "value")
return value return value

View File

@ -20,7 +20,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
NameRole = Qt.UserRole + 2 NameRole = Qt.UserRole + 2
## Colour of the material loaded in the extruder. ## Colour of the material loaded in the extruder.
ColourRole = Qt.UserRole + 3 ColorRole = Qt.UserRole + 3
## Index of the extruder, which is also the value of the setting itself. ## Index of the extruder, which is also the value of the setting itself.
# #
@ -31,7 +31,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
## List of colours to display if there is no material or the material has no known ## List of colours to display if there is no material or the material has no known
# colour. # colour.
defaultColours = ["#ffc924", "#86ec21", "#22eeee", "#245bff", "#9124ff", "#ff24c8"] defaultColors = ["#ffc924", "#86ec21", "#22eeee", "#245bff", "#9124ff", "#ff24c8"]
## Initialises the extruders model, defining the roles and listening for ## Initialises the extruders model, defining the roles and listening for
# changes in the data. # changes in the data.
@ -42,7 +42,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
self.addRoleName(self.IdRole, "id") self.addRoleName(self.IdRole, "id")
self.addRoleName(self.NameRole, "name") self.addRoleName(self.NameRole, "name")
self.addRoleName(self.ColourRole, "colour") self.addRoleName(self.ColorRole, "color")
self.addRoleName(self.IndexRole, "index") self.addRoleName(self.IndexRole, "index")
self._add_global = False self._add_global = False
@ -104,11 +104,11 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
if global_container_stack: if global_container_stack:
if self._add_global: if self._add_global:
material = global_container_stack.findContainer({ "type": "material" }) material = global_container_stack.findContainer({ "type": "material" })
colour = material.getMetaDataEntry("color_code", default = self.defaultColours[0]) if material else self.defaultColours[0] color = material.getMetaDataEntry("color_code", default = self.defaultColors[0]) if material else self.defaultColors[0]
item = { item = {
"id": global_container_stack.getId(), "id": global_container_stack.getId(),
"name": "Global", "name": "Global",
"colour": colour, "color": color,
"index": -1 "index": -1
} }
self.appendItem(item) self.appendItem(item)
@ -125,12 +125,12 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
position = int(position) position = int(position)
except ValueError: #Not a proper int. except ValueError: #Not a proper int.
position = -1 position = -1
default_colour = self.defaultColours[position] if position >= 0 and position < len(self.defaultColours) else self.defaultColours[0] default_color = self.defaultColors[position] if position >= 0 and position < len(self.defaultColors) else self.defaultColors[0]
colour = material.getMetaDataEntry("color_code", default = default_colour) if material else default_colour color = material.getMetaDataEntry("color_code", default = default_color) if material else default_color
item = { #Construct an item with only the relevant information. item = { #Construct an item with only the relevant information.
"id": extruder.getId(), "id": extruder.getId(),
"name": extruder_name, "name": extruder_name,
"colour": colour, "color": color,
"index": position "index": position
} }
self.appendItem(item) self.appendItem(item)

View File

@ -167,7 +167,7 @@ class MachineManager(QObject):
# Save the material that needs to be changed. Multiple changes will be handled by the callback. # Save the material that needs to be changed. Multiple changes will be handled by the callback.
self._auto_materials_changed[str(index)] = containers[0].getId() self._auto_materials_changed[str(index)] = containers[0].getId()
Application.getInstance().messageBox(catalog.i18nc("@window:title", "Changes on the Printer"), catalog.i18nc("@label", "Do you want to change the materials and hotends to match the material in your printer?"), Application.getInstance().messageBox(catalog.i18nc("@window:title", "Changes on the Printer"), catalog.i18nc("@label", "Do you want to change the materials and hotends to match the material in your printer?"),
catalog.i18nc("@label", "The materials and / or hotends on your printer were changed. For best results always slice for the materials . hotends that are inserted in your printer."), catalog.i18nc("@label", "The materials and / or hotends on your printer were changed. For best results always slice for the materials and hotends that are inserted in your printer."),
buttons = QMessageBox.Yes + QMessageBox.No, icon = QMessageBox.Question, callback = self._materialHotendChangedCallback) buttons = QMessageBox.Yes + QMessageBox.No, icon = QMessageBox.Question, callback = self._materialHotendChangedCallback)
else: else:
@ -629,6 +629,16 @@ class MachineManager(QObject):
return "" return ""
## Gets how the active definition calls variants
# Caveat: per-definition-variant-title is currently not translated (though the fallback is)
@pyqtProperty(str, notify = globalContainerChanged)
def activeDefinitionVariantsName(self):
fallback_title = catalog.i18nc("@label", "Nozzle")
if self._global_container_stack:
return self._global_container_stack.getBottom().getMetaDataEntry("variants_name", fallback_title)
return fallback_title
@pyqtSlot(str, str) @pyqtSlot(str, str)
def renameMachine(self, machine_id, new_name): def renameMachine(self, machine_id, new_name):
containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id) containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id)

View File

@ -5,6 +5,18 @@
import os import os
import sys import sys
import platform
from UM.Platform import Platform
#WORKAROUND: GITHUB-88 GITHUB-385 GITHUB-612
if Platform.isLinux(): # Needed for platform.linux_distribution, which is not available on Windows and OSX
# For Ubuntu: https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826
if platform.linux_distribution()[0] in ("debian", "Ubuntu", "LinuxMint"): # TODO: Needs a "if X11_GFX == 'nvidia'" here. The workaround is only needed on Ubuntu+NVidia drivers. Other drivers are not affected, but fine with this fix.
import ctypes
from ctypes.util import find_library
libGL = find_library("GL")
ctypes.CDLL(libGL, ctypes.RTLD_GLOBAL)
#WORKAROUND: GITHUB-704 GITHUB-708 #WORKAROUND: GITHUB-704 GITHUB-708
# It looks like setuptools creates a .pth file in # It looks like setuptools creates a .pth file in

View File

@ -68,6 +68,7 @@ class ChangeLog(Extension, QObject,):
line = line.replace("[","") line = line.replace("[","")
line = line.replace("]","") line = line.replace("]","")
open_version = Version(line) open_version = Version(line)
open_header = ""
self._change_logs[open_version] = collections.OrderedDict() self._change_logs[open_version] = collections.OrderedDict()
elif line.startswith("*"): elif line.startswith("*"):
open_header = line.replace("*","") open_header = line.replace("*","")

View File

@ -13,7 +13,6 @@ from UM.Resources import Resources
from UM.Settings.Validator import ValidatorState #To find if a setting is in an error state. We can't slice then. from UM.Settings.Validator import ValidatorState #To find if a setting is in an error state. We can't slice then.
from UM.Platform import Platform from UM.Platform import Platform
import cura.Settings import cura.Settings
from cura.OneAtATimeIterator import OneAtATimeIterator from cura.OneAtATimeIterator import OneAtATimeIterator
@ -33,7 +32,6 @@ import Arcus
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
class CuraEngineBackend(Backend): class CuraEngineBackend(Backend):
## Starts the back-end plug-in. ## Starts the back-end plug-in.
# #
@ -41,14 +39,30 @@ class CuraEngineBackend(Backend):
# with the back-end in general. # with the back-end in general.
def __init__(self): def __init__(self):
super().__init__() super().__init__()
# Find out where the engine is located, and how it is called. # Find out where the engine is located, and how it is called.
# This depends on how Cura is packaged and which OS we are running on. # This depends on how Cura is packaged and which OS we are running on.
default_engine_location = os.path.join(Application.getInstallPrefix(), "bin", "CuraEngine") executable_name = "CuraEngine"
if hasattr(sys, "frozen"):
default_engine_location = os.path.join(os.path.dirname(os.path.abspath(sys.executable)), "CuraEngine")
if Platform.isWindows(): if Platform.isWindows():
default_engine_location += ".exe" executable_name += ".exe"
default_engine_location = executable_name
if os.path.exists(os.path.join(Application.getInstallPrefix(), "bin", executable_name)):
default_engine_location = os.path.join(Application.getInstallPrefix(), "bin", executable_name)
if hasattr(sys, "frozen"):
default_engine_location = os.path.join(os.path.dirname(os.path.abspath(sys.executable)), executable_name)
if Platform.isLinux() and not default_engine_location:
if not os.getenv("PATH"):
raise OSError("There is something wrong with your Linux installation.")
for pathdir in os.getenv("PATH").split(os.pathsep):
execpath = os.path.join(pathdir, executable_name)
if os.path.exists(execpath):
default_engine_location = execpath
break
if not default_engine_location:
raise EnvironmentError("Could not find CuraEngine")
Logger.log("i", "Found CuraEngine at: %s" %(default_engine_location))
default_engine_location = os.path.abspath(default_engine_location) default_engine_location = os.path.abspath(default_engine_location)
Preferences.getInstance().addPreference("backend/location", default_engine_location) Preferences.getInstance().addPreference("backend/location", default_engine_location)
@ -222,7 +236,7 @@ class CuraEngineBackend(Backend):
if job.getResult() == StartSliceJob.StartJobResult.NothingToSlice: if job.getResult() == StartSliceJob.StartJobResult.NothingToSlice:
if Application.getInstance().getPlatformActivity: if Application.getInstance().getPlatformActivity:
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. No suitable objects found.")) self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. No suitable models found."))
self._error_message.show() self._error_message.show()
self.backendStateChange.emit(BackendState.Error) self.backendStateChange.emit(BackendState.Error)
else: else:

View File

@ -227,7 +227,7 @@ class StartSliceJob(Job):
# global_inherits_stack property. # global_inherits_stack property.
def _buildGlobalInheritsStackMessage(self, stack): def _buildGlobalInheritsStackMessage(self, stack):
for key in stack.getAllKeys(): for key in stack.getAllKeys():
extruder = int(stack.getProperty(key, "global_inherits_stack")) extruder = int(round(float(stack.getProperty(key, "global_inherits_stack"))))
if extruder >= 0: #Set to a specific extruder. if extruder >= 0: #Set to a specific extruder.
setting_extruder = self._slice_message.addRepeatedMessage("global_inherits_stack") setting_extruder = self._slice_message.addRepeatedMessage("global_inherits_stack")
setting_extruder.name = key setting_extruder.name = key

View File

@ -13,7 +13,40 @@ import ".."
Button { Button {
id: base; id: base;
style: UM.Theme.styles.sidebar_category; style: ButtonStyle {
background: Item { }
label: Row
{
spacing: UM.Theme.getSize("default_lining").width
UM.RecolorImage
{
anchors.verticalCenter: parent.verticalCenter
height: label.height / 2
width: height
source: control.checked ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_right");
color: control.hovered ? palette.highlight : palette.buttonText
}
UM.RecolorImage
{
anchors.verticalCenter: parent.verticalCenter
height: label.height
width: height
source: control.iconSource
color: control.hovered ? palette.highlight : palette.buttonText
}
Label
{
id: label
anchors.verticalCenter: parent.verticalCenter
text: control.text
color: control.hovered ? palette.highlight : palette.buttonText
font.bold: true
}
SystemPalette { id: palette }
}
}
signal showTooltip(string text); signal showTooltip(string text);
signal hideTooltip(); signal hideTooltip();

View File

@ -16,17 +16,17 @@ UM.TooltipArea
width: childrenRect.width; width: childrenRect.width;
height: childrenRect.height; height: childrenRect.height;
Button CheckBox
{ {
id: check id: check
text: definition.label text: definition.label
checked: addedSettingsModel.getVisible(model.key)
onClicked: onClicked:
{ {
addedSettingsModel.setVisible(model.key, true); addedSettingsModel.setVisible(model.key, checked);
settingPickDialog.visible = false UM.ActiveTool.forceUpdate();
UM.ActiveTool.forceUpdate()
} }
} }
} }

View File

@ -59,12 +59,18 @@ class PerObjectSettingVisibilityHandler(UM.Settings.Models.SettingVisibilityHand
definition = self._stack.getSettingDefinition(item) definition = self._stack.getSettingDefinition(item)
if definition: if definition:
new_instance = SettingInstance(definition, settings) new_instance = SettingInstance(definition, settings)
if definition.global_inherits_stack: stack_nr = -1
if definition.global_inherits_stack and self._stack.getProperty("machine_extruder_count", "value") > 1:
#Obtain the value from the correct container stack. Only once, upon adding the setting. #Obtain the value from the correct container stack. Only once, upon adding the setting.
stack_nr = self._stack.getProperty(item, "global_inherits_stack") #Stack to get the setting from. stack_nr = str(int(round(float(self._stack.getProperty(item, "global_inherits_stack"))))) #Stack to get the setting from. Round it and remove the fractional part.
if int(stack_nr) >= 0: #Only if it defines an extruder stack. if stack_nr not in ExtruderManager.getInstance().extruderIds and self._stack.getProperty("extruder_nr", "value"): #Property not defined, but we have an extruder number.
extruder_stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = ExtruderManager.getInstance().extruderIds[stack_nr])[0] stack_nr = str(int(round(float(self._stack.getProperty("extruder_nr", "value")))))
new_instance.value = extruder_stack.getProperty(item, "value") if stack_nr in ExtruderManager.getInstance().extruderIds: #We have either a global_inherits_stack or an extruder_nr.
stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = ExtruderManager.getInstance().extruderIds[stack_nr])[0]
else:
stack = UM.Application.getInstance().getGlobalContainerStack()
new_instance.setProperty("value", stack.getProperty(item, "value"))
new_instance.resetState() # Ensure that the state is not seen as a user state.
settings.addInstance(new_instance) settings.addInstance(new_instance)
visibility_changed = True visibility_changed = True
else: else:

View File

@ -31,7 +31,7 @@ Item {
spacing: UM.Theme.getSize("default_margin").width spacing: UM.Theme.getSize("default_margin").width
Label Label
{ {
text: catalog.i18nc("@label", "Print object with") text: catalog.i18nc("@label", "Print model with")
anchors.verticalCenter: extruderSelector.verticalCenter anchors.verticalCenter: extruderSelector.verticalCenter
color: UM.Theme.getColor("setting_control_text") color: UM.Theme.getColor("setting_control_text")
@ -47,9 +47,9 @@ Item {
id: extruders_model id: extruders_model
onRowsInserted: extruderSelector.visible = extruders_model.rowCount() > 1 onRowsInserted: extruderSelector.visible = extruders_model.rowCount() > 1
onModelReset: extruderSelector.visible = extruders_model.rowCount() > 1 onModelReset: extruderSelector.visible = extruders_model.rowCount() > 1
onModelChanged: extruderSelector.color = extruders_model.getItem(extruderSelector.currentIndex).colour onModelChanged: extruderSelector.color = extruders_model.getItem(extruderSelector.currentIndex).color
} }
property string color: extruders_model.getItem(extruderSelector.currentIndex).colour property string color: extruders_model.getItem(extruderSelector.currentIndex).color
visible: extruders_model.rowCount() > 1 visible: extruders_model.rowCount() > 1
textRole: "name" textRole: "name"
width: UM.Theme.getSize("setting_control").width width: UM.Theme.getSize("setting_control").width
@ -128,7 +128,11 @@ Item {
} }
} }
onActivated: UM.ActiveTool.setProperty("SelectedActiveExtruder", extruders_model.getItem(index).id); onActivated:
{
UM.ActiveTool.setProperty("SelectedActiveExtruder", extruders_model.getItem(index).id);
extruderSelector.color = extruders_model.getItem(index).color;
}
onModelChanged: updateCurrentIndex(); onModelChanged: updateCurrentIndex();
function updateCurrentIndex() function updateCurrentIndex()
@ -138,7 +142,7 @@ Item {
if(extruders_model.getItem(i).id == UM.ActiveTool.properties.getValue("SelectedActiveExtruder")) if(extruders_model.getItem(i).id == UM.ActiveTool.properties.getValue("SelectedActiveExtruder"))
{ {
extruderSelector.currentIndex = i; extruderSelector.currentIndex = i;
extruderSelector.color = extruders_model.getItem(i).colour; extruderSelector.color = extruders_model.getItem(i).color;
return; return;
} }
} }
@ -147,106 +151,111 @@ Item {
} }
} }
Repeater Column
{ {
id: contents spacing: UM.Theme.getSize("default_lining").height
height: childrenRect.height;
model: UM.SettingDefinitionsModel Repeater
{ {
id: addedSettingsModel; id: contents
containerId: Cura.MachineManager.activeDefinitionId height: childrenRect.height;
expanded: [ "*" ]
visibilityHandler: Cura.PerObjectSettingVisibilityHandler model: UM.SettingDefinitionsModel
{ {
selectedObjectId: UM.ActiveTool.properties.getValue("SelectedObjectId") id: addedSettingsModel;
} containerId: Cura.MachineManager.activeDefinitionId
} expanded: [ "*" ]
delegate: Row visibilityHandler: Cura.PerObjectSettingVisibilityHandler
{
Loader
{
id: settingLoader
width: UM.Theme.getSize("setting").width;
height: UM.Theme.getSize("section").height;
property var definition: model
property var settingDefinitionsModel: addedSettingsModel
property var propertyProvider: provider
//Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
//In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
//causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
asynchronous: model.type != "enum" && model.type != "extruder"
onLoaded: {
settingLoader.item.showRevertButton = false
settingLoader.item.showInheritButton = false
settingLoader.item.showLinkedSettingIcon = false
settingLoader.item.doDepthIndentation = false
settingLoader.item.doQualityUserSettingEmphasis = false
}
sourceComponent:
{ {
switch(model.type) selectedObjectId: UM.ActiveTool.properties.getValue("SelectedObjectId")
{ }
case "int": }
return settingTextField
case "float": delegate: Row
return settingTextField {
case "enum": Loader
return settingComboBox {
case "extruder": id: settingLoader
return settingExtruder width: UM.Theme.getSize("setting").width
case "bool": height: UM.Theme.getSize("section").height
return settingCheckBox
case "str": property var definition: model
return settingTextField property var settingDefinitionsModel: addedSettingsModel
case "category": property var propertyProvider: provider
return settingCategory
default: //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
return settingUnknown //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
//causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
asynchronous: model.type != "enum" && model.type != "extruder"
onLoaded: {
settingLoader.item.showRevertButton = false
settingLoader.item.showInheritButton = false
settingLoader.item.showLinkedSettingIcon = false
settingLoader.item.doDepthIndentation = false
settingLoader.item.doQualityUserSettingEmphasis = false
} }
}
}
Button sourceComponent:
{
width: UM.Theme.getSize("setting").height;
height: UM.Theme.getSize("setting").height;
onClicked: addedSettingsModel.setVisible(model.key, false);
style: ButtonStyle
{
background: Item
{ {
UM.RecolorImage switch(model.type)
{ {
anchors.verticalCenter: parent.verticalCenter case "int":
anchors.horizontalCenter: parent.horizontalCenter return settingTextField
width: parent.width/2 case "float":
height: parent.height/2 return settingTextField
sourceSize.width: width case "enum":
sourceSize.height: width return settingComboBox
color: control.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button") case "extruder":
source: UM.Theme.getIcon("cross1") return settingExtruder
case "bool":
return settingCheckBox
case "str":
return settingTextField
case "category":
return settingCategory
default:
return settingUnknown
} }
} }
} }
}
UM.SettingPropertyProvider
{
id: provider
containerStackId: UM.ActiveTool.properties.getValue("ContainerID") Button
key: model.key {
watchedProperties: [ "value", "enabled", "validationState" ] width: UM.Theme.getSize("setting").height / 2;
storeIndex: 0 height: UM.Theme.getSize("setting").height;
removeUnusedValue: false
onClicked: addedSettingsModel.setVisible(model.key, false);
style: ButtonStyle
{
background: Item
{
UM.RecolorImage
{
anchors.verticalCenter: parent.verticalCenter
width: parent.width
height: parent.height / 2
sourceSize.width: width
sourceSize.height: width
color: control.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button")
source: UM.Theme.getIcon("minus")
}
}
}
}
UM.SettingPropertyProvider
{
id: provider
containerStackId: UM.ActiveTool.properties.getValue("ContainerID")
key: model.key
watchedProperties: [ "value", "enabled", "validationState" ]
storeIndex: 0
removeUnusedValue: false
}
} }
} }
} }
@ -257,7 +266,7 @@ Item {
height: UM.Theme.getSize("setting").height; height: UM.Theme.getSize("setting").height;
visible: parseInt(UM.Preferences.getValue("cura/active_mode")) == 1 visible: parseInt(UM.Preferences.getValue("cura/active_mode")) == 1
text: catalog.i18nc("@action:button", "Add Setting"); text: catalog.i18nc("@action:button", "Select settings");
style: ButtonStyle style: ButtonStyle
{ {
@ -297,16 +306,28 @@ Item {
UM.Dialog { UM.Dialog {
id: settingPickDialog id: settingPickDialog
title: catalog.i18nc("@title:window", "Pick a Setting to Customize") title: catalog.i18nc("@title:window", "Select Settings to Customize for this model")
width: screenScaleFactor * 360;
property string labelFilter: "" property string labelFilter: ""
onVisibilityChanged:
{
// force updating the model to sync it with addedSettingsModel
if(visible)
{
listview.model.forceUpdate()
}
}
TextField { TextField {
id: filter; id: filter
anchors { anchors {
top: parent.top; top: parent.top
left: parent.left; left: parent.left
right: parent.right; right: toggleShowAll.left
rightMargin: UM.Theme.getSize("default_margin").width
} }
placeholderText: catalog.i18nc("@label:textbox", "Filter..."); placeholderText: catalog.i18nc("@label:textbox", "Filter...");
@ -324,6 +345,23 @@ Item {
} }
} }
CheckBox
{
id: toggleShowAll
anchors {
top: parent.top
right: parent.right
}
text: catalog.i18nc("@label:checkbox", "Show all")
checked: listview.model.showAll
onClicked:
{
listview.model.showAll = checked;
}
}
ScrollView ScrollView
{ {
id: scrollView id: scrollView
@ -377,7 +415,7 @@ Item {
rightButtons: [ rightButtons: [
Button { Button {
text: catalog.i18nc("@action:button", "Cancel"); text: catalog.i18nc("@action:button", "Close");
onClicked: { onClicked: {
settingPickDialog.visible = false; settingPickDialog.visible = false;
} }

View File

@ -11,15 +11,15 @@ i18n_catalog = i18nCatalog("cura")
def getMetaData(): def getMetaData():
return { return {
"plugin": { "plugin": {
"name": i18n_catalog.i18nc("@label", "Per Object Settings Tool"), "name": i18n_catalog.i18nc("@label", "Per Model Settings Tool"),
"author": "Ultimaker", "author": "Ultimaker",
"version": "1.0", "version": "1.0",
"description": i18n_catalog.i18nc("@info:whatsthis", "Provides the Per Object Settings."), "description": i18n_catalog.i18nc("@info:whatsthis", "Provides the Per Model Settings."),
"api": 3 "api": 3
}, },
"tool": { "tool": {
"name": i18n_catalog.i18nc("@label", "Per Object Settings"), "name": i18n_catalog.i18nc("@label", "Per Model Settings"),
"description": i18n_catalog.i18nc("@info:tooltip", "Configure Per Object Settings"), "description": i18n_catalog.i18nc("@info:tooltip", "Configure Per Model Settings"),
"icon": "setting_per_object", "icon": "setting_per_object",
"tool_panel": "PerObjectSettingsPanel.qml", "tool_panel": "PerObjectSettingsPanel.qml",
"weight": 3 "weight": 3

View File

@ -11,11 +11,8 @@ from UM.i18n import i18nCatalog
from UM.Logger import Logger from UM.Logger import Logger
from UM.Platform import Platform from UM.Platform import Platform
from UM.Qt.Duration import DurationFormat from UM.Qt.Duration import DurationFormat
from UM.Job import Job
import collections
import json
import os.path
import copy
import platform import platform
import math import math
import urllib.request import urllib.request
@ -24,6 +21,36 @@ import ssl
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
class SliceInfoJob(Job):
data = None
url = None
def __init__(self, url, data):
super().__init__()
self.url = url
self.data = data
def run(self):
if not self.url or not self.data:
Logger.log("e", "URL or DATA for sending slice info was not set!")
return
# Submit data
kwoptions = {"data" : self.data,
"timeout" : 5
}
if Platform.isOSX():
kwoptions["context"] = ssl._create_unverified_context()
try:
f = urllib.request.urlopen(self.url, **kwoptions)
Logger.log("i", "Sent anonymous slice info to %s", self.url)
f.close()
except urllib.error.HTTPError as http_exception:
Logger.log("e", "An HTTP error occurred while trying to send slice information: %s" % http_exception)
except Exception as e: # We don't want any exception to cause problems
Logger.log("e", "An exception occurred while trying to send slice information: %s" % e)
## This Extension runs in the background and sends several bits of information to the Ultimaker servers. ## This Extension runs in the background and sends several bits of information to the Ultimaker servers.
# The data is only sent when the user in question gave permission to do so. All data is anonymous and # The data is only sent when the user in question gave permission to do so. All data is anonymous and
@ -112,19 +139,10 @@ class SliceInfo(Extension):
submitted_data = urllib.parse.urlencode(submitted_data) submitted_data = urllib.parse.urlencode(submitted_data)
binary_data = submitted_data.encode("utf-8") binary_data = submitted_data.encode("utf-8")
# Submit data # Sending slice info non-blocking
kwoptions = {"data" : binary_data, reportJob = SliceInfoJob(self.info_url, binary_data)
"timeout" : 1 reportJob.start()
} except Exception as e:
if Platform.isOSX():
kwoptions["context"] = ssl._create_unverified_context()
try:
f = urllib.request.urlopen(self.info_url, **kwoptions)
Logger.log("i", "Sent anonymous slice info to %s", self.info_url)
f.close()
except Exception as e:
Logger.logException("e", "An exception occurred while trying to send slice information")
except:
# We really can't afford to have a mistake here, as this would break the sending of g-code to a device # We really can't afford to have a mistake here, as this would break the sending of g-code to a device
# (Either saving or directly to a printer). The functionality of the slice data is not *that* important. # (Either saving or directly to a printer). The functionality of the slice data is not *that* important.
pass Logger.log("e", "Exception raised while sending slice info: %s" %(repr(e))) # But we should be notified about these problems of course.

View File

@ -8,6 +8,7 @@ from UM.Resources import Resources
from UM.Application import Application from UM.Application import Application
from UM.Preferences import Preferences from UM.Preferences import Preferences
from UM.View.Renderer import Renderer from UM.View.Renderer import Renderer
from UM.Settings.Validator import ValidatorState
from UM.View.GL.OpenGL import OpenGL from UM.View.GL.OpenGL import OpenGL
@ -40,27 +41,32 @@ class SolidView(View):
self._disabled_shader.setUniformValue("u_diffuseColor2", [0.68, 0.68, 0.68, 1.0]) self._disabled_shader.setUniformValue("u_diffuseColor2", [0.68, 0.68, 0.68, 1.0])
self._disabled_shader.setUniformValue("u_width", 50.0) self._disabled_shader.setUniformValue("u_width", 50.0)
if Application.getInstance().getGlobalContainerStack(): multi_extrusion = False
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
if Preferences.getInstance().getValue("view/show_overhang"): if Preferences.getInstance().getValue("view/show_overhang"):
angle = Application.getInstance().getGlobalContainerStack().getProperty("support_angle", "value") angle = global_container_stack.getProperty("support_angle", "value")
if angle is not None: if angle is not None and global_container_stack.getProperty("support_angle", "validationState") == ValidatorState.Valid:
self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(90 - angle))) self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(90 - angle)))
else: else:
self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) #Overhang angle of 0 causes no area at all to be marked as overhang. self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) #Overhang angle of 0 causes no area at all to be marked as overhang.
else: else:
self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0)))
multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
for node in DepthFirstIterator(scene.getRoot()): for node in DepthFirstIterator(scene.getRoot()):
if not node.render(renderer): if not node.render(renderer):
if node.getMeshData() and node.isVisible(): if node.getMeshData() and node.isVisible():
# TODO: Find a better way to handle this
#if node.getBoundingBoxMesh():
# renderer.queueNode(scene.getRoot(), mesh = node.getBoundingBoxMesh(),mode = Renderer.RenderLines)
uniforms = {} uniforms = {}
if self._extruders_model.rowCount() == 0: if not multi_extrusion:
material = Application.getInstance().getGlobalContainerStack().findContainer({ "type": "material" }) if global_container_stack:
material_color = material.getMetaDataEntry("color_code", default = self._extruders_model.defaultColours[0]) if material else self._extruders_model.defaultColours[0] material = global_container_stack.findContainer({ "type": "material" })
material_color = material.getMetaDataEntry("color_code", default = self._extruders_model.defaultColors[0]) if material else self._extruders_model.defaultColors[0]
else:
material_color = self._extruders_model.defaultColors[0]
else: else:
# Get color to render this mesh in from ExtrudersModel # Get color to render this mesh in from ExtrudersModel
extruder_index = 0 extruder_index = 0
@ -68,7 +74,7 @@ class SolidView(View):
if extruder_id: if extruder_id:
extruder_index = max(0, self._extruders_model.find("id", extruder_id)) extruder_index = max(0, self._extruders_model.find("id", extruder_id))
material_color = self._extruders_model.getItem(extruder_index)["colour"] material_color = self._extruders_model.getItem(extruder_index)["color"]
try: try:
# Colors are passed as rgb hex strings (eg "#ffffff"), and the shader needs # Colors are passed as rgb hex strings (eg "#ffffff"), and the shader needs
# an rgba list of floats (eg [1.0, 1.0, 1.0, 1.0]) # an rgba list of floats (eg [1.0, 1.0, 1.0, 1.0])

View File

@ -32,16 +32,16 @@ UM.Dialog
} }
text: { text: {
if (manager.progress == 0) if (manager.firmwareUpdateCompleteStatus)
{
//: Firmware update status label
return catalog.i18nc("@label","Starting firmware update, this may take a while.")
}
else if (manager.progress > 99)
{ {
//: Firmware update status label //: Firmware update status label
return catalog.i18nc("@label","Firmware update completed.") return catalog.i18nc("@label","Firmware update completed.")
} }
else if (manager.progress == 0)
{
//: Firmware update status label
return catalog.i18nc("@label","Starting firmware update, this may take a while.")
}
else else
{ {
//: Firmware update status label //: Firmware update status label
@ -55,10 +55,10 @@ UM.Dialog
ProgressBar ProgressBar
{ {
id: prog id: prog
value: manager.progress value: manager.firmwareUpdateCompleteStatus ? 100 : manager.progress
minimumValue: 0 minimumValue: 0
maximumValue: 100 maximumValue: 100
indeterminate: manager.progress < 100 indeterminate: (manager.progress < 1) && (!manager.firmwareUpdateCompleteStatus)
anchors anchors
{ {
left: parent.left; left: parent.left;
@ -79,7 +79,7 @@ UM.Dialog
Button Button
{ {
text: catalog.i18nc("@action:button","Close"); text: catalog.i18nc("@action:button","Close");
enabled: manager.progress >= 100; enabled: manager.firmwareUpdateCompleteStatus;
onClicked: base.visible = false; onClicked: base.visible = false;
} }
] ]

View File

@ -21,12 +21,14 @@ catalog = i18nCatalog("cura")
class USBPrinterOutputDevice(PrinterOutputDevice): class USBPrinterOutputDevice(PrinterOutputDevice):
def __init__(self, serial_port): def __init__(self, serial_port):
super().__init__(serial_port) super().__init__(serial_port)
self.setName(catalog.i18nc("@item:inmenu", "USB printing")) self.setName(catalog.i18nc("@item:inmenu", "USB printing"))
self.setShortDescription(catalog.i18nc("@action:button", "Print via USB")) self.setShortDescription(catalog.i18nc("@action:button", "Print via USB"))
self.setDescription(catalog.i18nc("@info:tooltip", "Print via USB")) self.setDescription(catalog.i18nc("@info:tooltip", "Print via USB"))
self.setIconName("print") self.setIconName("print")
self.setConnectionText(catalog.i18nc("@info:status", "Connected via USB"))
self._serial = None self._serial = None
self._serial_port = serial_port self._serial_port = serial_port
@ -85,12 +87,14 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._updating_firmware = False self._updating_firmware = False
self._firmware_file_name = None self._firmware_file_name = None
self._firmware_update_finished = False
self._error_message = None self._error_message = None
onError = pyqtSignal() onError = pyqtSignal()
firmwareUpdateComplete = pyqtSignal() firmwareUpdateComplete = pyqtSignal()
firmwareUpdateChange = pyqtSignal()
endstopStateChanged = pyqtSignal(str ,bool, arguments = ["key","state"]) endstopStateChanged = pyqtSignal(str ,bool, arguments = ["key","state"])
@ -170,6 +174,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
## Private function (threaded) that actually uploads the firmware. ## Private function (threaded) that actually uploads the firmware.
def _updateFirmware(self): def _updateFirmware(self):
self.setProgress(0, 100) self.setProgress(0, 100)
self._firmware_update_finished = False
if self._connection_state != ConnectionState.closed: if self._connection_state != ConnectionState.closed:
self.close() self.close()
@ -177,10 +182,11 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
if len(hex_file) == 0: if len(hex_file) == 0:
Logger.log("e", "Unable to read provided hex file. Could not update firmware") Logger.log("e", "Unable to read provided hex file. Could not update firmware")
return self._updateFirmware_completed()
return
programmer = stk500v2.Stk500v2() programmer = stk500v2.Stk500v2()
programmer.progressCallback = self.setProgress programmer.progress_callback = self.setProgress
try: try:
programmer.connect(self._serial_port) programmer.connect(self._serial_port)
@ -192,6 +198,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
if not programmer.isConnected(): if not programmer.isConnected():
Logger.log("e", "Unable to connect with serial. Could not update firmware") Logger.log("e", "Unable to connect with serial. Could not update firmware")
self._updateFirmware_completed()
return return
self._updating_firmware = True self._updating_firmware = True
@ -201,13 +208,21 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._updating_firmware = False self._updating_firmware = False
except Exception as e: except Exception as e:
Logger.log("e", "Exception while trying to update firmware %s" %e) Logger.log("e", "Exception while trying to update firmware %s" %e)
self._updating_firmware = False self._updateFirmware_completed()
return return
programmer.close() programmer.close()
self.setProgress(100, 100) self._updateFirmware_completed()
return
## Private function which makes sure that firmware update process has completed/ended
def _updateFirmware_completed(self):
self.setProgress(100, 100)
self._firmware_update_finished = True
self.resetFirmwareUpdate(update_has_finished=True)
self.firmwareUpdateComplete.emit() self.firmwareUpdateComplete.emit()
return
## Upload new firmware to machine ## Upload new firmware to machine
# \param filename full path of firmware file to be uploaded # \param filename full path of firmware file to be uploaded
@ -216,6 +231,14 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._firmware_file_name = file_name self._firmware_file_name = file_name
self._update_firmware_thread.start() self._update_firmware_thread.start()
@property
def firmwareUpdateFinished(self):
return self._firmware_update_finished
def resetFirmwareUpdate(self, update_has_finished = False):
self._firmware_update_finished = update_has_finished
self.firmwareUpdateChange.emit()
@pyqtSlot() @pyqtSlot()
def startPollEndstop(self): def startPollEndstop(self):
if not self._poll_endstop: if not self._poll_endstop:
@ -251,7 +274,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
# If the programmer connected, we know its an atmega based version. # If the programmer connected, we know its an atmega based version.
# Not all that useful, but it does give some debugging information. # Not all that useful, but it does give some debugging information.
for baud_rate in self._getBaudrateList(): # Cycle all baud rates (auto detect) for baud_rate in self._getBaudrateList(): # Cycle all baud rates (auto detect)
Logger.log("d","Attempting to connect to printer with serial %s on baud rate %s", self._serial_port, baud_rate) Logger.log("d", "Attempting to connect to printer with serial %s on baud rate %s", self._serial_port, baud_rate)
if self._serial is None: if self._serial is None:
try: try:
self._serial = serial.Serial(str(self._serial_port), baud_rate, timeout = 3, writeTimeout = 10000) self._serial = serial.Serial(str(self._serial_port), baud_rate, timeout = 3, writeTimeout = 10000)
@ -260,7 +283,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
continue continue
else: else:
if not self.setBaudRate(baud_rate): if not self.setBaudRate(baud_rate):
continue # Could not set the baud rate, go to the next continue # Could not set the baud rate, go to the next
time.sleep(1.5) # Ensure that we are not talking to the bootloader. 1.5 seconds seems to be the magic number time.sleep(1.5) # Ensure that we are not talking to the bootloader. 1.5 seconds seems to be the magic number
sucesfull_responses = 0 sucesfull_responses = 0
@ -270,11 +293,13 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
while timeout_time > time.time(): while timeout_time > time.time():
line = self._readline() line = self._readline()
if line is None: if line is None:
Logger.log("d", "No response from serial connection received.")
# Something went wrong with reading, could be that close was called. # Something went wrong with reading, could be that close was called.
self.setConnectionState(ConnectionState.closed) self.setConnectionState(ConnectionState.closed)
return return
if b"T:" in line: if b"T:" in line:
Logger.log("d", "Correct response for auto-baudrate detection received.")
self._serial.timeout = 0.5 self._serial.timeout = 0.5
sucesfull_responses += 1 sucesfull_responses += 1
if sucesfull_responses >= self._required_responses_auto_baud: if sucesfull_responses >= self._required_responses_auto_baud:
@ -282,7 +307,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self.setConnectionState(ConnectionState.connected) self.setConnectionState(ConnectionState.connected)
self._listen_thread.start() # Start listening self._listen_thread.start() # Start listening
Logger.log("i", "Established printer connection on port %s" % self._serial_port) Logger.log("i", "Established printer connection on port %s" % self._serial_port)
return return
self._sendCommand("M105") # Send M105 as long as we are listening, otherwise we end up in an undefined state self._sendCommand("M105") # Send M105 as long as we are listening, otherwise we end up in an undefined state
@ -310,7 +335,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._connect_thread = threading.Thread(target = self._connect) self._connect_thread = threading.Thread(target = self._connect)
self._connect_thread.daemon = True self._connect_thread.daemon = True
self.setConnectionState(ConnectionState.closed) self.setConnectionState(ConnectionState.closed)
if self._serial is not None: if self._serial is not None:
try: try:
@ -539,7 +564,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
ret = self._serial.readline() ret = self._serial.readline()
except Exception as e: except Exception as e:
Logger.log("e", "Unexpected error while reading serial port. %s" % e) Logger.log("e", "Unexpected error while reading serial port. %s" % e)
self._setErrorState("Printer has been disconnected") self._setErrorState("Printer has been disconnected")
self.close() self.close()
return None return None
return ret return ret

View File

@ -48,15 +48,24 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
connectionStateChanged = pyqtSignal() connectionStateChanged = pyqtSignal()
progressChanged = pyqtSignal() progressChanged = pyqtSignal()
firmwareUpdateChange = pyqtSignal()
@pyqtProperty(float, notify = progressChanged) @pyqtProperty(float, notify = progressChanged)
def progress(self): def progress(self):
progress = 0 progress = 0
for printer_name, device in self._usb_output_devices.items(): # TODO: @UnusedVariable "printer_name" for printer_name, device in self._usb_output_devices.items(): # TODO: @UnusedVariable "printer_name"
progress += device.progress progress += device.progress
return progress / len(self._usb_output_devices) return progress / len(self._usb_output_devices)
## Return True if all printers finished firmware update
@pyqtProperty(float, notify = firmwareUpdateChange)
def firmwareUpdateCompleteStatus(self):
complete = True
for printer_name, device in self._usb_output_devices.items(): # TODO: @UnusedVariable "printer_name"
if not device.firmwareUpdateFinished:
complete = False
return complete
def start(self): def start(self):
self._check_updates = True self._check_updates = True
self._update_thread.start() self._update_thread.start()
@ -93,13 +102,20 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
Message(i18n_catalog.i18nc("@info","Cannot update firmware, there were no connected printers found.")).show() Message(i18n_catalog.i18nc("@info","Cannot update firmware, there were no connected printers found.")).show()
return return
for printer_connection in self._usb_output_devices:
self._usb_output_devices[printer_connection].resetFirmwareUpdate()
self.spawnFirmwareInterface("") self.spawnFirmwareInterface("")
for printer_connection in self._usb_output_devices: for printer_connection in self._usb_output_devices:
try: try:
self._usb_output_devices[printer_connection].updateFirmware(Resources.getPath(CuraApplication.ResourceTypes.Firmware, self._getDefaultFirmwareName())) self._usb_output_devices[printer_connection].updateFirmware(Resources.getPath(CuraApplication.ResourceTypes.Firmware, self._getDefaultFirmwareName()))
except FileNotFoundError: except FileNotFoundError:
# Should only happen in dev environments where the resources/firmware folder is absent.
self._usb_output_devices[printer_connection].setProgress(100, 100) self._usb_output_devices[printer_connection].setProgress(100, 100)
Logger.log("w", "No firmware found for printer %s", printer_connection) Logger.log("w", "No firmware found for printer %s called '%s'" %(printer_connection, self._getDefaultFirmwareName()))
Message(i18n_catalog.i18nc("@info",
"Could not find firmware required for the printer at %s.") % printer_connection).show()
self._firmware_view.close()
continue continue
@pyqtSlot(str, result = bool) @pyqtSlot(str, result = bool)
@ -110,7 +126,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
self._usb_output_devices[serial_port].updateFirmware(Resources.getPath(CuraApplication.ResourceTypes.Firmware, self._getDefaultFirmwareName())) self._usb_output_devices[serial_port].updateFirmware(Resources.getPath(CuraApplication.ResourceTypes.Firmware, self._getDefaultFirmwareName()))
except FileNotFoundError: except FileNotFoundError:
self._firmware_view.close() self._firmware_view.close()
Logger.log("e", "Could not find firmware required for this machine") Logger.log("e", "Could not find firmware required for this machine called '%s'" %(self._getDefaultFirmwareName()))
return False return False
return True return True
return False return False
@ -131,12 +147,12 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
Logger.log("e", "There is no global container stack. Can not update firmware.") Logger.log("e", "There is no global container stack. Can not update firmware.")
self._firmware_view.close() self._firmware_view.close()
return "" return ""
# The bottom of the containerstack is the machine definition # The bottom of the containerstack is the machine definition
machine_id = global_container_stack.getBottom().id machine_id = global_container_stack.getBottom().id
machine_has_heated_bed = global_container_stack.getProperty("machine_heated_bed", "value") machine_has_heated_bed = global_container_stack.getProperty("machine_heated_bed", "value")
if platform.system() == "Linux": if platform.system() == "Linux":
baudrate = 115200 baudrate = 115200
else: else:
@ -150,13 +166,15 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
"bq_hephestos_2" : "MarlinHephestos2.hex", "bq_hephestos_2" : "MarlinHephestos2.hex",
"ultimaker_original" : "MarlinUltimaker-{baudrate}.hex", "ultimaker_original" : "MarlinUltimaker-{baudrate}.hex",
"ultimaker_original_plus" : "MarlinUltimaker-UMOP-{baudrate}.hex", "ultimaker_original_plus" : "MarlinUltimaker-UMOP-{baudrate}.hex",
"ultimaker_original_dual" : "MarlinUltimaker-{baudrate}-dual.hex",
"ultimaker2" : "MarlinUltimaker2.hex", "ultimaker2" : "MarlinUltimaker2.hex",
"ultimaker2_go" : "MarlinUltimaker2go.hex", "ultimaker2_go" : "MarlinUltimaker2go.hex",
"ultimaker2_plus" : "MarlinUltimaker2plus.hex", "ultimaker2_plus" : "MarlinUltimaker2plus.hex",
"ultimaker2_extended" : "MarlinUltimaker2extended.hex", "ultimaker2_extended" : "MarlinUltimaker2extended.hex",
"ultimaker2_extended_plus" : "MarlinUltimaker2extended-plus.hex", "ultimaker2_extended_plus" : "MarlinUltimaker2extended-plus.hex",
} }
machine_with_heated_bed = {"ultimaker_original" : "MarlinUltimaker-HBK-{baudrate}.hex", machine_with_heated_bed = {"ultimaker_original" : "MarlinUltimaker-HBK-{baudrate}.hex",
"ultimaker_original_dual" : "MarlinUltimaker-HBK-{baudrate}-dual.hex",
} }
##TODO: Add check for multiple extruders ##TODO: Add check for multiple extruders
hex_file = None hex_file = None
@ -200,6 +218,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
device.connectionStateChanged.connect(self._onConnectionStateChanged) device.connectionStateChanged.connect(self._onConnectionStateChanged)
device.connect() device.connect()
device.progressChanged.connect(self.progressChanged) device.progressChanged.connect(self.progressChanged)
device.firmwareUpdateChange.connect(self.firmwareUpdateChange)
self._usb_output_devices[serial_port] = device self._usb_output_devices[serial_port] = device
## If one of the states of the connected devices change, we might need to add / remove them from the global list. ## If one of the states of the connected devices change, we might need to add / remove them from the global list.

View File

@ -21,7 +21,7 @@ class Stk500v2(ispBase.IspBase):
self.seq = 1 self.seq = 1
self.last_addr = -1 self.last_addr = -1
self.progress_callback = None self.progress_callback = None
def connect(self, port = "COM22", speed = 115200): def connect(self, port = "COM22", speed = 115200):
if self.serial is not None: if self.serial is not None:
self.close() self.close()
@ -69,7 +69,7 @@ class Stk500v2(ispBase.IspBase):
self.serial = None self.serial = None
return ret return ret
return None return None
def isConnected(self): def isConnected(self):
return self.serial is not None return self.serial is not None
@ -79,7 +79,7 @@ class Stk500v2(ispBase.IspBase):
def sendISP(self, data): def sendISP(self, data):
recv = self.sendMessage([0x1D, 4, 4, 0, data[0], data[1], data[2], data[3]]) recv = self.sendMessage([0x1D, 4, 4, 0, data[0], data[1], data[2], data[3]])
return recv[2:6] return recv[2:6]
def writeFlash(self, flash_data): def writeFlash(self, flash_data):
#Set load addr to 0, in case we have more then 64k flash we need to enable the address extension #Set load addr to 0, in case we have more then 64k flash we need to enable the address extension
page_size = self.chip["pageSize"] * 2 page_size = self.chip["pageSize"] * 2
@ -89,15 +89,15 @@ class Stk500v2(ispBase.IspBase):
self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00]) self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00])
else: else:
self.sendMessage([0x06, 0x00, 0x00, 0x00, 0x00]) self.sendMessage([0x06, 0x00, 0x00, 0x00, 0x00])
load_count = (len(flash_data) + page_size - 1) / page_size load_count = (len(flash_data) + page_size - 1) / page_size
for i in range(0, int(load_count)): for i in range(0, int(load_count)):
recv = self.sendMessage([0x13, page_size >> 8, page_size & 0xFF, 0xc1, 0x0a, 0x40, 0x4c, 0x20, 0x00, 0x00] + flash_data[(i * page_size):(i * page_size + page_size)]) recv = self.sendMessage([0x13, page_size >> 8, page_size & 0xFF, 0xc1, 0x0a, 0x40, 0x4c, 0x20, 0x00, 0x00] + flash_data[(i * page_size):(i * page_size + page_size)])
if self.progress_callback is not None: if self.progress_callback is not None:
if self._has_checksum: if self._has_checksum:
self.progress_callback(i + 1, load_count) self.progress_callback(i + 1, load_count)
else: else:
self.progress_callback(i + 1, load_count*2) self.progress_callback(i + 1, load_count * 2)
def verifyFlash(self, flash_data): def verifyFlash(self, flash_data):
if self._has_checksum: if self._has_checksum:
self.sendMessage([0x06, 0x00, (len(flash_data) >> 17) & 0xFF, (len(flash_data) >> 9) & 0xFF, (len(flash_data) >> 1) & 0xFF]) self.sendMessage([0x06, 0x00, (len(flash_data) >> 17) & 0xFF, (len(flash_data) >> 9) & 0xFF, (len(flash_data) >> 1) & 0xFF])
@ -121,7 +121,7 @@ class Stk500v2(ispBase.IspBase):
for i in range(0, int(load_count)): for i in range(0, int(load_count)):
recv = self.sendMessage([0x14, 0x01, 0x00, 0x20])[2:0x102] recv = self.sendMessage([0x14, 0x01, 0x00, 0x20])[2:0x102]
if self.progress_callback is not None: if self.progress_callback is not None:
self.progress_callback(load_count + i + 1, load_count*2) self.progress_callback(load_count + i + 1, load_count * 2)
for j in range(0, 0x100): for j in range(0, 0x100):
if i * 0x100 + j < len(flash_data) and flash_data[i * 0x100 + j] != recv[j]: if i * 0x100 + j < len(flash_data) and flash_data[i * 0x100 + j] != recv[j]:
raise ispBase.IspError("Verify error at: 0x%x" % (i * 0x100 + j)) raise ispBase.IspError("Verify error at: 0x%x" % (i * 0x100 + j))
@ -141,7 +141,7 @@ class Stk500v2(ispBase.IspBase):
raise ispBase.IspError("Serial send timeout") raise ispBase.IspError("Serial send timeout")
self.seq = (self.seq + 1) & 0xFF self.seq = (self.seq + 1) & 0xFF
return self.recvMessage() return self.recvMessage()
def recvMessage(self): def recvMessage(self):
state = "Start" state = "Start"
checksum = 0 checksum = 0

View File

@ -10,7 +10,7 @@ catalog = i18nCatalog("cura")
class BedLevelMachineAction(MachineAction): class BedLevelMachineAction(MachineAction):
def __init__(self): def __init__(self):
super().__init__("BedLevel", catalog.i18nc("@action", "Level bed")) super().__init__("BedLevel", catalog.i18nc("@action", "Level build plate"))
self._qml_url = "BedLevelMachineAction.qml" self._qml_url = "BedLevelMachineAction.qml"
self._bed_level_position = 0 self._bed_level_position = 0

View File

@ -24,7 +24,7 @@ Cura.MachineAction
{ {
id: pageTitle id: pageTitle
width: parent.width width: parent.width
text: catalog.i18nc("@title", "Bed Leveling") text: catalog.i18nc("@title", "Build Plate Leveling")
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
font.pointSize: 18; font.pointSize: 18;
} }
@ -44,7 +44,7 @@ Cura.MachineAction
anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width width: parent.width
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "For every position; insert a piece of paper under the nozzle and adjust the print bed height. The print bed height is right when the paper is slightly gripped by the tip of the nozzle.") text: catalog.i18nc("@label", "For every position; insert a piece of paper under the nozzle and adjust the print build plate height. The print build plate height is right when the paper is slightly gripped by the tip of the nozzle.")
} }
Row Row
@ -59,7 +59,7 @@ Cura.MachineAction
Button Button
{ {
id: startBedLevelingButton id: startBedLevelingButton
text: catalog.i18nc("@action:button","Start Bed Leveling") text: catalog.i18nc("@action:button","Start Build Plate Leveling")
onClicked: onClicked:
{ {
startBedLevelingButton.visible = false; startBedLevelingButton.visible = false;

View File

@ -220,7 +220,7 @@ Cura.MachineAction
anchors.left: parent.left anchors.left: parent.left
anchors.top: nozzleTempLabel.bottom anchors.top: nozzleTempLabel.bottom
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: catalog.i18nc("@label","Bed temperature check:") text: catalog.i18nc("@label","Build plate temperature check:")
visible: checkupMachineAction.usbConnected && manager.hasHeatedBed visible: checkupMachineAction.usbConnected && manager.hasHeatedBed
} }

View File

@ -42,7 +42,7 @@ Cura.MachineAction
anchors.top: pageDescription.bottom anchors.top: pageDescription.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.topMargin: UM.Theme.getSize("default_margin").height
text: catalog.i18nc("@label", "Heated bed (official kit or self-built)") text: catalog.i18nc("@label", "Heated Build Plate (official kit or self-built)")
checked: manager.hasHeatedBed checked: manager.hasHeatedBed
onClicked: checked ? manager.addHeatedBed() : manager.removeHeatedBed() onClicked: checked ? manager.addHeatedBed() : manager.removeHeatedBed()
} }

View File

@ -73,13 +73,21 @@ class MachineInstance:
config.set("general", "version", "2") # Hard-code version 2, since if this number changes the programmer MUST change this entire function. config.set("general", "version", "2") # Hard-code version 2, since if this number changes the programmer MUST change this entire function.
import VersionUpgrade21to22 # Import here to prevent circular dependencies. import VersionUpgrade21to22 # Import here to prevent circular dependencies.
has_machine_qualities = self._type_name in VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.machinesWithMachineQuality()
type_name = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translatePrinter(self._type_name) type_name = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translatePrinter(self._type_name)
active_profile = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateProfile(self._active_profile_name)
active_material = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateProfile(self._active_material_name) active_material = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateProfile(self._active_material_name)
variant = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateVariant(self._variant_name, type_name) variant = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateVariant(self._variant_name, type_name)
variant_materials = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateVariantForMaterials(self._variant_name, type_name)
active_profile = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateProfile(self._active_profile_name)
if has_machine_qualities: #This machine now has machine-quality profiles.
active_profile += "_" + active_material + "_" + variant
active_material += "_" + variant_materials #That means that the profile was split into multiple.
current_settings = "empty" #The profile didn't know the definition ID when it was upgraded, so it will have been invalid. Sorry, your current settings are lost now.
else:
current_settings = self._name + "_current_settings"
containers = [ containers = [
self._name + "_current_settings", current_settings,
active_profile, active_profile,
active_material, active_material,
variant, variant,
@ -97,4 +105,4 @@ class MachineInstance:
output = io.StringIO() output = io.StringIO()
config.write(output) config.write(output)
return self._filename, output.getvalue() return [self._filename], [output.getvalue()]

View File

@ -77,4 +77,4 @@ class Preferences:
#Output the result as a string. #Output the result as a string.
output = io.StringIO() output = io.StringIO()
self._config.write(output) self._config.write(output)
return self._filename, output.getvalue() return [self._filename], [output.getvalue()]

View File

@ -91,7 +91,7 @@ class Profile:
translated_machine = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translatePrinter(self._machine_type_id) translated_machine = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translatePrinter(self._machine_type_id)
config.set("general", "definition", translated_machine) config.set("general", "definition", translated_machine)
else: else:
config.set("general", "definition", "fdmprinter") config.set("general", "definition", "fdmprinter") #In this case, the machine definition is unknown, and it might now have machine-specific profiles, in which case this will fail.
config.add_section("metadata") config.add_section("metadata")
if self._type: if self._type:
@ -105,8 +105,6 @@ class Profile:
config.set("metadata", "variant", VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateVariant(self._machine_variant_name, self._machine_type_id)) config.set("metadata", "variant", VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateVariant(self._machine_variant_name, self._machine_type_id))
else: else:
config.set("metadata", "variant", self._machine_variant_name) config.set("metadata", "variant", self._machine_variant_name)
if self._material_name and self._type != "material":
config.set("metadata", "material", self._material_name)
if self._settings: if self._settings:
VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateSettings(self._settings) VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateSettings(self._settings)
@ -128,6 +126,34 @@ class Profile:
for item in disabled_settings_defaults[1:]: for item in disabled_settings_defaults[1:]:
disabled_defaults_string += "," + str(item) disabled_defaults_string += "," + str(item)
output = io.StringIO() #Material metadata may cause the file to split, so do it last to minimise processing time (do more with the copy).
config.write(output) filenames = []
return self._filename, output.getvalue() configs = []
if self._material_name and self._type != "material":
config.set("metadata", "material", self._material_name)
filenames.append(self._filename)
configs.append(config)
elif self._type != "material" and self._machine_type_id in VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.machinesWithMachineQuality():
#Split this profile into multiple profiles, one for each material.
_new_materials = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.machinesWithMachineQuality()[self._machine_type_id]["materials"]
_new_variants = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.machinesWithMachineQuality()[self._machine_type_id]["variants"]
translated_machine = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translatePrinter(self._machine_type_id)
for material_id in _new_materials:
for variant_id in _new_variants:
variant_id_new = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateVariant(variant_id, translated_machine)
filenames.append("{profile}_{material}_{variant}".format(profile = self._filename, material = material_id, variant = variant_id_new))
config_copy = configparser.ConfigParser(interpolation = None)
config_copy.read_dict(config) #Copy the config to a new ConfigParser instance.
variant_id_new_materials = VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateVariantForMaterials(variant_id, translated_machine)
config_copy.set("metadata", "material", "{material}_{variant}".format(material = material_id, variant = variant_id_new_materials))
configs.append(config_copy)
else:
configs.append(config)
filenames.append(self._filename)
outputs = []
for config in configs:
output = io.StringIO()
config.write(output)
outputs.append(output.getvalue())
return filenames, outputs

View File

@ -9,6 +9,29 @@ from . import MachineInstance # To upgrade machine instances.
from . import Preferences #To upgrade preferences. from . import Preferences #To upgrade preferences.
from . import Profile # To upgrade profiles. from . import Profile # To upgrade profiles.
## Which machines have material-specific profiles in the new version?
#
# These are the 2.1 machine identities with "has_machine_materials": true in
# their definitions in Cura 2.2. So these are the machines for which profiles
# need to split into multiple profiles, one for each material and variant.
#
# Each machine has the materials and variants listed in which it needs to
# split, since those might be different per machine.
#
# This should contain the definition as they are stated in the profiles. The
# inheritance structure cannot be found at this stage, since the definitions
# may have changed in later versions than 2.2.
_machines_with_machine_quality = {
"ultimaker2plus": {
"materials": { "generic_abs", "generic_cpe", "generic_pla", "generic_pva" },
"variants": { "0.25 mm", "0.4 mm", "0.6 mm", "0.8 mm" }
},
"ultimaker2_extended_plus": {
"materials": { "generic_abs", "generic_cpe", "generic_pla", "generic_pva" },
"variants": { "0.25 mm", "0.4 mm", "0.6 mm", "0.8 mm" }
}
}
## How to translate printer names from the old version to the new. ## How to translate printer names from the old version to the new.
_printer_translations = { _printer_translations = {
"ultimaker2plus": "ultimaker2_plus" "ultimaker2plus": "ultimaker2_plus"
@ -34,7 +57,14 @@ _setting_name_translations = {
"skirt_line_width": "skirt_brim_line_width", "skirt_line_width": "skirt_brim_line_width",
"skirt_minimal_length": "skirt_brim_minimal_length", "skirt_minimal_length": "skirt_brim_minimal_length",
"skirt_speed": "skirt_brim_speed", "skirt_speed": "skirt_brim_speed",
"speed_support_lines": "speed_support_infill" "speed_support_lines": "speed_support_infill",
"speed_support_roof": "speed_support_interface",
"support_roof_density": "support_interface_density",
"support_roof_enable": "support_interface_enable",
"support_roof_extruder_nr": "support_interface_extruder_nr",
"support_roof_line_distance": "support_interface_line_distance",
"support_roof_line_width": "support_interface_line_width",
"support_roof_pattern": "support_interface_pattern"
} }
## How to translate variants of specific machines from the old version to the ## How to translate variants of specific machines from the old version to the
@ -54,6 +84,24 @@ _variant_translations = {
} }
} }
## Cura 2.2's material profiles use a different naming scheme for variants.
#
# Getting pretty stressed out by this sort of thing...
_variant_translations_materials = {
"ultimaker2_plus": {
"0.25 mm": "ultimaker2_plus_0.25_mm",
"0.4 mm": "ultimaker2_plus_0.4_mm",
"0.6 mm": "ultimaker2_plus_0.6_mm",
"0.8 mm": "ultimaker2_plus_0.8_mm"
},
"ultimaker2_extended_plus": {
"0.25 mm": "ultimaker2_plus_0.25_mm",
"0.4 mm": "ultimaker2_plus_0.4_mm",
"0.6 mm": "ultimaker2_plus_0.6_mm",
"0.8 mm": "ultimaker2_plus_0.8_mm"
}
}
## Converts configuration from Cura 2.1's file formats to Cura 2.2's. ## Converts configuration from Cura 2.1's file formats to Cura 2.2's.
# #
# It converts the machine instances and profiles. # It converts the machine instances and profiles.
@ -70,6 +118,13 @@ class VersionUpgrade21to22(VersionUpgrade):
parser.read_string(serialised) parser.read_string(serialised)
return int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. return int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised.
## Gets a set of the machines which now have per-material quality profiles.
#
# \return A set of machine identifiers.
@staticmethod
def machinesWithMachineQuality():
return _machines_with_machine_quality
## Converts machine instances from format version 1 to version 2. ## Converts machine instances from format version 1 to version 2.
# #
# \param serialised The serialised machine instance in version 1. # \param serialised The serialised machine instance in version 1.
@ -146,32 +201,11 @@ class VersionUpgrade21to22(VersionUpgrade):
for key, value in settings.items(): for key, value in settings.items():
if key == "fill_perimeter_gaps": #Setting is removed. if key == "fill_perimeter_gaps": #Setting is removed.
del settings[key] del settings[key]
elif key == "remove_overlapping_walls_0_enabled": #Setting is functionally replaced.
del settings[key]
settings["travel_compensate_overlapping_walls_0_enabled"] = value
elif key == "remove_overlapping_walls_enabled": #Setting is functionally replaced.
del settings[key]
settings["travel_compensate_overlapping_walls_enabled"] = value
elif key == "remove_overlapping_walls_x_enabled": #Setting is functionally replaced.
del settings[key]
settings["travel_compensate_overlapping_walls_x_enabled"] = value
elif key == "retraction_combing": #Combing was made into an enum instead of a boolean. elif key == "retraction_combing": #Combing was made into an enum instead of a boolean.
settings[key] = "off" if (value == "False") else "all" settings[key] = "off" if (value == "False") else "all"
elif key == "retraction_hop": #Setting key was changed. elif key in _setting_name_translations:
del settings[key] del settings[key]
settings["retraction_hop_enabled"] = value settings[_setting_name_translations[key]] = value
elif key == "skirt_minimal_length": #Setting key was changed.
del settings[key]
settings["skirt_brim_minimal_length"] = value
elif key == "skirt_line_width": #Setting key was changed.
del settings[key]
settings["skirt_brim_line_width"] = value
elif key == "skirt_speed": #Setting key was changed.
del settings[key]
settings["skirt_brim_speed"] = value
elif key == "speed_support_lines": #Setting key was changed.
del settings[key]
settings["speed_support_infill"] = value
return settings return settings
## Translates a setting name for the change from Cura 2.1 to 2.2. ## Translates a setting name for the change from Cura 2.1 to 2.2.
@ -194,4 +228,18 @@ class VersionUpgrade21to22(VersionUpgrade):
def translateVariant(variant, machine): def translateVariant(variant, machine):
if machine in _variant_translations and variant in _variant_translations[machine]: if machine in _variant_translations and variant in _variant_translations[machine]:
return _variant_translations[machine][variant] return _variant_translations[machine][variant]
return variant
## Translates a variant name for the change from Cura 2.1 to 2.2 in
# material profiles.
#
# \param variant The name of the variant in Cura 2.1.
# \param machine The name of the machine this variant is part of in Cura
# 2.2's naming.
# \return The name of the corresponding variant for in material profiles
# in Cura 2.2.
@staticmethod
def translateVariantForMaterials(variant, machine):
if machine in _variant_translations_materials and variant in _variant_translations_materials[machine]:
return _variant_translations_materials[machine][variant]
return variant return variant

View File

@ -161,7 +161,7 @@
}, },
"platform_adhesion": "platform_adhesion":
{ {
"label": "Platform Adhesion", "label": "Build Plate Adhesion",
"type": "category", "type": "category",
"icon": "category_adhesion", "icon": "category_adhesion",
"description": "Adhesion", "description": "Adhesion",

View File

@ -67,8 +67,8 @@
}, },
"material_bed_temp_wait": "material_bed_temp_wait":
{ {
"label": "Wait for bed heatup", "label": "Wait for build plate heatup",
"description": "Whether to insert a command to wait until the bed temperature is reached at the start.", "description": "Whether to insert a command to wait until the build plate temperature is reached at the start.",
"default_value": true, "default_value": true,
"type": "bool", "type": "bool",
"settable_per_mesh": false, "settable_per_mesh": false,
@ -95,6 +95,16 @@
"settable_per_extruder": false, "settable_per_extruder": false,
"settable_per_meshgroup": false "settable_per_meshgroup": false
}, },
"material_bed_temp_prepend":
{
"label": "Include build plate temperature",
"description": "Whether to include build plate temperature commands at the start of the gcode. When the start_gcode already contains build plate temperature commands Cura frontend will automatically disable this setting.",
"default_value": true,
"type": "bool",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": false
},
"machine_width": "machine_width":
{ {
"label": "Machine width", "label": "Machine width",
@ -127,8 +137,8 @@
}, },
"machine_heated_bed": "machine_heated_bed":
{ {
"label": "Has heated bed", "label": "Has heated build plate",
"description": "Whether the machine has a heated bed present.", "description": "Whether the machine has a heated build plate present.",
"default_value": false, "default_value": false,
"type": "bool", "type": "bool",
"settable_per_mesh": false, "settable_per_mesh": false,
@ -635,16 +645,16 @@
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
"support_roof_line_width": "support_interface_line_width":
{ {
"label": "Support Roof Line Width", "label": "Support Interface Line Width",
"description": "Width of a single support roof line.", "description": "Width of a single support interface line.",
"unit": "mm", "unit": "mm",
"default_value": 0.4, "default_value": 0.4,
"minimum_value": "0.0001", "minimum_value": "0.0001",
"maximum_value_warning": "machine_nozzle_size * 2", "maximum_value_warning": "machine_nozzle_size * 2",
"type": "float", "type": "float",
"enabled": "support_roof_enable", "enabled": "extruderValue(support_extruder_nr, 'support_interface_enable')",
"value": "line_width", "value": "line_width",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
@ -784,7 +794,7 @@
"wall_0_inset": "wall_0_inset":
{ {
"label": "Outer Wall Inset", "label": "Outer Wall Inset",
"description": "Inset applied to the path of the outer wall. If the outer wall is smaller than the nozzle, and printed after the inner walls, use this offset to get the hole in the nozzle to overlap with the inner walls instead of the outside of the object.", "description": "Inset applied to the path of the outer wall. If the outer wall is smaller than the nozzle, and printed after the inner walls, use this offset to get the hole in the nozzle to overlap with the inner walls instead of the outside of the model.",
"unit": "mm", "unit": "mm",
"type": "float", "type": "float",
"default_value": 0.0, "default_value": 0.0,
@ -1053,7 +1063,7 @@
"unit": "°C", "unit": "°C",
"type": "float", "type": "float",
"default_value": 210, "default_value": 210,
"minimum_value": "0", "minimum_value": "-273.15",
"maximum_value_warning": "260", "maximum_value_warning": "260",
"enabled": "not (material_flow_dependent_temperature)", "enabled": "not (material_flow_dependent_temperature)",
"settable_per_mesh": false, "settable_per_mesh": false,
@ -1085,12 +1095,12 @@
"settable_per_extruder": true "settable_per_extruder": true
}, },
"material_bed_temperature": { "material_bed_temperature": {
"label": "Bed Temperature", "label": "Build Plate Temperature",
"description": "The temperature used for the heated bed. Set at 0 to pre-heat the printer manually.", "description": "The temperature used for the heated build plate. Set at 0 to pre-heat the printer manually.",
"unit": "°C", "unit": "°C",
"type": "float", "type": "float",
"default_value": 60, "default_value": 60,
"minimum_value": "0", "minimum_value": "-273.15",
"maximum_value_warning": "260", "maximum_value_warning": "260",
"enabled": "machine_heated_bed", "enabled": "machine_heated_bed",
"settable_per_mesh": false, "settable_per_mesh": false,
@ -1147,7 +1157,7 @@
"type": "float", "type": "float",
"default_value": 25, "default_value": 25,
"minimum_value": "0", "minimum_value": "0",
"maximum_value": "299792458000", "maximum_value": "machine_max_feedrate_e",
"maximum_value_warning": "100", "maximum_value_warning": "100",
"enabled": "retraction_enable", "enabled": "retraction_enable",
"settable_per_mesh": false, "settable_per_mesh": false,
@ -1160,7 +1170,7 @@
"type": "float", "type": "float",
"default_value": 25, "default_value": 25,
"minimum_value": "0", "minimum_value": "0",
"maximum_value": "299792458000", "maximum_value": "machine_max_feedrate_e",
"maximum_value_warning": "100", "maximum_value_warning": "100",
"enabled": "retraction_enable", "enabled": "retraction_enable",
"value": "retraction_speed", "value": "retraction_speed",
@ -1174,7 +1184,7 @@
"type": "float", "type": "float",
"default_value": 25, "default_value": 25,
"minimum_value": "0", "minimum_value": "0",
"maximum_value": "299792458000", "maximum_value": "machine_max_feedrate_e",
"maximum_value_warning": "100", "maximum_value_warning": "100",
"enabled": "retraction_enable", "enabled": "retraction_enable",
"value": "retraction_speed", "value": "retraction_speed",
@ -1269,7 +1279,7 @@
"type": "float", "type": "float",
"unit": "°C", "unit": "°C",
"default_value": 150, "default_value": 150,
"minimum_value": "0", "minimum_value": "-273.15",
"maximum_value_warning": "260", "maximum_value_warning": "260",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
@ -1359,7 +1369,7 @@
"type": "float", "type": "float",
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value_warning": "150", "maximum_value_warning": "150",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"default_value": 60, "default_value": 60,
"settable_per_mesh": true, "settable_per_mesh": true,
"children": "children":
@ -1371,7 +1381,7 @@
"unit": "mm/s", "unit": "mm/s",
"type": "float", "type": "float",
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150", "maximum_value_warning": "150",
"default_value": 60, "default_value": 60,
"value": "speed_print", "value": "speed_print",
@ -1384,7 +1394,7 @@
"unit": "mm/s", "unit": "mm/s",
"type": "float", "type": "float",
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150", "maximum_value_warning": "150",
"default_value": 30, "default_value": 30,
"value": "speed_print / 2", "value": "speed_print / 2",
@ -1398,7 +1408,7 @@
"unit": "mm/s", "unit": "mm/s",
"type": "float", "type": "float",
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150", "maximum_value_warning": "150",
"default_value": 30, "default_value": 30,
"value": "speed_wall", "value": "speed_wall",
@ -1411,7 +1421,7 @@
"unit": "mm/s", "unit": "mm/s",
"type": "float", "type": "float",
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150", "maximum_value_warning": "150",
"default_value": 60, "default_value": 60,
"value": "speed_wall * 2", "value": "speed_wall * 2",
@ -1426,7 +1436,7 @@
"unit": "mm/s", "unit": "mm/s",
"type": "float", "type": "float",
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150", "maximum_value_warning": "150",
"default_value": 30, "default_value": 30,
"value": "speed_print / 2", "value": "speed_print / 2",
@ -1439,7 +1449,7 @@
"unit": "mm/s", "unit": "mm/s",
"type": "float", "type": "float",
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150", "maximum_value_warning": "150",
"default_value": 60, "default_value": 60,
"value": "speed_print", "value": "speed_print",
@ -1456,24 +1466,24 @@
"type": "float", "type": "float",
"default_value": 60, "default_value": 60,
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150", "maximum_value_warning": "150",
"value": "speed_support", "value": "speed_support",
"enabled": "support_enable", "enabled": "support_enable",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
"speed_support_roof": "speed_support_interface":
{ {
"label": "Support Roof Speed", "label": "Support Interface Speed",
"description": "The speed at which the roofs of support are printed. Printing the support roof at lower speeds can improve overhang quality.", "description": "The speed at which the roofs and bottoms of support are printed. Printing the them at lower speeds can improve overhang quality.",
"unit": "mm/s", "unit": "mm/s",
"type": "float", "type": "float",
"default_value": 40, "default_value": 40,
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150", "maximum_value_warning": "150",
"enabled": "support_roof_enable and support_enable", "enabled": "extruderValue(support_extruder_nr, 'support_interface_enable') and support_enable",
"value": "speed_support / 1.5", "value": "speed_support / 1.5",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
@ -1490,6 +1500,7 @@
"default_value": 60, "default_value": 60,
"value": "speed_print", "value": "speed_print",
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150", "maximum_value_warning": "150",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
@ -1504,7 +1515,7 @@
"type": "float", "type": "float",
"default_value": 120, "default_value": 120,
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "300", "maximum_value_warning": "300",
"value": "speed_print if magic_spiralize else 120", "value": "speed_print if magic_spiralize else 120",
"settable_per_mesh": false, "settable_per_mesh": false,
@ -1517,7 +1528,7 @@
"type": "float", "type": "float",
"default_value": 30, "default_value": 30,
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "300", "maximum_value_warning": "300",
"settable_per_mesh": true, "settable_per_mesh": true,
"children": "children":
@ -1531,7 +1542,7 @@
"default_value": 30, "default_value": 30,
"value": "speed_layer_0", "value": "speed_layer_0",
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "300", "maximum_value_warning": "300",
"settable_per_mesh": true "settable_per_mesh": true
}, },
@ -1544,7 +1555,7 @@
"default_value": 60, "default_value": 60,
"value": "speed_layer_0 * speed_travel / speed_print", "value": "speed_layer_0 * speed_travel / speed_print",
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "300", "maximum_value_warning": "300",
"settable_per_extruder": true, "settable_per_extruder": true,
"settable_per_mesh": false "settable_per_mesh": false
@ -1558,25 +1569,60 @@
"type": "float", "type": "float",
"default_value": 30, "default_value": 30,
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "300", "maximum_value_warning": "300",
"value": "speed_layer_0", "value": "speed_layer_0",
"enabled": "adhesion_type == \"skirt\" or adhesion_type == \"brim\"", "enabled": "adhesion_type == \"skirt\" or adhesion_type == \"brim\"",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
"max_feedrate_z_override":
{
"label": "Maximum Z Speed",
"description": "The maximum speed with which the build plate is moved. Setting this to zero causes the print to use the firmware defaults for the maximum z speed.",
"unit": "mm/s",
"type": "float",
"default_value": 0,
"minimum_value": "0",
"maximum_value": "299792458000",
"maximum_value_warning": "machine_max_feedrate_z",
"settable_per_mesh": false,
"settable_per_extruder": true
},
"speed_slowdown_layers": "speed_slowdown_layers":
{ {
"label": "Number of Slower Layers", "label": "Number of Slower Layers",
"description": "The first few layers are printed slower than the rest of the object, to get better adhesion to the build plate and improve the overall success rate of prints. The speed is gradually increased over these layers.", "description": "The first few layers are printed slower than the rest of the model, to get better adhesion to the build plate and improve the overall success rate of prints. The speed is gradually increased over these layers.",
"type": "int", "type": "int",
"default_value": 2, "default_value": 2,
"minimum_value": "0", "minimum_value": "0",
"maximum_value": "299792458000", "maximum_value_warning": "1.0 / layer_height",
"maximum_value_warning": "300",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false "settable_per_extruder": false
}, },
"speed_equalize_flow_enabled":
{
"label": "Equalize Filament Flow",
"description": "Print thinner than normal lines faster so that the amount of material extruded per second remains the same. Thin pieces in your model might require lines printed with smaller line width than provided in the settings. This setting controls the speed changes for such lines.",
"type": "bool",
"default_value": false,
"settable_per_mesh": false,
"settable_per_extruder": true
},
"speed_equalize_flow_max":
{
"label": "Maximum Speed for Flow Equalization",
"description": "Maximum print speed when adjusting the print speed in order to equalize flow.",
"type": "float",
"unit": "mm/s",
"enabled": "speed_equalize_flow_enabled",
"default_value": 150,
"minimum_value": "0.1",
"maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150",
"settable_per_mesh": false,
"settable_per_extruder": true
},
"acceleration_enabled": { "acceleration_enabled": {
@ -1694,9 +1740,9 @@
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
"acceleration_support_roof": { "acceleration_support_interface": {
"label": "Support Roof Acceleration", "label": "Support Interface Acceleration",
"description": "The acceleration with which the roofs of support are printed. Printing the support roof at lower accelerations can improve overhang quality.", "description": "The acceleration with which the roofs and bottoms of support are printed. Printing them at lower accelerations can improve overhang quality.",
"unit": "mm/s²", "unit": "mm/s²",
"type": "float", "type": "float",
"default_value": 3000, "default_value": 3000,
@ -1704,7 +1750,7 @@
"minimum_value": "0.1", "minimum_value": "0.1",
"minimum_value_warning": "100", "minimum_value_warning": "100",
"maximum_value_warning": "10000", "maximum_value_warning": "10000",
"enabled": "acceleration_enabled and support_roof_enable and support_enable", "enabled": "acceleration_enabled and extruderValue(support_extruder_nr, 'support_interface_enable') and support_enable",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
} }
@ -1913,9 +1959,9 @@
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
"jerk_support_roof": { "jerk_support_interface": {
"label": "Support Roof Jerk", "label": "Support Interface Jerk",
"description": "The maximum instantaneous velocity change with which the roofs of support are printed.", "description": "The maximum instantaneous velocity change with which the roofs and bottoms of support are printed.",
"unit": "mm/s", "unit": "mm/s",
"type": "float", "type": "float",
"default_value": 20, "default_value": 20,
@ -1923,7 +1969,7 @@
"minimum_value": "0.1", "minimum_value": "0.1",
"minimum_value_warning": "5", "minimum_value_warning": "5",
"maximum_value_warning": "50", "maximum_value_warning": "50",
"enabled": "jerk_enabled and support_roof_enable and support_enable", "enabled": "jerk_enabled and extruderValue(support_extruder_nr, 'support_interface_enable') and support_enable",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
} }
@ -2074,8 +2120,8 @@
{ {
"cool_fan_enabled": "cool_fan_enabled":
{ {
"label": "Enable Cooling Fans", "label": "Enable Print Cooling",
"description": "Enables the cooling fans while printing. The fans improve print quality on layers with short layer times and bridging / overhangs.", "description": "Enables the print cooling fans while printing. The fans improve print quality on layers with short layer times and bridging / overhangs.",
"type": "bool", "type": "bool",
"default_value": true, "default_value": true,
"settable_per_mesh": false, "settable_per_mesh": false,
@ -2084,7 +2130,7 @@
"cool_fan_speed": "cool_fan_speed":
{ {
"label": "Fan Speed", "label": "Fan Speed",
"description": "The speed at which the cooling fans spin.", "description": "The speed at which the print cooling fans spin.",
"unit": "%", "unit": "%",
"type": "float", "type": "float",
"minimum_value": "0", "minimum_value": "0",
@ -2261,6 +2307,7 @@
}, },
"default_value": "zigzag", "default_value": "zigzag",
"enabled": "support_enable", "enabled": "support_enable",
"global_inherits_stack": "support_extruder_nr",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
@ -2270,7 +2317,7 @@
"description": "Connect the ZigZags. This will increase the strength of the zig zag support structure.", "description": "Connect the ZigZags. This will increase the strength of the zig zag support structure.",
"type": "bool", "type": "bool",
"default_value": true, "default_value": true,
"enabled": "support_enable and (support_pattern == \"zigzag\")", "enabled": "support_enable and (support_pattern == 'zigzag')",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
@ -2310,7 +2357,7 @@
"type": "float", "type": "float",
"minimum_value": "0", "minimum_value": "0",
"maximum_value_warning": "10", "maximum_value_warning": "10",
"default_value": 0.15, "default_value": 0.1,
"global_inherits_stack": "support_extruder_nr", "global_inherits_stack": "support_extruder_nr",
"enabled": "support_enable", "enabled": "support_enable",
"settable_per_mesh": true, "settable_per_mesh": true,
@ -2323,10 +2370,10 @@
"unit": "mm", "unit": "mm",
"minimum_value": "0", "minimum_value": "0",
"maximum_value_warning": "10", "maximum_value_warning": "10",
"default_value": 0.15, "default_value": 0.1,
"type": "float", "type": "float",
"enabled": "support_enable", "enabled": "support_enable",
"value": "support_z_distance", "value": "extruderValue(support_extruder_nr, 'support_z_distance')",
"global_inherits_stack": "support_extruder_nr", "global_inherits_stack": "support_extruder_nr",
"settable_per_mesh": true "settable_per_mesh": true
}, },
@ -2338,7 +2385,7 @@
"minimum_value": "0", "minimum_value": "0",
"maximum_value_warning": "10", "maximum_value_warning": "10",
"default_value": 0.1, "default_value": 0.1,
"value": "0.1 if support_type == 'everywhere' else 0", "value": "extruderValue(support_extruder_nr, 'support_z_distance') if support_type == 'everywhere' else 0",
"global_inherits_stack": "support_extruder_nr", "global_inherits_stack": "support_extruder_nr",
"type": "float", "type": "float",
"enabled": "support_enable and support_type == 'everywhere'", "enabled": "support_enable and support_type == 'everywhere'",
@ -2382,7 +2429,7 @@
"default_value": 0.2, "default_value": 0.2,
"value": "machine_nozzle_size / 2", "value": "machine_nozzle_size / 2",
"global_inherits_stack": "support_extruder_nr", "global_inherits_stack": "support_extruder_nr",
"enabled": "support_enable and support_xy_overrides_z=='z_overrides_xy'", "enabled": "support_enable and extruderValue(support_extruder_nr, 'support_xy_overrides_z') == 'z_overrides_xy'",
"settable_per_mesh": true "settable_per_mesh": true
}, },
"support_bottom_stair_step_height": "support_bottom_stair_step_height":
@ -2437,62 +2484,96 @@
"enabled": "support_enable", "enabled": "support_enable",
"settable_per_mesh": true "settable_per_mesh": true
}, },
"support_roof_enable": "support_interface_enable":
{ {
"label": "Enable Support Roof", "label": "Enable Support Interface",
"description": "Generate a dense top skin at the top of the support on which the model is printed.", "description": "Generate a dense interface between the model and the support. This will create a skin at the top of the support on which the model is printed and at the bottom of the support, where it rests on the model.",
"type": "bool", "type": "bool",
"default_value": false, "default_value": false,
"global_inherits_stack": "support_extruder_nr", "global_inherits_stack": "support_extruder_nr",
"enabled": "support_enable", "enabled": "support_enable",
"settable_per_mesh": true "settable_per_mesh": true
}, },
"support_roof_height": "support_interface_height":
{ {
"label": "Support Roof Thickness", "label": "Support Interface Thickness",
"description": "The thickness of the support roofs.", "description": "The thickness of the interface of the support where it touches with the model on the bottom or the top.",
"unit": "mm", "unit": "mm",
"type": "float", "type": "float",
"default_value": 1, "default_value": 1,
"minimum_value": "0", "minimum_value": "0",
"global_inherits_stack": "support_extruder_nr", "global_inherits_stack": "support_extruder_nr",
"maximum_value_warning": "10", "maximum_value_warning": "10",
"enabled": "support_roof_enable and support_enable", "enabled": "extruderValue(support_extruder_nr, 'support_interface_enable') and support_enable",
"settable_per_mesh": true "settable_per_mesh": true,
"children":
{
"support_roof_height":
{
"label": "Support Roof Thickness",
"description": "The thickness of the support roofs. This controls the amount of dense layers at the top of the support on which the model rests.",
"unit": "mm",
"type": "float",
"default_value": 1,
"value": "extruderValue(support_extruder_nr, 'support_interface_height')",
"minimum_value": "0",
"global_inherits_stack": "support_extruder_nr",
"maximum_value_warning": "10",
"enabled": "extruderValue(support_extruder_nr, 'support_interface_enable') and support_enable",
"settable_per_mesh": true
},
"support_bottom_height":
{
"label": "Support Bottom Thickness",
"description": "The thickness of the support bottoms. This controls the number of dense layers are printed on top of places of a model on which support rests.",
"unit": "mm",
"type": "float",
"default_value": 1,
"value": "extruderValue(support_extruder_nr, 'support_interface_height')",
"minimum_value": "0",
"minimum_value_warning": "extruderValue(support_extruder_nr, 'support_bottom_stair_step_height')",
"global_inherits_stack": "support_extruder_nr",
"maximum_value_warning": "10",
"enabled": "extruderValue(support_extruder_nr, 'support_interface_enable') and support_enable",
"settable_per_mesh": true
}
}
}, },
"support_roof_density": "support_interface_density":
{ {
"label": "Support Roof Density", "label": "Support Interface Density",
"description": "Adjusts the density of the roof of the support structure. A higher value results in better overhangs, but the supports are harder to remove.", "description": "Adjusts the density of the roofs and bottoms of the support structure. A higher value results in better overhangs, but the supports are harder to remove.",
"unit": "%", "unit": "%",
"type": "float", "type": "float",
"default_value": 100, "default_value": 100,
"minimum_value": "0", "minimum_value": "0",
"maximum_value_warning": "100", "maximum_value_warning": "100",
"enabled":"support_roof_enable and support_enable", "global_inherits_stack": "support_extruder_nr",
"enabled": "extruderValue(support_extruder_nr, 'support_interface_enable') and support_enable",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true, "settable_per_extruder": true,
"children": "children":
{ {
"support_roof_line_distance": "support_interface_line_distance":
{ {
"label": "Support Roof Line Distance", "label": "Support Interface Line Distance",
"description": "Distance between the printed support roof lines. This setting is calculated by the support roof Density, but can be adjusted separately.", "description": "Distance between the printed support interface lines. This setting is calculated by the Support Interface Density, but can be adjusted separately.",
"unit": "mm", "unit": "mm",
"type": "float", "type": "float",
"default_value": 0.4, "default_value": 0.4,
"minimum_value": "0", "minimum_value": "0",
"value": "0 if support_roof_density == 0 else (support_roof_line_width * 100) / support_roof_density * (2 if support_roof_pattern == \"grid\" else (3 if support_roof_pattern == \"triangles\" else 1))", "value": "0 if support_interface_density == 0 else (support_interface_line_width * 100) / support_interface_density * (2 if support_interface_pattern == \"grid\" else (3 if support_interface_pattern == \"triangles\" else 1))",
"enabled": "support_roof_enable and support_enable", "global_inherits_stack": "support_extruder_nr",
"enabled": "extruderValue(support_extruder_nr, 'support_interface_enable') and support_enable",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
} }
} }
}, },
"support_roof_pattern": "support_interface_pattern":
{ {
"label": "Support Roof Pattern", "label": "Support Interface Pattern",
"description": "The pattern with which the top of the support is printed.", "description": "The pattern with which the interface of the support with the model is printed.",
"type": "enum", "type": "enum",
"options": "options":
{ {
@ -2503,7 +2584,8 @@
"zigzag": "Zig Zag" "zigzag": "Zig Zag"
}, },
"default_value": "concentric", "default_value": "concentric",
"enabled": "support_roof_enable and support_enable", "global_inherits_stack": "support_extruder_nr",
"enabled": "extruderValue(support_extruder_nr, 'support_interface_enable') and support_enable",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
@ -2527,7 +2609,7 @@
"global_inherits_stack": "support_extruder_nr", "global_inherits_stack": "support_extruder_nr",
"minimum_value": "0", "minimum_value": "0",
"maximum_value_warning": "10", "maximum_value_warning": "10",
"enabled": "support_enable and support_use_towers", "enabled": "support_enable and extruderValue(support_extruder_nr, 'support_use_towers')",
"settable_per_mesh": true "settable_per_mesh": true
}, },
"support_minimal_diameter": "support_minimal_diameter":
@ -2540,8 +2622,8 @@
"global_inherits_stack": "support_extruder_nr", "global_inherits_stack": "support_extruder_nr",
"minimum_value": "0", "minimum_value": "0",
"maximum_value_warning": "10", "maximum_value_warning": "10",
"maximum_value": "support_tower_diameter", "maximum_value": "extruderValue(support_extruder_nr, 'support_tower_diameter')",
"enabled": "support_enable and support_use_towers", "enabled": "support_enable and extruderValue(support_extruder_nr, 'support_use_towers')",
"settable_per_mesh": true "settable_per_mesh": true
}, },
"support_tower_roof_angle": "support_tower_roof_angle":
@ -2554,14 +2636,14 @@
"maximum_value": "90", "maximum_value": "90",
"default_value": 65, "default_value": 65,
"global_inherits_stack": "support_extruder_nr", "global_inherits_stack": "support_extruder_nr",
"enabled": "support_enable and support_use_towers", "enabled": "support_enable and extruderValue(support_extruder_nr, 'support_use_towers')",
"settable_per_mesh": true "settable_per_mesh": true
} }
} }
}, },
"platform_adhesion": "platform_adhesion":
{ {
"label": "Platform Adhesion", "label": "Build Plate Adhesion",
"type": "category", "type": "category",
"icon": "category_adhesion", "icon": "category_adhesion",
"description": "Adhesion", "description": "Adhesion",
@ -2595,8 +2677,8 @@
}, },
"adhesion_type": "adhesion_type":
{ {
"label": "Platform Adhesion Type", "label": "Build Plate Adhesion Type",
"description": "Different options that help to improve both priming your extrusion and adhesion to the build plate. Brim adds a single layer flat area around the base of your object to prevent warping. Raft adds a thick grid with a roof below the object. Skirt is a line printed around the object, but not connected to the model.", "description": "Different options that help to improve both priming your extrusion and adhesion to the build plate. Brim adds a single layer flat area around the base of your model to prevent warping. Raft adds a thick grid with a roof below the model. Skirt is a line printed around the model, but not connected to the model.",
"type": "enum", "type": "enum",
"options": "options":
{ {
@ -2611,7 +2693,7 @@
"skirt_line_count": "skirt_line_count":
{ {
"label": "Skirt Line Count", "label": "Skirt Line Count",
"description": "Multiple skirt lines help to prime your extrusion better for small objects. Setting this to 0 will disable the skirt.", "description": "Multiple skirt lines help to prime your extrusion better for small models. Setting this to 0 will disable the skirt.",
"type": "int", "type": "int",
"default_value": 1, "default_value": 1,
"minimum_value": "0", "minimum_value": "0",
@ -2676,10 +2758,20 @@
} }
} }
}, },
"brim_outside_only":
{
"label": "Brim Only on Outside",
"description": "Only print the brim on the outside of the model. This reduces the amount of brim you need to remove afterwards, while it doesn't reduce the bed adhesion that much.",
"type": "bool",
"default_value": true,
"enabled": "adhesion_type == \"brim\"",
"settable_per_mesh": false,
"settable_per_extruder": true
},
"raft_margin": "raft_margin":
{ {
"label": "Raft Extra Margin", "label": "Raft Extra Margin",
"description": "If the raft is enabled, this is the extra raft area around the object which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.", "description": "If the raft is enabled, this is the extra raft area around the model which is also given a raft. Increasing this margin will create a stronger raft while using more material and leaving less area for your print.",
"unit": "mm", "unit": "mm",
"type": "float", "type": "float",
"default_value": 15, "default_value": 15,
@ -2690,7 +2782,7 @@
"raft_airgap": "raft_airgap":
{ {
"label": "Raft Air Gap", "label": "Raft Air Gap",
"description": "The gap between the final raft layer and the first layer of the object. Only the first layer is raised by this amount to lower the bonding between the raft layer and the object. Makes it easier to peel off the raft.", "description": "The gap between the final raft layer and the first layer of the model. Only the first layer is raised by this amount to lower the bonding between the raft layer and the model. Makes it easier to peel off the raft.",
"unit": "mm", "unit": "mm",
"type": "float", "type": "float",
"default_value": 0.3, "default_value": 0.3,
@ -2702,7 +2794,7 @@
}, },
"layer_0_z_overlap": { "layer_0_z_overlap": {
"label": "Initial Layer Z Overlap", "label": "Initial Layer Z Overlap",
"description": "Make the first and second layer of the object overlap in the Z direction to compensate for the filament lost in the airgap. All models above the first model layer will be shifted down by this amount.", "description": "Make the first and second layer of the model overlap in the Z direction to compensate for the filament lost in the airgap. All models above the first model layer will be shifted down by this amount.",
"unit": "mm", "unit": "mm",
"type": "float", "type": "float",
"default_value": 0.22, "default_value": 0.22,
@ -2716,7 +2808,7 @@
"raft_surface_layers": "raft_surface_layers":
{ {
"label": "Raft Top Layers", "label": "Raft Top Layers",
"description": "The number of top layers on top of the 2nd raft layer. These are fully filled layers that the object sits on. 2 layers result in a smoother top surface than 1.", "description": "The number of top layers on top of the 2nd raft layer. These are fully filled layers that the model sits on. 2 layers result in a smoother top surface than 1.",
"type": "int", "type": "int",
"default_value": 2, "default_value": 2,
"minimum_value": "0", "minimum_value": "0",
@ -2784,7 +2876,7 @@
"raft_interface_line_width": "raft_interface_line_width":
{ {
"label": "Raft Middle Line Width", "label": "Raft Middle Line Width",
"description": "Width of the lines in the middle raft layer. Making the second layer extrude more causes the lines to stick to the bed.", "description": "Width of the lines in the middle raft layer. Making the second layer extrude more causes the lines to stick to the build plate.",
"unit": "mm", "unit": "mm",
"type": "float", "type": "float",
"default_value": 0.7, "default_value": 0.7,
@ -2812,7 +2904,7 @@
"raft_base_thickness": "raft_base_thickness":
{ {
"label": "Raft Base Thickness", "label": "Raft Base Thickness",
"description": "Layer thickness of the base raft layer. This should be a thick layer which sticks firmly to the printer bed.", "description": "Layer thickness of the base raft layer. This should be a thick layer which sticks firmly to the printer build plate.",
"unit": "mm", "unit": "mm",
"type": "float", "type": "float",
"default_value": 0.3, "default_value": 0.3,
@ -2826,7 +2918,7 @@
"raft_base_line_width": "raft_base_line_width":
{ {
"label": "Raft Base Line Width", "label": "Raft Base Line Width",
"description": "Width of the lines in the base raft layer. These should be thick lines to assist in bed adhesion.", "description": "Width of the lines in the base raft layer. These should be thick lines to assist in build plate adhesion.",
"unit": "mm", "unit": "mm",
"type": "float", "type": "float",
"default_value": 0.8, "default_value": 0.8,
@ -2859,7 +2951,7 @@
"type": "float", "type": "float",
"default_value": 20, "default_value": 20,
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "200", "maximum_value_warning": "200",
"enabled": "adhesion_type == \"raft\"", "enabled": "adhesion_type == \"raft\"",
"value": "speed_print / 60 * 30", "value": "speed_print / 60 * 30",
@ -2875,7 +2967,7 @@
"type": "float", "type": "float",
"default_value": 20, "default_value": 20,
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "100", "maximum_value_warning": "100",
"enabled": "adhesion_type == \"raft\"", "enabled": "adhesion_type == \"raft\"",
"value": "raft_speed", "value": "raft_speed",
@ -2891,7 +2983,7 @@
"default_value": 15, "default_value": 15,
"value": "raft_speed * 0.75", "value": "raft_speed * 0.75",
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150", "maximum_value_warning": "150",
"enabled": "adhesion_type == \"raft\"", "enabled": "adhesion_type == \"raft\"",
"settable_per_mesh": false, "settable_per_mesh": false,
@ -2905,7 +2997,7 @@
"type": "float", "type": "float",
"default_value": 15, "default_value": 15,
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "200", "maximum_value_warning": "200",
"enabled": "adhesion_type == \"raft\"", "enabled": "adhesion_type == \"raft\"",
"value": "0.75 * raft_speed", "value": "0.75 * raft_speed",
@ -3099,10 +3191,11 @@
{ {
"adhesion_extruder_nr": "adhesion_extruder_nr":
{ {
"label": "Platform Adhesion Extruder", "label": "Build Plate Adhesion Extruder",
"description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.", "description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.",
"type": "extruder", "type": "extruder",
"default_value": "0", "default_value": "0",
"enabled": "machine_extruder_count > 1",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false "settable_per_extruder": false
}, },
@ -3112,7 +3205,7 @@
"description": "The extruder train to use for printing the support. This is used in multi-extrusion.", "description": "The extruder train to use for printing the support. This is used in multi-extrusion.",
"type": "extruder", "type": "extruder",
"default_value": "0", "default_value": "0",
"enabled": "support_enable", "enabled": "support_enable and machine_extruder_count > 1",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false, "settable_per_extruder": false,
"children": { "children": {
@ -3123,7 +3216,7 @@
"type": "extruder", "type": "extruder",
"default_value": "0", "default_value": "0",
"value": "support_extruder_nr", "value": "support_extruder_nr",
"enabled": "support_enable", "enabled": "support_enable and machine_extruder_count > 1",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false "settable_per_extruder": false
}, },
@ -3134,18 +3227,18 @@
"type": "extruder", "type": "extruder",
"default_value": "0", "default_value": "0",
"value": "support_extruder_nr", "value": "support_extruder_nr",
"enabled": "support_enable", "enabled": "support_enable and machine_extruder_count > 1",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false "settable_per_extruder": false
}, },
"support_roof_extruder_nr": "support_interface_extruder_nr":
{ {
"label": "Support Roof Extruder", "label": "Support Interface Extruder",
"description": "The extruder train to use for printing the roof of the support. This is used in multi-extrusion.", "description": "The extruder train to use for printing the roofs and bottoms of the support. This is used in multi-extrusion.",
"type": "extruder", "type": "extruder",
"default_value": "0", "default_value": "0",
"value": "support_extruder_nr", "value": "support_extruder_nr",
"enabled": "support_enable and support_roof_enable", "enabled": "support_enable and machine_extruder_count > 1 and extruderValue(support_extruder_nr, 'support_interface_enable')",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false "settable_per_extruder": false
} }
@ -3156,6 +3249,7 @@
"label": "Enable Prime Tower", "label": "Enable Prime Tower",
"description": "Print a tower next to the print which serves to prime the material after each nozzle switch.", "description": "Print a tower next to the print which serves to prime the material after each nozzle switch.",
"type": "bool", "type": "bool",
"enabled": "machine_extruder_count > 1",
"default_value": false, "default_value": false,
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false "settable_per_extruder": false
@ -3227,7 +3321,7 @@
"multiple_mesh_overlap": "multiple_mesh_overlap":
{ {
"label": "Dual Extrusion Overlap", "label": "Dual Extrusion Overlap",
"description": "Make the objects printed with different extruder trains overlap a bit. This makes the different materials bond together better.", "description": "Make the models printed with different extruder trains overlap a bit. This makes the different materials bond together better.",
"type": "float", "type": "float",
"unit": "mm", "unit": "mm",
"default_value": 0.15, "default_value": 0.15,
@ -3238,7 +3332,7 @@
"ooze_shield_enabled": "ooze_shield_enabled":
{ {
"label": "Enable Ooze Shield", "label": "Enable Ooze Shield",
"description": "Enable exterior ooze shield. This will create a shell around the object which is likely to wipe a second nozzle if it's at the same height as the first nozzle.", "description": "Enable exterior ooze shield. This will create a shell around the model which is likely to wipe a second nozzle if it's at the same height as the first nozzle.",
"type": "bool", "type": "bool",
"default_value": false, "default_value": false,
"settable_per_mesh": false, "settable_per_mesh": false,
@ -3325,7 +3419,7 @@
"print_sequence": "print_sequence":
{ {
"label": "Print Sequence", "label": "Print Sequence",
"description": "Whether to print all objects one layer at a time or to wait for one object to finish, before moving on to the next. One at a time mode is only possible if all models are separated in such a way that the whole print head can move in between and all models are lower than the distance between the nozzle and the X/Y axes.", "description": "Whether to print all models one layer at a time or to wait for one model to finish, before moving on to the next. One at a time mode is only possible if all models are separated in such a way that the whole print head can move in between and all models are lower than the distance between the nozzle and the X/Y axes.",
"type": "enum", "type": "enum",
"options": "options":
{ {
@ -3379,7 +3473,7 @@
"magic_spiralize": "magic_spiralize":
{ {
"label": "Spiralize Outer Contour", "label": "Spiralize Outer Contour",
"description": "Spiralize smooths out the Z move of the outer edge. This will create a steady Z increase over the whole print. This feature turns a solid object into a single walled print with a solid bottom. This feature used to be called Joris in older versions.", "description": "Spiralize smooths out the Z move of the outer edge. This will create a steady Z increase over the whole print. This feature turns a solid model into a single walled print with a solid bottom. This feature used to be called Joris in older versions.",
"type": "bool", "type": "bool",
"default_value": false, "default_value": false,
"settable_per_mesh": true "settable_per_mesh": true
@ -3397,7 +3491,7 @@
"draft_shield_enabled": "draft_shield_enabled":
{ {
"label": "Enable Draft Shield", "label": "Enable Draft Shield",
"description": "This will create a wall around the object, which traps (hot) air and shields against exterior airflow. Especially useful for materials which warp easily.", "description": "This will create a wall around the model, which traps (hot) air and shields against exterior airflow. Especially useful for materials which warp easily.",
"type": "bool", "type": "bool",
"default_value": false, "default_value": false,
"settable_per_mesh": false, "settable_per_mesh": false,
@ -3419,7 +3513,7 @@
"draft_shield_height_limitation": "draft_shield_height_limitation":
{ {
"label": "Draft Shield Limitation", "label": "Draft Shield Limitation",
"description": "Set the height of the draft shield. Choose to print the draft shield at the full height of the object or at a limited height.", "description": "Set the height of the draft shield. Choose to print the draft shield at the full height of the model or at a limited height.",
"type": "enum", "type": "enum",
"options": "options":
{ {
@ -3664,7 +3758,7 @@
"type": "float", "type": "float",
"default_value": 5, "default_value": 5,
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2 + max(max_feedrate_z_override, machine_max_feedrate_z) ** 2)",
"maximum_value_warning": "50", "maximum_value_warning": "50",
"enabled": "wireframe_enabled", "enabled": "wireframe_enabled",
"settable_per_mesh": false, "settable_per_mesh": false,
@ -3680,7 +3774,7 @@
"type": "float", "type": "float",
"default_value": 5, "default_value": 5,
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "50", "maximum_value_warning": "50",
"enabled": "wireframe_enabled", "enabled": "wireframe_enabled",
"value": "wireframe_printspeed", "value": "wireframe_printspeed",
@ -3696,7 +3790,7 @@
"type": "float", "type": "float",
"default_value": 5, "default_value": 5,
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2 + max(max_feedrate_z_override, machine_max_feedrate_z) ** 2)",
"maximum_value_warning": "50", "maximum_value_warning": "50",
"enabled": "wireframe_enabled", "enabled": "wireframe_enabled",
"value": "wireframe_printspeed", "value": "wireframe_printspeed",
@ -3712,7 +3806,7 @@
"type": "float", "type": "float",
"default_value": 5, "default_value": 5,
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2 + max(max_feedrate_z_override, machine_max_feedrate_z) ** 2)",
"maximum_value_warning": "50", "maximum_value_warning": "50",
"enabled": "wireframe_enabled", "enabled": "wireframe_enabled",
"value": "wireframe_printspeed", "value": "wireframe_printspeed",
@ -3723,12 +3817,12 @@
"wireframe_printspeed_flat": "wireframe_printspeed_flat":
{ {
"label": "WP Horizontal Printing Speed", "label": "WP Horizontal Printing Speed",
"description": "Speed of printing the horizontal contours of the object. Only applies to Wire Printing.", "description": "Speed of printing the horizontal contours of the model. Only applies to Wire Printing.",
"unit": "mm/s", "unit": "mm/s",
"type": "float", "type": "float",
"default_value": 5, "default_value": 5,
"minimum_value": "0.1", "minimum_value": "0.1",
"maximum_value": "299792458000", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "100", "maximum_value_warning": "100",
"value": "wireframe_printspeed", "value": "wireframe_printspeed",
"enabled": "wireframe_enabled", "enabled": "wireframe_enabled",

View File

@ -7,5 +7,16 @@
"author": "Ultimaker", "author": "Ultimaker",
"manufacturer": "Ultimaker", "manufacturer": "Ultimaker",
"visible": false "visible": false
},
"overrides": {
"material_print_temperature": {
"minimum_value": "0"
},
"material_bed_temperature": {
"minimum_value": "0"
},
"material_standby_temperature": {
"minimum_value": "0"
}
} }
} }

View File

@ -18,10 +18,12 @@
}, },
"overrides": { "overrides": {
"machine_start_gcode" : { "machine_start_gcode" : {
"default_value": "" "default_value": "",
"value": "\"\" if machine_gcode_flavor == \"UltiGCode\" else \"G21 ;metric values\\nG90 ;absolute positioning\\nM82 ;set extruder to absolute mode\\nM107 ;start with the fan off\\nG1 X10 Y0 F4000;move X/Y to min endstops\\nG28 Z0 ;move Z to bottom endstops\\nG1 Z15.0 F9000 ;move the platform to 15mm\\nG92 E0 ;zero the extruded length\\nG1 F200 E10 ;extrude 10 mm of feed stock\\nG92 E0 ;zero the extruded length again\\nG1 F9000\\n;Put printing message on LCD screen\\nM117 Printing...\""
}, },
"machine_end_gcode" : { "machine_end_gcode" : {
"default_value": "" "default_value": "",
"value": "\"\" if machine_gcode_flavor == \"UltiGCode\" else \"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_width": { "machine_width": {
"default_value": 223 "default_value": 223

View File

@ -0,0 +1,76 @@
{
"id": "ultimaker_original_dual",
"version": 2,
"name": "Ultimaker Original Dual Extrusion",
"inherits": "ultimaker",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "Ultimaker",
"category": "Ultimaker",
"weight": 4,
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker.png",
"platform": "ultimaker_platform.stl",
"has_materials": true,
"preferred_material": "*pla*",
"preferred_quality": "*normal*",
"machine_extruder_trains":
{
"0": "ultimaker_original_dual_left",
"1": "ultimaker_original_dual_right"
},
"first_start_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel"],
"supported_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel", "UpgradeFirmware"]
},
"overrides": {
"machine_width": {
"default_value": 205
},
"machine_height": {
"default_value": 200
},
"machine_depth": {
"default_value": 195
},
"machine_center_is_zero": {
"default_value": false
},
"machine_nozzle_size": {
"default_value": 0.4
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"machine_head_with_fans_polygon":
{
"default_value": [
[ -75, 35 ],
[ -75, -18 ],
[ 18, 35 ],
[ 18, -18 ]
]
},
"gantry_height": {
"default_value": 55
},
"machine_use_extruder_offset_to_offset_coords": {
"default_value": true
},
"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 E6 ;extrude 6 mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\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 },
"print_sequence": {"enabled": false}
}
}

View File

@ -12,7 +12,8 @@
"icon": "icon_ultimaker.png", "icon": "icon_ultimaker.png",
"platform": "ultimaker2_platform.obj", "platform": "ultimaker2_platform.obj",
"platform_texture": "UltimakerPlusbackplate.png", "platform_texture": "UltimakerPlusbackplate.png",
"supported_actions":["UMOCheckup", "UpgradeFirmware", "BedLevel"] "first_start_actions": ["UMOCheckup", "BedLevel"],
"supported_actions": ["UMOCheckup", "BedLevel", "UpgradeFirmware"]
}, },
"overrides": { "overrides": {

View File

@ -0,0 +1,19 @@
{
"id": "ultimaker_original_dual_left",
"version": 2,
"name": "Left Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "ultimaker_original_dual",
"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 }
}
}

View File

@ -0,0 +1,19 @@
{
"id": "ultimaker_original_dual_right",
"version": 2,
"name": "Right Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "ultimaker_original_dual",
"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": 21.6 }
}
}

View File

@ -11,7 +11,7 @@ Generic PLA profile. Serves as an example file, data in this file is not correct
</name> </name>
<GUID>60636bb4-518f-42e7-8237-fe77b194ebe0</GUID> <GUID>60636bb4-518f-42e7-8237-fe77b194ebe0</GUID>
<version>0</version> <version>0</version>
<color_code>#FF0000</color_code> <color_code>#8cb219</color_code>
</metadata> </metadata>
<properties> <properties>
<density>1.07</density> <density>1.07</density>

View File

@ -11,7 +11,7 @@ Generic PLA profile. Serves as an example file, data in this file is not correct
</name> </name>
<GUID>12f41353-1a33-415e-8b4f-a775a6c70cc6</GUID> <GUID>12f41353-1a33-415e-8b4f-a775a6c70cc6</GUID>
<version>0</version> <version>0</version>
<color_code>#0000FF</color_code> <color_code>#159499</color_code>
</metadata> </metadata>
<properties> <properties>
<density>0.94</density> <density>0.94</density>

View File

@ -11,7 +11,7 @@ Generic PLA profile. Serves as an example file, data in this file is not correct
</name> </name>
<GUID>506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9</GUID> <GUID>506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9</GUID>
<version>0</version> <version>0</version>
<color_code>#00FF00</color_code> <color_code>#ffc924</color_code>
</metadata> </metadata>
<properties> <properties>
<density>1.3</density> <density>1.3</density>

View File

@ -183,7 +183,7 @@ Item
Action Action
{ {
id: deleteObjectAction; id: deleteObjectAction;
text: catalog.i18nc("@action:inmenu","Delete Object"); text: catalog.i18nc("@action:inmenu","Delete Model");
enabled: UM.Controller.toolsEnabled; enabled: UM.Controller.toolsEnabled;
iconName: "edit-delete"; iconName: "edit-delete";
} }
@ -191,13 +191,13 @@ Item
Action Action
{ {
id: centerObjectAction; id: centerObjectAction;
text: catalog.i18nc("@action:inmenu","Ce&nter Object on Platform"); text: catalog.i18nc("@action:inmenu","Ce&nter Model on Platform");
} }
Action Action
{ {
id: groupObjectsAction id: groupObjectsAction
text: catalog.i18nc("@action:inmenu menubar:edit","&Group Objects"); text: catalog.i18nc("@action:inmenu menubar:edit","&Group Models");
enabled: UM.Scene.numObjectsSelected > 1 ? true: false enabled: UM.Scene.numObjectsSelected > 1 ? true: false
iconName: "object-group" iconName: "object-group"
shortcut: "Ctrl+G"; shortcut: "Ctrl+G";
@ -207,7 +207,7 @@ Item
Action Action
{ {
id: unGroupObjectsAction id: unGroupObjectsAction
text: catalog.i18nc("@action:inmenu menubar:edit","Ungroup Objects"); text: catalog.i18nc("@action:inmenu menubar:edit","Ungroup Models");
enabled: UM.Scene.isGroupSelected enabled: UM.Scene.isGroupSelected
iconName: "object-ungroup" iconName: "object-ungroup"
shortcut: "Ctrl+Shift+G"; shortcut: "Ctrl+Shift+G";
@ -217,7 +217,7 @@ Item
Action Action
{ {
id: mergeObjectsAction id: mergeObjectsAction
text: catalog.i18nc("@action:inmenu menubar:edit","&Merge Objects"); text: catalog.i18nc("@action:inmenu menubar:edit","&Merge Models");
enabled: UM.Scene.numObjectsSelected > 1 ? true: false enabled: UM.Scene.numObjectsSelected > 1 ? true: false
iconName: "merge"; iconName: "merge";
shortcut: "Ctrl+Alt+G"; shortcut: "Ctrl+Alt+G";
@ -227,14 +227,14 @@ Item
Action Action
{ {
id: multiplyObjectAction; id: multiplyObjectAction;
text: catalog.i18nc("@action:inmenu","&Duplicate Object"); text: catalog.i18nc("@action:inmenu","&Duplicate Model");
iconName: "edit-duplicate" iconName: "edit-duplicate"
} }
Action Action
{ {
id: selectAllAction; id: selectAllAction;
text: catalog.i18nc("@action:inmenu menubar:edit","&Select All Objects"); text: catalog.i18nc("@action:inmenu menubar:edit","&Select All Models");
enabled: UM.Controller.toolsEnabled; enabled: UM.Controller.toolsEnabled;
iconName: "edit-select-all"; iconName: "edit-select-all";
shortcut: "Ctrl+A"; shortcut: "Ctrl+A";
@ -244,7 +244,7 @@ Item
Action Action
{ {
id: deleteAllAction; id: deleteAllAction;
text: catalog.i18nc("@action:inmenu menubar:edit","&Clear Build Platform"); text: catalog.i18nc("@action:inmenu menubar:edit","&Clear Build Plate");
enabled: UM.Controller.toolsEnabled; enabled: UM.Controller.toolsEnabled;
iconName: "edit-delete"; iconName: "edit-delete";
shortcut: "Ctrl+D"; shortcut: "Ctrl+D";
@ -254,7 +254,7 @@ Item
Action Action
{ {
id: reloadAllAction; id: reloadAllAction;
text: catalog.i18nc("@action:inmenu menubar:file","Re&load All Objects"); text: catalog.i18nc("@action:inmenu menubar:file","Re&load All Models");
iconName: "document-revert"; iconName: "document-revert";
onTriggered: Printer.reloadAll(); onTriggered: Printer.reloadAll();
} }
@ -262,14 +262,14 @@ Item
Action Action
{ {
id: resetAllTranslationAction; id: resetAllTranslationAction;
text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Object Positions"); text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Model Positions");
onTriggered: Printer.resetAllTranslation(); onTriggered: Printer.resetAllTranslation();
} }
Action Action
{ {
id: resetAllAction; id: resetAllAction;
text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Object &Transformations"); text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Model &Transformations");
onTriggered: Printer.resetAll(); onTriggered: Printer.resetAll();
} }

View File

@ -183,13 +183,17 @@ UM.Dialog
text: catalog.i18nc("@action:button", "Add Printer") text: catalog.i18nc("@action:button", "Add Printer")
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
onClicked: onClicked: addMachine()
{ }
base.visible = false
var item = machineList.model.getItem(machineList.currentIndex); onAccepted: addMachine()
Cura.MachineManager.addMachine(machineName.text, item.id)
base.machineAdded(item.id) // Emit signal that the user added a machine. function addMachine()
} {
base.visible = false
var item = machineList.model.getItem(machineList.currentIndex);
Cura.MachineManager.addMachine(machineName.text, item.id)
base.machineAdded(item.id) // Emit signal that the user added a machine.
} }
Item Item

View File

@ -209,7 +209,7 @@ Rectangle {
lengths = ["0.00"]; lengths = ["0.00"];
weights = ["0"]; weights = ["0"];
} }
return catalog.i18nc("@label", "%1 m / %2 g").arg(lengths.join(" + ")).arg(weights.join(" + ")); return catalog.i18nc("@label", "%1 m / ~ %2 g").arg(lengths.join(" + ")).arg(weights.join(" + "));
} }
} }
} }

View File

@ -15,25 +15,57 @@ Rectangle
UM.I18nCatalog { id: catalog; name:"cura"} UM.I18nCatalog { id: catalog; name:"cura"}
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
property real progress: printerConnected ? Cura.MachineManager.printerOutputDevices[0].progress : 0; property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
property int backendState: UM.Backend.state; property real progress: printerConnected ? Cura.MachineManager.printerOutputDevices[0].progress : 0
property int backendState: UM.Backend.state
property bool showProgress: {
// determine if we need to show the progress bar + percentage
if(!printerConnected || !printerAcceptsCommands) {
return false;
}
switch(Cura.MachineManager.printerOutputDevices[0].jobState)
{
case "printing":
case "paused":
return true;
case "pre_print": // heating, etc.
case "wait_cleanup":
case "offline":
case "abort": // note sure if this jobState actually occurs in the wild
case "error": // after clicking abort you apparently get "error"
case "ready": // ready to print or getting ready
case "": // ready to print or getting ready
default:
return false;
}
}
property variant statusColor: property variant statusColor:
{ {
if(!printerConnected) if(!printerConnected || !printerAcceptsCommands)
return UM.Theme.getColor("status_offline") return UM.Theme.getColor("text");
else if(Cura.MachineManager.printerOutputDevices[0].jobState == "printing" || Cura.MachineManager.printerOutputDevices[0].jobState == "pre_print" || Cura.MachineManager.printerOutputDevices[0].jobState == "wait_cleanup" )
return UM.Theme.getColor("status_busy") switch(Cura.MachineManager.printerOutputDevices[0].jobState)
else if(Cura.MachineManager.printerOutputDevices[0].jobState == "ready" || Cura.MachineManager.printerOutputDevices[0].jobState == "") {
return UM.Theme.getColor("status_ready") case "printing":
else if(Cura.MachineManager.printerOutputDevices[0].jobState == "paused") case "pre_print":
return UM.Theme.getColor("status_paused") case "wait_cleanup":
else if (Cura.MachineManager.printerOutputDevices[0].jobState == "error") return UM.Theme.getColor("status_busy");
return UM.Theme.getColor("status_stopped") case "ready":
else if (Cura.MachineManager.printerOutputDevices[0].jobState == "offline") case "":
return UM.Theme.getColor("status_offline") return UM.Theme.getColor("status_ready");
else case "paused":
return UM.Theme.getColor("text") return UM.Theme.getColor("status_paused");
case "error":
return UM.Theme.getColor("status_stopped");
case "offline":
return UM.Theme.getColor("status_offline");
default:
return UM.Theme.getColor("text");
}
} }
property bool activity: Printer.getPlatformActivity; property bool activity: Printer.getPlatformActivity;
@ -42,31 +74,28 @@ Rectangle
property string statusText: property string statusText:
{ {
if(!printerConnected) if(!printerConnected)
{ return catalog.i18nc("@label:MonitorStatus", "Not connected to a printer");
return catalog.i18nc("@label:", "Not connected to a printer") if(!printerAcceptsCommands)
} else if(Cura.MachineManager.printerOutputDevices[0].jobState == "offline") return catalog.i18nc("@label:MonitorStatus", "Printer does not accept commands");
{
return catalog.i18nc("@label:", "Lost connection with the printer")
} else if(Cura.MachineManager.printerOutputDevices[0].jobState == "printing")
{
return catalog.i18nc("@label:", "Printing...")
} else if(Cura.MachineManager.printerOutputDevices[0].jobState == "paused")
{
return catalog.i18nc("@label:", "Paused")
}
else if(Cura.MachineManager.printerOutputDevices[0].jobState == "pre_print")
{
return catalog.i18nc("@label:", "Preparing...")
}
else if(Cura.MachineManager.printerOutputDevices[0].jobState == "wait_cleanup")
{
return catalog.i18nc("@label:", "Waiting for cleanup...")
}
else
{
return " "
}
var printerOutputDevice = Cura.MachineManager.printerOutputDevices[0]
switch(printerOutputDevice.jobState)
{
case "offline":
return catalog.i18nc("@label:MonitorStatus", "Lost connection with the printer");
case "printing":
return catalog.i18nc("@label:MonitorStatus", "Printing...");
case "paused":
return catalog.i18nc("@label:MonitorStatus", "Paused");
case "pre_print":
return catalog.i18nc("@label:MonitorStatus", "Preparing...");
case "wait_cleanup":
return catalog.i18nc("@label:MonitorStatus", "Please remove the print");
case "error":
return printerOutputDevice.errorText;
default:
return " ";
}
} }
Label Label
@ -79,7 +108,7 @@ Rectangle
color: base.statusColor color: base.statusColor
font: UM.Theme.getFont("large") font: UM.Theme.getFont("large")
text: statusText; text: statusText
} }
Label Label
@ -90,8 +119,8 @@ Rectangle
color: base.statusColor color: base.statusColor
font: UM.Theme.getFont("large") font: UM.Theme.getFont("large")
text: Math.round(progress) + "%"; text: Math.round(progress) + "%"
visible: printerConnected visible: showProgress
} }
Rectangle Rectangle
@ -105,6 +134,7 @@ Rectangle
anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.leftMargin: UM.Theme.getSize("default_margin").width
radius: UM.Theme.getSize("progressbar_radius").width radius: UM.Theme.getSize("progressbar_radius").width
color: UM.Theme.getColor("progressbar_background") color: UM.Theme.getColor("progressbar_background")
visible: showProgress
Rectangle Rectangle
{ {
@ -120,7 +150,8 @@ Rectangle
id: abortButton id: abortButton
visible: printerConnected visible: printerConnected
enabled: printerConnected && (Cura.MachineManager.printerOutputDevices[0].jobState == "paused" || Cura.MachineManager.printerOutputDevices[0].jobState == "printing") enabled: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands &&
(["paused", "printing", "pre_print"].indexOf(Cura.MachineManager.printerOutputDevices[0].jobState) >= 0)
height: UM.Theme.getSize("save_button_save_to_button").height height: UM.Theme.getSize("save_button_save_to_button").height
anchors.top: progressBar.bottom anchors.top: progressBar.bottom
@ -129,20 +160,35 @@ Rectangle
anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.rightMargin: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@label:", "Abort Print") text: catalog.i18nc("@label:", "Abort Print")
onClicked: { Cura.MachineManager.printerOutputDevices[0].setJobState("abort") } onClicked: Cura.MachineManager.printerOutputDevices[0].setJobState("abort")
style: ButtonStyle style: ButtonStyle
{ {
background: Rectangle background: Rectangle
{ {
border.width: UM.Theme.getSize("default_lining").width border.width: UM.Theme.getSize("default_lining").width
border.color: !control.enabled ? UM.Theme.getColor("action_button_disabled_border") : border.color:
control.pressed ? UM.Theme.getColor("action_button_active_border") : {
control.hovered ? UM.Theme.getColor("action_button_hovered_border") : UM.Theme.getColor("action_button_border") if(!control.enabled)
color: !control.enabled ? UM.Theme.getColor("action_button_disabled") : return UM.Theme.getColor("action_button_disabled_border");
control.pressed ? UM.Theme.getColor("action_button_active") : else if(control.pressed)
control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button") return UM.Theme.getColor("action_button_active_border");
else if(control.hovered)
return UM.Theme.getColor("action_button_hovered_border");
else
return UM.Theme.getColor("action_button_border");
}
color:
{
if(!control.enabled)
return UM.Theme.getColor("action_button_disabled");
else if(control.pressed)
return UM.Theme.getColor("action_button_active");
else if(control.hovered)
return UM.Theme.getColor("action_button_hovered");
else
return UM.Theme.getColor("action_button");
}
Behavior on color { ColorAnimation { duration: 50; } } Behavior on color { ColorAnimation { duration: 50; } }
implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("default_margin").width * 2) implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("default_margin").width * 2)
@ -151,9 +197,17 @@ Rectangle
{ {
id: actualLabel id: actualLabel
anchors.centerIn: parent anchors.centerIn: parent
color: !control.enabled ? UM.Theme.getColor("action_button_disabled_text") : color:
control.pressed ? UM.Theme.getColor("action_button_active_text") : {
control.hovered ? UM.Theme.getColor("action_button_hovered_text") : UM.Theme.getColor("action_button_text") if(!control.enabled)
return UM.Theme.getColor("action_button_disabled_text");
else if(control.pressed)
return UM.Theme.getColor("action_button_active_text");
else if(control.hovered)
return UM.Theme.getColor("action_button_hovered_text");
else
return UM.Theme.getColor("action_button_text");
}
font: UM.Theme.getFont("action_button") font: UM.Theme.getFont("action_button")
text: control.text; text: control.text;
} }
@ -164,10 +218,7 @@ Rectangle
Button Button
{ {
id: pauseButton id: pauseResumeButton
visible: printerConnected
enabled: printerConnected && (Cura.MachineManager.printerOutputDevices[0].jobState == "paused" || Cura.MachineManager.printerOutputDevices[0].jobState == "printing")
height: UM.Theme.getSize("save_button_save_to_button").height height: UM.Theme.getSize("save_button_save_to_button").height
anchors.top: progressBar.bottom anchors.top: progressBar.bottom
@ -175,20 +226,77 @@ Rectangle
anchors.right: abortButton.left anchors.right: abortButton.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.rightMargin: UM.Theme.getSize("default_margin").width
text: printerConnected ? Cura.MachineManager.printerOutputDevices[0].jobState == "paused" ? catalog.i18nc("@label:", "Resume") : catalog.i18nc("@label:", "Pause") : "" property bool userClicked: false
onClicked: { Cura.MachineManager.printerOutputDevices[0].jobState == "paused" ? Cura.MachineManager.printerOutputDevices[0].setJobState("print") : Cura.MachineManager.printerOutputDevices[0].setJobState("pause") } property string lastJobState: ""
visible: printerConnected
enabled: (!userClicked) && printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands &&
(["paused", "printing"].indexOf(Cura.MachineManager.printerOutputDevices[0].jobState) >= 0)
text: {
var result = "";
var jobState = Cura.MachineManager.printerOutputDevices[0].jobState;
if (!printerConnected) {
return "";
}
if (lastJobState !== jobState) {
// the userClicked message must disappear when an "automated" jobState comes by
userClicked = false;
lastJobState = jobState;
}
if (jobState == "paused")
{
if (userClicked) {
// User feedback for pretending we're already in "printing" mode.
result = catalog.i18nc("@label:", "Pause");
} else {
result = catalog.i18nc("@label:", "Resume");
}
} else {
if (userClicked) {
// User feedback for pretending we're already in "pause" mode.
result = catalog.i18nc("@label:", "Resume");
} else {
result = catalog.i18nc("@label:", "Pause");
}
}
return result;
}
onClicked: {
var newJobState = Cura.MachineManager.printerOutputDevices[0].jobState == "paused" ? "print" : "pause";
Cura.MachineManager.printerOutputDevices[0].setJobState(newJobState);
userClicked = true;
}
style: ButtonStyle style: ButtonStyle
{ {
background: Rectangle background: Rectangle
{ {
border.width: UM.Theme.getSize("default_lining").width border.width: UM.Theme.getSize("default_lining").width
border.color: !control.enabled ? UM.Theme.getColor("action_button_disabled_border") : border.color:
control.pressed ? UM.Theme.getColor("action_button_active_border") : {
control.hovered ? UM.Theme.getColor("action_button_hovered_border") : UM.Theme.getColor("action_button_border") if(!control.enabled)
color: !control.enabled ? UM.Theme.getColor("action_button_disabled") : return UM.Theme.getColor("action_button_disabled_border");
control.pressed ? UM.Theme.getColor("action_button_active") : else if(control.pressed)
control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button") return UM.Theme.getColor("action_button_active_border");
else if(control.hovered)
return UM.Theme.getColor("action_button_hovered_border");
else
return UM.Theme.getColor("action_button_border");
}
color:
{
if(!control.enabled)
return UM.Theme.getColor("action_button_disabled");
else if(control.pressed)
return UM.Theme.getColor("action_button_active");
else if(control.hovered)
return UM.Theme.getColor("action_button_hovered");
else
return UM.Theme.getColor("action_button");
}
Behavior on color { ColorAnimation { duration: 50; } } Behavior on color { ColorAnimation { duration: 50; } }
implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("default_margin").width * 2) implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("default_margin").width * 2)
@ -197,11 +305,19 @@ Rectangle
{ {
id: actualLabel id: actualLabel
anchors.centerIn: parent anchors.centerIn: parent
color: !control.enabled ? UM.Theme.getColor("action_button_disabled_text") : color:
control.pressed ? UM.Theme.getColor("action_button_active_text") : {
control.hovered ? UM.Theme.getColor("action_button_hovered_text") : UM.Theme.getColor("action_button_text") if(!control.enabled)
return UM.Theme.getColor("action_button_disabled_text");
else if(control.pressed)
return UM.Theme.getColor("action_button_active_text");
else if(control.hovered)
return UM.Theme.getColor("action_button_hovered_text");
else
return UM.Theme.getColor("action_button_text");
}
font: UM.Theme.getFont("action_button") font: UM.Theme.getFont("action_button")
text: control.text; text: control.text
} }
} }
label: Item { } label: Item { }

View File

@ -69,6 +69,7 @@ UM.PreferencesPage
Row Row
{ {
spacing: UM.Theme.getSize("default_margin").width
Label Label
{ {
id: languageLabel id: languageLabel
@ -167,7 +168,7 @@ UM.PreferencesPage
UM.TooltipArea { UM.TooltipArea {
width: childrenRect.width; width: childrenRect.width;
height: childrenRect.height; height: childrenRect.height;
text: catalog.i18nc("@info:tooltip","Moves the camera so the object is in the center of the view when an object is selected") text: catalog.i18nc("@info:tooltip","Moves the camera so the model is in the center of the view when an model is selected")
CheckBox CheckBox
{ {
@ -181,12 +182,12 @@ UM.PreferencesPage
UM.TooltipArea { UM.TooltipArea {
width: childrenRect.width width: childrenRect.width
height: childrenRect.height height: childrenRect.height
text: catalog.i18nc("@info:tooltip", "Should objects on the platform be moved so that they no longer intersect?") text: catalog.i18nc("@info:tooltip", "Should models on the platform be moved so that they no longer intersect?")
CheckBox CheckBox
{ {
id: pushFreeCheckbox id: pushFreeCheckbox
text: catalog.i18nc("@option:check", "Ensure objects are kept apart") text: catalog.i18nc("@option:check", "Ensure models are kept apart")
checked: boolCheck(UM.Preferences.getValue("physics/automatic_push_free")) checked: boolCheck(UM.Preferences.getValue("physics/automatic_push_free"))
onCheckedChanged: UM.Preferences.setValue("physics/automatic_push_free", checked) onCheckedChanged: UM.Preferences.setValue("physics/automatic_push_free", checked)
} }
@ -246,12 +247,12 @@ UM.PreferencesPage
UM.TooltipArea { UM.TooltipArea {
width: childrenRect.width width: childrenRect.width
height: childrenRect.height height: childrenRect.height
text: catalog.i18nc("@info:tooltip","Should objects be scaled to the build volume if they are too large?") text: catalog.i18nc("@info:tooltip","Should models be scaled to the build volume if they are too large?")
CheckBox CheckBox
{ {
id: scaleToFitCheckbox id: scaleToFitCheckbox
text: catalog.i18nc("@option:check","Scale large objects") text: catalog.i18nc("@option:check","Scale large models")
checked: boolCheck(UM.Preferences.getValue("mesh/scale_to_fit")) checked: boolCheck(UM.Preferences.getValue("mesh/scale_to_fit"))
onCheckedChanged: UM.Preferences.setValue("mesh/scale_to_fit", checked) onCheckedChanged: UM.Preferences.setValue("mesh/scale_to_fit", checked)
} }
@ -260,12 +261,12 @@ UM.PreferencesPage
UM.TooltipArea { UM.TooltipArea {
width: childrenRect.width width: childrenRect.width
height: childrenRect.height height: childrenRect.height
text: catalog.i18nc("@info:tooltip","An object may appear extremely small if its unit is for example in meters rather than millimeters. Should these objects be scaled up?") text: catalog.i18nc("@info:tooltip","An model may appear extremely small if its unit is for example in meters rather than millimeters. Should these models be scaled up?")
CheckBox CheckBox
{ {
id: scaleTinyCheckbox id: scaleTinyCheckbox
text: catalog.i18nc("@option:check","Scale extremely small objects") text: catalog.i18nc("@option:check","Scale extremely small models")
checked: boolCheck(UM.Preferences.getValue("mesh/scale_tiny_meshes")) checked: boolCheck(UM.Preferences.getValue("mesh/scale_tiny_meshes"))
onCheckedChanged: UM.Preferences.setValue("mesh/scale_tiny_meshes", checked) onCheckedChanged: UM.Preferences.setValue("mesh/scale_tiny_meshes", checked)
} }

View File

@ -18,7 +18,10 @@ UM.ManagementPage
} }
activeId: Cura.MachineManager.activeMachineId activeId: Cura.MachineManager.activeMachineId
activeIndex: { activeIndex: activeMachineIndex()
function activeMachineIndex()
{
for(var i = 0; i < model.rowCount(); i++) { for(var i = 0; i < model.rowCount(); i++) {
if (model.getItem(i).id == Cura.MachineManager.activeMachineId) { if (model.getItem(i).id == Cura.MachineManager.activeMachineId) {
return i; return i;
@ -129,10 +132,10 @@ UM.ManagementPage
Label Label
{ {
text: catalog.i18nc("@label", "Type") text: catalog.i18nc("@label", "Type")
visible: base.currentItem && base.currentItem.metadata visible: base.currentItem && "definition_name" in base.currentItem.metadata
} }
Label { Label {
text: (base.currentItem && base.currentItem.metadata) ? base.currentItem.metadata.definition_name : "" text: (base.currentItem && "definition_name" in base.currentItem.metadata) ? base.currentItem.metadata.definition_name : ""
} }
} }
@ -142,7 +145,16 @@ UM.ManagementPage
{ {
id: confirmDialog; id: confirmDialog;
object: base.currentItem && base.currentItem.name ? base.currentItem.name : ""; object: base.currentItem && base.currentItem.name ? base.currentItem.name : "";
onYes: Cura.MachineManager.removeMachine(base.currentItem.id); onYes:
{
Cura.MachineManager.removeMachine(base.currentItem.id);
if(!base.currentItem)
{
objectList.currentIndex = activeMachineIndex()
}
//Force updating currentItem and the details panel
objectList.onCurrentIndexChanged()
}
} }
UM.RenameDialog UM.RenameDialog
@ -152,11 +164,20 @@ UM.ManagementPage
onAccepted: onAccepted:
{ {
Cura.MachineManager.renameMachine(base.currentItem.id, newName.trim()); Cura.MachineManager.renameMachine(base.currentItem.id, newName.trim());
//Reselect current item to update details panel //Force updating currentItem and the details panel
var index = objectList.currentIndex objectList.onCurrentIndexChanged()
objectList.currentIndex = -1
objectList.currentIndex = index
} }
} }
Connections
{
target: Cura.MachineManager
onGlobalContainerChanged:
{
objectList.currentIndex = activeMachineIndex()
objectList.onCurrentIndexChanged()
}
}
} }
} }

View File

@ -12,6 +12,18 @@ import Cura 1.0 as Cura
Column Column
{ {
id: printMonitor id: printMonitor
property var connectedPrinter: printerConnected ? Cura.MachineManager.printerOutputDevices[0] : null
Cura.ExtrudersModel { id: extrudersModel }
Label
{
text: printerConnected ? connectedPrinter.connectionText : catalog.i18nc("@label", "The printer is not connected.")
color: printerConnected && printerAcceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("default")
wrapMode: Text.WordWrap
width: base.width
}
Loader Loader
{ {
@ -24,8 +36,8 @@ Column
delegate: Loader delegate: Loader
{ {
sourceComponent: monitorItem sourceComponent: monitorItem
property string label: machineExtruderCount.properties.value > 1 ? catalog.i18nc("@label", "Hotend Temperature %1").arg(index + 1) : catalog.i18nc("@label", "Hotend Temperature") property string label: machineExtruderCount.properties.value > 1 ? extrudersModel.getItem(index).name : catalog.i18nc("@label", "Hotend")
property string value: printerConnected ? Math.round(Cura.MachineManager.printerOutputDevices[0].hotendTemperatures[index]) + "°C" : "" property string value: printerConnected ? Math.round(connectedPrinter.hotendTemperatures[index]) + "°C" : ""
} }
} }
Repeater Repeater
@ -34,8 +46,8 @@ Column
delegate: Loader delegate: Loader
{ {
sourceComponent: monitorItem sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Bed Temperature") property string label: catalog.i18nc("@label", "Build plate")
property string value: printerConnected ? Math.round(Cura.MachineManager.printerOutputDevices[0].bedTemperature) + "°C" : "" property string value: printerConnected ? Math.round(connectedPrinter.bedTemperature) + "°C" : ""
} }
} }
@ -48,19 +60,19 @@ Column
{ {
sourceComponent: monitorItem sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Job Name") property string label: catalog.i18nc("@label", "Job Name")
property string value: printerConnected ? Cura.MachineManager.printerOutputDevices[0].jobName : "" property string value: printerConnected ? connectedPrinter.jobName : ""
} }
Loader Loader
{ {
sourceComponent: monitorItem sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Printing Time") property string label: catalog.i18nc("@label", "Printing Time")
property string value: printerConnected ? getPrettyTime(Cura.MachineManager.printerOutputDevices[0].timeTotal) : "" property string value: printerConnected ? getPrettyTime(connectedPrinter.timeTotal) : ""
} }
Loader Loader
{ {
sourceComponent: monitorItem sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Estimated time left") property string label: catalog.i18nc("@label", "Estimated time left")
property string value: printerConnected ? getPrettyTime(Cura.MachineManager.printerOutputDevices[0].timeTotal - Cura.MachineManager.printerOutputDevices[0].timeElapsed) : "" property string value: printerConnected ? getPrettyTime(connectedPrinter.timeTotal - connectedPrinter.timeElapsed) : ""
} }
Component Component
@ -70,21 +82,24 @@ Column
Row Row
{ {
height: UM.Theme.getSize("setting_control").height height: UM.Theme.getSize("setting_control").height
width: base.width - 2 * UM.Theme.getSize("default_margin").width
Label Label
{ {
text: label width: parent.width * 0.4
color: printerConnected ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("default")
width: base.width * 0.4
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: label
color: printerConnected && printerAcceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("default")
elide: Text.ElideRight
} }
Label Label
{ {
text: value width: parent.width * 0.6
color: printerConnected ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("default")
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: value
color: printerConnected && printerAcceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("default")
elide: Text.ElideRight
} }
} }
} }

View File

@ -19,7 +19,10 @@ SettingItem
model: Cura.ExtrudersModel model: Cura.ExtrudersModel
{ {
id: extruders_model id: extruders_model
onModelChanged: control.color = extruders_model.getItem(control.currentIndex).color
} }
property string color: extruders_model.getItem(control.currentIndex).color
textRole: "name" textRole: "name"
anchors.fill: parent anchors.fill: parent
@ -64,7 +67,7 @@ SettingItem
anchors.leftMargin: UM.Theme.getSize("default_lining").width anchors.leftMargin: UM.Theme.getSize("default_lining").width
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: extruders_model.getItem(control.currentIndex).colour color: control.color
border.width: UM.Theme.getSize("default_lining").width border.width: UM.Theme.getSize("default_lining").width
border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : UM.Theme.getColor("setting_control_border") border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : UM.Theme.getColor("setting_control_border")
} }
@ -105,7 +108,8 @@ SettingItem
onActivated: onActivated:
{ {
forceActiveFocus(); forceActiveFocus();
propertyProvider.setPropertyValue("value", extruders_model.getItem(index).index) propertyProvider.setPropertyValue("value", extruders_model.getItem(index).index);
control.color = extruders_model.getItem(index).color;
} }
onModelChanged: updateCurrentIndex(); onModelChanged: updateCurrentIndex();
@ -121,7 +125,8 @@ SettingItem
{ {
if(extruders_model.getItem(i).index == propertyProvider.properties.value) if(extruders_model.getItem(i).index == propertyProvider.properties.value)
{ {
currentIndex = i; control.currentIndex = i;
control.color = extruders_model.getItem(i).color;
return; return;
} }
} }

View File

@ -100,7 +100,7 @@ SettingItem
maximumLength: 10; maximumLength: 10;
validator: RegExpValidator { regExp: /[0-9.,-]{0,10}/ } validator: RegExpValidator { regExp: (definition.type == "int") ? /^-?[0-9]{0,10}/ : /^-?[0-9.,]{0,10}/ } // definition.type property from parent loader used to disallow fractional number entry
Binding Binding
{ {

View File

@ -28,6 +28,7 @@ Rectangle
// Is there an output device for this printer? // Is there an output device for this printer?
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
color: UM.Theme.getColor("sidebar"); color: UM.Theme.getColor("sidebar");
UM.I18nCatalog { id: catalog; name:"cura"} UM.I18nCatalog { id: catalog; name:"cura"}
@ -107,19 +108,28 @@ Rectangle
onClicked: monitoringPrint = true onClicked: monitoringPrint = true
iconSource: { iconSource: {
if(!printerConnected) if(!printerConnected)
return UM.Theme.getIcon("tab_monitor") return UM.Theme.getIcon("tab_monitor");
else if(Cura.MachineManager.printerOutputDevices[0].jobState == "printing" || Cura.MachineManager.printerOutputDevices[0].jobState == "pre_print" || Cura.MachineManager.printerOutputDevices[0].jobState == "wait_cleanup" ) else if(!printerAcceptsCommands)
return UM.Theme.getIcon("tab_monitor_busy") return UM.Theme.getIcon("tab_monitor_unknown");
else if(Cura.MachineManager.printerOutputDevices[0].jobState == "ready" || Cura.MachineManager.printerOutputDevices[0].jobState == "")
return UM.Theme.getIcon("tab_monitor_connected") switch(Cura.MachineManager.printerOutputDevices[0].jobState)
else if(Cura.MachineManager.printerOutputDevices[0].jobState == "paused") {
return UM.Theme.getIcon("tab_monitor_paused") case "printing":
else if (Cura.MachineManager.printerOutputDevices[0].jobState == "error") case "pre_print":
return UM.Theme.getIcon("tab_monitor_stopped") case "wait_cleanup":
else if (Cura.MachineManager.printerOutputDevices[0].jobState == "offline") return UM.Theme.getIcon("tab_monitor_busy");
return UM.Theme.getIcon("tab_monitor_offline") case "ready":
else case "":
return UM.Theme.getIcon("tab_monitor") return UM.Theme.getIcon("tab_monitor_connected")
case "paused":
return UM.Theme.getIcon("tab_monitor_paused")
case "error":
return UM.Theme.getIcon("tab_monitor_stopped")
case "offline":
return UM.Theme.getIcon("tab_monitor_offline")
default:
return UM.Theme.getIcon("tab_monitor")
}
} }
checkable: true checkable: true
checked: monitoringPrint checked: monitoringPrint

View File

@ -138,7 +138,7 @@ Column
anchors.leftMargin: (parent.height - height) / 2 anchors.leftMargin: (parent.height - height) / 2
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: model.colour color: model.color
border.width: UM.Theme.getSize("default_lining").width border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("toggle_checked") border.color: UM.Theme.getColor("toggle_checked")
} }
@ -183,8 +183,23 @@ Column
Label Label
{ {
id: variantLabel id: variantLabel
text: (Cura.MachineManager.hasVariants && Cura.MachineManager.hasMaterials) ? catalog.i18nc("@label","Nozzle & Material:"): text:
Cura.MachineManager.hasVariants ? catalog.i18nc("@label","Nozzle:") : catalog.i18nc("@label","Material:"); {
var label;
if(Cura.MachineManager.hasVariants && Cura.MachineManager.hasMaterials)
{
label = "%1 & %2".arg(Cura.MachineManager.activeDefinitionVariantsName).arg(catalog.i18nc("@label","Material"));
}
else if(Cura.MachineManager.hasVariants)
{
label = Cura.MachineManager.activeDefinitionVariantsName;
}
else
{
label = catalog.i18nc("@label","Material");
}
return "%1:".arg(label);
}
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width

View File

@ -216,7 +216,7 @@ Item
anchors.verticalCenter: brimCheckBox.verticalCenter anchors.verticalCenter: brimCheckBox.verticalCenter
width: parent.width / 100 * 35 - 3 * UM.Theme.getSize("default_margin").width width: parent.width / 100 * 35 - 3 * UM.Theme.getSize("default_margin").width
//: Bed adhesion label //: Bed adhesion label
text: catalog.i18nc("@label:listbox", "Bed Adhesion:"); text: catalog.i18nc("@label", "Helper Parts:");
font: UM.Theme.getFont("default"); font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text"); color: UM.Theme.getColor("text");
} }
@ -264,7 +264,7 @@ Item
anchors.verticalCenter: supportCheckBox.verticalCenter anchors.verticalCenter: supportCheckBox.verticalCenter
width: parent.width / 100 * 35 - 3 * UM.Theme.getSize("default_margin").width width: parent.width / 100 * 35 - 3 * UM.Theme.getSize("default_margin").width
//: Support label //: Support label
text: catalog.i18nc("@label:listbox", "Support:"); text: "";
font: UM.Theme.getFont("default"); font: UM.Theme.getFont("default");
color: UM.Theme.getColor("text"); color: UM.Theme.getColor("text");
} }
@ -327,7 +327,8 @@ Item
supportEnabled.setPropertyValue("value", false); supportEnabled.setPropertyValue("value", false);
} else { } else {
supportEnabled.setPropertyValue("value", true); supportEnabled.setPropertyValue("value", true);
supportExtruderNr.setPropertyValue("value", index - 1); // Send the extruder nr as a string.
supportExtruderNr.setPropertyValue("value", String(index - 1));
} }
} }
MouseArea { MouseArea {
@ -372,7 +373,7 @@ Item
for(var extruderNumber = 0; extruderNumber < extruders.model.rowCount() ; extruderNumber++) { for(var extruderNumber = 0; extruderNumber < extruders.model.rowCount() ; extruderNumber++) {
extruderModel.append({ extruderModel.append({
text: catalog.i18nc("@label", "Print using %1").arg(extruders.model.getItem(extruderNumber).name), text: catalog.i18nc("@label", "Print using %1").arg(extruders.model.getItem(extruderNumber).name),
color: extruders.model.getItem(extruderNumber).colour color: extruders.model.getItem(extruderNumber).color
}) })
} }
} }

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 760 KiB

View File

@ -1,13 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 16.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve"> viewBox="0 0 30 30" xml:space="preserve">
<path d="M240.168,503.311c-60.098,21.117-109.643-3.1-99.704-60.816c9.942-57.73,66.971-181.316,75.107-204.688 <path d="M13.628 29.557c-3.53 1.24-6.44-.182-5.857-3.572.584-3.39 3.934-10.65 4.412-12.023.477-1.373-.438-1.75-1.42-1.19-.566.326-1.408.98-2.13 1.617-.2-.404-.482-.865-.694-1.306 1.18-1.181 3.15-2.765 5.482-3.339 2.787-.688 7.446.413 5.444 5.739-1.43 3.797-2.441 6.417-3.078 8.372-.637 1.952.125 2.365 1.239 1.6.87-.594 1.798-1.403 2.478-2.03.315.513.413.676.726 1.264-1.185 1.2-4.27 4.042-6.598 4.868h-.004zM20.942 6.071c-1.601 1.363-3.974 1.333-5.302-.067-1.328-1.399-1.106-3.638.495-5.001 1.6-1.363 3.974-1.333 5.306.062 1.323 1.399 1.1 3.639-.501 5.006h.002z"/>
c8.129-23.371-7.46-29.777-24.172-20.267c-9.638,5.56-23.963,16.704-36.26,27.535c-3.41-6.866-8.206-14.712-11.807-22.226
c20.067-20.109,53.61-47.07,93.318-56.841c47.445-11.711,126.759,7.031,92.673,97.695c-24.338,64.636-41.549,109.239-52.396,142.524
c-10.84,33.233,2.13,40.266,21.092,27.25c14.825-10.123,30.618-23.892,42.195-34.568c5.357,8.733,7.03,11.505,12.356,21.516
c-20.175,20.447-72.704,68.808-112.33,82.886H240.168z"/>
<path d="M364.689,103.474c-27.258,23.203-67.66,22.7-90.263-1.134c-22.598-23.819-18.828-61.943,8.426-85.149
c27.254-23.2,67.665-22.697,90.328,1.065c22.531,23.805,18.745,61.939-8.524,85.218H364.689z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 960 B

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30"
height="30"
viewBox="0 0 30 30"
version="1.1"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="tab_monitor_unavailable.svg">
<metadata
id="metadata15">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Fill 1 Copy 3</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1148"
id="namedview13"
showgrid="false"
showborder="true"
inkscape:zoom="12.987195"
inkscape:cx="14.346643"
inkscape:cy="15.151358"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg2"
inkscape:snap-global="true"
inkscape:object-nodes="false"
inkscape:snap-smooth-nodes="false"
inkscape:snap-midpoints="false"
inkscape:snap-intersection-paths="false"
inkscape:snap-bbox="true"
inkscape:snap-others="false"
inkscape:snap-nodes="false" />
<!-- Generator: Sketch 3.4.4 (17249) - http://www.bohemiancoding.com/sketch -->
<title
id="title4">Fill 1 Copy 3</title>
<desc
id="desc6">Created with Sketch.</desc>
<defs
id="defs8" />
<g
id="Page-1"
sketch:type="MSPage"
style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:1"
transform="matrix(1.3157895,0,0,1.3157895,2.5,2.4999995)">
<g
id="HIG"
sketch:type="MSArtboardGroup"
transform="translate(-718,-2432)"
style="fill:#ffffff">
<path
d="m 718,2432 19,0 0,0.9048 -19,0 0,-0.9048 0,0 z m 0,18.0952 1.73776,0 1.7267,-0.9047 12.13477,0 1.69775,0.9047 1.70302,0 0,0.9048 -1.70166,0 -1.69911,-0.9048 -12.13593,0 -1.72554,0.8949 L 718,2451 l 0,-0.9048 0,0 z m 18.13636,-17.1904 0.86364,0 0,17.1904 -0.86364,0 0,-17.1904 0,0 z m -18.13636,0 0.86364,0 0,17.1904 -0.86364,0 0,-17.1904 0,0 z m 2.59091,1.8095 13.81818,0 0,12.6667 -13.81818,0 0,-12.6667 0,0 z m 0.86364,0.9047 12.0909,0 0,10.8572 -12.0909,0 0,-10.8572 0,0 z m 4.31818,0 3.45454,0 0,2.7143 -3.45454,0 0,-2.7143 0,0 z m -2.59091,9.9524 8.63636,0 0,0.9048 -8.63636,0 0,-0.9048 0,0 z m 3.45454,-7.2381 1.72728,0 0,0.9048 -1.72728,0 0,-0.9048 0,0 z"
id="Fill-1-Copy-3"
sketch:type="MSShapeGroup"
inkscape:connector-curvature="0" />
</g>
</g>
<circle
style="fill:#7f7f7f;fill-opacity:1"
id="path3337"
cx="22.5"
cy="7.5"
r="7.5" />
<g
style="font-style:normal;font-weight:normal;font-size:10.78604317px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="text3339">
<path
d="m 25.53769,5.6750499 q 0,0.5319289 -0.157999,0.9427255 -0.152732,0.4055299 -0.43713,0.7057274 -0.284397,0.3001975 -0.68466,0.5371955 -0.394997,0.236998 -0.895326,0.4318631 l 0,1.2007899 -1.853851,0 0,-1.7748518 q 0.37393,-0.1000658 0.674127,-0.2053983 0.305464,-0.1053324 0.637262,-0.3423305 0.31073,-0.2106649 0.484529,-0.4897959 0.179065,-0.279131 0.179065,-0.6319947 0,-0.5266622 -0.34233,-0.7478604 -0.337064,-0.2264648 -0.953259,-0.2264648 -0.379197,0 -0.85846,0.1632653 -0.473996,0.1632653 -0.868992,0.4213298 l -0.210665,0 0,-1.6063199 q 0.337064,-0.1421988 1.037524,-0.2949308 0.700461,-0.1579987 1.421988,-0.1579987 1.300856,0 2.064517,0.5740619 0.76366,0.5740618 0.76366,1.5009874 z M 23.51004,11.6 l -2.127715,0 0,-1.390388 2.127715,0 0,1.390388 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Verdana;-inkscape-font-specification:'Verdana Bold';fill:#ffffff"
id="path4144" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB