chiark / gitweb /
If programmer based auto-detection of serial port fails, try all ports and baudrates...
[cura.git] / Cura / gui / sceneView.py
index c25cbc90acdc3e90aa8a1d71db3ed48c8285d757..7ed81be208b8fe847cb50c3fe39050d259bfa455 100644 (file)
@@ -25,6 +25,7 @@ from Cura.util import sliceEngine
 from Cura.util import machineCom
 from Cura.util import removableStorage
 from Cura.util import gcodeInterpreter
+from Cura.util import explorer
 from Cura.util.printerConnection import printerConnectionManager
 from Cura.gui.util import previewTools
 from Cura.gui.util import opengl
@@ -226,10 +227,10 @@ class SceneView(openglGui.glGuiPanel):
 
        def OnPrintButton(self, button):
                if button == 1:
-                       connectionEntry = self._printerConnectionManager.getAvailableConnection()
+                       connectionGroup = self._printerConnectionManager.getAvailableGroup()
                        if machineCom.machineIsConnected():
                                self.showPrintWindow()
-                       elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionEntry is None or connectionEntry.priority < 0):
+                       elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionGroup is None or connectionGroup.getPriority() < 0):
                                drives = removableStorage.getPossibleSDcardDrives()
                                if len(drives) > 1:
                                        dlg = wx.SingleChoiceDialog(self, "Select SD drive", "Multiple removable drives have been found,\nplease select your SD card drive", map(lambda n: n[0], drives))
@@ -242,27 +243,46 @@ class SceneView(openglGui.glGuiPanel):
                                        drive = drives[0]
                                filename = self._scene._objectList[0].getName() + '.gcode'
                                threading.Thread(target=self._copyFile,args=(self._gcodeFilename, drive[1] + filename, drive[1])).start()
-                       elif connectionEntry is not None:
-                               connection = connectionEntry.connection
-                               if connectionEntry.window is None or not connectionEntry.window:
-                                       connectionEntry.window = printWindow2.printWindow(connection)
-                               connectionEntry.window.Show()
-                               connectionEntry.window.Raise()
-                               if not connection.loadFile(self._gcodeFilename):
-                                       if connection.isPrinting():
-                                               self.notification.message("Cannot start print, because other print still running.")
-                                       else:
-                                               self.notification.message("Failed to start print...")
+                       elif connectionGroup is not None:
+                               connections = connectionGroup.getAvailableConnections()
+                               if len(connections) < 2:
+                                       connection = connections[0]
+                               else:
+                                       dlg = wx.SingleChoiceDialog(self, "Select the %s connection to use" % (connectionGroup.getName()), "Multiple %s connections found" % (connectionGroup.getName()), map(lambda n: n.getName(), connections))
+                                       if dlg.ShowModal() != wx.ID_OK:
+                                               dlg.Destroy()
+                                               return
+                                       connection = connections[dlg.GetSelection()]
+                                       dlg.Destroy()
+                               self._openPrintWindowForConnection(connection)
                        else:
                                self.showSaveGCode()
                if button == 3:
                        menu = wx.Menu()
                        self.Bind(wx.EVT_MENU, lambda e: self.showPrintWindow(), menu.Append(-1, _("Print with USB")))
+                       connections = self._printerConnectionManager.getAvailableConnections()
+                       menu.connectionMap = {}
+                       for connection in connections:
+                               i = menu.Append(-1, _("Print with %s") % (connection.getName()))
+                               menu.connectionMap[i.GetId()] = connection
+                               self.Bind(wx.EVT_MENU, lambda e: self._openPrintWindowForConnection(e.GetEventObject().connectionMap[e.GetId()]), i)
                        self.Bind(wx.EVT_MENU, lambda e: self.showSaveGCode(), menu.Append(-1, _("Save GCode...")))
                        self.Bind(wx.EVT_MENU, lambda e: self._showSliceLog(), menu.Append(-1, _("Slice engine log...")))
                        self.PopupMenu(menu)
                        menu.Destroy()
 
+       def _openPrintWindowForConnection(self, connection):
+               print '_openPrintWindowForConnection', connection.getName()
+               if connection.window is None or not connection.window:
+                       connection.window = printWindow2.printWindow(connection)
+               connection.window.Show()
+               connection.window.Raise()
+               if not connection.loadFile(self._gcodeFilename):
+                       if connection.isPrinting():
+                               self.notification.message("Cannot start print, because other print still running.")
+                       else:
+                               self.notification.message("Failed to start print...")
+
        def showPrintWindow(self):
                if self._gcodeFilename is None:
                        return
@@ -306,13 +326,21 @@ class SceneView(openglGui.glGuiPanel):
                        self.notification.message("Failed to save")
                else:
                        if allowEject:
