From: daid303 Date: Thu, 28 Feb 2013 08:32:58 +0000 (+0100) Subject: Add layer slider. Solve the issue where loading a new file takes a long time and... X-Git-Tag: 13.03~41 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=df490aae4be10fe08bafe8712d178a110abe0758;p=cura.git Add layer slider. Solve the issue where loading a new file takes a long time and hangs the GUI when a large GCode file is still being loaded. --- diff --git a/Cura/gui/preview3d.py b/Cura/gui/preview3d.py index 69ab9beb..046f70c9 100644 --- a/Cura/gui/preview3d.py +++ b/Cura/gui/preview3d.py @@ -22,7 +22,6 @@ from Cura.util import util3d from Cura.util import sliceRun from Cura.gui.util import opengl -from Cura.gui.util import toolbarUtil from Cura.gui.util import previewTools from Cura.gui.util import openglGui @@ -72,31 +71,7 @@ class previewPanel(wx.Panel): parent.Bind(wx.EVT_MOVE, self.OnMove) parent.Bind(wx.EVT_SIZE, self.OnMove) - self.toolbar = toolbarUtil.Toolbar(self) - - group = [] - toolbarUtil.RadioButton(self.toolbar, group, 'object-3d-on.png', 'object-3d-off.png', '3D view', callback=self.On3DClick) - toolbarUtil.RadioButton(self.toolbar, group, 'object-top-on.png', 'object-top-off.png', 'Topdown view', callback=self.OnTopClick) - self.toolbar.AddSeparator() - - self.showBorderButton = toolbarUtil.ToggleButton(self.toolbar, '', 'view-border-on.png', 'view-border-off.png', 'Show model borders', callback=self.OnViewChange) - self.showSteepOverhang = toolbarUtil.ToggleButton(self.toolbar, '', 'steepOverhang-on.png', 'steepOverhang-off.png', 'Show steep overhang', callback=self.OnViewChange) - self.toolbar.AddSeparator() - - group = [] - self.normalViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-normal-on.png', 'view-normal-off.png', 'Normal model view', callback=self.OnViewChange) - self.transparentViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-transparent-on.png', 'view-transparent-off.png', 'Transparent model view', callback=self.OnViewChange) - self.xrayViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-xray-on.png', 'view-xray-off.png', 'X-Ray view', callback=self.OnViewChange) - self.gcodeViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-gcode-on.png', 'view-gcode-off.png', 'GCode view', callback=self.OnViewChange) - self.mixedViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-mixed-on.png', 'view-mixed-off.png', 'Mixed model/GCode view', callback=self.OnViewChange) - self.toolbar.AddSeparator() - - self.layerSpin = wx.SpinCtrl(self.toolbar, -1, '', size=(21*4,21), style=wx.SP_ARROW_KEYS) - self.toolbar.AddControl(self.layerSpin) - self.Bind(wx.EVT_SPINCTRL, self.OnLayerNrChange, self.layerSpin) - sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(self.toolbar, 0, flag=wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, border=1) sizer.Add(self.glCanvas, 1, flag=wx.EXPAND) self.SetSizer(sizer) @@ -149,6 +124,7 @@ class previewPanel(wx.Panel): self.scaleUniform = openglGui.glCheckbox(self.scaleForm, True, (1,8), None) self.viewSelection = openglGui.glComboButton(self.glCanvas, 'View mode', [0,1,2,3,4], ['3D Model', 'Transparent', 'X-Ray', 'Overhang', 'Layers'], (-1,0), self.OnViewChange) + self.layerSelect = openglGui.glSlider(self.glCanvas, 0, 0, 100, (-1,-1), self.OnLayerNrChange) self.OnViewChange() self.OnToolSelect() @@ -330,15 +306,14 @@ class previewPanel(wx.Panel): self.glCanvas.offsetY = 0 self.glCanvas.Refresh() - def OnLayerNrChange(self, e): + def OnLayerNrChange(self): self.glCanvas.Refresh() def setViewMode(self, mode): if mode == "Normal": - self.normalViewButton.SetValue(True) + self.viewSelection.setValue(0) if mode == "GCode": - self.gcodeViewButton.SetValue(True) - self.glCanvas.viewMode = mode + self.viewSelection.setValue(5) wx.CallAfter(self.glCanvas.Refresh) def loadModelFiles(self, filelist, showWarning = False): @@ -358,7 +333,9 @@ class previewPanel(wx.Panel): self.gcodeFilename = sliceRun.getExportFilename(filelist[0]) #Do the STL file loading in a background thread so we don't block the UI. if self.loadThread is not None and self.loadThread.isAlive(): + self.abortLoading = True self.loadThread.join() + self.abortLoading = False self.loadThread = threading.Thread(target=self.doFileLoadThread) self.loadThread.daemon = True self.loadThread.start() @@ -408,7 +385,7 @@ class previewPanel(wx.Panel): obj.steepDirty = True self.updateModelTransform() self.OnScaleMax(True) - self.glCanvas.zoom = numpy.max(self.objectsSize) * 3.5 + self.glCanvas.zoom = self.objectsBoundaryCircleSize * 6.0 self.errorList = [] wx.CallAfter(self.updateToolbar) wx.CallAfter(self.glCanvas.Refresh) @@ -438,7 +415,7 @@ class previewPanel(wx.Panel): wx.CallAfter(self.checkReloadFileTimer.Start, 1000) def loadProgress(self, progress): - pass + return self.abortLoading def OnResetAll(self, e = None): profile.putProfileSetting('model_matrix', '1,0,0,0,1,0,0,0,1') @@ -470,19 +447,15 @@ class previewPanel(wx.Panel): self.warningPopup.timer.Stop() def updateToolbar(self): - self.gcodeViewButton.Show(self.gcode is not None) - self.mixedViewButton.Show(self.gcode is not None) - self.layerSpin.Show(self.glCanvas.viewMode == "GCode" or self.glCanvas.viewMode == "Mixed") self.printButton.setDisabled(self.gcode is None) if self.gcode is not None: - self.layerSpin.SetRange(1, len(self.gcode.layerList) - 1) - self.toolbar.Realize() + self.layerSelect.setRange(1, len(self.gcode.layerList) - 1) self.Update() def OnViewChange(self): selection = self.viewSelection.getValue() self.glCanvas.drawSteepOverhang = False - self.glCanvas.drawBorders = self.showBorderButton.GetValue() + self.glCanvas.drawBorders = False if selection == 0: self.glCanvas.viewMode = "Normal" elif selection == 1: @@ -493,10 +466,11 @@ class previewPanel(wx.Panel): self.glCanvas.viewMode = "Normal" self.glCanvas.drawSteepOverhang = True elif selection == 4: - self.layerSpin.SetValue(self.layerSpin.GetMax()) + self.layerSelect.setValue(self.layerSelect.getMaxValue()) self.glCanvas.viewMode = "GCode" elif selection == 5: self.glCanvas.viewMode = "Mixed" + self.layerSelect.setHidden(self.glCanvas.viewMode != "GCode") self.updateToolbar() self.glCanvas.Refresh() @@ -659,8 +633,8 @@ class PreviewGLCanvas(openglGui.glGuiPanel): glRotate(self.yaw, 0,0,1) if self.viewMode == "GCode" or self.viewMode == "Mixed": - if self.parent.gcode is not None and len(self.parent.gcode.layerList) > self.parent.layerSpin.GetValue() and len(self.parent.gcode.layerList[self.parent.layerSpin.GetValue()]) > 0: - self.viewTarget[2] = self.parent.gcode.layerList[self.parent.layerSpin.GetValue()][0].list[-1].z + if self.parent.gcode is not None and len(self.parent.gcode.layerList) > self.parent.layerSelect.getValue() and len(self.parent.gcode.layerList[self.parent.layerSelect.getValue()]) > 0: + self.viewTarget[2] = self.parent.gcode.layerList[self.parent.layerSelect.getValue()][0].list[-1].z else: if self.parent.objectsMaxV is not None: self.viewTarget = self.getObjectCenterPos() @@ -725,11 +699,11 @@ class PreviewGLCanvas(openglGui.glGuiPanel): glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, 0) glEnable(GL_COLOR_MATERIAL) glEnable(GL_LIGHTING) - drawUpToLayer = min(self.gcodeDisplayListMade, self.parent.layerSpin.GetValue() + 1) + drawUpToLayer = min(self.gcodeDisplayListMade, self.parent.layerSelect.getValue() + 1) starttime = time.time() for i in xrange(drawUpToLayer - 1, -1, -1): c = 1.0 - if i < self.parent.layerSpin.GetValue(): + if i < self.parent.layerSelect.getValue(): c = 0.9 - (drawUpToLayer - i) * 0.1 if c < 0.4: c = (0.4 + c) / 2 diff --git a/Cura/gui/util/openglGui.py b/Cura/gui/util/openglGui.py index dd7cf246..726b6727 100644 --- a/Cura/gui/util/openglGui.py +++ b/Cura/gui/util/openglGui.py @@ -2,6 +2,8 @@ from __future__ import absolute_import from __future__ import division import wx +import math + from wx import glcanvas import OpenGL OpenGL.ERROR_CHECKING = False @@ -51,6 +53,9 @@ class glGuiControl(object): def hasFocus(self): return self._base._focus == self + def OnMouseUp(self, x, y): + pass + def OnKeyChar(self, key): pass @@ -70,6 +75,12 @@ class glGuiContainer(glGuiControl): return True return False + def OnMouseUp(self, x, y): + for ctrl in self._glGuiControlList: + if ctrl.OnMouseUp(x, y): + return True + return False + def OnMouseMotion(self, x, y): handled = False for ctrl in self._glGuiControlList: @@ -103,6 +114,7 @@ class glGuiPanel(glcanvas.GLCanvas): wx.EVT_SIZE(self, self._OnSize) wx.EVT_ERASE_BACKGROUND(self, self._OnEraseBackground) wx.EVT_LEFT_DOWN(self, self._OnGuiMouseLeftDown) + wx.EVT_LEFT_UP(self, self._OnGuiMouseLeftUp) wx.EVT_MOTION(self, self._OnGuiMouseMotion) wx.EVT_CHAR(self, self.OnKeyChar) wx.EVT_KILL_FOCUS(self, self.OnFocusLost) @@ -122,6 +134,11 @@ class glGuiPanel(glcanvas.GLCanvas): self.Refresh() return self.OnMouseLeftDown(e) + def _OnGuiMouseLeftUp(self, e): + if self._container.OnMouseUp(e.GetX(), e.GetY()): + self.Refresh() + return + self.OnMouseLeftUp(e) def _OnGuiMouseMotion(self,e): self.Refresh() @@ -132,9 +149,11 @@ class glGuiPanel(glcanvas.GLCanvas): h = self.GetSize().GetHeight() w = self.GetSize().GetWidth() oldButtonSize = self._buttonSize - if h / 3 > w / 4: + if h / 3 < w / 4: w = h * 4 / 3 - if w < 64 * 10: + if w < 64 * 8: + self._buttonSize = 32 + elif w < 64 * 10: self._buttonSize = 48 elif w < 64 * 15: self._buttonSize = 64 @@ -181,6 +200,8 @@ class glGuiPanel(glcanvas.GLCanvas): def OnMouseLeftDown(self,e): pass + def OnMouseLeftUp(self,e): + pass def OnMouseMotion(self, e): pass def OnPaint(self, e): @@ -198,7 +219,7 @@ class glGuiLayoutButtons(object): def update(self): bs = self._parent._base._buttonSize x0, y0, w, h = self._parent.getSize() - gridSize = bs * 1.3 + gridSize = bs * 1.2 for ctrl in self._parent._glGuiControlList: pos = ctrl._pos if pos[0] < 0: @@ -426,6 +447,10 @@ class glComboButton(glButton): def getValue(self): return self._selection + def setValue(self, value): + self._selection = value + self._comboCallback() + def OnMouseDown(self, x, y): if self._hidden or self._disabled: return False @@ -731,3 +756,124 @@ class glCheckbox(glGuiControl): self._value = not self._value return True return False + +class glSlider(glGuiControl): + def __init__(self, parent, value, minValue, maxValue, pos, callback): + super(glSlider, self).__init__(parent, pos) + self._callback = callback + self._focus = False + self._hidden = False + self._value = value + self._minValue = minValue + self._maxValue = maxValue + + def setValue(self, value): + self._value = value + self._value = max(self._minValue, self._value) + self._value = min(self._maxValue, self._value) + + def getValue(self): + return self._value + + def setRange(self, minValue, maxValue): + self._minValue = minValue + self._maxValue = maxValue + self._value = max(minValue, self._value) + self._value = min(maxValue, self._value) + + def getMinValue(self): + return self._minValue + + def getMaxValue(self): + return self._maxValue + + def setHidden(self, value): + self._hidden = value + + def getMinSize(self): + return self._base._buttonSize, self._base._buttonSize + + def _getPixelPos(self): + x0, y0, w, h = self.getSize() + return x0 + w / 2, y0 + + def draw(self): + if self._hidden: + return + + cx = 0 + cy = 0 + bs = self._base._buttonSize + pos = self._getPixelPos() + + glPushMatrix() + glTranslatef(pos[0], pos[1], 0) + glDisable(GL_TEXTURE_2D) + if self.hasFocus(): + glColor4ub(32,32,32,255) + else: + glColor4ub(32,32,32,192) + glScalef(bs, bs, bs) + glBegin(GL_QUADS) + glVertex2f( 0.1,-1.0) + glVertex2f(-0.1,-1.0) + glVertex2f(-0.1, 1.0) + glVertex2f( 0.1, 1.0) + glEnd() + glTranslate(0.0,0.9,0) + if self._focus: + glColor4ub(0,0,0,255) + glPushMatrix() + glTranslate(-0.1,0,0) + opengl.glDrawStringRight(str(self._minValue)) + glTranslate(0,-1.8,0) + opengl.glDrawStringRight(str(self._maxValue)) + glTranslate(0.2,1.8-1.8*((self._value-self._minValue)/(self._maxValue-self._minValue)),0) + opengl.glDrawStringLeft(str(self._value)) + glPopMatrix() + glColor4ub(255,255,255,240) + glTranslate(0.0,-1.8*((self._value-self._minValue)/(self._maxValue-self._minValue)),0) + glBegin(GL_QUADS) + glVertex2f( 0.1,-0.1) + glVertex2f(-0.1,-0.1) + glVertex2f(-0.1, 0.1) + glVertex2f( 0.1, 0.1) + glEnd() + glPopMatrix() + + def _checkHit(self, x, y): + if self._hidden: + return False + bs = self._base._buttonSize + pos = self._getPixelPos() + return -bs * 0.1 <= x - pos[0] <= bs * 0.1 and -bs * 1.0 <= y - pos[1] <= bs * 1.0 + + def setFocus(self): + self._base._focus = self + return True + + def OnMouseMotion(self, x, y): + if self.hasFocus(): + bs = self._base._buttonSize + pos = self._getPixelPos() + self.setValue(int(self._minValue + (self._maxValue - self._minValue) * -(y - pos[1] - bs * 0.9) / (bs * 1.8))) + self._callback() + return True + if self._checkHit(x, y): + self._focus = True + return True + self._focus = False + return False + + def OnMouseDown(self, x, y): + if self._checkHit(x, y): + self.setFocus() + self.OnMouseMotion(x, y) + return True + return False + + def OnMouseUp(self, x, y): + if self.hasFocus(): + self._base._focus = None + return True + return False diff --git a/Cura/util/gcodeInterpreter.py b/Cura/util/gcodeInterpreter.py index ce0c13ee..32c762a4 100644 --- a/Cura/util/gcodeInterpreter.py +++ b/Cura/util/gcodeInterpreter.py @@ -75,11 +75,7 @@ class gcode(object): for line in gcodeFile: if type(line) is tuple: line = line[0] - if self.progressCallback != None: - if filePos != gcodeFile.tell(): - filePos = gcodeFile.tell() - self.progressCallback(float(filePos) / float(self._fileSize)) - + #Parse Cura_SF comments if line.startswith(';TYPE:'): pathType = line[6:].strip() @@ -97,6 +93,13 @@ class gcode(object): pathType = 'SKIRT' if comment.startswith('LAYER:'): self.layerList.append(currentLayer) + if self.progressCallback is not None: + if filePos != gcodeFile.tell(): + filePos = gcodeFile.tell() + if self.progressCallback(float(filePos) / float(self._fileSize)): + #Abort the loading, we can safely return as the results here will be discarded + gcodeFile.close() + return currentLayer = [] if pathType != "CUSTOM": startCodeDone = True diff --git a/Cura/util/profile.py b/Cura/util/profile.py index 4e43f9ef..259e33a9 100644 --- a/Cura/util/profile.py +++ b/Cura/util/profile.py @@ -180,7 +180,7 @@ preferencesDefaultSettings = { 'extruder_head_size_max_y': '35.0', 'extruder_head_size_height': '60.0', - 'model_colour': '#72CB30', + 'model_colour': '#7AB645', 'model_colour2': '#CB3030', 'model_colour3': '#DDD93C', 'model_colour4': '#4550D3',