Merge branch '2.3'

Conflicts:
	resources/qml/MonitorButton.qml
This commit is contained in:
Ghostkeeper 2016-09-06 10:43:54 +02:00
commit fcbf4a93f3
No known key found for this signature in database
GPG key ID: 701948C5954A7385
15 changed files with 140 additions and 77 deletions

View file

@ -180,6 +180,8 @@ class CuraApplication(QtApplication):
ContainerRegistry.getInstance().addContainer(empty_material_container)
empty_quality_container = copy.deepcopy(empty_container)
empty_quality_container._id = "empty_quality"
empty_quality_container.setName("Not supported")
empty_quality_container.addMetaDataEntry("quality_type", "normal")
empty_quality_container.addMetaDataEntry("type", "quality")
ContainerRegistry.getInstance().addContainer(empty_quality_container)
empty_quality_changes_container = copy.deepcopy(empty_container)
@ -509,8 +511,6 @@ class CuraApplication(QtApplication):
if self.getController().getActiveTool():
self._previous_active_tool = self.getController().getActiveTool().getPluginId()
self.getController().setActiveTool(None)
else:
self._previous_active_tool = None
def _onToolOperationStopped(self, event):
if self._center_after_select:

View file

@ -14,8 +14,9 @@ class LayerPolygon:
SupportInfillType = 7
MoveCombingType = 8
MoveRetractionType = 9
SupportInterfaceType = 10
__jump_map = numpy.logical_or( numpy.arange(10) == NoneType, numpy.arange(10) >= MoveCombingType )
__jump_map = numpy.logical_or( numpy.arange(11) == NoneType, numpy.arange(11) >= MoveRetractionType )
def __init__(self, mesh, extruder, line_types, data, line_widths):
self._mesh = mesh
@ -178,10 +179,11 @@ class LayerPolygon:
SkinType: Color(1.0, 1.0, 0.0, 1.0),
SupportType: Color(0.0, 1.0, 1.0, 1.0),
SkirtType: Color(0.0, 1.0, 1.0, 1.0),
InfillType: Color(1.0, 0.74, 0.0, 1.0),
InfillType: Color(1.0, 0.75, 0.0, 1.0),
SupportInfillType: Color(0.0, 1.0, 1.0, 1.0),
MoveCombingType: Color(0.0, 0.0, 1.0, 1.0),
MoveRetractionType: Color(0.5, 0.5, 1.0, 1.0),
SupportInterfaceType: Color(0.25, 0.75, 1.0, 1.0),
}
# Should be generated in better way, not hardcoded.
@ -192,8 +194,9 @@ class LayerPolygon:
[1.0, 1.0, 0.0, 1.0],
[0.0, 1.0, 1.0, 1.0],
[0.0, 1.0, 1.0, 1.0],
[1.0, 0.74, 0.0, 1.0],
[1.0, 0.75, 0.0, 1.0],
[0.0, 1.0, 1.0, 1.0],
[0.0, 0.0, 1.0, 1.0],
[0.5, 0.5, 1.0, 1.0]
[0.5, 0.5, 1.0, 1.0],
[0.25, 0.75, 1.0, 1.0]
])

View file

