from life import Game from Tkinter import * from FileDialog import LoadFileDialog, SaveFileDialog import string inmain = __name__ == '__main__' class tklife: def __init__(self, master, cols=100, rows=80, cellwidth=8, cellheight=8, **kw): self.master = master self.rows = rows self.cols = cols self.cellwidth = cellwidth self.cellheight = cellheight self.add_buttons() self.canvas = Canvas(master, width=self.cols*self.cellwidth, height=self.rows*self.cellheight, relief=SUNKEN, borderwidth=2) if inmain: self.canvas.pack(expand=1, fill=BOTH) else: self.canvas.pack(side=LEFT) self.canvas.bind('', self.configure_event) self.canvas.bind('<1>', self.mouse_down_event) self.game = Game(width=cols, height=rows) self.game.letter_r(row=rows/2, col=cols/2) self.clearbits() self.sid = None self.update() def add_buttons(self): self.bbframe = Frame(self.master) self.bbframe.pack(fill=BOTH, side=BOTTOM) self.bframe = Frame(self.master) self.bframe.pack(fill=BOTH, side=BOTTOM) if inmain: self.quit_button = Button(self.bframe, text="Quit", command=self.quit_command) self.quit_button.pack(side=LEFT) self.clear_button = Button(self.bframe, text="Clear", command=self.clear_command) self.clear_button.pack(side=LEFT) self.load_button = Button(self.bframe, text="Load...", command=self.load_command) self.load_button.pack(side=LEFT) self.save_button = Button(self.bframe, text="Save...", command=self.save_command) self.save_button.pack(side=LEFT) self.recenter_button = Button(self.bframe, text="Recenter", command=self.recenter_command) self.recenter_button.pack(side=LEFT) self.step1_button = Button(self.bbframe, text="Step 1", command=self.step1_command) self.step1_button.pack(side=LEFT) self.step_button = Button(self.bbframe, text="Step n", command=self.step_command) self.step_button.pack(side=LEFT) self.go_flag = BooleanVar() self.go_button = Checkbutton(self.bbframe, text="Go", variable=self.go_flag, onvalue="on", offvalue="off", relief=RAISED, borderwidth=2, command=self.go_command) self.go_button.pack(side=LEFT, ipadx=4, ipady=4) self.stepsize_label = Label(self.bbframe, text="Step size:", width=10) self.stepsize_label.pack(side=LEFT) self.stepsize_entry = Entry(self.bbframe, width=5) self.stepsize_entry.insert(0, "1") self.stepsize_entry.pack(side=LEFT) self.iter_label = Label(self.master) self.iter_label.pack(side=TOP, anchor=W) def getstepsize(self): s = self.stepsize_entry.get() try: n = string.atoi(s) if n >= 1: return n except string.atoi_error: pass self.stepsize_entry.delete(0, END) self.stepsize_entry.insert(0, "1") return 1 def quit_command(self): self.master.quit() def clear_command(self): self.game.reset() self.stop_command() self.update() def load_command(self): self.stop_command() fd = LoadFileDialog(self.master) filename = fd.go(pattern="*.lif") if not filename: return try: file = open(filename, "r") self.game.load_from_file(file) except IOError, msg: self.message(msg) return self.resize(self.game.width, self.game.height) def save_command(self): self.stop_command() fd = SaveFileDialog(self.master) filename = fd.go(default="grid.lif") if not filename: return try: file = open(filename, "w") self.game.save_to_file(file) except IOError, msg: self.message(msg) return def message(self, msg): top = Toplevel(self.master) label = Label(top, text=msg) label.pack() ok = Button(top, text="OK", command=top.destroy) ok.pack() def recenter_command(self): self.game.recenter() self.update() def step1_command(self): if self.go_flag.get(): self.stop_command() else: self.move(1) def step_command(self): if self.go_flag.get(): self.stop_command() else: self.move(self.getstepsize()) def stop_command(self): self.go_flag.set("off") self.unschedule() def go_command(self): if self.go_flag.get(): self.schedule() else: self.unschedule() self.master.update_idletasks() def resize(self, cols, rows): self.game.resize(cols, rows) self.cols = cols self.rows = rows self.canvas.config(width=self.cols*self.cellwidth, height=self.rows*self.cellheight) self.update(1) def configure_event(self, event): cols = (self.canvas.winfo_width() - 2*string.atoi(self.canvas['borderwidth'])) / self.cellwidth rows = (self.canvas.winfo_height() - 2*string.atoi(self.canvas['borderwidth'])) / self.cellheight if (cols, rows) != (self.cols, self.rows): self.resize(cols, rows) def mouse_down_event(self, event): self.stop_command() col = (event.x) / self.cellwidth row = (event.y) / self.cellheight if 0 <= row < self.rows and 0 <= col < self.cols: bit = self.game.get(row, col) if bit: self.game.clear(row, col) else: self.game.set(row, col) self.update() def redisplay(self): """Redisplay everything, assuming nothing about display contents.""" self.update(1) def schedule(self): """Schedule the next animation""" self.sid = self.master.after(0, self.animate) def animate(self): """Callback for schedule""" self.sid = None self.move(self.getstepsize()) self.schedule() def unschedule(self): """Canceled the scheduled animation""" if self.sid: self.master.after_cancel(self.sid) self.sid = None def move(self, n=1): """Execute n moves (default 1), and update the display.""" for i in range(n): self.game.move() self.update() def move(self, n=1): """Execute n moves (default 1), and update the display.""" for i in range(n): self.game.move() self.update() def update(self, clear=0): """Update our notion of the state, as well as the display. If the optional 'clear' argument is true, first clear the display (not sure why you would want this, but just in case). """ if clear: self.clearbits() colrange = range(self.cols) for row in range(self.rows): olddata = self.grid[row] newdata = self.game.grid[row] diff = olddata^newdata if diff: bit = self.game.one for col in colrange: if diff & bit: if olddata & bit: self.clearbit(col, row) else: self.setbit(col, row) bit = bit + bit if bit > diff: break self.grid[row] = newdata self.iter_label.config(text=("Iteration: %d" % self.game.iteration)) self.master.update_idletasks() def clearbits(self): self.canvas.delete('all') self.grid = [0]*self.rows self.idmap = {} def clearbit(self, col, row): id = self.idmap[(col, row)] del self.idmap[(col, row)] self.canvas.delete(id) def setbit(self, col, row): cw = self.cellwidth ch = self.cellheight id = self.canvas.create_rectangle( col*cw+1, row*ch+1, (col+1)*cw-1, (row+1)*ch-1, fill='black') self.idmap[(col, row)] = id if inmain: root = Tk() tklife(root) root.mainloop()