-                               self.notification.message("Saved as %s" % (fileB), lambda : self.notification.message('You can now eject the card.') if removableStorage.ejectDrive(allowEject) else self.notification.message('Safe remove failed...'))
+                               self.notification.message("Saved as %s" % (fileB), lambda : self._doEjectSD(allowEject), 31, 'Eject')
+                       elif explorer.hasExplorer():
+                               self.notification.message("Saved as %s" % (fileB), lambda : explorer.openExplorer(fileB), 4, 'Open folder')
                        else:
                                self.notification.message("Saved as %s" % (fileB))
                self.printButton.setProgressBar(None)
                if fileA == self._slicer.getGCodeFilename():
                        self._slicer.submitSliceInfoOnline()
 
+       def _doEjectSD(self, drive):
+               if removableStorage.ejectDrive(drive):
+                       self.notification.message('You can now eject the card.')
+               else:
+                       self.notification.message('Safe remove failed...')
+
        def _showSliceLog(self):
                dlg = wx.TextEntryDialog(self, _("The slicing engine reported the following"), _("Engine log..."), '\n'.join(self._slicer.getSliceLog()), wx.TE_MULTILINE | wx.OK | wx.CENTRE)
                dlg.ShowModal()
@@ -371,7 +399,7 @@ class SceneView(openglGui.glGuiPanel):
                if self._selectedObj is None:
                        return
                self._selectedObj.resetRotation()
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                self._selectObject(self._selectedObj)
                self.sceneUpdated()
 
@@ -379,7 +407,7 @@ class SceneView(openglGui.glGuiPanel):
                if self._selectedObj is None:
                        return
                self._selectedObj.layFlat()
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                self._selectObject(self._selectedObj)
                self.sceneUpdated()
 
@@ -396,19 +424,19 @@ class SceneView(openglGui.glGuiPanel):
                        return
                machine = profile.getMachineSetting('machine_type')
                self._selectedObj.setPosition(numpy.array([0.0, 0.0]))
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                #self.sceneUpdated()
                if machine == "ultimaker2":
                        #This is bad and Jaime should feel bad!
                        self._selectedObj.setPosition(numpy.array([0.0,-10.0]))
                        self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2 - numpy.array([1,1,1], numpy.float32))
                        self._selectedObj.setPosition(numpy.array([0.0,0.0]))
-                       self._scene.pushFree()
+                       self._scene.pushFree(self._selectedObj)
                else:
                        self._selectedObj.setPosition(numpy.array([0.0, 0.0]))
-                       self._scene.pushFree()
+                       self._scene.pushFree(self._selectedObj)
                        self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2 - numpy.array([1,1,1], numpy.float32))
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                self._selectObject(self._selectedObj)
                self.updateProfileToControls()
                self.sceneUpdated()
@@ -428,7 +456,7 @@ class SceneView(openglGui.glGuiPanel):
                        return
                self._selectedObj.setScale(value, axis, self.scaleUniform.getValue())
                self.updateProfileToControls()
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                self._selectObject(self._selectedObj)
                self.sceneUpdated()
 
@@ -441,7 +469,7 @@ class SceneView(openglGui.glGuiPanel):
                        return
                self._selectedObj.setSize(value, axis, self.scaleUniform.getValue())
                self.updateProfileToControls()
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                self._selectObject(self._selectedObj)
                self.sceneUpdated()
 
@@ -491,7 +519,7 @@ class SceneView(openglGui.glGuiPanel):
                if self._focusObj is None:
                        return
                self._focusObj.setPosition(numpy.array([0.0, 0.0]))
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                newViewPos = numpy.array([self._focusObj.getPosition()[0], self._focusObj.getPosition()[1], self._focusObj.getSize()[2] / 2])
                self._animView = openglGui.animation(self, self._viewTarget.copy(), newViewPos, 0.5)
                self.sceneUpdated()
@@ -611,7 +639,7 @@ class SceneView(openglGui.glGuiPanel):
        def _selectObject(self, obj, zoom = True):
                if obj != self._selectedObj:
                        self._selectedObj = obj
-                       self.updateProfileToControls()
+                       self.updateModelSettingsToControls()
                        self.updateToolButtons()
                if zoom and obj is not None:
                        newViewPos = numpy.array([obj.getPosition()[0], obj.getPosition()[1], obj.getSize()[2] / 2])
@@ -634,7 +662,9 @@ class SceneView(openglGui.glGuiPanel):
                self._objColors[2] = profile.getPreferenceColour('model_colour3')
                self._objColors[3] = profile.getPreferenceColour('model_colour4')
                self._scene.updateMachineDimensions()
+               self.updateModelSettingsToControls()
 
+       def updateModelSettingsToControls(self):
                if self._selectedObj is not None:
                        scale = self._selectedObj.getScale()
                        size = self._selectedObj.getSize()
