Merge branch 'master' into output_device

* master: (22 commits)
  Added grouping action
  LayerData now works by using decorators
  Do not cause "dictionary changed size during iteration" errors when changing view
  Adds an idle-state for the layerview slider
  Adds an idle-state for the safebutton
  Sets the platform activity on true when a model is loaded
  Sets the platform activity on true when a model is loaded
  Create functions that get & set platform activity
  Send M104 to set the temperature to 0
  Do not store files that fail to load in recent files
  feat: infill wipe dist; wireframe restructure & renaming; bugfix: draft_shield_height inherit_function
  Also add the parent class' command line arguments
  Only process the layer data if the layer view is active.
  Write to the correct variable so bed temperature is properly updated
  Correct a copy-paste error in getConnectionList
  Properly close all open USB connections on shut down
  Catch errors when trying to close the connection thread
  Enlarge the zone where you can use scrolling to look trough the layer mode.
  included retraction_extra_prime_amount
  tiniest detail concerning the padding of the layer count label
  ...
This commit is contained in:
Arjen Hiemstra 2015-07-31 12:15:18 +02:00
commit a8c36282fb
16 changed files with 426 additions and 86 deletions

View file

@ -37,6 +37,12 @@ class CuraEngineBackend(Backend):
self._scene = Application.getInstance().getController().getScene()
self._scene.sceneChanged.connect(self._onSceneChanged)
# Workaround to disable layer view processing if layer view is not active.
self._layer_view_active = False
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
self._onActiveViewChanged()
self._stored_layer_data = None
self._settings = None
Application.getInstance().activeMachineChanged.connect(self._onActiveMachineChanged)
self._onActiveMachineChanged()
@ -150,7 +156,7 @@ class CuraEngineBackend(Backend):
obj = msg.objects.add()
obj.id = id(object)
verts = numpy.array(mesh_data.getVertices(), copy=True)
verts = numpy.array(mesh_data.getVertices())
verts[:,[1,2]] = verts[:,[2,1]]
verts[:,1] *= -1
obj.vertices = verts.tostring()
@ -188,8 +194,11 @@ class CuraEngineBackend(Backend):
def _onSlicedObjectListMessage(self, message):
if self._save_polygons:
job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(message)
job.start()
if self._layer_view_active:
job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(message)
job.start()
else :
self._stored_layer_data = message
def _onProgressMessage(self, message):
if message.amount >= 0.99:
@ -248,3 +257,14 @@ class CuraEngineBackend(Backend):
def _onToolOperationStopped(self, tool):
self._enabled = True
self._onChanged()
def _onActiveViewChanged(self):
if Application.getInstance().getController().getActiveView():
view = Application.getInstance().getController().getActiveView()
if view.getPluginId() == "LayerView":
self._layer_view_active = True
if self._stored_layer_data:
job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(self._stored_layer_data)
job.start()
else:
self._layer_view_active = False

View file

@ -0,0 +1,12 @@
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
class LayerDataDecorator(SceneNodeDecorator):
def __init__(self):
super().__init__()
self._layer_data = None
def getLayerData(self):
return self._layer_data
def setLayerData(self, layer_data):
self._layer_data = layer_data

View file

