class App(Frame): def __init__(self, master, settings): self.master = master self.settings = settings Frame.__init__(self, master, relief=SUNKEN, bd=2) self.master.protocol('WM_DELETE_WINDOW', self.quitApp) self.objNumber = 1 self.modified = False self.preview = True self.lbMap = [] self.lbSelection = None self.stlFrame = StlFrame(self, scale=settings.scale) self.stlFrame.grid(row=1, column=1, rowspan=4, sticky=N) self.lbFrame = LabelFrame(self, text=" File List ") self.lbFrame.grid(row=1, column=2, padx=5, pady=5, sticky=N) self.bFrame = Frame(self) self.bFrame.grid(row=2, column=2, padx=5, sticky=N) self.lbFiles = Listbox(self.lbFrame, width=60) self.lbFiles.grid(row=1,column=1,sticky=N+E+W+S) self.sbFiles = Scrollbar(self.lbFrame, command=self.lbFiles.yview, orient="vertical") self.sbFiles.grid(column=2, row=1, sticky=N+S+E) self.lbFiles.config(yscrollcommand=self.sbFiles.set) self.lbFiles.bind("<ButtonRelease>", self.doClickList) self.imgAdd = self.loadImage("add.gif") self.bAdd = Button(self.bFrame, image=self.imgAdd, width=48, height=48, command=self.doAdd) self.bAdd.grid(row=1, column=1, pady=2, padx=2, sticky=N) createToolTip(self.bAdd, "Add an STL file to the plate") self.imgClone = self.loadImage("clone.gif") self.bClone = Button(self.bFrame, image=self.imgClone, width=48, height=48, command=self.doClone, state=DISABLED) self.bClone.grid(row=1, column=2, pady=2, padx=2, sticky=N) createToolTip(self.bClone, "Clone the selected object") self.imgDel = self.loadImage("del.gif") self.bDel = Button(self.bFrame, image=self.imgDel, width=48, height=48, command=self.doDelete, state=DISABLED) self.bDel.grid(row=1, column=3, pady=2, padx=2, sticky=N) createToolTip(self.bDel, "Delete the selected object") self.imgDelAll = self.loadImage("delall.gif") self.bDelAll = Button(self.bFrame, image=self.imgDelAll, width=48, height=48, command=self.doDelAll, state=DISABLED) self.bDelAll.grid(row=1, column=4, pady=2, padx=2, sticky=N) createToolTip(self.bDelAll, "Delete all objects from the plate") self.imgArrange = self.loadImage("arrange.gif") self.bArrange = Button(self.bFrame, image=self.imgArrange, width=48, height=48, command=self.doArrange, state=DISABLED) self.bArrange.grid(row=2, column=1, pady=2, padx=2, sticky=N) createToolTip(self.bArrange, "Arrange the objects to fit") self.imgExport = self.loadImage("export.gif") self.bExport = Button(self.bFrame, image=self.imgExport, width=48, height=48, command=self.doExport, state=DISABLED) self.bExport.grid(row=2, column=4, pady=2, padx=2, sticky=N) createToolTip(self.bExport, "Save the plate to an STL file") self.cbPrev = IntVar() if self.settings.preview: self.cbPrev.set(1) else: self.cbPrev.set(0) self.cbPreview = Checkbutton( self.bFrame, text="Preview", variable=self.cbPrev, command=self.doCbPreview) self.cbPreview.grid(row=3, column=2, pady=5) def doCbPreview(self): if self.cbPrev.get() == 0: self.preview = False else: self.preview = True self.settings.preview = self.preview self.settings.setModified() def loadImage(self, fn): return PhotoImage(file=os.path.join(cmd_folder, "images", fn)) def checkModified(self): if self.modified: if not askyesno("Exit?", "Lose unsaved changes?"): return True return False def quitApp(self): if self.checkModified(): return False self.destroy() self.master.quit() return True def doAdd(self): while True: confirmed = False fn = askopenfilename(filetypes=[("STL files", "*.stl")], initialdir=self.settings.lastdirectory) if fn: if self.preview: subprocess.Popen([self.settings.viewer, fn]) if askyesno("Confirm Add", "Add this object?"): confirmed = True else: confirmed = True else: return if confirmed: self.modified = True self.filename = fn dn = os.path.dirname(fn) if dn != self.settings.lastdirectory: self.settings.lastdirectory = dn self.settings.setModified() name = "OBJECT%03d" % self.objNumber index = self.lbFiles.index(END) self.lbFiles.insert(END, "%2d: %s" % (self.objNumber, fn)) if self.lbSelection is not None: self.lbFiles.selection_clear(self.lbSelection) self.lbFiles.selection_set(index) self.lbSelection = index self.objNumber += 1 stlFile = stltool.stl(filename=fn, name=name) self.lbMap.append(stlFile) self.stlFrame.addStl(stlFile, highlight=True) self.bDel.config(state=NORMAL) self.bDelAll.config(state=NORMAL) self.bExport.config(state=NORMAL) self.bArrange.config(state=NORMAL) self.bClone.config(state=NORMAL) return def doClone(self): stlObj = self.stlFrame.getSelectedStl() if stlObj is None: return name = "OBJECT%03d" % self.objNumber index = self.lbFiles.index(END) self.lbFiles.insert(END, "%2d: %s" % (self.objNumber, stlObj.filename)) if self.lbSelection is not None: self.lbFiles.selection_clear(self.lbSelection) self.lbFiles.selection_set(index) self.lbSelection = index self.objNumber += 1 s = stlObj.clone(name=name) self.lbMap.append(s) self.stlFrame.addStl(s, highlight=True) def doDelete(self): self.modified = True if self.lbSelection is not None: del self.lbMap[self.lbSelection] self.lbFiles.delete(self.lbSelection) self.lbSelection = None self.stlFrame.delStl() if self.stlFrame.countObjects() == 0: self.modified = False self.bDel.config(state=DISABLED) self.bDelAll.config(state=DISABLED) self.bExport.config(state=DISABLED) self.bArrange.config(state=DISABLED) self.bClone.config(state=DISABLED) def doDelAll(self): if askyesno("Confirm Delete All", "Are you sure you want to delete all objects?"): self.modified = False self.stlFrame.delAll() self.bDel.config(state=DISABLED) self.bDelAll.config(state=DISABLED) self.bExport.config(state=DISABLED) self.bArrange.config(state=DISABLED) self.bClone.config(state=DISABLED) self.lbFiles.delete(0, END) self.lbMap = [] self.lbSelection = None self.objNumber = 1 def doExport(self): self.stlFrame.commit() objs = self.stlFrame.getStls() facets = [] for o in objs: facets.extend(o.facets) fn = asksaveasfilename(parent=self, title="Export to File", filetypes=[("STL files", "*.stl")], initialdir=self.settings.lastdirectory, defaultextension=".stl") if not fn: return stltool.emitstl(fn, facets=facets, objname="PlaterObject", binary=False) self.modified = False def setModified(self, flag=True): self.modified = flag def setSelection(self, stlObj): found = False for i in range(len(self.lbMap)): o = self.lbMap[i] if o.name == stlObj.name: found = True break if not found: return if self.lbSelection is not None: self.lbFiles.selection_clear(self.lbSelection) self.lbFiles.selection_set(i) self.lbSelection = i def doClickList(self, *arg): items = self.lbFiles.curselection() try: i = int(items[0]) except: return if i < 0 or i >= len(self.lbMap): return self.stlFrame.setSelectionByName(self.lbMap[i].name) def doArrange(self): self.stlFrame.arrange()