@ -29,6 +29,8 @@ class PlatformPhysics:
self._change_timer.setInterval(100)
self._change_timer.setSingleShot(True)
self._change_timer.timeout.connect(self._onChangeTimerFinished)
self._move_factor = 1.1 # By how much should we multiply overlap to calculate a new spot?
self._max_overlap_checks = 10 # How many times should we try to find a new spot per tick?
Preferences.getInstance().addPreference("physics/automatic_push_free", True)
Preferences.getInstance().addPreference("physics/automatic_drop_down", True)
@ -97,29 +99,42 @@ class PlatformPhysics:
continue
if other_node in transformed_nodes:
continue # Other node is already moving, wait for next pass.
continue # Other node is already moving, wait for next pass.
# Get the overlap distance for both convex hulls. If this returns None, there is no intersection.
head_hull = node.callDecoration("getConvexHullHead")
if head_hull:
overlap = head_hull.intersectsPolygon(other_node.callDecoration("getConvexHull"))
if not overlap:
other_head_hull = other_node.callDecoration("getConvexHullHead")
if other_head_hull:
overlap = node.callDecoration("getConvexHull").intersectsPolygon(other_head_hull)
else:
own_convex_hull = node.callDecoration("getConvexHull")
other_convex_hull = other_node.callDecoration("getConvexHull")
if own_convex_hull and other_convex_hull:
overlap = own_convex_hull.intersectsPolygon(other_convex_hull)
overlap = (0, 0) # Start loop with no overlap
move_vector = move_vector.set(x=overlap[0] * self._move_factor, z=overlap[1] * self._move_factor)
current_overlap_checks = 0
# Continue to check the overlap until we no longer find one.
while overlap and current_overlap_checks < self._max_overlap_checks:
current_overlap_checks += 1
head_hull = node.callDecoration("getConvexHullHead")
if head_hull: # One at a time intersection.
overlap = head_hull.translate(move_vector.x, move_vector.z).intersectsPolygon(other_node.callDecoration("getConvexHull"))
if not overlap:
other_head_hull = other_node.callDecoration("getConvexHullHead")
if other_head_hull:
overlap = node.callDecoration("getConvexHull").translate(move_vector.x, move_vector.z).intersectsPolygon(other_head_hull)
if overlap:
# Moving ensured that overlap was still there. Try anew!
move_vector = move_vector.set(x=move_vector.x + overlap[0] * self._move_factor,
z=move_vector.z + overlap[1] * self._move_factor)
else:
# Moving ensured that overlap was still there. Try anew!
move_vector = move_vector.set(x=move_vector.x + overlap[0] * self._move_factor,
z=move_vector.z + overlap[1] * self._move_factor)
else:
# This can happen in some cases if the object is not yet done with being loaded.
# Simply waiting for the next tick seems to resolve this correctly.
overlap = None
own_convex_hull = node.callDecoration("getConvexHull")
other_convex_hull = other_node.callDecoration("getConvexHull")
if own_convex_hull and other_convex_hull:
overlap = own_convex_hull.translate(move_vector.x, move_vector.z).intersectsPolygon(other_convex_hull)
if overlap: # Moving ensured that overlap was still there. Try anew!
move_vector = move_vector.set(x=move_vector.x + overlap[0] * self._move_factor,
z=move_vector.z + overlap[1] * self._move_factor)
else:
# This can happen in some cases if the object is not yet done with being loaded.
# Simply waiting for the next tick seems to resolve this correctly.
overlap = None
if overlap is None:
continue
move_vector = move_vector.set(x=overlap[0] * 1.1, z=overlap[1] * 1.1)
convex_hull = node.callDecoration("getConvexHull")
if convex_hull:
if not convex_hull.isValid():

View file

@ -7,7 +7,7 @@ from PyQt5.QtWidgets import QMessageBox
from UM.Application import Application
from UM.Preferences import Preferences
from UM.Logger import Logger
from UM.Message import Message
from UM.Settings.SettingRelation import RelationType
import UM.Settings
@ -547,6 +547,7 @@ class MachineManager(QObject):
preferred_material = None
if old_material:
preferred_material_name = old_material.getName()
self.setActiveMaterial(self._updateMaterialContainer(self._global_container_stack.getBottom(), containers[0], preferred_material_name).id)
else:
Logger.log("w", "While trying to set the active variant, no variant was found to replace.")
@ -806,15 +807,15 @@ class MachineManager(QObject):
if containers:
return containers[0]
if "name" in search_criteria or "id" in search_criteria:
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
if "variant" in search_criteria or "id" in search_criteria:
# If a material by this name can not be found, try a wider set of search criteria
search_criteria.pop("name", None)
search_criteria.pop("variant", None)
search_criteria.pop("id", None)
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
if containers:
return containers[0]
Logger.log("w", "Unable to find a material container with provided criteria, returning an empty one instead.")
return self._empty_material_container
def _updateQualityContainer(self, definition, variant_container, material_container = None, preferred_quality_name = None):
@ -855,10 +856,9 @@ class MachineManager(QObject):
containers = container_registry.findInstanceContainers(**search_criteria)
if containers:
return containers[0]
# We still weren't able to find a quality for this specific material.
# Try to find qualities for a generic version of the material.
material_search_criteria = { "type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic" }
material_search_criteria = { "type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic"}
if definition.getMetaDataEntry("has_machine_quality"):
if material_container:
material_search_criteria["definition"] = material_container.getDefinition().id
@ -872,7 +872,6 @@ class MachineManager(QObject):
material_search_criteria["variant"] = variant_container.id
else:
material_search_criteria["definition"] = "fdmprinter"
material_containers = container_registry.findInstanceContainers(**material_search_criteria)
if material_containers:
search_criteria["material"] = material_containers[0].getId()
@ -890,6 +889,9 @@ class MachineManager(QObject):
if containers:
return containers[0]
# Notify user that we were unable to find a matching quality
message = Message(catalog.i18nc("@info:status", "Unable to find a quality profile for this combination. Default settings will be used instead."))
message.show()
return self._empty_quality_container
## Finds a quality-changes container to use if any other container