@ -11,6 +11,7 @@ from UM.Message import Message
from UM.i18n import i18nCatalog
from . import LayerData
from . import LayerDataDecorator
import numpy
import struct
@ -22,21 +23,22 @@ class ProcessSlicedObjectListJob(Job):
super().__init__()
self._message = message
self._scene = Application.getInstance().getController().getScene()
self._progress = None
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
def run(self):
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
self._progress = Message(catalog.i18nc("Layers View mode", "Layers"), 0, False, 0)
self._progress.show()
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
objectIdMap = {}
new_node = SceneNode()
## Put all nodes in a dict identified by ID
for node in DepthFirstIterator(self._scene.getRoot()):
if type(node) is SceneNode and node.getMeshData():
if hasattr(node.getMeshData(), "layerData"):
if node.callDecoration("getLayerData"):
#if hasattr(node.getMeshData(), "layerData"):
self._scene.getRoot().removeChild(node)
else:
objectIdMap[id(node)] = node
@ -83,14 +85,18 @@ class ProcessSlicedObjectListJob(Job):
# We are done processing all the layers we got from the engine, now create a mesh out of the data
layerData.build()
mesh.layerData = layerData
if self._progress:
self._progress.setProgress(100)
#Add layerdata decorator to scene node to indicate that the node has layerdata
decorator = LayerDataDecorator.LayerDataDecorator()
decorator.setLayerData(layerData)
new_node.addDecorator(decorator)
new_node.setMeshData(mesh)
new_node.setParent(self._scene.getRoot())
view = Application.getInstance().getController().getActiveView()
if view.getPluginId() == "LayerView":
view.resetLayerData()

View file

@ -27,9 +27,13 @@ class LayerView(View):
self._max_layers = 10
self._current_layer_num = 10
self._current_layer_mesh = None
self._activity = False
self._solid_layers = 5
def getActivity(self):
return self._activity
def getCurrentLayer(self):
return self._current_layer_num
@ -64,10 +68,8 @@ class LayerView(View):
if node.getMeshData() and node.isVisible():
if Selection.isSelected(node):
renderer.queueNode(node, material = self._selection_material, transparent = True)
try:
layer_data = node.getMeshData().layerData
except AttributeError:
layer_data = node.callDecoration("getLayerData")
if not layer_data:
continue
# Render all layers below a certain number as line mesh instead of vertices.
@ -114,13 +116,14 @@ class LayerView(View):
self._current_layer_mesh = None
self.currentLayerNumChanged.emit()
currentLayerNumChanged = Signal()
def calculateMaxLayers(self):
scene = self.getController().getScene()
renderer = self.getRenderer()
if renderer and self._material:
self._activity = True
renderer.setRenderSelection(False)
self._old_max_layers = self._max_layers
## Recalculate num max layers
@ -128,21 +131,25 @@ class LayerView(View):
for node in DepthFirstIterator(scene.getRoot()):
if not node.render(renderer):
if node.getMeshData() and node.isVisible():
try:
layer_data = node.getMeshData().layerData
except AttributeError:
layer_data = node.callDecoration("getLayerData")
if not layer_data:
continue
if new_max_layers < len(layer_data.getLayers()):
new_max_layers = len(layer_data.getLayers()) - 1
if new_max_layers > 0 and new_max_layers != self._old_max_layers:
self._max_layers = new_max_layers
self.maxLayersChanged.emit()
self._current_layer_num = self._max_layers
# This makes sure we update the current layer
self.setLayer(int(self._max_layers * (self._current_layer_num / self._old_max_layers)))
self.setLayer(int(self._max_layers))
self.currentLayerNumChanged.emit()
maxLayersChanged = Signal()
currentLayerNumChanged = Signal()
## Hackish way to ensure the proxy is already created, which ensures that the layerview.qml is already created
# as this caused some issues.

View file

@ -15,9 +15,11 @@ Item
Slider
{
id: slider
width: 10
height: 250
anchors.right : parent.right
anchors.rightMargin: UM.Theme.sizes.slider_layerview_margin.width
orientation: Qt.Vertical
minimumValue: 0;
maximumValue: UM.LayerView.numLayers;
@ -26,6 +28,31 @@ Item
value: UM.LayerView.currentLayer
onValueChanged: UM.LayerView.setCurrentLayer(value)
style: UM.Theme.styles.slider;
style: UM.Theme.styles.layerViewSlider
}
Rectangle {
anchors.right: parent.right
y: -UM.Theme.sizes.slider_layerview_background_extension.height
z: slider.z - 1
width: UM.Theme.sizes.button.width
height: UM.Theme.sizes.slider_layerview_background_extension.height
color: UM.Theme.colors.slider_text_background
}
UM.AngledCornerRectangle {
anchors.right : parent.right
anchors.verticalCenter: parent.verticalCenter
z: slider.z - 1
cornerSize: UM.Theme.sizes.default_margin.width;
width: UM.Theme.sizes.slider_layerview_background.width
height: slider.height + UM.Theme.sizes.default_margin.height * 2
color: UM.Theme.colors.slider_text_background
MouseArea {
id: sliderMouseArea
property double manualStepSize: slider.maximumValue / 11
anchors.fill: parent
onWheel: {
slider.value = wheel.angleDelta.y < 0 ? slider.value - sliderMouseArea.manualStepSize : slider.value + sliderMouseArea.manualStepSize
}
}
}
}