@@ -650,18 +680,68 @@ class SceneView(openglGui.glGuiPanel):
                        if self._selectedObj is not None:
                                self._deleteObject(self._selectedObj)
                                self.QueueRefresh()
-               if keyCode == wx.WXK_UP:
-                       self.layerSelect.setValue(self.layerSelect.getValue() + 1)
-                       self.QueueRefresh()
-               elif keyCode == wx.WXK_DOWN:
-                       self.layerSelect.setValue(self.layerSelect.getValue() - 1)
-                       self.QueueRefresh()
-               elif keyCode == wx.WXK_PAGEUP:
-                       self.layerSelect.setValue(self.layerSelect.getValue() + 10)
-                       self.QueueRefresh()
-               elif keyCode == wx.WXK_PAGEDOWN:
-                       self.layerSelect.setValue(self.layerSelect.getValue() - 10)
-                       self.QueueRefresh()
+               if self.viewMode == 'gcode':
+                       if keyCode == wx.WXK_UP:
+                               self.layerSelect.setValue(self.layerSelect.getValue() + 1)
+                               self.QueueRefresh()
+                       elif keyCode == wx.WXK_DOWN:
+                               self.layerSelect.setValue(self.layerSelect.getValue() - 1)
+                               self.QueueRefresh()
+                       elif keyCode == wx.WXK_PAGEUP:
+                               self.layerSelect.setValue(self.layerSelect.getValue() + 10)
+                               self.QueueRefresh()
+                       elif keyCode == wx.WXK_PAGEDOWN:
+                               self.layerSelect.setValue(self.layerSelect.getValue() - 10)
+                               self.QueueRefresh()
+               else:
+                       if keyCode == wx.WXK_UP:
+                               if wx.GetKeyState(wx.WXK_SHIFT):
+                                       self._zoom /= 1.2
+                                       if self._zoom < 1:
+                                               self._zoom = 1
+                               else:
+                                       self._pitch -= 15
+                               self.QueueRefresh()
+                       elif keyCode == wx.WXK_DOWN:
+                               if wx.GetKeyState(wx.WXK_SHIFT):
+                                       self._zoom *= 1.2
+                                       if self._zoom > numpy.max(self._machineSize) * 3:
+                                               self._zoom = numpy.max(self._machineSize) * 3
+                               else:
+                                       self._pitch += 15
+                               self.QueueRefresh()
+                       elif keyCode == wx.WXK_LEFT:
+                               self._yaw -= 15
+                               self.QueueRefresh()
+                       elif keyCode == wx.WXK_RIGHT:
+                               self._yaw += 15
+                               self.QueueRefresh()
+                       elif keyCode == wx.WXK_NUMPAD_ADD or keyCode == wx.WXK_ADD or keyCode == ord('+') or keyCode == ord('='):
+                               self._zoom /= 1.2
+                               if self._zoom < 1:
+                                       self._zoom = 1
+                               self.QueueRefresh()
+                       elif keyCode == wx.WXK_NUMPAD_SUBTRACT or keyCode == wx.WXK_SUBTRACT or keyCode == ord('-'):
+                               self._zoom *= 1.2
+                               if self._zoom > numpy.max(self._machineSize) * 3:
+                                       self._zoom = numpy.max(self._machineSize) * 3
+                               self.QueueRefresh()
+                       elif keyCode == wx.WXK_HOME:
+                               self._yaw = 30
+                               self._pitch = 60
+                               self.QueueRefresh()
+                       elif keyCode == wx.WXK_PAGEUP:
+                               self._yaw = 0
+                               self._pitch = 0
+                               self.QueueRefresh()
+                       elif keyCode == wx.WXK_PAGEDOWN:
+                               self._yaw = 0
+                               self._pitch = 90
+                               self.QueueRefresh()
+                       elif keyCode == wx.WXK_END:
+                               self._yaw = 90
+                               self._pitch = 90
+                               self.QueueRefresh()
 
                if keyCode == wx.WXK_F3 and wx.GetKeyState(wx.WXK_SHIFT):
                        shaderEditor(self, self.ShaderUpdate, self._objectLoadShader.getVertexShader(), self._objectLoadShader.getFragmentShader())
@@ -731,12 +811,12 @@ class SceneView(openglGui.glGuiPanel):
                                                self.PopupMenu(menu)
                                        menu.Destroy()
                elif self._mouseState == 'dragObject' and self._selectedObj is not None:
-                       self._scene.pushFree()
+                       self._scene.pushFree(self._selectedObj)
                        self.sceneUpdated()
                elif self._mouseState == 'tool':
                        if self.tempMatrix is not None and self._selectedObj is not None:
                                self._selectedObj.applyMatrix(self.tempMatrix)