View file

@ -56,6 +56,7 @@ message Polygon {
SupportInfillType = 7;
MoveCombingType = 8;
MoveRetractionType = 9;
SupportInterfaceType = 10;
}
Type type = 1; // Type of move
bytes points = 2; // The points of the polygon, or two points if only a line segment (Currently only line segments are used)

View file

@ -229,7 +229,7 @@ class CuraEngineBackend(Backend):
if job.getResult() == StartSliceJob.StartJobResult.SettingError:
if Application.getInstance().getPlatformActivity:
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. Please check your setting values for errors."))
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current settings. Please check your settings for errors."))
self._error_message.show()
self.backendStateChange.emit(BackendState.Error)
else:
@ -238,7 +238,7 @@ class CuraEngineBackend(Backend):
if job.getResult() == StartSliceJob.StartJobResult.NothingToSlice:
if Application.getInstance().getPlatformActivity:
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. No suitable models found."))
self._error_message = Message(catalog.i18nc("@info:status", "Nothing to slice because none of the models fit the build volume. Please scale or rotate models to fit."))
self._error_message.show()
self.backendStateChange.emit(BackendState.Error)
else:

View file

@ -103,10 +103,11 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
self._firmware_view.show()
@pyqtSlot()
def updateAllFirmware(self):
@pyqtSlot(str)
def updateAllFirmware(self, file_name):
file_name = file_name.replace("file://", "") # File dialogs prepend the path with file://, which we don't need / want
if not self._usb_output_devices:
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
for printer_connection in self._usb_output_devices:
@ -114,26 +115,26 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
self.spawnFirmwareInterface("")
for printer_connection in self._usb_output_devices:
try:
self._usb_output_devices[printer_connection].updateFirmware(Resources.getPath(CuraApplication.ResourceTypes.Firmware, self._getDefaultFirmwareName()))
self._usb_output_devices[printer_connection].updateFirmware(file_name)
except FileNotFoundError:
# Should only happen in dev environments where the resources/firmware folder is absent.
self._usb_output_devices[printer_connection].setProgress(100, 100)
Logger.log("w", "No firmware found for printer %s called '%s'" %(printer_connection, self._getDefaultFirmwareName()))
Logger.log("w", "No firmware found for printer %s called '%s'", printer_connection, file_name)
Message(i18n_catalog.i18nc("@info",
"Could not find firmware required for the printer at %s.") % printer_connection).show()
self._firmware_view.close()
continue
@pyqtSlot(str, result = bool)
def updateFirmwareBySerial(self, serial_port):
@pyqtSlot(str, str, result = bool)
def updateFirmwareBySerial(self, serial_port, file_name):
if serial_port in self._usb_output_devices:
self.spawnFirmwareInterface(self._usb_output_devices[serial_port].getSerialPort())
try:
self._usb_output_devices[serial_port].updateFirmware(Resources.getPath(CuraApplication.ResourceTypes.Firmware, self._getDefaultFirmwareName()))
self._usb_output_devices[serial_port].updateFirmware(file_name)
except FileNotFoundError:
self._firmware_view.close()
Logger.log("e", "Could not find firmware required for this machine called '%s'" %(self._getDefaultFirmwareName()))
Logger.log("e", "Could not find firmware required for this machine called '%s'", file_name)
return False
return True
return False
@ -147,7 +148,8 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
return USBPrinterOutputDeviceManager._instance
def _getDefaultFirmwareName(self):
@pyqtSlot(result = str)
def getDefaultFirmwareName(self):
# Check if there is a valid global container stack
global_container_stack = Application.getInstance().getGlobalContainerStack()
if not global_container_stack:
@ -193,13 +195,13 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
Logger.log("d", "Choosing basic firmware for machine %s.", machine_id)
hex_file = machine_without_extras[machine_id] # Return "basic" firmware
else:
Logger.log("e", "There is no firmware for machine %s.", machine_id)
Logger.log("w", "There is no firmware for machine %s.", machine_id)
if hex_file:
return hex_file.format(baudrate=baudrate)
return Resources.getPath(CuraApplication.ResourceTypes.Firmware, hex_file.format(baudrate=baudrate))
else:
Logger.log("e", "Could not find any firmware for machine %s.", machine_id)
raise FileNotFoundError()
Logger.log("w", "Could not find any firmware for machine %s.", machine_id)
return ""
## Helper to identify serial ports (and scan for them)
def _addRemovePorts(self, serial_ports):