View file

@ -11,7 +11,13 @@ class LayerViewProxy(QObject):
currentLayerChanged = pyqtSignal()
maxLayersChanged = pyqtSignal()
activityChanged = pyqtSignal()
@pyqtProperty(bool, notify = activityChanged)
def getLayerActivity(self):
active_view = self._controller.getActiveView()
return active_view.getActivity()
@pyqtProperty(int, notify = maxLayersChanged)
def numLayers(self):
active_view = self._controller.getActiveView()
@ -30,9 +36,13 @@ class LayerViewProxy(QObject):
active_view = self._controller.getActiveView()
if type(active_view) == LayerView.LayerView.LayerView:
active_view.setLayer(layer_num)
def _layerActivityChanged(self):
self.activityChanged.emit()
def _onLayerChanged(self):
self.currentLayerChanged.emit()
self._layerActivityChanged()
def _onMaxLayersChanged(self):
self.maxLayersChanged.emit()

View file

@ -469,7 +469,7 @@ class PrinterConnection(SignalEmitter):
# Turn of temperatures
self._sendCommand("M140 S0")
self._sendCommand("M109 S0")
self._sendCommand("M104 S0")
self._is_printing = False
## Check if the process did not encounter an error yet.

View file

@ -46,6 +46,8 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
## Add menu item to top menu of the application.
self.setMenuName("Firmware")
self.addMenuItem(i18n_catalog.i18n("Update Firmware"), self.updateAllFirmware)
Application.getInstance().applicationShuttingDown.connect(self._onApplicationShuttingDown)
pyqtError = pyqtSignal(str, arguments = ["error"])
processingProgress = pyqtSignal(float, arguments = ["amount"])
@ -170,7 +172,7 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
## Callback for bed temperature change
def onBedTemperature(self, serial_port,temperature):
self._bed_temperature = temperature
self._bed_temp = temperature
self.pyqtBedTemperature.emit(temperature)
## Callback for error
@ -280,15 +282,19 @@ class USBPrinterManager(QObject, SignalEmitter, Extension):
i = 0
while True:
values = winreg.EnumValue(key, i)
if not base_list or "USBSER" in values[0]:
if not only_list_usb or "USBSER" in values[0]:
base_list += [values[1]]
i += 1
except Exception as e:
pass
if base_list:
base_list = base_list + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/cu.usb*")
base_list = filter(lambda s: "Bluetooth" not in s, base_list) # Filter because mac sometimes puts them in the list
else:
base_list = base_list + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/cu.*") + glob.glob("/dev/tty.usb*") + glob.glob("/dev/rfcomm*") + glob.glob("/dev/serial/by-id/*")
if only_list_usb:
base_list = base_list + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/cu.usb*")
base_list = filter(lambda s: "Bluetooth" not in s, base_list) # Filter because mac sometimes puts them in the list
else:
base_list = base_list + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/cu.*") + glob.glob("/dev/tty.usb*") + glob.glob("/dev/rfcomm*") + glob.glob("/dev/serial/by-id/*")
return base_list
def _onApplicationShuttingDown(self):
for connection in self._printer_connections:
connection.close()