From 7a77a44dea345bd894b21925ab1e378a7c21e2d1 Mon Sep 17 00:00:00 2001 From: Daid Date: Tue, 21 Feb 2012 23:05:30 +0100 Subject: [PATCH] Added start/end gcode editor (read only, doesn't save yet) Added GCode preview (Loads to do there) Added help tooltip option (Loads of help to write) --- .../fabmetheus_utilities/settings.py | 17 +++- SkeinPyPy_NewUI/newui/alterationPanel.py | 29 ++++++ SkeinPyPy_NewUI/newui/mainWindow.py | 20 +++-- SkeinPyPy_NewUI/newui/preview3d.py | 90 +++++++++++++++++-- SkeinPyPy_NewUI/newui/skeinRun.py | 3 +- SkeinPyPy_NewUI/newui/sliceProgessPanel.py | 33 ++++--- 6 files changed, 159 insertions(+), 33 deletions(-) create mode 100644 SkeinPyPy_NewUI/newui/alterationPanel.py diff --git a/SkeinPyPy_NewUI/fabmetheus_utilities/settings.py b/SkeinPyPy_NewUI/fabmetheus_utilities/settings.py index 311544c2..dc479a9b 100644 --- a/SkeinPyPy_NewUI/fabmetheus_utilities/settings.py +++ b/SkeinPyPy_NewUI/fabmetheus_utilities/settings.py @@ -10,6 +10,8 @@ import __init__ import ConfigParser import os, sys +from fabmetheus_utilities import archive + def getSkeinPyPyConfigInformation(): return { 'carve': { @@ -401,12 +403,19 @@ def printProgressByNumber(layerIndex, numberOfLayers, procedureName): def getAlterationFileLines(fileName): 'Get the alteration file line and the text lines from the fileName in the alterations directories.' - print ('getAlterationFileLines:', fileName) - return [] + return getAlterationLines(fileName) def getAlterationLines(fileName): - print ('getAlterationLines:', fileName) - return [] + #print ('getAlterationLines:', fileName) + return archive.getTextLines(getAlterationFile(fileName)) + +def getAlterationFile(fileName): + "Get the file from the fileName or the lowercase fileName in the alterations directories." + alterationsDirectory = archive.getSkeinforgePath('alterations') + fullFilename = os.path.join(alterationsDirectory, fileName) + if os.path.isfile(fullFilename): + return archive.getFileText( fullFilename ) + return '' #################################### ## Configuration settings classes ## diff --git a/SkeinPyPy_NewUI/newui/alterationPanel.py b/SkeinPyPy_NewUI/newui/alterationPanel.py new file mode 100644 index 00000000..6618a245 --- /dev/null +++ b/SkeinPyPy_NewUI/newui/alterationPanel.py @@ -0,0 +1,29 @@ +import wx +import sys,math,threading + +from fabmetheus_utilities import settings + +class alterationPanel(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent,-1) + + self.alterationFileList = ['start.gcode', 'end.gcode', 'cool_start.gcode', 'cool_end.gcode'] + + self.textArea = wx.TextCtrl(self, style=wx.TE_MULTILINE) + self.list = wx.ListBox(self, choices=self.alterationFileList, style=wx.LB_SINGLE) + self.list.SetSelection(0) + self.Bind(wx.EVT_LISTBOX, self.OnSelect, self.list) + self.OnSelect(None) + + sizer = wx.GridBagSizer() + sizer.Add(self.list, (0,0), span=(1,1), flag=wx.EXPAND) + sizer.Add(self.textArea, (0,1), span=(1,1), flag=wx.EXPAND) + sizer.AddGrowableCol(1) + sizer.AddGrowableRow(0) + self.SetSizer(sizer) + + def OnSelect(self, e): + self.loadFile(self.alterationFileList[self.list.GetSelection()]) + + def loadFile(self, filename): + self.textArea.SetValue(settings.getAlterationFile(filename)) diff --git a/SkeinPyPy_NewUI/newui/mainWindow.py b/SkeinPyPy_NewUI/newui/mainWindow.py index ec6f1b65..b42822cd 100644 --- a/SkeinPyPy_NewUI/newui/mainWindow.py +++ b/SkeinPyPy_NewUI/newui/mainWindow.py @@ -9,6 +9,7 @@ from skeinforge_application.skeinforge_utilities import skeinforge_profile from newui import preview3d from newui import sliceProgessPanel +from newui import alterationPanel def main(): app = wx.App(False) @@ -31,6 +32,8 @@ class mainWindow(wx.Frame): #menubar.Append(wx.Menu(), 'Expert') self.SetMenuBar(menubar) + wx.ToolTip.SetDelay(0) + self.lastPath = "" self.filename = None self.progressPanelList = [] @@ -57,7 +60,7 @@ class mainWindow(wx.Frame): configPanel.SetSizer(sizer) self.AddTitle(configPanel, "Accuracy") - self.AddSetting(configPanel, "Layer height (mm)", self.plugins['carve'].preferencesDict['Layer_Height_mm']) + self.AddSetting(configPanel, "Layer height (mm)", self.plugins['carve'].preferencesDict['Layer_Height_mm'], 'Layer height in millimeters.\n0.2 is a good value for quick prints.\n0.1 gives high quality prints.') self.AddTitle(configPanel, "Skirt") self.AddSetting(configPanel, "Enable skirt", self.plugins['skirt'].preferencesDict['Activate_Skirt']) self.AddSetting(configPanel, "Skirt distance (mm)", self.plugins['skirt'].preferencesDict['Gap_Width_mm']) @@ -93,7 +96,7 @@ class mainWindow(wx.Frame): self.AddSetting(configPanel, "Diameter (mm)", self.plugins['dimension'].preferencesDict['Filament_Diameter_mm']) self.AddSetting(configPanel, "Packing Density", self.plugins['dimension'].preferencesDict['Filament_Packing_Density_ratio']) - nb.AddPage(wx.Panel(nb), "Start/End-GCode") + nb.AddPage(alterationPanel.alterationPanel(nb), "Start/End-GCode") #Preview window, load and slice buttons. self.preview3d = preview3d.myGLCanvas(p) @@ -102,7 +105,7 @@ class mainWindow(wx.Frame): sliceButton = wx.Button(p, -1, 'Slice to GCode') self.Bind(wx.EVT_BUTTON, self.OnLoadSTL, loadButton) self.Bind(wx.EVT_BUTTON, self.OnSlice, sliceButton) - + sizer = wx.GridBagSizer() sizer.Add(nb, (0,0), span=(2,1), flag=wx.EXPAND) sizer.Add(self.preview3d, (0,1), span=(1,3), flag=wx.EXPAND) @@ -128,7 +131,7 @@ class mainWindow(wx.Frame): sizer.Add(wx.StaticLine(panel), (sizer.GetRows()+1,1), (1,3), flag=wx.EXPAND) sizer.SetRows(sizer.GetRows() + 2) - def AddSetting(self, panel, name, setting, help = False): + def AddSetting(self, panel, name, setting, help = 'TODO'): "Add a setting to the configuration panel" sizer = panel.GetSizer() sizer.Add(wx.StaticText(panel, -1, name), (sizer.GetRows(),1), flag=wx.ALIGN_CENTER_VERTICAL) @@ -148,6 +151,7 @@ class mainWindow(wx.Frame): sizer.Add(ctrl, (sizer.GetRows(),2), flag=wx.ALIGN_BOTTOM|wx.EXPAND) helpButton = wx.Button(panel, -1, "?", style=wx.BU_EXACTFIT) sizer.Add(helpButton, (sizer.GetRows(),3)) + helpButton.SetToolTip(wx.ToolTip(help)) sizer.SetRows(sizer.GetRows()+1) return ctrl @@ -179,15 +183,14 @@ class mainWindow(wx.Frame): if not(os.path.exists(self.filename)): return self.lastPath = os.path.split(self.filename)[0] - self.preview3d.loadFile(self.filename) + self.preview3d.loadModelFile(self.filename) dlg.Destroy() def OnSlice(self, e): if self.filename == None: return - for pluginName in self.plugins.keys(): - settings.storeRepository(self.plugins[pluginName]) - settings.saveGlobalConfig(settings.getDefaultConfigPath()) + self.updateConfigFromControls() + #Create a progress panel and add it to the window. The progress panel will start the Skein operation. spp = sliceProgessPanel.sliceProgessPanel(self, self.panel, self.filename) self.sizer.Add(spp, (len(self.progressPanelList)+2,0), span=(1,4), flag=wx.EXPAND) @@ -209,6 +212,7 @@ class mainWindow(wx.Frame): for spp in self.progressPanelList: self.sizer.Add(spp, (i,0), span=(1,4), flag=wx.EXPAND) i += 1 + self.sizer.Layout() def updateConfigToControls(self): "Update the configuration wx controls to show the new configuration settings" diff --git a/SkeinPyPy_NewUI/newui/preview3d.py b/SkeinPyPy_NewUI/newui/preview3d.py index cccfb457..cf3853b7 100644 --- a/SkeinPyPy_NewUI/newui/preview3d.py +++ b/SkeinPyPy_NewUI/newui/preview3d.py @@ -1,4 +1,3 @@ -#from wxPython.glcanvas import wxGLCanvas import wx import sys,math,threading @@ -25,28 +24,83 @@ class myGLCanvas(GLCanvas): self.init = 0 self.triangleMesh = None self.modelDisplayList = None + self.pathList = None self.yaw = 30 self.pitch = 60 self.zoom = 150 self.renderTransparent = False self.machineSize = Vector3(210, 210, 200) - self.machineCenter = Vector3(100, 100, 0) + self.machineCenter = Vector3(105, 105, 0) configButton = wx.Button(self, -1, '', (3,3), (10,10)) self.Bind(wx.EVT_BUTTON, self.OnConfigClick, configButton) - def loadFile(self, filename): - self.filename = filename + def loadModelFile(self, filename): + self.modelFilename = filename #Do the STL file loading in a background thread so we don't block the UI. - thread = threading.Thread(target=self.DoLoad) + thread = threading.Thread(target=self.DoModelLoad) + thread.setDaemon(True) + thread.start() + + def loadGCodeFile(self, filename): + self.gcodeFilename = filename + #Do the STL file loading in a background thread so we don't block the UI. + thread = threading.Thread(target=self.DoGCodeLoad) thread.setDaemon(True) thread.start() - def DoLoad(self): + def DoModelLoad(self): self.modelDirty = False - self.triangleMesh = fabmetheus_interpret.getCarving(self.filename) + self.triangleMesh = fabmetheus_interpret.getCarving(self.modelFilename) self.moveModel() self.Refresh() + def getCode(self, str, id): + pos = str.find(id) + if pos < 0: + return ''; + posEnd = str.find(' ', pos) + if posEnd < 0: + return str[pos+1:] + return str[pos+1:posEnd] + + def DoGCodeLoad(self): + f = open(self.gcodeFilename, 'r') + pos = Vector3() + currentE = 0 + pathList = [] + currentPath = {'type': 'move', 'list': [pos.copy()]} + for line in f: + G = self.getCode(line, 'G') + if G != '': + if G == '0' or G == '1': + X = self.getCode(line, 'X') + Y = self.getCode(line, 'Y') + Z = self.getCode(line, 'Z') + E = self.getCode(line, 'E') + if X != '': + pos.x = float(X) + if X != '': + pos.y = float(Y) + if Z != '': + pos.z = float(Z) + newPoint = pos.copy() + type = 'move' + if E != '': + newEvalue = float(E) + if newEvalue > currentE: + type = 'extrude' + if newEvalue < currentE: + type = 'retract' + if currentPath['type'] != type: + pathList.append(currentPath) + currentPath = {'type': type, 'list': [currentPath['list'][-1]]} + currentPath['list'].append(newPoint) + else: + print "Unknown G code:" + G + self.pathList = pathList + self.triangleMesh = None + self.Refresh() + def OnConfigClick(self, e): self.renderTransparent = not self.renderTransparent self.Refresh() @@ -104,6 +158,7 @@ class myGLCanvas(GLCanvas): glTranslate(-self.machineCenter.x, -self.machineCenter.y, 0) + glColor3f(1,1,1) glLineWidth(4) glDisable(GL_LIGHTING) glBegin(GL_LINE_LOOP) @@ -138,6 +193,19 @@ class myGLCanvas(GLCanvas): glVertex3f(0, self.machineSize.y, 0) glVertex3f(0, self.machineSize.y, self.machineSize.z) glEnd() + + if self.pathList != None: + for path in self.pathList: + if path['type'] == 'move': + glColor3f(0,0,1) + if path['type'] == 'extrude': + glColor3f(1,0,0) + if path['type'] == 'retract': + glColor3f(0,1,0) + glBegin(GL_LINE_STRIP) + for v in path['list']: + glVertex3f(v.x, v.y, v.z) + glEnd() if self.triangleMesh != None: if self.modelDisplayList == None: @@ -185,9 +253,13 @@ class myGLCanvas(GLCanvas): glLoadIdentity() glViewport(0,0, self.GetSize().GetWidth(), self.GetSize().GetHeight()) - glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 0.8, 0.6, 1.0]) + if self.renderTransparent: + glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.5, 0.4, 0.3, 1.0]) + glLightfv(GL_LIGHT0, GL_AMBIENT, [0.1, 0.1, 0.1, 0.0]) + else: + glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 0.8, 0.6, 1.0]) + glLightfv(GL_LIGHT0, GL_AMBIENT, [0.2, 0.2, 0.2, 0.0]) glLightfv(GL_LIGHT0, GL_POSITION, [1.0, 1.0, 1.0, 0.0]) - glLightfv(GL_LIGHT0, GL_AMBIENT, [0.2, 0.2, 0.2, 0.0]) glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) diff --git a/SkeinPyPy_NewUI/newui/skeinRun.py b/SkeinPyPy_NewUI/newui/skeinRun.py index 08be13cd..bd1c3c93 100644 --- a/SkeinPyPy_NewUI/newui/skeinRun.py +++ b/SkeinPyPy_NewUI/newui/skeinRun.py @@ -44,5 +44,4 @@ def getSkeinCommand(filename): pypyExe = getPyPyExe() if pypyExe == False: pypyExe = sys.executable - return [pypyExe, os.path.join(sys.path[0], sys.argv[0]), filename] - + return [pypyExe, os.path.join(sys.path[0], os.path.split(sys.argv[0])[1]), filename] diff --git a/SkeinPyPy_NewUI/newui/sliceProgessPanel.py b/SkeinPyPy_NewUI/newui/sliceProgessPanel.py index fe90cfe4..55e378c4 100644 --- a/SkeinPyPy_NewUI/newui/sliceProgessPanel.py +++ b/SkeinPyPy_NewUI/newui/sliceProgessPanel.py @@ -12,18 +12,18 @@ class sliceProgessPanel(wx.Panel): self.abort = False box = wx.StaticBox(self, -1, filename) - sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL) - + self.sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL) + mainSizer = wx.BoxSizer(wx.VERTICAL) - mainSizer.Add(sizer, 0, flag=wx.EXPAND) + mainSizer.Add(self.sizer, 0, flag=wx.EXPAND) self.statusText = wx.StaticText(self, -1, "Starting...") self.progressGauge = wx.Gauge(self, -1) self.abortButton = wx.Button(self, -1, "X", style=wx.BU_EXACTFIT) - sizer.Add(self.statusText, 2, flag=wx.ALIGN_CENTER ) - sizer.Add(self.progressGauge, 2) - sizer.Add(self.abortButton, 0) - + self.sizer.Add(self.statusText, 2, flag=wx.ALIGN_CENTER ) + self.sizer.Add(self.progressGauge, 2) + self.sizer.Add(self.abortButton, 0) + self.Bind(wx.EVT_BUTTON, self.OnAbort, self.abortButton) self.SetSizer(mainSizer) @@ -34,6 +34,20 @@ class sliceProgessPanel(wx.Panel): self.mainWindow.removeSliceProgress(self) else: self.abort = True + + def OnShowGCode(self, e): + self.mainWindow.preview3d.loadGCodeFile(self.filename[: self.filename.rfind('.')] + "_export.gcode") + + def OnSliceDone(self): + self.statusText.SetLabel("Ready.") + self.progressGauge.Destroy() + self.showButton = wx.Button(self, -1, "Show GCode") + self.Bind(wx.EVT_BUTTON, self.OnShowGCode, self.showButton) + self.sizer.Remove(self.abortButton) + self.sizer.Add(self.showButton, 0) + self.sizer.Add(self.abortButton, 0) + self.sizer.Layout() + self.abort = True class WorkerThread(threading.Thread): def __init__(self, notifyWindow, filename): @@ -48,6 +62,7 @@ class WorkerThread(threading.Thread): maxValue = 1 while(len(line) > 0): line = line.rstrip() + print line if line[0:9] == "Progress[" and line[-1:] == "]": progress = line[9:-1].split(":") if len(progress) > 2: @@ -62,6 +77,4 @@ class WorkerThread(threading.Thread): wx.CallAfter(self.notifyWindow.statusText.SetLabel, "Aborted by user.") return line = p.stdout.readline() - wx.CallAfter(self.notifyWindow.progressGauge.SetValue, maxValue) - wx.CallAfter(self.notifyWindow.statusText.SetLabel, "Ready.") - + wx.CallAfter(self.notifyWindow.OnSliceDone) -- 2.30.2