Browse Source

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
  ...
Arjen Hiemstra 9 years ago
parent
commit
a8c36282fb

+ 1 - 0
cura/BuildVolume.py

@@ -33,6 +33,7 @@ class BuildVolume(SceneNode):
 
         self.setCalculateBoundingBox(False)
 
+
     def setWidth(self, width):
         self._width = width
 

+ 42 - 2
cura/CuraApplication.py

@@ -22,6 +22,7 @@ from UM.Math.Polygon import Polygon
 
 from UM.Scene.BoxRenderer import BoxRenderer
 from UM.Scene.Selection import Selection
+from UM.Scene.GroupDecorator import GroupDecorator
 
 from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
 from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
@@ -74,6 +75,7 @@ class CuraApplication(QtApplication):
         self._print_information = None
         self._i18n_catalog = None
         self._previous_active_tool = None
+        self._platform_activity = False
 
         self.activeMachineChanged.connect(self._onActiveMachineChanged)
 
@@ -106,6 +108,7 @@ class CuraApplication(QtApplication):
             raise RuntimeError("Could not load the backend plugin!")
 
     def addCommandLineOptions(self, parser):
+        super().addCommandLineOptions(parser)
         parser.add_argument("file", nargs="*", help="Files to load after starting the application.")
 
     def run(self):
@@ -199,6 +202,31 @@ class CuraApplication(QtApplication):
                 self._previous_active_tool = None
 
     requestAddPrinter = pyqtSignal()
+    activityChanged = pyqtSignal()
+
+    @pyqtProperty(bool, notify = activityChanged)
+    def getPlatformActivity(self):
+        return self._platform_activity
+
+    @pyqtSlot(bool)
+    def setPlatformActivity(self, activity):
+        ##Sets the _platform_activity variable on true or false depending on whether there is a mesh on the platform
+        if activity == True:
+            self._platform_activity = activity
+        elif activity == False:
+            nodes = []
+            for node in DepthFirstIterator(self.getController().getScene().getRoot()):
+                if type(node) is not SceneNode or not node.getMeshData():
+                    continue
+                nodes.append(node)
+            i = 0
+            for node in nodes:
+                if not node.getMeshData():
+                    continue
+                i += 1
+            if i <= 1: ## i == 0 when the meshes are removed using the deleteAll function; i == 1 when the last remaining mesh is removed using the deleteObject function
+                self._platform_activity = activity
+        self.activityChanged.emit()
 
     ##  Remove an object from the scene
     @pyqtSlot("quint64")
@@ -211,6 +239,7 @@ class CuraApplication(QtApplication):
         if object:
             op = RemoveSceneNodeOperation(object)
             op.push()
+            self.setPlatformActivity(False)
     
     ##  Create a number of copies of existing object.
     @pyqtSlot("quint64", int)
@@ -251,7 +280,6 @@ class CuraApplication(QtApplication):
             if type(node) is not SceneNode or not node.getMeshData():
                 continue
             nodes.append(node)
-
         if nodes:
             op = GroupedOperation()
 
@@ -259,6 +287,7 @@ class CuraApplication(QtApplication):
                 op.addOperation(RemoveSceneNodeOperation(node))
 
             op.push()
+        self.setPlatformActivity(False)
     
     ## Reset all translation on nodes with mesh data. 
     @pyqtSlot()
@@ -362,6 +391,17 @@ class CuraApplication(QtApplication):
             return
 
         self.getActiveMachine().setSettingValueByKey(key, value)
+        
+        
+    @pyqtSlot()
+    def groupSelected(self):
+        group_node = SceneNode()
+        group_decorator = GroupDecorator()
+        group_node.addDecorator(group_decorator)
+        group_node.setParent(self.getController().getScene().getRoot())
+        for node in Selection.getAllSelectedObjects():
+            node.setParent(group_node)
+            
 
     def _onActiveMachineChanged(self):
         machine = self.getActiveMachine()
@@ -401,7 +441,7 @@ class CuraApplication(QtApplication):
             op.push()
 
     def _onJobFinished(self, job):
-        if type(job) is not ReadMeshJob:
+        if type(job) is not ReadMeshJob or not job.getResult():
             return
 
         f = QUrl.fromLocalFile(job.getFileName())

+ 23 - 3
plugins/CuraEngineBackend/CuraEngineBackend.py

@@ -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

+ 12 - 0
plugins/CuraEngineBackend/LayerDataDecorator.py

@@ -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

+ 12 - 6
plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py

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

+ 18 - 11
plugins/LayerView/LayerView.py

@@ -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. 

+ 28 - 1
plugins/LayerView/LayerView.qml

@@ -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
+            }
+        }
     }
 }

+ 11 - 1
plugins/LayerView/LayerViewProxy.py

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

+ 1 - 1
plugins/USBPrinting/PrinterConnection.py

@@ -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.

+ 13 - 7
plugins/USBPrinting/USBPrinterManager.py

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

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