#!/usr/bin/python __author__ = "Stefan Blanke (greenarrow) (greenarrow@users.sourceforge.net)" __credits__ = "" __license__ = "GPL 3.0" __version__ = "0.8" __licence__ = """ pyRepRap is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. pyRepRap is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with pyRepRap. If not, see . """ # -*- coding: utf-8 -*- # generated by wxGlade 0.6.1 on Wed Apr 23 11:49:08 2008 import wx, pygame, reprap, time, sys, os, threading import replath.wxpygame as wxpygame import reprap.shapeplotter, replath.plugins, reprap.toolpath import replath appTitle = "RepRap Plot" plotterPlugins = replath.plugins.getPlugins(replath.plugins.PLUGIN_IMPORT) outputPlugins = replath.plugins.getPlugins(replath.plugins.PLUGIN_OUTPUT) toolheadPlugins = replath.plugins.getPlugins(replath.plugins.PLUGIN_TOOLHEAD) plotterList = replath.plugins.listTitles(plotterPlugins) outputList = replath.plugins.listTitles(outputPlugins) toolheadList = replath.plugins.listTitles(toolheadPlugins) if sys.platform=="win32": # Windows (taking path of this script) iconPath = os.path.join( os.getcwd(), "graphics" ) else: # Linux iconPath = "/usr/local/share/replath/icons/" appIcon = os.path.join(iconPath, "reprap.png") # Feedback action definitions EVT_FBM_ID = wx.NewId() FB_STATUS = 1 FB_COMPLETE = 2 FB_ABORTED = 3 FB_MESSAGE = 4 # Feedback message event object. Always used by feedbackmessagehandler (external plotters do not use it) class FeedbackMessageEvent(wx.PyEvent): """Simple event to carry arbitrary result data.""" def __init__(self, action, data): """Init Result Event.""" wx.PyEvent.__init__(self) self.SetEventType(EVT_FBM_ID) self.action = action self.data = data # Passed to plotters so they can give feedback info to the gui (including when they are finished) class FeedbackMessageHandler: def __init__(self, parent): self.parent = parent parent.Connect(-1, -1, EVT_FBM_ID, self.onEvent) def onEvent(self, event): if event.action == FB_STATUS: self.parent.setStatusBar(event.data) elif event.action == FB_COMPLETE: self.parent.plotComplete() elif event.action == FB_ABORTED: self.parent.plotAborted() elif event.action == FB_MESSAGE: dlg = wx.MessageDialog(self.parent, str(event.data) + '\n', caption = appTitle, style = wx.OK) #dlg = wx.MessageDialog(self.parent, 'moo\n', caption = 'moo', style = wx.OK) dlg.ShowModal() def plotComplete(self): wx.PostEvent( self.parent, FeedbackMessageEvent(FB_COMPLETE, None) ) def setStatus(self, text): wx.PostEvent( self.parent, FeedbackMessageEvent(FB_STATUS, text) ) def setProgressPopup(self, text, progress = 0): #if text: # #show window # self.progressDialog.progress.SetValue(int(progress)) #else: # #hide window pass def updateProgressPopup(self, progress): #self.progressDialog.progress.SetValue(int(progress)) pass def showMessagePopup(self, text): wx.PostEvent( self.parent, FeedbackMessageEvent(FB_MESSAGE, text) ) def aborted(self): wx.PostEvent( self.parent, FeedbackMessageEvent(FB_ABORTED, None) ) # content of this block not found: did you rename this class? pass # Dialog class for preferences class PreferencesDialog(wx.Dialog): def __init__(self, *args, **kwds): # begin wxGlade: PreferencesDialog.__init__ kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) self.notebook_main = wx.Notebook(self, -1, style=wx.NB_LEFT) self.panel_toolheads = wx.Panel(self.notebook_main, -1) self.panel_outputs = wx.Panel(self.notebook_main, -1) self.panel_inputs = wx.Panel(self.notebook_main, -1) self.panel_general = wx.Panel(self.notebook_main, -1) self.sizer_7_staticbox = wx.StaticBox(self, -1, "") self.sizer_9_staticbox = wx.StaticBox(self.panel_general, -1, "") self.label_8 = wx.StaticText(self.panel_general, -1, "Plot offset (mm) : ") self.label_9 = wx.StaticText(self.panel_general, -1, "X : ") self.text_offsetX = wx.TextCtrl(self.panel_general, -1, "") self.label_10 = wx.StaticText(self.panel_general, -1, "Y :") self.text_offsetY = wx.TextCtrl(self.panel_general, -1, "") self.label_11 = wx.StaticText(self.panel_general, -1, "Fill density (lines / mm) :") self.text_fillDensity = wx.TextCtrl(self.panel_general, -1, "") self.label_16 = wx.StaticText(self.panel_general, -1, "Circle resolution (lines / mm in c) :") self.text_circleResolution = wx.TextCtrl(self.panel_general, -1, "") self.label_1 = wx.StaticText(self.panel_general, -1, "Delay between lines (seconds) :") self.text_lineDelay = wx.TextCtrl(self.panel_general, -1, "") self.label_2 = wx.StaticText(self.panel_general, -1, "Zoom step (factor) :") self.text_zoomStep = wx.TextCtrl(self.panel_general, -1, "") self.label_3 = wx.StaticText(self.panel_general, -1, "Grid division (mm) :") self.text_gridDivision = wx.TextCtrl(self.panel_general, -1, "") self.checkbox_debug = wx.CheckBox(self.panel_general, -1, "Debug") self.notebook_inputs = wx.Notebook(self.panel_inputs, -1, style=wx.NB_LEFT) self.notebook_outputs = wx.Notebook(self.panel_outputs, -1, style=wx.NB_LEFT) self.notebook_toolheads = wx.Notebook(self.panel_toolheads, -1, style=wx.NB_LEFT) self.button_Ok = wx.Button(self, wx.ID_OK, "") self.button_Cancel = wx.Button(self, wx.ID_CANCEL, "") self.__set_properties() self.__do_layout() self.Bind(wx.EVT_BUTTON, self.hanBtnOk, self.button_Ok) self.Bind(wx.EVT_BUTTON, self.hanBtnCancel, self.button_Cancel) # end wxGlade def __set_properties(self): # begin wxGlade: PreferencesDialog.__set_properties self.SetTitle("RepRap Gerber Plotter - Preferences") _icon = wx.EmptyIcon() _icon.CopyFromBitmap(wx.Bitmap(appIcon)) self.SetIcon(_icon) # end wxGlade def __do_layout(self): print "panel load" # Dynamically load panels from plugins self.preferencePanels = [] for plugin in outputPlugins: if dir(plugin).count('PreferencesPanel'): newPanel = plugin.PreferencesPanel(self.notebook_outputs) self.preferencePanels.append( newPanel ) self.notebook_outputs.AddPage(newPanel, plugin.Title) for plugin in toolheadPlugins: if dir(plugin).count('PreferencesPanel'): newPanel = plugin.PreferencesPanel(self.notebook_toolheads) self.preferencePanels.append( newPanel ) self.notebook_toolheads.AddPage(newPanel, plugin.Title) for plugin in plotterPlugins: if dir(plugin).count('PreferencesPanel'): newPanel = plugin.PreferencesPanel(self.notebook_inputs) self.preferencePanels.append( newPanel ) self.notebook_inputs.AddPage(newPanel, plugin.Title) # begin wxGlade: PreferencesDialog.__do_layout sizer_7 = wx.StaticBoxSizer(self.sizer_7_staticbox, wx.VERTICAL) sizer_5 = wx.BoxSizer(wx.VERTICAL) sizer_7_copy = wx.BoxSizer(wx.HORIZONTAL) sizer_4 = wx.BoxSizer(wx.HORIZONTAL) sizer_3 = wx.BoxSizer(wx.HORIZONTAL) sizer_1 = wx.BoxSizer(wx.HORIZONTAL) sizer_2 = wx.BoxSizer(wx.VERTICAL) sizer_9 = wx.StaticBoxSizer(self.sizer_9_staticbox, wx.VERTICAL) grid_sizer_2 = wx.FlexGridSizer(7, 3, 4, 0) grid_sizer_1 = wx.FlexGridSizer(4, 11, 4, 0) grid_sizer_1.Add(self.label_8, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) grid_sizer_1.Add((20, 20), 0, wx.ADJUST_MINSIZE, 0) grid_sizer_1.Add(self.label_9, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) grid_sizer_1.Add((10, 20), 0, wx.ADJUST_MINSIZE, 0) grid_sizer_1.Add(self.text_offsetX, 0, wx.EXPAND|wx.ADJUST_MINSIZE, 0) grid_sizer_1.Add((20, 20), 0, wx.ADJUST_MINSIZE, 0) grid_sizer_1.Add(self.label_10, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) grid_sizer_1.Add((10, 20), 0, wx.ADJUST_MINSIZE, 0) grid_sizer_1.Add(self.text_offsetY, 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) grid_sizer_1.Add((20, 20), 0, wx.ADJUST_MINSIZE, 0) grid_sizer_1.Add((20, 20), 0, wx.ADJUST_MINSIZE, 0) grid_sizer_1.AddGrowableCol(4) grid_sizer_1.AddGrowableCol(8) sizer_9.Add(grid_sizer_1, 0, wx.ALL|wx.EXPAND, 10) grid_sizer_2.Add(self.label_11, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add((10, 20), 0, wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add(self.text_fillDensity, 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add(self.label_16, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add((10, 20), 0, wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add(self.text_circleResolution, 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add(self.label_1, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add((10, 20), 0, wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add(self.text_lineDelay, 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add(self.label_2, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add((10, 20), 0, wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add(self.text_zoomStep, 0, wx.EXPAND|wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add(self.label_3, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add((10, 20), 0, wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add(self.text_gridDivision, 0, wx.EXPAND|wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add(self.checkbox_debug, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add((10, 20), 0, wx.ADJUST_MINSIZE, 0) grid_sizer_2.Add((20, 20), 0, wx.ADJUST_MINSIZE, 0) grid_sizer_2.AddGrowableCol(2) sizer_9.Add(grid_sizer_2, 1, wx.ALL|wx.EXPAND, 10) sizer_2.Add(sizer_9, 1, wx.ALL|wx.EXPAND, 10) self.panel_general.SetSizer(sizer_2) sizer_1.Add(self.notebook_inputs, 1, wx.ALL|wx.EXPAND, 10) self.panel_inputs.SetSizer(sizer_1) sizer_3.Add(self.notebook_outputs, 1, wx.ALL|wx.EXPAND, 10) self.panel_outputs.SetSizer(sizer_3) sizer_4.Add(self.notebook_toolheads, 1, wx.ALL|wx.EXPAND, 10) self.panel_toolheads.SetSizer(sizer_4) self.notebook_main.AddPage(self.panel_general, "General") self.notebook_main.AddPage(self.panel_inputs, "Plotter Plugins") self.notebook_main.AddPage(self.panel_outputs, "Output Plugins") self.notebook_main.AddPage(self.panel_toolheads, "Toolhead Plugins") sizer_5.Add(self.notebook_main, 1, wx.EXPAND, 0) sizer_5.Add((20, 20), 0, wx.ADJUST_MINSIZE, 0) sizer_7_copy.Add(self.button_Ok, 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) sizer_7_copy.Add(self.button_Cancel, 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) sizer_5.Add(sizer_7_copy, 0, wx.EXPAND, 0) sizer_7.Add(sizer_5, 1, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 16) self.SetSizer(sizer_7) sizer_7.Fit(self) self.Layout() self.Centre() # end wxGlade def setPrefHandler(self, pref): self.preferences = pref # Set values of frame control def setPrefValues(self): self.text_offsetX.SetValue( str(self.preferences.pref_plotOffsetX) ) self.text_offsetY.SetValue( str(self.preferences.pref_plotOffsetY) ) self.text_fillDensity.SetValue( str(self.preferences.pref_fillDensity) ) self.text_lineDelay.SetValue( str(self.preferences.pref_lineDelay) ) self.checkbox_debug.SetValue( self.preferences.pref_debug ) self.text_circleResolution.SetValue( str(self.preferences.pref_circleResolution) ) self.text_gridDivision.SetValue( str(self.preferences.pref_gridDivision) ) self.text_zoomStep.SetValue( str(self.preferences.pref_zoomStep) ) def getPreferences(self): return self.preferences # User clicked OK def hanBtnOk(self, event): # wxGlade: PreferencesDialog. self.preferences.pref_plotOffsetX = float( self.text_offsetX.GetValue() ) self.preferences.pref_plotOffsetY = float( self.text_offsetY.GetValue() ) self.preferences.pref_fillDensity = int( self.text_fillDensity.GetValue() ) self.preferences.pref_lineDelay = float( self.text_lineDelay.GetValue() ) self.preferences.pref_debug = self.checkbox_debug.GetValue() self.preferences.pref_circleResolution = float( self.text_circleResolution.GetValue() ) self.preferences.pref_gridDivision = float( self.text_gridDivision.GetValue() ) self.preferences.pref_zoomStep = float( self.text_zoomStep.GetValue() ) for p in self.preferencePanels: p.savePrefValues() self.EndModal(wx.OK) # User clicked Cancel def hanBtnCancel(self, event): # wxGlade: PreferencesDialog. self.preferences = False self.EndModal(wx.CANCEL) # end of class PreferencesDialog """ # A set of lines for drawing on the screen TODO - put draw back in class lineSet: def __init__(self, parent, colour): self.parent = parent self.colour = colour self.clear() def setColour(colour): self.colour = colour self.tableChanged = True def addLine(self, line): self.lines.append(line) #self.parent.draw() #not ideal #pygame.display.flip() self.tableChanged = True def getLines(self): return self.lines def clear(self): self.lines = [] self.tableChanged = True def hasChanged(self): if self.tableChanged: self.tableChanged = False return True else: return False """ # Class for pygame canvas class DrawCanvas(wxpygame.wxSDLPanel): def __init__( self, parent, ID=-1 ): wxpygame.wxSDLPanel.__init__(self, parent, ID) self.previewScale = 5.0 self.offsetX, self.offsetY = 0, 0 self.black = 0, 0, 0 self.white = 255, 255, 255 self.grey = 160, 160, 160 self.greyGreen = 170, 195, 170 self.darkGrey = 140, 140, 140 self.backroundColour = self.white self.baseColour = 166, 211, 166 self.gridColour = self.greyGreen self.previewColour = self.darkGrey self.plotColour = self.black pygame.font.init() self.font = pygame.font.Font(None, 17) self.drawSurface = pygame.Surface( ( 0, 0 ) ) self.drawn = False self.drawRect = 0, 0, 10, 10 def setParent(self, parent): self.parent = parent self.fullRedraw() def drawText( self, surface, x, y, text, font ): text = font.render( text, True, (255, 255, 255), (159, 182, 205) ) textRect = text.get_rect() textRect.centerx = x textRect.centery = y surface.blit(text, textRect) # Draw plot to widget def draw( self ): surface = self.getSurface() w, h = self.GetSizeTuple() if not surface is None: surface.fill( self.backroundColour ) if self.drawn: surface.blit( self.drawSurface, (self.offsetX, -self.offsetY) )#limit region to visible - is this needed? for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() pygame.display.flip() def fullRedraw(self): if self.parent.currentToolpath: fileOffsetX, fileOffsetY = self.parent.currentToolpath.offsetX, self.parent.currentToolpath.offsetY # Find limits #if len(self.polygons) > 0: minX, minY, maxX, maxY = 1000000, 1000000, -1000000, -1000000 if len(self.parent.currentToolpath.layers): for layer in self.parent.currentToolpath.layers: for poly in layer.polygons: for p in poly.points: minX = min(minX, p.x + fileOffsetX) minY = min(minY, p.y + fileOffsetY) maxX = max(maxX, p.x + fileOffsetX) maxY = max(maxY, p.y + fileOffsetY) else: minX, minY, maxX, maxY = 0, 0, 0, 0 border = int(self.parent.preferences.pref_gridDivision * self.previewScale / 2) w, h = self.GetSizeTuple() width, height = int(maxX * self.previewScale) + (2 * border), int(maxY * self.previewScale) + (2 *border) #print "wh", width, height if width > 0 and height > 0: self.drawSurface = pygame.Surface( ( width, height ) ) self.drawRect = 0, 0, width, height # Only draw if we have something to show #if len(self.polygons) > 0: # Draw background pygame.draw.rect( self.drawSurface, self.baseColour, self.drawRect, 0) # Draw grid for x in frange( 0, maxX, self.parent.preferences.pref_gridDivision ): pygame.draw.line( self.drawSurface, self.gridColour, ( int( float(x) * self.previewScale ) + border , border ), ( int( float(x) * self.previewScale ) + border , height - border ) ) for y in frange( 0, maxY, self.parent.preferences.pref_gridDivision ): pygame.draw.line( self.drawSurface, self.gridColour, ( border, height - border - int( float(y) * self.previewScale ) ), ( width - border, height - border - int( float(y) * self.previewScale ) ) ) # Draw axis labels pygame.draw.line( self.drawSurface, self.black, (border, height - border), (border + 50, height - border) ) pygame.draw.line( self.drawSurface, self.black, (border, height - border), (border, height - 50 - border ) ) self.drawText( self.drawSurface, border + 25, height - border , "X", self.font ) self.drawText( self.drawSurface, border, height - border - 25, "Y", self.font ) #else: # # Draw blank white box # pygame.draw.rect( self.drawSurface, self.white, self.drawRect, 0) for layer in self.parent.currentToolpath.layers: # Draw polygons for poly in layer.polygons: #print "plotting poly", poly, len(poly.points) oldX, oldY = poly.points[0].x, poly.points[0].y for ip, p in enumerate(poly.points[ 1: ]): if ip < poly.pointsPlotted: lineColour = self.black else: lineColour = self.previewColour x1, y1, x2, y2 = self.scaleRect( (oldX + fileOffsetX, oldY + fileOffsetY, p.x + fileOffsetX, p.y + fileOffsetY), self.previewScale ) pygame.draw.line( self.drawSurface, lineColour, (x1 + border, height - y1 - border), (x2 + border, height - y2 -border) ) oldX, oldY = p.x, p.y # Final line if closed if poly.closed: x, y = poly.points[0].x, poly.points[0].y x1, y1, x2, y2 = self.scaleRect( (oldX + fileOffsetX, oldY + fileOffsetY, x + fileOffsetX, y + fileOffsetY), self.previewScale ) pygame.draw.line( self.drawSurface, self.previewColour, (x1 + border, height - y1 - border), (x2 + border, height - y2 -border) ) self.drawn = True self.draw() # Simple coordiante manipulation def scaleRect( self, rect, scale ): x1, y1, x2, y2 = rect scaleX = float(scale) scaleY = float(scale) return int( float(x1) * scale ), int( float(y1) * scale ), int( float(x2) * scale ), int( float(y2) * scale ) def offsetRect( self, rect, x, y ): x1, y1, x2, y2 = rect return x1 + x, y1 + y, x2, y2 def offsetLine(self, rect, x, y): x1, y1, x2, y2 = rect return x1 + x, y1 + y, x2 + x, y2 + y def centreView(self, x, y): widthV, heightV = self.GetSizeTuple() null, null, widthD, heightD = self.drawRect self.offsetX = (widthV - widthD + x) / 2 self.offsetY = (heightV - heightD + y) / -2 # Change draw offset to allow dragging of plot def MouseMove(self, event): w, h = self.GetSizeTuple() if event.LeftIsDown(): x, y = event.GetPosition() if event.Dragging(): self.offsetX, self.offsetY = x + self.moveDeltaX, self.moveDeltaY - y # Record offsets for use in drag movement def OnMouseDown(self, event): w, h = self.GetSizeTuple() x, y = event.GetPosition() #print x, y self.moveDeltaX, self.moveDeltaY = self.offsetX - x, self.offsetY + y def OnMouseUp(self, event): pass # When mouse wheel moved, zoom in or out def OnMouseWheel(self, event): w, h = self.GetSizeTuple() centreX, centreY = w / 2, h / 2 x, y = event.GetPosition() #deltaX, deltaY = centreX - x, y - centreY if event.GetWheelRotation() > 0: self.previewScale = self.previewScale + self.parent.preferences.pref_zoomStep elif self.previewScale >= self.parent.preferences.pref_zoomStep: self.previewScale = self.previewScale - self.parent.preferences.pref_zoomStep self.fullRedraw() #null, null, widthD, heightD = self.drawRect #self.centreView(x - self.offsetX, h - y - self.offsetY) #self.centreView(100, 100) # Main frame class class MyFrame(wx.Frame): def __init__(self, *args, **kwds): # Create preference handler that stores preferences on itself self.preferences = replath.preferences.PreferenceHandler( False, "pyRepRap.conf" ) # default values for preferences self.preferences.pref_plotOffsetX = 10.0 self.preferences.pref_plotOffsetY = 10.0 self.preferences.pref_fillDensity = 5 self.preferences.pref_lineDelay = 0.0 self.preferences.pref_debug = False self.preferences.pref_circleResolution = 3.0 self.preferences.pref_gridDivision = 5.0 self.preferences.pref_zoomStep = 1 self.preferences.load() self.fileName = False self.currentPlotter = False self.currentToolpath = False # begin wxGlade: MyFrame.__init__ kwds["style"] = wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, *args, **kwds) self.panel_1 = wx.Panel(self, -1) # Menu Bar self.frmMain_menubar = wx.MenuBar() self.mnuFile = wx.Menu() self.mnuOpen = wx.MenuItem(self.mnuFile, 0, "&Open\tCtrl+O", "", wx.ITEM_NORMAL) self.mnuFile.AppendItem(self.mnuOpen) self.mnuFile.AppendSeparator() self.mnuPlot = wx.MenuItem(self.mnuFile, 2, "&Plot\tCtrl+P", "", wx.ITEM_NORMAL) self.mnuFile.AppendItem(self.mnuPlot) self.mnuFile.AppendSeparator() self.mnuQuit = wx.MenuItem(self.mnuFile, 1, "&Quit\tCtrl+Q", "", wx.ITEM_NORMAL) self.mnuFile.AppendItem(self.mnuQuit) self.frmMain_menubar.Append(self.mnuFile, "&File") wxglade_tmp_menu = wx.Menu() wxglade_tmp_menu.Append(10, "Pr&eferences", "", wx.ITEM_NORMAL) self.frmMain_menubar.Append(wxglade_tmp_menu, "&Edit") wxglade_tmp_menu = wx.Menu() self.mnuAbout = wx.MenuItem(wxglade_tmp_menu, 40, "&About", "", wx.ITEM_NORMAL) wxglade_tmp_menu.AppendItem(self.mnuAbout) self.frmMain_menubar.Append(wxglade_tmp_menu, "&Help") self.SetMenuBar(self.frmMain_menubar) # Menu Bar end self.frmMain_statusbar = self.CreateStatusBar(1, 0) # Tool Bar self.frmMain_toolbar = wx.ToolBar(self, -1, style=wx.TB_HORIZONTAL|wx.TB_TEXT) self.SetToolBar(self.frmMain_toolbar) self.frmMain_toolbar.AddLabelTool(100, "Open", (wx.Bitmap( os.path.join(iconPath, 'document-open.png'), wx.BITMAP_TYPE_ANY )), wx.NullBitmap, wx.ITEM_NORMAL, "Open file", "") self.frmMain_toolbar.AddSeparator() self.frmMain_toolbar.AddLabelTool(110, "Stop", (wx.Bitmap( os.path.join(iconPath, 'media-playback-stop.png'), wx.BITMAP_TYPE_ANY )), wx.NullBitmap, wx.ITEM_NORMAL, "Stop current plotting action", "") self.frmMain_toolbar.AddSeparator() self.frmMain_toolbar.AddLabelTool(120, "Plot", (wx.Bitmap( os.path.join(iconPath, 'media-playback-start.png'), wx.BITMAP_TYPE_ANY )), wx.NullBitmap, wx.ITEM_NORMAL, "Plot to output plugin", "") self.frmMain_toolbar.AddSeparator() self.frmMain_toolbar.AddLabelTool(130, "Preferences", (wx.Bitmap( os.path.join(iconPath, 'configure.png'), wx.BITMAP_TYPE_ANY )), wx.NullBitmap, wx.ITEM_NORMAL, "", "") # Tool Bar end self.static_line_1 = wx.StaticLine(self.panel_1, -1) self.label_22 = wx.StaticText(self.panel_1, -1, "Output :") self.choice_output = wx.Choice(self.panel_1, -1, choices=[]) self.label_23 = wx.StaticText(self.panel_1, -1, "Toolhead :") self.choice_toolhead = wx.Choice(self.panel_1, -1, choices=[]) self.static_line_2 = wx.StaticLine(self.panel_1, -1) self.pygameCanvas = DrawCanvas(self.panel_1, -1) self.__set_properties() self.__do_layout() self.Bind(wx.EVT_MENU, self.onClickOpen, self.mnuOpen) self.Bind(wx.EVT_MENU, self.onClickPlot, self.mnuPlot) self.Bind(wx.EVT_MENU, self.onClickQuit, self.mnuQuit) self.Bind(wx.EVT_MENU, self.onClickPreferences, id=10) self.Bind(wx.EVT_MENU, self.onClickAbout, self.mnuAbout) self.Bind(wx.EVT_TOOL, self.onClickOpen, id=100) self.Bind(wx.EVT_TOOL, self.onClickStop, id=110) self.Bind(wx.EVT_TOOL, self.onClickPlot, id=120) self.Bind(wx.EVT_TOOL, self.onClickPreferences, id=130) # end wxGlade #self.Bind(wx.EVT_CLOSE, self.onCloseWindow) self.pygameCanvas.setParent(self) self.setStatusBar("RepRap Plot") def __set_properties(self): # begin wxGlade: MyFrame.__set_properties self.SetTitle("RepRap Plotter") _icon = wx.EmptyIcon() _icon.CopyFromBitmap(wx.Bitmap(appIcon)) self.SetIcon(_icon) self.SetSize((869, 579)) self.frmMain_statusbar.SetStatusWidths([-1]) # statusbar fields frmMain_statusbar_fields = ["frmMain_statusbar"] for i in range(len(frmMain_statusbar_fields)): self.frmMain_statusbar.SetStatusText(frmMain_statusbar_fields[i], i) self.frmMain_toolbar.SetToolBitmapSize((32, 32)) self.frmMain_toolbar.Realize() # end wxGlade # Load plugin names into choice lists self.choice_output.Append("None") for p in outputList: self.choice_output.Append(p) self.choice_output.SetSelection(0) for p in toolheadList: self.choice_toolhead.Append(p) self.choice_toolhead.SetSelection(0) def __do_layout(self): # begin wxGlade: MyFrame.__do_layout sizer_6 = wx.BoxSizer(wx.VERTICAL) sizer_main = wx.BoxSizer(wx.VERTICAL) sizer_19 = wx.BoxSizer(wx.HORIZONTAL) sizer_main.Add(self.static_line_1, 0, wx.ALL|wx.EXPAND, 5) sizer_19.Add((10, 1), 0, wx.ADJUST_MINSIZE, 0) sizer_19.Add(self.label_22, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) sizer_19.Add((10, 1), 0, wx.ADJUST_MINSIZE, 0) sizer_19.Add(self.choice_output, 0, wx.ADJUST_MINSIZE, 0) sizer_19.Add((20, 1), 0, wx.ADJUST_MINSIZE, 0) sizer_19.Add(self.label_23, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) sizer_19.Add((10, 1), 0, wx.ADJUST_MINSIZE, 0) sizer_19.Add(self.choice_toolhead, 0, wx.ADJUST_MINSIZE, 0) sizer_main.Add(sizer_19, 0, wx.EXPAND, 0) sizer_main.Add(self.static_line_2, 0, wx.ALL|wx.EXPAND, 5) sizer_main.Add(self.pygameCanvas, 5, wx.EXPAND, 1) self.panel_1.SetSizer(sizer_main) sizer_6.Add(self.panel_1, 1, wx.EXPAND, 0) self.SetSizer(sizer_6) self.Layout() self.Centre() # end wxGlade def plotComplete(self): self.pygameCanvas.fullRedraw() self.pygameCanvas.centreView(0, 0) self.currentPlotter.join() self.currentPlotter = False self.setStatusBar("Plot Complete") #dlg = wx.MessageDialog(self, "Plot Complete\n", caption = appTitle, style = wx.OK) #dlg.ShowModal() def plotAborted(self): self.pygameCanvas.fullRedraw() if self.currentPlotter: self.currentPlotter.join() self.currentPlotter = False self.setStatusBar("Plot aborted") dlg = wx.MessageDialog(self, "Plot aborted\n", caption = appTitle, style = wx.OK) dlg.ShowModal() # Produces strings for file formats in wx file dialog e.g. 'Gerber Files (*.pho)|*.pho' def dialogFilterString(self, extensions, name): rText = name + " (" for e in extensions: rText += '*' + e + ';' rText = rText[ :-1 ] rText += ")|" for e in extensions: rText += '*' + e + ';' # Removed as windows did not like having no end chr rText = rText[ :-1 ] return rText def importPlot(self, fileName = False, quiet = False): if fileName: self.fileName = fileName else: self.fileName = False filters = "" allFormats = [] # Produce strings for file formats for wx file dialog for p in plotterPlugins: filters += self.dialogFilterString( p.SupportedFileExtensions, p.FileTitle ) + '|' allFormats += p.SupportedFileExtensions # Produce all supported formats string, put it at the start of the list filters = self.dialogFilterString( allFormats, "All Supported Files" ) + '|' + filters filters = filters[ :-1 ] #print "ff [" + filters + "]" dialog = wx.FileDialog ( None, message = 'Open Gerber File', wildcard = filters, style = wx.OPEN ) if dialog.ShowModal() == wx.ID_OK: self.fileName = dialog.GetPath() self.setStatusBar( "Opened File '" + self.fileName + "'" ) dialog.Destroy() if self.fileName or fileName: self.currentToolpath = reprap.toolpath.Object() self.currentToolpath.offsetX, self.currentToolpath.offsetY = self.preferences.pref_plotOffsetX, self.preferences.pref_plotOffsetY self.currentPlotter = False plugin = False cancel = False feedbackHandler = FeedbackMessageHandler(self) # Find a plugin that claims to handle files with the extension for p in plotterPlugins: # TODO - change to look for last dot not first, as it gets confused with network locations #(fileBaseName, fileExtension)=os.path.splitext(fileName) extension = self.fileName[ self.fileName.find('.'): ].lower() if p.SupportedFileExtensions.count( extension ) > 0: # # Check if the plotter has a preferences dialog and show it if it has one if dir(p).count('PreferencesDialog') and not quiet: plotPrefDialog = p.PreferencesDialog(None, -1, "") app.SetTopWindow(plotPrefDialog) if plotPrefDialog.ShowModal() == wx.OK: plugin = p else: cancel = True break else: plugin = p # If a suitable plugin has been found if plugin: # Create plotter self.currentPlotter = plugin.plotter(self.fileName, self.currentToolpath, feedbackHandler = feedbackHandler, arcResolution = self.preferences.pref_circleResolution, fillDensity = self.preferences.pref_fillDensity, debug = self.preferences.pref_debug, ) if self.currentPlotter: # Start plotter thread self.currentPlotter.start() elif not cancel : dlg = wx.MessageDialog(self, "File format unsupported\n", caption = appTitle, style = wx.OK) dlg.ShowModal() def exportPlot(self, fileName = False): #self.setStatusBar( "Plotting File '" + self.fileName + "'" ) # Use user selected output module if self.choice_output.GetSelection() > 0: outputs = [ self.choice_output.GetSelection() - 1 ] else: outputs = [] feedbackHandler = FeedbackMessageHandler(self) toolhead = toolheadPlugins[ self.choice_toolhead.GetSelection() ].tool() outputPlotters = [] for o in outputs: outputFilename = None if outputPlugins[o].FileOutput: saveDialog = wx.FileDialog(self, message='Save file as...', wildcard=outputPlugins[o].Wildcard, style=wx.SAVE | wx.OVERWRITE_PROMPT) #defaultDir=dir, defaultFile='', if saveDialog.ShowModal() == wx.ID_OK: outputFilename = saveDialog.GetPath() else: outputFilename = None saveDialog.Destroy() self.currentPlotter = outputPlugins[o].output(self.currentToolpath, toolhead, feedbackHandler, outputFilename) self.currentPlotter.start() def setStatusBar(self, text): self.frmMain_statusbar.SetStatusText( text, 0 ) def onClickOpen(self, event): # wxGlade: MyFrame. if self.currentPlotter: dlg = wx.MessageDialog(self, "Current action must be stopped before opening a file.\n", caption = appTitle, style = wx.OK) dlg.ShowModal() else: self.importPlot() #def onCloseWindow(self, evt): # #self.Destroy() # wx.Exit() def onClickQuit(self, event): # wxGlade: MyFrame. wx.Exit() def onClickPreferences(self, event): # wxGlade: MyFrame. dialogPref = PreferencesDialog(None, -1, "") app.SetTopWindow(dialogPref) dialogPref.setPrefHandler( self.preferences ) dialogPref.setPrefValues() dialogPref.ShowModal() self.pygameCanvas.fullRedraw() dialogPref.Destroy() self.preferences.save() def onClickAbout(self, event): # wxGlade: MyFrame. description = "RepRap Plotter is a program for plotting Gerber and CAD files on a RepRap machine." info = wx.AboutDialogInfo() info.SetIcon(wx.Icon(appIcon, wx.BITMAP_TYPE_PNG)) info.SetName('About RepRap Plotter') info.SetVersion(__version__) info.SetDescription(description) #info.SetCopyright('') info.SetLicence(__licence__) info.AddDeveloper(__author__) wx.AboutBox(info) def onClickStop(self, event): # wxGlade: MyFrame. # tell plotter thread to quit if self.currentPlotter: self.currentPlotter.terminate() else: dlg = wx.MessageDialog(self, "Nothing is currently being plotted.\n", caption = appTitle, style = wx.OK) dlg.ShowModal() def onClickPlot(self, event): # wxGlade: MyFrame. if self.currentPlotter: dlg = wx.MessageDialog(self, "Current action must be stopped before plotting.\n", caption = appTitle, style = wx.OK) dlg.ShowModal() else: self.exportPlot() # end of class MyFrame # Range function accepting floats (by Dinu Gherman) def frange(start, end=None, inc=None): if end == None: end = start + 0.0 start = 0.0 if inc == None: inc = 1.0 L = [] while 1: next = start + len(L) * inc if inc > 0 and next >= end: break elif inc < 0 and next <= end: break L.append(next) return L # Strip quotations def stripQuotes(text): if (text[0] == '"' and text[-1] == '"') or (text[0] == "'" and text[-1] == "'"): return text[ 1:-1 ] else: return text showGui = True if len(sys.argv) > 1: if sys.argv.count("--nogui") or sys.argv.count("--g") or sys.argv.count("--help") or sys.argv.count("-h") > 0: showGui = False if __name__ == "__main__": if showGui: app = wx.PySimpleApp(0) wx.InitAllImageHandlers() frmMain = MyFrame(None, -1, "") app.SetTopWindow(frmMain) frmMain.Show() # Command line arg plot file temp TODO proper if sys.argv.count("--quiet") or sys.argv.count("--q"): quiet = True else: quiet = False if len(sys.argv) > 1: frmMain.importPlot( stripQuotes(sys.argv[-1]), quiet ) app.MainLoop() else: print "TODO : Command line only mode" if sys.argv.count("--help"): print "Usage: reprapplot [OPTIONS] [FILE]..." print "Option GNU long option Meaning" print " -h --help Show this message" print " -g --nogui Don't show GUI" print " -q --quiet Don't ask questions"