-                               self._scene.pushFree()
+                               self._scene.pushFree(self._selectedObj)
                                self._selectObject(self._selectedObj)
                        self.tempMatrix = None
                        self.tool.OnDragEnd()
@@ -846,16 +926,16 @@ class SceneView(openglGui.glGuiPanel):
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
 
        def OnPaint(self,e):
-               connectionEntry = self._printerConnectionManager.getAvailableConnection()
+               connectionGroup = self._printerConnectionManager.getAvailableGroup()
                if machineCom.machineIsConnected():
                        self.printButton._imageID = 6
                        self.printButton._tooltip = _("Print")
-               elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionEntry is None or connectionEntry.priority < 0):
+               elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionGroup is None or connectionGroup.getPriority() < 0):
                        self.printButton._imageID = 2
                        self.printButton._tooltip = _("Toolpath to SD")
-               elif connectionEntry is not None:
-                       self.printButton._imageID = connectionEntry.icon
-                       self.printButton._tooltip = _("Print with %s") % (connectionEntry.name)
+               elif connectionGroup is not None:
+                       self.printButton._imageID = connectionGroup.getIconID()
+                       self.printButton._tooltip = _("Print with %s") % (connectionGroup.getName())
                else:
                        self.printButton._imageID = 3
                        self.printButton._tooltip = _("Save toolpath")
@@ -1147,16 +1227,28 @@ void main(void)
                self._drawMachine()
 
                if self._usbPrintMonitor.getState() == 'PRINTING' and self._usbPrintMonitor.getID() == self._slicer.getID():
-                       glEnable(GL_BLEND)
                        z = self._usbPrintMonitor.getZ()
-                       size = self._machineSize
-                       glColor4ub(255,255,0,128)
-                       glBegin(GL_QUADS)
-                       glVertex3f(-size[0]/2,-size[1]/2, z)
-                       glVertex3f( size[0]/2,-size[1]/2, z)
-                       glVertex3f( size[0]/2, size[1]/2, z)
-                       glVertex3f(-size[0]/2, size[1]/2, z)
-                       glEnd()
+                       if self.viewMode == 'gcode':
+                               layer_height = profile.getProfileSettingFloat('layer_height')
+                               layer1_height = profile.getProfileSettingFloat('bottom_thickness')
+                               if layer_height > 0:
+                                       if layer1_height > 0:
+                                               layer = int((z - layer1_height) / layer_height) + 1
+                                       else:
+                                               layer = int(z / layer_height)
+                               else:
+                                       layer = 1
+                               self.layerSelect.setValue(layer)
+                       else:
+                               size = self._machineSize
+                               glEnable(GL_BLEND)
+                               glColor4ub(255,255,0,128)
+                               glBegin(GL_QUADS)
+                               glVertex3f(-size[0]/2,-size[1]/2, z)
+                               glVertex3f( size[0]/2,-size[1]/2, z)
+                               glVertex3f( size[0]/2, size[1]/2, z)
+                               glVertex3f(-size[0]/2, size[1]/2, z)
+                               glEnd()
 
                if self.viewMode == 'gcode':
                        if self._gcodeLoadThread is not None and self._gcodeLoadThread.isAlive():
@@ -1182,20 +1274,21 @@ void main(void)
                                                glVertex3f(p[0], p[1], 0)
                                        glEnd()
                                        glPopMatrix()
-                               glPushMatrix()
-                               glColor4f(0,0,0,0.06)
-                               glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0)
-                               glBegin(GL_TRIANGLE_FAN)
-                               for p in self._selectedObj._printAreaHull[::-1]:
-                                       glVertex3f(p[0], p[1], 0)
-                               glEnd()
-                               glBegin(GL_TRIANGLE_FAN)
-                               for p in self._selectedObj._headAreaMinHull[::-1]:
-                                       glVertex3f(p[0], p[1], 0)
-                               glEnd()
+                               if self._scene.isOneAtATime():
+                                       glPushMatrix()
+                                       glColor4f(0,0,0,0.06)
+                                       glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0)
+                                       glBegin(GL_TRIANGLE_FAN)
+                                       for p in self._selectedObj._printAreaHull[::-1]:
+                                               glVertex3f(p[0], p[1], 0)
+                                       glEnd()
+                                       glBegin(GL_TRIANGLE_FAN)
+                                       for p in self._selectedObj._headAreaMinHull[::-1]:
+                                               glVertex3f(p[0], p[1], 0)
+                                       glEnd()
+                                       glPopMatrix()
                                glDepthMask(True)
                                glDisable(GL_CULL_FACE)
-                               glPopMatrix()
 
                        #Draw the outline of the selected object, on top of everything else except the GUI.
                        if self._selectedObj is not None and self._selectedObj._loadAnim is None: