Пример #1
0
	def createPBView(self):
		#self.updateProtoBoard(False)
		if not self.pbView is None:
			try:
				self.prevPosition = self.pbView.GetPosition()
				self.pbView.Destroy()
			except wx.PyDeadObjectError:
				self.pbView = None
				self.prevPosition = [-1, -1]
			
		self.pbView = ProtoBoardView(self, self.pb, self.prevPosition, self.settings)
		self.dsp = self.pbView.getPBFrame()
		self.pbView.Show()
Пример #2
0
class ProtoBoardDialog(wx.Dialog):
	def __init__(self, parent, pb, fn, settings):
		self.parent = parent 
		
		title = TITLETEXT
		if not fn is None:
			title += " - %s" % fn	   
		wx.Dialog.__init__(self, parent, wx.ID_ANY, title, size=(400, 400))
		self.SetBackgroundColour("white")
		
		self.printData = wx.PrintData()
		self.printData.SetPaperId(wx.PAPER_LETTER)
		self.printData.SetPrintMode(wx.PRINT_MODE_PRINTER)

		self.pb = pb
		self.pbView = None
		self.prevPosition = [-1, -1]
		self.fileName = fn
		self.SetClientSize((600, 300))
		self.Bind(wx.EVT_CLOSE, self.onClose)
		
		self.dx = 0
		self.dy = 0
		
		self.settings = settings
		self.images = settings.images
		self.compImages = settings.compImages
		self.fixedComponentList = settings.fixedComponentList
		self.stretchComponentList = settings.stretchComponentList
		self.growComponentList = settings.growComponentList
		
		self.fixedComponentTypes = self.fixedComponentList.getComponentTypes()
		self.currentFixedComponentChoice = self.fixedComponentTypes[0]

		self.stretchComponentNames = self.stretchComponentList.getComponentNames()
		if WIRENAME in self.stretchComponentNames:
			self.stretchComponentNames.remove(WIRENAME)
		self.currentStretchName = self.stretchComponentNames[0]

		self.growComponentNames = self.growComponentList.getComponentNames()
		self.currentGrowComponentChoice = self.growComponentNames[0]

		self.currentComponentPrefix = ""
		self.currentFixedComponent = None
		self.currentStretchComponent = None
		self.currentGrowComponent = None
		
		self.wireColor = wx.Colour(0, 255, 0)
		self.lastReport = []
				
		self.tb = wx.BoxSizer(wx.HORIZONTAL)
		self.tb.AddSpacer((20, 20))

		self.tbExamine = wx.BitmapButton(self, wx.ID_ANY, self.images.pngView, size=TBDIM)
		self.tbExamine.SetToolTipString("Examine the trace/wire network")
		self.Bind(wx.EVT_BUTTON, self.onExamine, self.tbExamine)
		self.tb.Add(self.tbExamine)

		self.tbName = wx.BitmapButton(self, wx.ID_ANY, self.images.pngProperties, size=TBDIM)
		self.tbName.SetToolTipString("Assign name and/or value to a component")
		self.Bind(wx.EVT_BUTTON, self.onName, self.tbName)
		self.tb.Add(self.tbName)
		
		self.tb.AddSpacer((20, 20))
		
		self.tbCut = wx.BitmapButton(self, wx.ID_ANY, self.images.pngCut, size=TBDIM)
		self.tbCut.SetToolTipString("Cut/replace traces and/or jumpers")
		self.Bind(wx.EVT_BUTTON, self.onCut, self.tbCut)
		self.tb.Add(self.tbCut)
		
		self.tbWire = wx.BitmapButton(self, wx.ID_ANY, self.images.pngWire, size=TBDIM)
		self.tbWire.SetToolTipString("Add a wire to the circuit")
		self.Bind(wx.EVT_BUTTON, self.onWire, self.tbWire)
		self.tbWire.Bind(wx.EVT_RIGHT_DOWN, self.onColor)
		self.tb.Add(self.tbWire)
		
		self.tbComponent = wx.BitmapButton(self, wx.ID_ANY, self.images.pngComponent, size=TBDIM)
		self.tbComponent.SetToolTipString("Add a fixed-shape component")
		self.Bind(wx.EVT_BUTTON, self.onComponent, self.tbComponent)
		self.tbComponent.Bind(wx.EVT_RIGHT_DOWN, self.onChooseComponent)
		self.tb.Add(self.tbComponent)
		
		self.tbStretch = wx.BitmapButton(self, wx.ID_ANY, self.images.pngStretch, size=TBDIM)
		self.tbStretch.SetToolTipString("Add a stretchable component")
		self.Bind(wx.EVT_BUTTON, self.onStretch, self.tbStretch)
		self.tbStretch.Bind(wx.EVT_RIGHT_DOWN, self.onChooseStretch)
		self.tb.Add(self.tbStretch)
		
		self.tbGrow = wx.BitmapButton(self, wx.ID_ANY, self.images.pngGrow, size=TBDIM)
		self.tbGrow.SetToolTipString("Add a growable component")
		self.Bind(wx.EVT_BUTTON, self.onGrow, self.tbGrow)
		self.tbGrow.Bind(wx.EVT_RIGHT_DOWN, self.onChooseGrow)
		self.tb.Add(self.tbGrow)
		
		self.tb.AddSpacer((50, 20))

		self.tbGrab = wx.BitmapButton(self, wx.ID_ANY, self.images.pngGrab, size=TBDIM)
		self.tbGrab.SetToolTipString("Select item")
		self.Bind(wx.EVT_BUTTON, self.onGrab, self.tbGrab)
		self.tb.Add(self.tbGrab)
		
		self.tbMove = wx.BitmapButton(self, wx.ID_ANY, self.images.pngMove, size=TBDIM)
		self.tbMove.SetToolTipString("Move item")
		self.Bind(wx.EVT_BUTTON, self.onMove, self.tbMove)
		self.tb.Add(self.tbMove)
		
		self.tbTrim = wx.BitmapButton(self, wx.ID_ANY, self.images.pngResize, size=TBDIM)
		self.tbTrim.SetToolTipString("Resize PCB")
		self.Bind(wx.EVT_BUTTON, self.onTrim, self.tbTrim)
		self.tb.Add(self.tbTrim)
		
		self.tb.AddSpacer((30, 20))
		
		self.tbTrash = wx.BitmapButton(self, wx.ID_ANY, self.images.pngTrash, size=TBDIM)
		self.tbTrash.SetToolTipString("Delete item")
		self.Bind(wx.EVT_BUTTON, self.onTrash, self.tbTrash)
		self.tb.Add(self.tbTrash)
		
		self.tb.AddSpacer((40, 20))
		
		self.bSave = wx.BitmapButton(self, wx.ID_ANY, self.images.pngSave, size=TBDIM)
		self.bSave.SetToolTipString("Save")
		self.Bind(wx.EVT_BUTTON, self.onSave, self.bSave)
		self.tb.Add(self.bSave)
		
		self.bSaveAs = wx.BitmapButton(self, wx.ID_ANY, self.images.pngSaveas, size=TBDIM)
		self.bSaveAs.SetToolTipString("Save As")
		self.Bind(wx.EVT_BUTTON, self.onSaveAs, self.bSaveAs)
		self.tb.Add(self.bSaveAs)
		
		self.bPrint = wx.BitmapButton(self, wx.ID_ANY, self.images.pngPrint, size=TBDIM)
		self.bPrint.SetToolTipString("Print - right click for preview")
		self.Bind(wx.EVT_BUTTON, self.onPrint, self.bPrint)
		self.bPrint.Bind(wx.EVT_RIGHT_DOWN, self.onPrintPreview)
		self.tb.Add(self.bPrint)
		
		self.bPrintInstr = wx.BitmapButton(self, wx.ID_ANY, self.images.pngInstructions, size=TBDIM)
		self.bPrintInstr.SetToolTipString("Print Instructions")
		self.Bind(wx.EVT_BUTTON, self.onPrintInstr, self.bPrintInstr)
		self.tb.Add(self.bPrintInstr)
		
		self.bExit = wx.BitmapButton(self, wx.ID_ANY, self.images.pngExit, size=TBDIM)
		self.bExit.SetToolTipString("Exit")
		self.Bind(wx.EVT_BUTTON, self.onClose, self.bExit)
		self.tb.Add(self.bExit)
		
		self.tb.AddSpacer((20, 20))

		self.pbSizer = wx.BoxSizer()
		#self.dsp = PBFrame(self, self.pb, self.settings)
		#self.pbSizer.Add(self.dsp)
		
		self.statusSizer = wx.BoxSizer(wx.HORIZONTAL)
		self.statusSizer.AddSpacer((5,5))
		
		self.bitmapStatus = wx.StaticBitmap(self, wx.ID_ANY, self.images.pngCut)
		self.statusSizer.Add(self.bitmapStatus)
		self.statusSizer.AddSpacer((5,5))
	
		statusMsgSizer = wx.BoxSizer(wx.VERTICAL)
		
		self.hintLine1 = wx.StaticText(self, wx.ID_ANY, "")
		statusMsgSizer.Add(self.hintLine1)
		
		self.hintLine2 = wx.StaticText(self, wx.ID_ANY, "")
		statusMsgSizer.Add(self.hintLine2)
		statusMsgSizer.AddSpacer((5,5))

		self.statusLine = wx.StaticText(self, wx.ID_ANY, "")
		statusMsgSizer.Add(self.statusLine)
		
		self.statusSizer.Add(statusMsgSizer)
		
		self.buildSizer()
		wx.CallAfter(self.createPBView)
		wx.CallAfter(self.setInitialTool)
		
	def createPBView(self):
		#self.updateProtoBoard(False)
		if not self.pbView is None:
			try:
				self.prevPosition = self.pbView.GetPosition()
				self.pbView.Destroy()
			except wx.PyDeadObjectError:
				self.pbView = None
				self.prevPosition = [-1, -1]
			
		self.pbView = ProtoBoardView(self, self.pb, self.prevPosition, self.settings)
		self.dsp = self.pbView.getPBFrame()
		self.pbView.Show()
		
	def buildSizer(self):
		sizer = wx.BoxSizer(wx.VERTICAL)
		sizer.AddSpacer((10, 10))
		sizer.Add(self.tb)
		sizer.AddSpacer((10, 10))
		sizer.Add(self.pbSizer, 1, wx.LEFT+wx.RIGHT, 10)
		sizer.AddSpacer((10, 10))
		sizer.Add(self.statusSizer)
		sizer.AddSpacer((10, 10))
		self.SetSizer(sizer)
		self.mySizer = sizer
		self.Fit()
		
	def updateTitle(self):
		title = TITLETEXT
		if not self.fileName is None:
			title += " - %s" % self.fileName
		self.SetTitle(title)
		
	def setInitialTool(self):
		self.selectTool(TOOL_CUT)
		
	def setStatusText(self, msg):
		self.statusLine.SetLabel(msg)
		
	def setStatusBitmap(self, tid):
		if tid == TOOL_CUT:
			self.bitmapStatus.SetBitmap(self.images.pngCut)
		elif tid == TOOL_EXAMINE:
			self.bitmapStatus.SetBitmap(self.images.pngView)
		elif tid == TOOL_NAME:
			self.bitmapStatus.SetBitmap(self.images.pngProperties)
		elif tid == TOOL_WIRE:
			self.bitmapStatus.SetBitmap(self.images.pngWire)
		elif tid == TOOL_COMPONENT:
			self.bitmapStatus.SetBitmap(self.images.pngComponent)
		elif tid == TOOL_STRETCH:
			self.bitmapStatus.SetBitmap(self.images.pngStretch)
		elif tid == TOOL_GROW:
			self.bitmapStatus.SetBitmap(self.images.pngGrow)
		elif tid == TOOL_GRAB:
			self.bitmapStatus.SetBitmap(self.images.pngGrab)
		elif tid == TOOL_MOVE:
			self.bitmapStatus.SetBitmap(self.images.pngMove)
		elif tid == TOOL_TRIM:
			self.bitmapStatus.SetBitmap(self.images.pngTrim)
		elif tid == TOOL_TRASH:
			self.bitmapStatus.SetBitmap(self.images.pngTrash)
		
	def setHintText(self, tid):
		if tid is None:
			self.hintLine1.SetLabel("")
			self.hintLine2.SetLabel("")
			
		elif tid in toolHintText.keys():
			self.hintLine1.SetLabel(toolHintText[tid][0])
			self.hintLine2.SetLabel(toolHintText[tid][1])
		
	def onCut(self, evt):
		self.clearAllComponents()
		self.selectTool(TOOL_CUT)
		
	def onExamine(self, evt):
		self.clearAllComponents()
		self.selectTool(TOOL_EXAMINE)
		
	def onName(self, evt):
		self.clearAllComponents()
		self.selectTool(TOOL_NAME)
		
	def onWire(self, evt):
		self.dsp.setFixedComponent(None)
		self.currentFixedComponent = None
		self.dsp.setGrowComponent(None)
		self.currentGrowComponent = None
		self.selectTool(TOOL_WIRE)
		
	def onComponent(self, evt):
		self.dsp.setStretchComponent(None)
		self.currentStretchComponent = None
		self.dsp.setGrowComponent(None)
		self.currentGrowComponent = None
		self.selectTool(TOOL_COMPONENT)
		
	def onStretch(self, evt):
		self.dsp.setFixedComponent(None)
		self.currentFixedComponent = None
		self.dsp.setGrowComponent(None)
		self.currentGrowComponent = None
		self.selectTool(TOOL_STRETCH)
		
	def onGrow(self, evt):
		self.dsp.setStretchComponent(None)
		self.currentStretchComponent = None
		self.dsp.setFixedComponent(None)
		self.currentFixedComponent = None
		self.selectTool(TOOL_GROW)
		
	def onGrab(self, evt):
		self.clearAllComponents()
		self.selectTool(TOOL_GRAB) 
		
	def onMove(self, evt):
		dlg = MoveDlg(self, self.pb.getSize(), self.settings)
		rc = dlg.ShowModal()
		failedMoves = []
		if rc == wx.ID_OK:
			self.dx, self.dy = dlg.getValues()
			self.clearAllComponents()
			self.selectTool(TOOL_MOVE) 
		elif rc == wx.ID_EXECUTE:
			self.dx, self.dy = dlg.getValues()
			failedMoves = self.moveAllComponents([self.dx, self.dy])
			
		dlg.Destroy()
		
		if len(failedMoves) != 0:
			print "%d failed moves" % len(failedMoves)
			for f in failedMoves:
				print "  %s" % f
		
	def onTrim(self, evt):
		dlg = TrimDlg(self, self.settings)
		dlg.ShowModal()
		dlg.Destroy()
		
	def trimRight(self):
		if self.pb.trimRight():
			self.dsp.reSize()
			self.createPBView()
		
	def growRight(self):
		if self.pb.growRight():
			self.dsp.reSize()
			self.createPBView()
		
	def trimBottom(self):
		if self.pb.trimBottom():
			self.dsp.reSize()
			self.createPBView()
		
	def growBottom(self):
		if self.pb.growBottom():
			self.dsp.reSize()
			self.createPBView()
		
	def trimLeft(self):
		if self.pb.trimLeft():
			self.moveAllComponents([-1, 0])
			self.dsp.reSize()
			self.createPBView()
		
	def growLeft(self):
		if self.pb.growLeft():
			self.moveAllComponents([1, 0])
			self.dsp.reSize()
			self.createPBView()
			
	def trimTop(self):
		if self.pb.trimTop():
			self.moveAllComponents([0, -1])
			self.dsp.reSize()
			self.createPBView()
			
	def growTop(self):
		if self.pb.growTop():
			self.moveAllComponents([0, 1])
			self.dsp.reSize()
			self.createPBView()
		
	def onTrash(self, evt):
		self.clearAllComponents()
		self.selectTool(TOOL_TRASH) 
		
	def clearAllComponents(self):	 
		self.dsp.setStretchComponent(None)
		self.currentStretchComponent = None
		self.dsp.setFixedComponent(None)
		self.currentFixedComponent = None
		self.dsp.setGrowComponent(None)
		self.currentGrowComponent = None
		
	def selectTool(self, tid, newComponent=True):
		self.selectedTool = tid
		self.setHintText(tid)
		self.setStatusBitmap(tid)
		self.dsp.setHiLightedNet(None)
		self.dsp.refresh()

		if newComponent:	   
			if tid == TOOL_COMPONENT:
				self.currentFixedComponent = self.newFixedComponent()
				self.dsp.setFixedComponent(self.currentFixedComponent)
			elif tid == TOOL_STRETCH:
				self.currentStretchComponent = self.newStretchComponent()
				self.dsp.setStretchComponent(self.currentStretchComponent)
			elif tid == TOOL_WIRE:
				self.currentStretchComponent = self.newStretchComponent(WIRENAME)
				self.dsp.setWireColor(self.wireColor)
				self.dsp.setStretchComponent(self.currentStretchComponent)
			elif tid == TOOL_GROW:
				self.currentGrowComponent = self.newGrowComponent()
				self.dsp.setGrowComponent(self.currentGrowComponent)

	def onColor(self, evt):
		self.chooseColor(evt)
		self.onWire(None)
		
	def onChooseComponent(self, evt):
		dlg = wx.SingleChoiceDialog(
				self, 'Choose component to add to circuit', 'Component Type',
				self.fixedComponentTypes, 
				wx.CHOICEDLG_STYLE
				)

		if dlg.ShowModal() == wx.ID_OK:
			self.currentFixedComponentChoice = dlg.GetStringSelection()
			if not self.currentFixedComponent is None:
				self.currentFixedComponent = self.newFixedComponent()
				self.dsp.setFixedComponent(self.currentFixedComponent)

		dlg.Destroy()
		self.onComponent(None)
		
	def onChooseStretch(self, evt):
		dlg = wx.SingleChoiceDialog(
				self, 'Choose component to add to circuit', 'Component Type',
				sorted(self.stretchComponentNames), 
				wx.CHOICEDLG_STYLE
				)

		if dlg.ShowModal() == wx.ID_OK:
			self.currentStretchName = dlg.GetStringSelection()
			self.currentStretchComponent = self.newStretchComponent()
			self.dsp.setStretchComponent(self.currentStretchComponent)

		dlg.Destroy()
		self.onStretch(None)
		
	def onChooseGrow(self, evt):
		dlg = wx.SingleChoiceDialog(
				self, 'Choose component to add to circuit', 'Component Type',
				sorted(self.growComponentNames), 
				wx.CHOICEDLG_STYLE
				)
		
		if dlg.ShowModal() == wx.ID_OK:
			self.currentGrowComponentChoice = dlg.GetStringSelection()
			self.currentGrowComponent = self.newGrowComponent()
			self.dsp.setGrowComponent(self.currentGrowComponent)
			
		dlg.Destroy()
		self.onGrow(None)

	def newFixedComponent(self):
		c, self.currentComponentPrefix = self.fixedComponentList.getComponent(self.currentFixedComponentChoice)
		return c

	def newStretchComponent(self, nm = None):
		if nm is None:
			nm = self.currentStretchName
		c, self.currentComponentPrefix = self.stretchComponentList.getComponent(nm)
		return c
	
	def newGrowComponent(self):
		c, self.currentComponentPrefix = self.growComponentList.getComponent(self.currentGrowComponentChoice)
		return c

	def holeClick(self, pos):
		self.dsp.selectHole(pos[0], pos[1])
		
	def rightClick(self, pos):
		if self.selectedTool == TOOL_COMPONENT:
			self.fixedComponentList.nextView(self.currentFixedComponent)
			self.dsp.refresh()
		elif self.selectedTool in [TOOL_STRETCH, TOOL_WIRE]:
			self.currentStretchComponent.setP1(pos)
			self.currentStretchComponent.setP2(pos)
			self.dsp.refresh()
		elif self.selectedTool == TOOL_GROW:
			self.currentGrowComponent.setP1(pos)
			self.currentGrowComponent.setP2(pos)
			self.dsp.refresh()


		
	def holeDrag(self, p1, p2):
		if self.selectedTool == TOOL_CUT:
			dx = p2[0] - p1[0]
			dy = p2[1] - p1[1]
			dcut = None
			if dx == 0 and (dy == 1 or dy == -1):
				dcut = 'v'
			elif dy == 0 and (dx == 1 or dx == -1):
				dcut = 'h'
				
			if not dcut is None:
				if self.pb.sameTrace(p1, p2):
					if dcut == 'v':
						self.pb.addVCut(p1[0], p1[1], p2[1])
					else:
						self.pb.addHCut(p1[0], p2[0], p1[1])
					self.dsp.refresh()
				else:
					if dcut == 'v':
						rc = self.pb.delVCut(p1[0], p1[1], p2[1])
					else:
						rc = self.pb.delHCut(p1[0], p2[0], p1[1])
					if not rc:
						if not self.pb.addJumper(p1, p2):
							self.pb.delJumper(p1, p2)
					self.dsp.refresh()
		

	def holeDoubleClick(self, pos):
		if self.selectedTool == TOOL_CUT:
			self.doBreak(pos)
		elif self.selectedTool == TOOL_EXAMINE:
			self.doExamine(pos)
		elif self.selectedTool == TOOL_NAME:
			self.doName(pos)
		elif self.selectedTool == TOOL_WIRE:
			self.doStretchComponent(pos, WIRENAME)
		elif self.selectedTool == TOOL_COMPONENT:
			self.doFixedComponent(pos)
		elif self.selectedTool == TOOL_STRETCH:
			self.doStretchComponent(pos)
		elif self.selectedTool == TOOL_GROW:
			self.doGrowComponent(pos)
		elif self.selectedTool == TOOL_GRAB:
			self.doGrab(pos)
		elif self.selectedTool == TOOL_MOVE:
			self.doMove(pos)
		elif self.selectedTool == TOOL_TRASH:
			self.doTrash(pos)
			
	def doStretchComponent(self, pos, nm=None):
		if self.pb.occupied(pos):
			self.setStatusText("Position is already occupied")
			return
		
		if self.pb.noTrace(pos):
			self.setStatusText("No trace at that position")
			return

		if nm == WIRENAME:
			self.dsp.setWireColor(self.wireColor)

		pt = self.currentStretchComponent.getP1()
		if pt is None:
			self.currentStretchComponent.setP1(pos)
			self.currentStretchComponent.setP2(pos)

		else:
			if pos[0] == pt[0] and pos[1] == pt[1]:
				self.setStatusText("Cannot start and end on the same position")
				return
			
			if self.pb.sameTrace(pos, pt):
				# re-anchor
				self.currentStretchComponent.setP1(pos)
				self.currentStretchComponent.setP2(pos)

			elif nm == WIRENAME:
				self.currentStretchComponent.setP2(pos)
				wid = compID.generateID(self.currentComponentPrefix) 
				self.currentStretchComponent.setID(wid)
				self.pb.addWire(self.currentStretchComponent, self.wireColor)
				self.currentStretchComponent = self.newStretchComponent(WIRENAME)
				self.dsp.setStretchComponent(self.currentStretchComponent)
				
			else:
				self.currentStretchComponent.setP2(pos)
				nm = compID.generateID(self.currentComponentPrefix) 
				self.currentStretchComponent.setID(nm)
				self.pb.addStretchComponent(self.currentStretchComponent)
				self.currentStretchComponent = self.newStretchComponent()
				self.dsp.setStretchComponent(self.currentStretchComponent)
		self.dsp.refresh()
			
	def doGrowComponent(self, pos):
		if self.pb.occupied(pos):
			self.setStatusText("Position is already occupied")
			return
		
		if self.pb.noTrace(pos):
			self.setStatusText("no Trace at that position")
			return

		pt = self.currentGrowComponent.getP1()
		if pt is None:
			self.currentGrowComponent.setP1(pos)
			self.currentGrowComponent.setP2(pos)

		else:
			self.dsp.checkGrowEnd(pos)
			nm = compID.generateID(self.currentComponentPrefix) 
			self.currentGrowComponent.setID(nm)
			self.pb.addGrowComponent(self.currentGrowComponent)
			self.currentGrowComponent = self.newGrowComponent()
			self.dsp.setGrowComponent(self.currentGrowComponent)
		self.dsp.refresh()
			
	def doFixedComponent(self, pos):
		if self.currentFixedComponent is None:
			return
		
		cx = self.currentFixedComponent.getConnections()
		ncols, nrows = self.pb.getSize()
		for p in cx:
			if (pos[0]+p[0] >= ncols or pos[1]+p[1] >= nrows or
					pos[0]+p[0] < 0 or pos[1]+p[1] < 0):
				self.setStatusText("Component goes beyond board edge")
				return
			if self.pb.occupied([pos[0]+p[0], pos[1]+p[1]]):
				self.setStatusText("Position(s) already occupied")
				return
			if self.pb.noTrace([pos[0]+p[0], pos[1]+p[1]]):
				self.setStatusText("no Trace at that position")
				return

		self.currentFixedComponent.setAnchor(pos)

		nm = compID.generateID(self.currentComponentPrefix) 
		self.currentFixedComponent.setID(nm)  
		cv = self.currentFixedComponent.getView()		
		self.pb.addComponent(self.currentFixedComponent)
		self.currentFixedComponent = self.newFixedComponent()
		self.currentFixedComponent.setAnchor(pos)
		self.fixedComponentList.setView(self.currentFixedComponent, cv)
		self.dsp.setFixedComponent(self.currentFixedComponent)

	def doExamine(self, pos):
		if self.pb.noTrace(pos):
			self.setStatusText("No trace at that position")
			return
		
		self.dsp.setHiLightedNet(pos)
		self.dsp.refresh()
		
	def doName(self, pos):
		c, cclass = self.pb.findByPosition(pos)
		if c is None:
			return
		
		if cclass == CLASS_WIRE:
			return
		
		dlg = InfoDialog(self, c.getID(), c.getName(), c.getValue())
		rc = dlg.ShowModal()
		if rc == wx.ID_OK:
			n,v = dlg.getData()
			
			c.setName(n)
			c.setValue(v)
			self.pb.setModified()
			
		dlg.Destroy()
	
	def doBreak(self, pos):
		if self.pb.occupied(pos, covered=False):
			self.setStatusText("Position is occupied")
			return
		
		if not self.pb.traceRemovable(pos):
			self.setStatusText("Cannot remove/replace trace at this location")
			return
		
		if self.pb.traceRemoved(pos):
			self.pb.traceReplace(pos)
		else:
			self.pb.traceRemove(pos)
		
		self.dsp.refresh()
		
	def doGrab(self, pos):
		c, cclass = self.pb.findByPosition(pos, True)
		if c is None:
			return
		
		if cclass == CLASS_WIRE:
			self.dsp.setFixedComponent(None)
			self.currentFixedComponent = None
			self.dsp.setGrowComponent(None)
			self.currentGrowComponent = None

			p1 = c.getP1()
			p2 = c.getP2()
			self.wireColor = c.getColor()
			c = self.newStretchComponent(WIRENAME)
			if p2 == pos:
				c.setP1(p1)
				c.setP2(p2)
			else:
				c.setP1(p2)
				c.setP2(p1)
			
			self.currentStretchComponent = c
			self.dsp.setWireColor(self.wireColor)
			self.dsp.setStretchComponent(self.currentStretchComponent)

			self.selectTool(TOOL_WIRE, False)

		elif cclass == CLASS_FIXED:
			self.dsp.setStretchComponent(None)
			self.currentStretchComponent = None
			self.dsp.setGrowComponent(None)
			self.currentGrowComponent = None
			self.getIDPrefix(c)
			compID.returnID(c.getID())
			c.setID(None)
			self.currentFixedComponent = c
			self.dsp.setFixedComponent(self.currentFixedComponent)
			self.selectTool(TOOL_COMPONENT, False)

		elif cclass == CLASS_STRETCH:
			self.dsp.setFixedComponent(None)
			self.currentFixedComponent = None
			self.dsp.setGrowComponent(None)
			self.currentGrowComponent = None
			p2 = c.getP2()
			if p2 != pos:
				# reanchor from the other end
				p1 = c.getP1()
				c.setP2(p1)
				c.setP1(p2)
				
			self.getIDPrefix(c)
			compID.returnID(c.getID())
			c.setID(None)
			self.currentStretchComponent = c
			self.dsp.setStretchComponent(self.currentStretchComponent)
			self.selectTool(TOOL_STRETCH, False)
			
		elif cclass == CLASS_GROW:
			self.dsp.setStretchComponent(None)
			self.currentStretchComponent = None
			self.dsp.setFixedComponent(None)
			self.currentFixedComponent = None
			
			# calculate new anchor based on where within the component the click occurred
			p1 = c.getP1()
			p2 = c.getP2()
			minx = p1[0]
			maxx = p2[0]
			if maxx < minx:
				minx = p2[0]
				maxx = p1[0]
			midx = (maxx - minx)/2 + minx
			
			miny = p1[1]
			maxy = p2[1]
			if maxy < miny:
				miny = p2[1]
				maxy = p1[1]
			midy = (maxy - miny)/2 + miny
			
			#anchor should be on the opposite side from where we selected
			if pos[0] < midx:
				xa = maxx
				xb = minx
			else:
				xa = minx
				xb = maxx
			if pos[1] < midy:
				ya = maxy
				yb = miny
			else:
				ya = miny
				yb = maxy
				
			c.setP1([xa, ya])
			c.setP2([xb, yb])

			self.getIDPrefix(c)
			compID.returnID(c.getID())
			c.setID(None)
			self.currentGrowComponent = c
			self.dsp.setGrowComponent(self.currentGrowComponent)
			self.selectTool(TOOL_GROW, False)
			
		else:
			print "unknown component class"
			return
		
	def doMove(self, pos):
		c, cclass = self.pb.findByPosition(pos, False)
		self.moveComponent(c, cclass, [self.dx, self.dy])
		
	def moveAllComponents(self, delta):
		failedMoves = []
		for c in self.pb.getComponentList():
			if not self.moveComponent(c, CLASS_FIXED, delta, True):
				failedMoves.append(c.getID())
			
		for c in self.pb.getStretchComponentList():
			if not self.moveComponent(c, CLASS_STRETCH, delta, True):
				failedMoves.append(c.getID())
			
		for c in self.pb.getWireList():
			if not self.moveComponent(c, CLASS_WIRE, delta, True):
				failedMoves.append(c.getID())
			
		for c in self.pb.getGrowComponentList():
			if not self.moveComponent(c, CLASS_GROW, delta, True):
				failedMoves.append(c.getID())
			
		return failedMoves


		
	def moveComponent(self, c, cclass, delta, silent=False):
		if c is None:
			return
		
		dx = delta[0]
		dy = delta[1]

		if cclass in [CLASS_WIRE, CLASS_STRETCH]:
			self.dsp.setFixedComponent(None)
			self.currentFixedComponent = None
			self.dsp.setGrowComponent(None)
			self.currentGrowComponent = None
			
			p1 = c.getP1()
			p2 = c.getP2()
			
			np1 = [p1[0]+dx, p1[1]+dy]
			np2 = [p2[0]+dx, p2[1]+dy]

			if self.pb.outOfBounds(np1):
				if not silent:
					self.setStatusText("New position A is off of the board")
				return False
			
			if self.pb.occupied(np1, comp=c):
				if not silent:
					self.setStatusText("New position A is already occupied")
				return False
			
			if self.pb.noTrace(np1):
				if not silent:
					self.setStatusText("No trace at new position A")
				return False

			if self.pb.outOfBounds(np2):
				if not silent:
					self.setStatusText("New position B is off of the board")
				return False

			if self.pb.occupied(np2, comp=c):
				if not silent:
					self.setStatusText("New position B is already occupied")
				return False
			
			if self.pb.noTrace(np2):
				if not silent:
					self.setStatusText("No trace at new position B")
				return False

			c.setP1(np1)
			c.setP2(np2)

			self.dsp.refresh()
			return True
			
		elif cclass == CLASS_FIXED:
			self.dsp.setStretchComponent(None)
			self.currentStretchComponent = None
			self.dsp.setGrowComponent(None)
			self.currentGrowComponent = None
			
			ap = c.getAnchor()
			
			for p in c.getCovered():
				np = [p[0] + ap[0] + dx, p[1]+ap[1] + dy]
				if self.pb.outOfBounds(np):
					if not silent:
						self.setStatusText("Component will be off of the board")
					return False

				if self.pb.occupied(np, comp=c):
					if not silent:
						self.setStatusText("New position is already occupied")
					return False
			
				if self.pb.noTrace(np):
					if not silent:
						self.setStatusText("No trace at new position")
					return False
				
			c.setAnchor([ap[0]+dx, ap[1]+dy])
			
			self.dsp.refresh()
			return True

		elif cclass == CLASS_GROW:
			self.dsp.setStretchComponent(None)
			self.currentStretchComponent = None
			self.dsp.setFixedComponent(None)
			self.currentFixedComponent = None

			p1 = c.getP1()
			p2 = c.getP2()
			
			minx = min(p1[0], p2[0])
			maxx = max(p1[0], p2[0])
			miny = min(p1[1], p2[1])
			maxy = max(p1[1], p2[1])
			
			for px in range(minx, maxx+1):
				for py in range(miny, maxy+1):
					np = [px + dx, py + dy]
					if self.pb.outOfBounds(np):
						if not silent:
							self.setStatusText("Component will be off of the board")
						return False
	
					if self.pb.occupied(np, comp=c):
						if not silent:
							self.setStatusText("New position is already occupied")
						return False
				
					if self.pb.noTrace(np):
						if not silent:
							self.setStatusText("No trace at new position")
						return False
					
			c.setP1([p1[0]+dx, p1[1]+dy])
			c.setP2([p2[0]+dx, p2[1]+dy])
			
			self.dsp.refresh();
			return True
			
		
	def getIDPrefix(self, c):
		try:
			cid = c.getID()
		except:
			self.currentComponentPrefix = "?"
			return
		self.currentComponentPrefix = rePrefix.match(cid).group()
		
	def doTrash(self, pos):
		if not self.pb.deleteByPosition(pos):
			self.setStatusText("Nothing at that position")
			return
		
		self.dsp.refresh()
		
	def reportCoordinate(self, pos):
		if pos == self.lastReport:
			return
		
		self.lastReport = pos
		
		
		c, ct = self.pb.findByPosition(pos)
		
		text = "(%s,%d)" % (pos[0], pos[1])
		if (not c is None) and (ct != CLASS_WIRE):
			text += "   " + c.getID()
			s = c.getName().strip()
			if s != "":
				text += "  " + s

			s = c.getValue().strip()
			if s != "":
				text += " (" + s + ")"   

		self.setStatusText(text)
		
		if not self.currentStretchComponent is None:
			self.dsp.checkStretchEnd(pos)
			
		if not self.currentGrowComponent is None:
			rc = self.dsp.checkGrowEnd(pos)
			if rc == OV_OVERLAP:
				self.setStatusText("Components would overlap")
			elif rc == OV_SKIPPED_HOLE:
				self.setStatusText("Component would extend over region with no holes")

		if not self.currentFixedComponent is None:
			self.currentFixedComponent.setAnchor(pos)
			self.dsp.refresh()
			
	def chooseColor(self, evt):
		dlg = wx.ColourDialog(self)
		dlg.GetColourData().SetChooseFull(True)

		if dlg.ShowModal() == wx.ID_OK:
			rgb = dlg.GetColourData().GetColour().Get()
			self.wireColor = wx.Colour(rgb[0], rgb[1], rgb[2])
			self.dsp.setWireColor(self.wireColor)

		dlg.Destroy()
		
	def onSave(self, evt):
		if self.fileName is None:
			self.onSaveAs(None)
			return
		self.saveToFile(self.fileName)
		
	def onSaveAs(self, evt):
		dfn = ""
		if not self.fileName is None:
			dfn = self.fileName
			
		dlg = wx.FileDialog(
			self, message="Save proto board as ...", defaultDir=os.getcwd(), 
			defaultFile=dfn, wildcard=wildcard, style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT
			)
		
		rc = dlg.ShowModal()
		if rc == wx.ID_OK:
			path = dlg.GetPath()
			
		dlg.Destroy()
		
		if rc != wx.ID_OK:
			return
		
		if not path.lower().endswith(".pb"):
			path += ".pb"
			
		if self.saveToFile(path):
			self.fileName = path
			self.updateTitle()
		
	def saveToFile(self, fn):
		try:
			fp = open(fn, "w")
			fp.write(self.pb.getXml())
			fp.write("\n")
			fp.close()
		except:
			dlg = wx.MessageDialog(self, 'Error writing to file ' + fn,
				'Save Error', wx.OK | wx.ICON_ERROR)
			dlg.ShowModal()
			dlg.Destroy()
			return False

		self.pb.setModified(False)
		dlg = wx.MessageDialog(self, 'Proto Board saved to ' + fn,
			'Saved', wx.OK | wx.ICON_INFORMATION)
		dlg.ShowModal()
		dlg.Destroy()
		return True

	def onClose(self, evt):
		if self.pb.isModified():
			dlg = wx.MessageDialog(self, 'Are you sure you want to exit?\nPending changes will be lost',
				'Changes pending',
				wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
			rc = dlg.ShowModal()
			dlg.Destroy()
			
			if rc == wx.ID_NO:
				return
			
		self.parent.onEditorClose()
		
	def onPrint(self, evt):
		self.printData = wx.PrintData()
		self.printData.SetPaperId(wx.PAPER_LETTER)
		self.printData.SetPrintMode(wx.PRINT_MODE_PRINTER)

		pdd = wx.PrintDialogData(self.printData)
		pdd.SetToPage(2)
		printer = wx.Printer(pdd)
		printout = PBPrint(self.dsp, self.fileName)

		if not printer.Print(self, printout, True):
			rc = printer.GetLastError()
			if rc == wx.PRINTER_ERROR:
				wx.MessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wx.OK)
		else:
			self.printData = wx.PrintData( printer.GetPrintDialogData().GetPrintData() )
		printout.Destroy()
		
	def onPrintPreview(self, evt):
		data = wx.PrintDialogData(self.printData)
		printout = PBPrint(self.dsp, self.fileName)
		printout2 = PBPrint(self.dsp, self.fileName)
		self.preview = wx.PrintPreview(printout, printout2, data)

		if not self.preview.Ok():
			rc = self.preview.GetLastError()
			if rc == wx.PRINTER_ERROR:
				wx.MessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wx.OK)
				return

		title = "Print Preview: "
		if self.fileName is None:
			title += "<untitled>"
		else:
			title += self.fileName
		pfrm = wx.PreviewFrame(self.preview, self.parent, title)

		pfrm.Initialize()
		pfrm.SetPosition(self.GetPosition())
		pfrm.SetSize(self.GetSize())
		pfrm.Show(True)

		
	def onPrintInstr(self, evt):
		pdd = wx.PrintDialogData(self.printData)
		pdd.SetToPage(2)
		printer = wx.Printer(pdd)
		printout = PBInstructionsPrint(self.pb)

		if not printer.Print(self, printout, True):
			rc = printer.GetLastError()
			if rc == wx.PRINTER_ERROR:
				wx.MessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wx.OK)
		else:
			self.printData = wx.PrintData( printer.GetPrintDialogData().GetPrintData() )
		printout.Destroy()