View file

@ -1,5 +1,7 @@
from cura.MachineAction import MachineAction
from UM.i18n import i18nCatalog
import cura.Settings.CuraContainerRegistry
import UM.Settings.DefinitionContainer
catalog = i18nCatalog("cura")
@ -7,3 +9,9 @@ class UpgradeFirmwareMachineAction(MachineAction):
def __init__(self):
super().__init__("UpgradeFirmware", catalog.i18nc("@action", "Upgrade Firmware"))
self._qml_url = "UpgradeFirmwareMachineAction.qml"
cura.Settings.CuraContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded)
def _onContainerAdded(self, container):
# Add this action as a supported action to all machine definitions
if isinstance(container, UM.Settings.DefinitionContainer) and container.getMetaDataEntry("type") == "machine" and container.getMetaDataEntry("supports_usb_connection"):
UM.Application.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey())

View file

@ -5,6 +5,7 @@ import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import QtQuick.Dialogs 1.2 // For filedialog
import UM 1.2 as UM
import Cura 1.0 as Cura
@ -44,34 +45,45 @@ Cura.MachineAction
anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width
wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "The firmware shipping with new Ultimakers works, but upgrades have been made to make better prints, and make calibration easier.");
text: catalog.i18nc("@label", "The firmware shipping with new printers works, but new versions tend to have more features and improvements.");
}
Label
{
id: upgradeText2
anchors.top: upgradeText1.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width
wrapMode: Text.WordWrap
text: catalog.i18nc("@label", "Cura requires these new features and thus your firmware will most likely need to be upgraded. You can do so now.");
}
Row
{
anchors.top: upgradeText2.bottom
anchors.top: upgradeText1.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.horizontalCenter: parent.horizontalCenter
width: childrenRect.width
spacing: UM.Theme.getSize("default_margin").width
property var firmwareName: Cura.USBPrinterManager.getDefaultFirmwareName()
Button
{
id: upgradeButton
text: catalog.i18nc("@action:button","Upgrade to Marlin Firmware");
id: autoUpgradeButton
text: catalog.i18nc("@action:button", "Automatically upgrade Firmware");
enabled: parent.firmwareName != ""
onClicked:
{
Cura.USBPrinterManager.updateAllFirmware()
Cura.USBPrinterManager.updateAllFirmware(parent.firmwareName)
}
}
Button
{
id: manualUpgradeButton
text: catalog.i18nc("@action:button", "Upload custom Firmware");
onClicked:
{
customFirmwareDialog.open()
}
}
}
FileDialog
{
id: customFirmwareDialog
title: catalog.i18nc("@title:window", "Select custom firmware")
nameFilters: "Firmware image files (*.hex)"
selectExisting: true
onAccepted: Cura.USBPrinterManager.updateAllFirmware(fileUrl)
}
}
}

View file

@ -15,7 +15,8 @@
"machine_extruder_trains":
{
"0": "fdmextruder"
}
},
"supports_usb_connection": true
},
"settings":
{
@ -402,7 +403,7 @@
"description": "The maximum speed of the filament.",
"unit": "mm/s",
"type": "float",
"default_value": 25,
"default_value": 299792458000,
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": false
@ -1160,7 +1161,7 @@
"default_value": 25,
"minimum_value": "0",
"maximum_value": "machine_max_feedrate_e",
"maximum_value_warning": "100",
"maximum_value_warning": "25",
"enabled": "retraction_enable",
"settable_per_mesh": false,
"settable_per_extruder": true,
@ -1173,7 +1174,7 @@
"default_value": 25,
"minimum_value": "0",
"maximum_value": "machine_max_feedrate_e",
"maximum_value_warning": "100",
"maximum_value_warning": "25",
"enabled": "retraction_enable",
"value": "retraction_speed",
"settable_per_mesh": false,
@ -1187,7 +1188,7 @@
"default_value": 25,
"minimum_value": "0",
"maximum_value": "machine_max_feedrate_e",
"maximum_value_warning": "100",
"maximum_value_warning": "25",
"enabled": "retraction_enable",
"value": "retraction_speed",
"settable_per_mesh": false,
@ -3518,7 +3519,7 @@
},
"experimental":
{
"label": "Experimental Modes",
"label": "Experimental",
"type": "category",
"icon": "category_experimental",
"description": "experimental!",
@ -3763,6 +3764,7 @@
"type": "float",
"unit": "mm",
"default_value": 3,
"value": "machine_nozzle_head_distance",
"minimum_value": "0.0001",
"maximum_value_warning": "20",
"enabled": "wireframe_enabled",

View file

@ -9,6 +9,9 @@
"visible": false
},
"overrides": {
"machine_max_feedrate_e": {
"default_value": 45
},
"material_print_temperature": {
"minimum_value": "0"
},

View file

@ -346,6 +346,7 @@ UM.MainWindow
bottom: parent.bottom;
right: parent.right;
}
z: 1
onMonitoringPrintChanged: base.monitoringPrint = monitoringPrint
width: UM.Theme.getSize("sidebar").width;
}

View file

@ -4,7 +4,6 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1
import UM 1.1 as UM
@ -161,7 +160,7 @@ Rectangle
anchors.rightMargin: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@label:", "Abort Print")
onClicked: confirmationDialog.visible = true
onClicked: Cura.MachineManager.printerOutputDevices[0].setJobState("abort")
style: ButtonStyle
{
@ -221,9 +220,9 @@ Rectangle
{
id: confirmationDialog
title: catalog.i18nc("@text:MessageDialog", "Abort print")
title: catalog.i18nc("@window:title", "Abort print")
icon: StandardIcon.Warning
text: catalog.i18nc("@text:MessageDialog", "Do you really want to abort the print?")
text: catalog.i18nc("@label", "Are you sure you want to abort the print?")
standardButtons: StandardButton.Yes | StandardButton.No
Component.onCompleted: visible = false
onYes: Cura.MachineManager.printerOutputDevices[0].setJobState("abort")

View file

@ -277,7 +277,7 @@ Column
height: UM.Theme.getSize("setting_control").height
tooltip: Cura.MachineManager.activeQualityName
style: UM.Theme.styles.sidebar_header_button
property var valueWarning: Cura.MachineManager.activeQualityId == "empty_quality"
menu: ProfileMenu { }
UM.SimpleButton

View file

@ -11,7 +11,22 @@ QtObject {
property Component sidebar_header_button: Component {
ButtonStyle {
background: Rectangle {
color: control.enabled ? Theme.getColor("setting_control") : Theme.getColor("setting_control_disabled")
color:
{
if(control.enabled)
{
if(control.valueWarning)
{
return Theme.getColor("setting_validation_warning");
} else
{
return Theme.getColor("setting_control");
}
} else {
return Theme.getColor("setting_control_disabled");
}
}
border.width: Theme.getSize("default_lining").width
border.color: !control.enabled ? Theme.getColor("setting_control_disabled_border") :
control.hovered ? Theme.getColor("setting_control_border_highlight") : Theme.getColor("setting_control_border")