class ScrolledCanvas(Frame): """ A scrolling canvas of frames with checkboxes. """ def __init__(self, master, name=None, scrollregion=(0, 0, '5i', '5i'), items=[], window_size=[160, 30], **canvaskw): Frame.__init__(self, master, name=name) self.scrollcanvas = Canvas(self, name='scrollcanvas', scrollregion=scrollregion, **canvaskw) self.yscroll = Scrollbar(self, name='yscroll', command=self.scrollcanvas.yview) self.scrollcanvas['yscrollcommand'] = self.yscroll.set self.yscroll.pack(side=RIGHT, fill=Y) self.scrollcanvas.pack(side=LEFT, fill=BOTH, expand=YES) self.items = dict.fromkeys(items) for n, i in enumerate(items): self.items[i] = {'frame': Frame(self, name=(i.lower() + '_frame'))} self.items[i]['frame'].config(relief=GROOVE, padding=5) self.items[i]['chbx'] = Checkbutton(self.items[i]['frame'], name=(i.lower() + '_chbx')) self.items[i]['chbx']['text'] = i self.items[i]['chbx'].pack(side=LEFT, fill=X) y = window_size[1] / 2 + window_size[1] * n self.items[i]['window'] = self.scrollcanvas.create_window(0, y) self.scrollcanvas.itemconfigure(self.items[i]['window'], window=self.items[i]['frame'], anchor=W, width=window_size[0], height=window_size[1])
class Display(Frame): def __init__(self, master=None): Frame.__init__(self, master) self.canvas = None self.buffer = {} self.pixels = {} self.pack() self.init_display() def init_display(self): self.canvas = Canvas(self.master, width=DISPLAY_W, height=DISPLAY_H, bg='white') self.canvas.pack() for x in range(PIXELS_X): for y in range(PIXELS_Y): pixel_x = ((PIXEL_W + PIXEL_SPACING) * x) + BORDER pixel_y = ((PIXEL_H + PIXEL_SPACING) * y) + BORDER self.buffer[(x, y)] = [0, 0, 0] self.pixels[(x, y)] = self.canvas.create_rectangle( pixel_x, pixel_y, pixel_x + PIXEL_W, pixel_y + PIXEL_H, fill='black', width=0) def set_pixel(self, x, y, r, g, b): self.buffer[(x, y)] = [r, g, b] def clear(): # Clear the display for x in range(8): for x in range(8): self.set_pixel(x, y, 0, 0, 0) self.show() def show_q(self, pixels): x = 0 for idx, pixel in enumerate(pixels): x = idx % 8 y = int(idx / 8) self.canvas.itemconfigure(self.pixels[(x, y)], fill='#' + pixel) x += 1 def show(self): for position, colour in self.buffer.iteritems(): pixel = self.pixels[position] r = hex(colour[0])[2:].zfill(2) g = hex(colour[1])[2:].zfill(2) b = hex(colour[2])[2:].zfill(2) self.canvas.itemconfigure(pixel, fill='#' + r + g + b)
class SimulationStrip(Strip): def __init__(self, length, row_length, led_size=DEFAULT_LED_SIZE): super(SimulationStrip, self).__init__(length) led_window = Tk() led_window.title('LED Simulator') MARGIN = 5 led_size = min( (led_window.winfo_screenwidth() - 2 * MARGIN) / row_length, led_size) num_rows = math.ceil(length / row_length) height = num_rows * led_size + (1 + num_rows) * MARGIN width = led_size * row_length + 2 * MARGIN self.canvas = Canvas(led_window, width=width, height=height) self.canvas.pack() self.leds = [] * length self.leds = [ self.create_rectangle(i, row_length, led_size, MARGIN) for i in xrange(length) ] self.canvas.update() def show(self): for i in xrange(self.length): color = '#%02x%02x%02x' % tuple([(255 * c) / MAX_BRIGHTNESS for c in self[i]]) self.canvas.itemconfigure(self.leds[i], fill=color) self.canvas.update() time.sleep(SHOW_SLEEP_TIME) def create_rectangle(self, index, row_length, led_size, margin): #x0 if (index / row_length) % 2 == 0: x0 = margin + (index % row_length) * led_size else: x0 = margin + (row_length - (index % row_length) - 1) * led_size #y0 y0 = margin + (led_size + margin) * (index / row_length) #x1 if (index / row_length) % 2 == 0: x1 = margin + ((index % row_length) + 1) * led_size else: x1 = margin + (row_length - (index % row_length)) * led_size #y1 y1 = margin + (led_size + margin) * (index / row_length) + led_size return self.canvas.create_rectangle(x0, y0, x1, y1)
class SimulationStrip(Strip): def __init__(self, length, row_length, led_size=DEFAULT_LED_SIZE): super(SimulationStrip, self).__init__(length) led_window = Tk() led_window.title('LED Simulator') MARGIN = 5 led_size = min((led_window.winfo_screenwidth() - 2 * MARGIN) / row_length, led_size) num_rows = math.ceil(length / row_length) height = num_rows * led_size + (1 + num_rows) * MARGIN width = led_size * row_length + 2 * MARGIN self.canvas = Canvas(led_window, width=width, height=height) self.canvas.pack() self.leds = [] * length self.leds = [self.create_rectangle(i, row_length, led_size, MARGIN) for i in xrange(length)] self.canvas.update() def show(self): for i in xrange(self.length): color = '#%02x%02x%02x' % tuple([(255 * c) / MAX_BRIGHTNESS for c in self[i]]) self.canvas.itemconfigure(self.leds[i], fill=color) self.canvas.update() time.sleep(SHOW_SLEEP_TIME) def create_rectangle(self, index, row_length, led_size, margin): #x0 if (index / row_length) % 2 == 0: x0 = margin + (index % row_length) * led_size else: x0 = margin + (row_length - (index % row_length) - 1) * led_size #y0 y0 = margin + (led_size + margin) * (index / row_length) #x1 if (index / row_length) % 2 == 0: x1 = margin + ((index % row_length) + 1) * led_size else: x1 = margin + (row_length - (index % row_length)) * led_size #y1 y1 = margin + (led_size + margin) * (index / row_length) + led_size return self.canvas.create_rectangle(x0, y0, x1, y1)
class App(Frame): """Tkinter App.""" def __init__(self, parent, queue): """Init Tkinter app.""" Frame.__init__(self, parent) self.parent = parent self.parent.wm_attributes('-type', 'dialog') self.queue = queue self.initUI() self.worker() def initUI(self): """Init UI.""" self.parent.title('PySnake') self.canvas = Canvas(self.parent, width=500, height=300, bg='black') self.canvas.pack() self.score = self.canvas.create_text(30, 270, anchor=W, fill='blue', text='Score: 0') self.food = self.canvas.create_rectangle(0, 0, 0, 0, fill='white') self.snake = self.canvas.create_line((0, 0), (0, 0), fill='green', width=10) def worker(self): try: while True: job = self.queue.get_nowait() if job.has_key('snake'): #self.snake = self.canvas.create_line(*job['snake'], fill='green', width=10) points = [x for point in job['snake'] for x in point] self.canvas.coords(self.snake, *points) elif job.has_key('food'): x, y = job['food'] self.canvas.coords(self.food, (x - 5), (y - 5), (x + 5), (y + 5)) elif job.has_key('score'): self.canvas.itemconfigure(self.score, text='Score: {}'.format(job['score'])) elif job.has_key('quit'): self.parent.quit() self.queue.task_done() except Queue.Empty: pass self.after(50, self.worker)
class App(Frame): """Tkinter App.""" def __init__(self, parent, queue): """Init Tkinter app.""" Frame.__init__(self, parent) self.parent = parent self.parent.wm_attributes("-type", "dialog") self.queue = queue self.initUI() self.worker() def initUI(self): """Init UI.""" self.parent.title("PySnake") self.canvas = Canvas(self.parent, width=500, height=300, bg="black") self.canvas.pack() self.score = self.canvas.create_text(30, 270, anchor=W, fill="blue", text="Score: 0") self.food = self.canvas.create_rectangle(0, 0, 0, 0, fill="white") self.snake = self.canvas.create_line((0, 0), (0, 0), fill="green", width=10) def worker(self): try: while True: job = self.queue.get_nowait() if job.has_key("snake"): # self.snake = self.canvas.create_line(*job['snake'], fill='green', width=10) points = [x for point in job["snake"] for x in point] self.canvas.coords(self.snake, *points) elif job.has_key("food"): x, y = job["food"] self.canvas.coords(self.food, (x - 5), (y - 5), (x + 5), (y + 5)) elif job.has_key("score"): self.canvas.itemconfigure(self.score, text="Score: {}".format(job["score"])) elif job.has_key("quit"): self.parent.quit() self.queue.task_done() except Queue.Empty: pass self.after(50, self.worker)
class MemoCaras(Frame): def __init__(self, root): Frame.__init__(self, root) self.grid(column=0, row=0) self.canvas = Canvas(self, width=604, height=480) self.canvas.grid(column=0, row=0, columnspan=2) self.bt_prox = Button(self, text='Próximo', command=self.proximo) self.bt_prox.grid(column=0, row=1, sticky=W) self.nome = Label(self, text='(passe aqui para ver o nome)') self.nome.bind('<Enter>', self.mostra_nome) self.nome.bind('<Leave>', self.esconde_nome) self.nome.grid(column=1, row=1, sticky=EW) self.foto = PhotoImage(file=NOME_ARQ_FOTO) self.canvas.create_image(0, 0, image=self.foto, anchor=NW) self.caras = {} for nome, bbox in pessoas: marca = self.canvas.create_oval(*bbox, outline='green', width=5, state=HIDDEN) self.caras[nome] = marca self.sequencia = [] self.cara_ativa = None def proximo(self): if self.cara_ativa is not None: marca = self.caras[self.cara_ativa] self.canvas.itemconfigure(marca, state=HIDDEN) if len(self.sequencia) == 0: self.sequencia = self.caras.keys() shuffle(self.sequencia) self.cara_ativa = self.sequencia.pop() marca = self.caras[self.cara_ativa] self.canvas.itemconfigure(marca, state=NORMAL) def mostra_nome(self, evento): self.texto_nome = self.nome['text'] self.nome['text'] = self.cara_ativa def esconde_nome(self, evento): self.nome['text'] = self.texto_nome
canvas = Canvas(root, height=h) canvas.pack(fill=BOTH) field_height = h / cell_size field_width = w / cell_size cell_matrix = [] for i in range(field_height): for j in range(field_width): square = canvas.create_rectangle(2 + cell_size * j, 2 + cell_size * i, cell_size + cell_size * j - 2, cell_size + cell_size * i - 2, fill="green") canvas.itemconfigure(square, state=HIDDEN, tags=('hid', '0')) cell_matrix.append(square) fict_square = canvas.create_rectangle(0, 0, 0, 0, state=HIDDEN, tags=('hid', '0')) cell_matrix.append(fict_square) frame = Frame(root) bt1 = Button(frame, text='Eval', command=step) bt2 = Button(frame, text='Clear', command=clear)
class Example(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.buttons = {} self.nodes = {} self.edges = {} self.active_node = None self.active_edge = None self.start = None self.x = None self.y = None self.cycles = None self.show_cycles_only_mode = False self.steps = None self.step_index = None self.parent.title("Demonstrační aplikace - nalezení elementárních cyklů v orientovaném grafu") self.style = Style() self.style.theme_use("default") self.pack(fill=BOTH, expand=1) self.columnconfigure(1, weight=1) self.columnconfigure(3, pad=7) self.rowconfigure(5, weight=1) self.rowconfigure(6, pad=7) self.label = Label(self, text="graf1.graphml") self.label.grid(sticky=W, pady=4, padx=5) self.canvas = Canvas(self) self.canvas.bind('<Double-Button-1>', self.event_add_node) self.canvas.bind('<Button-1>', self.event_add_edge_start) self.canvas.bind('<B1-Motion>', self.event_add_edge_move) self.canvas.bind('<ButtonRelease-1>', self.event_add_edge_end) self.canvas.bind('<Button-3>', self.event_move_node_start) self.canvas.bind('<B3-Motion>', self.event_move_node) self.canvas.pack() self.canvas.grid(row=1, column=0, columnspan=2, rowspan=6, padx=5, sticky=E + W + S + N) self.buttons['start'] = b = Button(self, text="Start", width=15) b.bind('<Button-1>', self.event_start) b.grid(row=1, column=3) self.buttons['next'] = b = Button(self, text=">>", width=15, state=DISABLED) b.bind('<Button-1>', self.event_next_step) b.grid(row=2, column=3, pady=4) self.buttons['prev'] = b = Button(self, text="<<", width=15, state=DISABLED) b.bind('<Button-1>', self.event_prev_step) b.grid(row=3, column=3, pady=4) b = Checkbutton(self, text="Pouze cykly", command=self.event_change_mode) b.grid(row=4, column=3, pady=4) self.buttons['reset'] = b = Button(self, text="Reset", width=15) b.bind('<Button-1>', self.event_reset) b.grid(row=6, column=3) menubar = Menu(self.parent) self.parent.config(menu=menubar) fileMenu = Menu(menubar) fileMenu.add_command(label="Načíst", command=self.onLoad) fileMenu.add_command(label="Uložit", command=self.onSave) fileMenu.add_separator() fileMenu.add_command(label="Konec", command=self.onExit) menubar.add_cascade(label="Soubor", menu=fileMenu) fileMenu = Menu(menubar) fileMenu.add_command(label="O aplikaci", command=self.onAbout) menubar.add_cascade(label="Nápověda", menu=fileMenu) def onExit(self): self.quit() def onLoad(self): fileTypes = [('Soubory typu GraphML', '*.graphml')] dialog = tkFileDialog.Open(self, filetypes=fileTypes) filename = dialog.show() if filename != '': self.readFile(filename) def onSave(self): fileTypes = [('GraphML files', '*.graphml')] dialog = tkFileDialog.SaveAs(self, filetypes=fileTypes) filename = dialog.show() if filename != '': if not filename.endswith(".graphml"): filename += ".graphml" self.writeFile(filename) def onAbout(self): box.showinfo("O aplikaci", "Demonstrace algoritmu nalezení elementárních cyklů v orientovaném grafu podle D. B. Johnsona. \n\n" "Autoři:\n" "Paulík Miroslav\n" "Pavlů Igor\n" "FIT VUT v Brně 2013") def readFile(self, filename): self.reset() try: parser = GraphMLParser() g = parser.parse(filename) except Exception: box.showerror("Chyba při zpracování vstupního souboru", "Chybný formát souboru.") return nodeMap = {} try: for gnode in g.nodes(): nodeMap[gnode.id] = self.__add_node(int(gnode['x']), int(gnode['y'])) except KeyError: box.showerror("Chyba při zpracování vstupního souboru", "Uzlum chybi udaje o pozici (atributy x a y).") self.reset() return try: for gedge in g.edges(): start = nodeMap[gedge.node1.id] end = nodeMap[gedge.node2.id] isCurve = gedge.node1.id == gedge.node2.id self.__add_edge(start, end, isCurve) self.label.configure(text=os.path.basename(filename)) except KeyError: box.showerror("Chyba při zpracování vstupního souboru", "Soubor obsahuje hrany spojujici neexistujici hrany") self.reset() return self.repaint() def writeFile(self, filename): g = Graph() for i in self.nodes: node = self.nodes[i] node.name = str(i) gnode = g.add_node(i) gnode['label'] = i gnode['x'] = node.x gnode['y'] = node.y for i in self.edges: edge = self.edges[i] edge.name = i parser = GraphMLParser() parser.write(g, filename) def repaint(self): for e in self.edges: edge = self.edges[e] self.canvas.itemconfigure(e, fill=edge.color) for v in self.nodes: node = self.nodes[v] self.canvas.itemconfigure(v, fill=node.color) def reset_colors(self): for n in self.nodes: self.nodes[n].color = "white" for e in self.edges: self.edges[e].color = "grey" def reset(self): self.nodes = {} self.edges = {} self.canvas.delete("all") self.buttons['prev'].config(state=DISABLED) self.buttons['next'].config(state=DISABLED) def run(self): x = ElementaryCircuitsDetector(self.nodes, self.edges) x.detect_cycles() self.cycles = x.cycles self.step_index = 0 self.steps = x.get_all_steps() self.algorithm_step_move(0) if len(self.steps) > 0: self.buttons['prev'].config(state=1) self.buttons['next'].config(state=1) def event_reset(self, event): self.reset() def event_prev_step(self, event): if str(self.buttons['prev'].cget("state")) != str(DISABLED): self.algorithm_step_move(-1) def event_next_step(self, event): if str(self.buttons['next'].cget("state")) != str(DISABLED): self.algorithm_step_move(1) def event_start(self, event): self.run() def event_change_mode(self): self.show_cycles_only_mode = not self.show_cycles_only_mode self.run() def event_add_edge_start(self, event): self.x = event.x self.y = event.y def event_add_edge_move(self, event): if self.active_edge is None: self.active_edge = self.canvas.create_line(self.x, self.y, event.x, event.y, arrow="last", width=2) else: x1, y1, x2, y2 = self.canvas.coords(self.active_edge) self.canvas.coords(self.active_edge, x1, y1, event.x, event.y) def event_add_edge_end(self, event): if self.active_edge is None: return x1, y1, x2, y2 = self.canvas.coords(self.active_edge) start = self.__get_node_from_position(x1, y1) end = self.__get_node_from_position(x2, y2) if start is None or end is None: self.canvas.delete(self.active_edge) elif start == end: self.canvas.delete(self.active_edge) edge = Edge(start, start, True) points = edge.get_coords() self.active_edge = self.canvas.create_line(points, width=2, smooth=True, arrow="last") self.canvas.tag_lower(self.active_edge, min(self.nodes.keys())) self.edges[self.active_edge] = edge else: x, y = self.__calculate_edge_end_from_nodes(start, end) self.canvas.coords(self.active_edge, start.x, start.y, x, y) self.canvas.tag_lower(self.active_edge, min(self.nodes.keys())) edge = Edge(start, end) self.edges[self.active_edge] = edge self.active_edge = None self.x = None self.y = None def event_move_node_start(self, event): id = self.__get_id_from_position(event.x, event.y) if id is None: return self.__activate_node(id) self.x = event.x self.y = event.y def event_move_node(self, event): id = self.active_node if id is None: return deltax = event.x - self.x deltay = event.y - self.y self.canvas.move(id, deltax, deltay) self.x = event.x self.y = event.y coord = self.canvas.coords(id) self.nodes[self.active_node].x = (coord[2] - coord[0]) / 2 + coord[0] self.nodes[self.active_node].y = (coord[3] - coord[1]) / 2 + coord[1] self.__repair_edge_starting_in_node(self.nodes[self.active_node]) self.__repair_edge_ending_in_node(self.nodes[self.active_node]) def event_add_node(self, event): id = self.__get_id_from_position(event.x, event.y, reverse=True) if id is None or id not in self.nodes: self.__add_node(event.x, event.y) def __repair_edge_ending_in_node(self, node): list_of_edge_ids = [] for edge_id in self.edges: edge = self.edges[edge_id] if edge.end == node: list_of_edge_ids.append(edge_id) for edge_id in list_of_edge_ids: edge = self.edges[edge_id] x, y = self.__calculate_edge_end_from_nodes(edge.start, edge.end) if edge.is_curve: coords = edge.get_coords() self.canvas.coords(edge_id, coords[0][0], coords[0][1], coords[1][0], coords[1][1], coords[2][0], coords[2][1], coords[3][0], coords[3][1]) else: self.canvas.coords(edge_id, edge.start.x, edge.start.y, x, y) def __repair_edge_starting_in_node(self, node): list_of_edge_ids = [] for edge_id in self.edges: edge = self.edges[edge_id] if edge.start == node: list_of_edge_ids.append(edge_id) for edge_id in list_of_edge_ids: edge = self.edges[edge_id] x, y = self.__calculate_edge_end_from_nodes(edge.start, edge.end) if edge.is_curve: coords = edge.get_coords() self.canvas.coords(edge_id, coords[0][0], coords[0][1], coords[1][0], coords[1][1], coords[2][0], coords[2][1], coords[3][0], coords[3][1]) else: self.canvas.coords(edge_id, edge.start.x, edge.start.y, x, y) def __calculate_edge_end_from_nodes(self, start_node, end_node): diffx = end_node.x - start_node.x diffy = end_node.y - start_node.y distance = math.sqrt(diffx ** 2 + diffy ** 2) if distance > 0: ratio = NODE_SIZE / 2 / distance x = end_node.x - diffx * ratio y = end_node.y - diffy * ratio return x, y return end_node.x, end_node.y def __activate_node(self, id): self.__deactivate_node() if id in self.nodes: self.active_node = id def __deactivate_node(self): self.active_node = None def __get_id_from_position(self, x, y, reverse=False): overlaping = self.canvas.find_overlapping(x, y, x, y) if len(overlaping) > 0: if reverse: return overlaping[-1] else: return overlaping[0] else: return None def __get_node_from_position(self, x, y): id = self.__get_id_from_position(x, y) if id is not None and id in self.nodes: return self.nodes[id] else: return None def __add_node(self, x, y): node = Node(x, y) id = self.canvas.create_oval(node.get_coord(), fill="blue") self.nodes[id] = node return node def __add_edge(self, start, end, is_curve=False): edge = Edge(start, end, is_curve) if is_curve: id = self.canvas.create_line(edge.get_coords(), width=2, smooth=True, arrow="last") else: id = self.canvas.create_line(start.x, start.y, end.x, end.y, arrow="last", width=2) self.edges[id] = edge self.canvas.tag_lower(id, min(self.nodes.keys())) self.__repair_edge_starting_in_node(start) return edge def algorithm_step_move(self, move): if self.show_cycles_only_mode: # cycles only if (self.step_index + move) < len(self.cycles) and self.step_index + move >= 0: self.step_index += move self.reset_colors() colors = ['green', 'blue', 'red', 'yellow', 'purple', 'brown'] color_index = self.step_index % len(colors) for edge in self.cycles[self.step_index]: edge.color = edge.start.color = edge.end.color = colors[color_index] self.repaint() else: if (self.step_index + move) < len(self.steps) and self.step_index + move >= 0: self.step_index += move self.reset_colors() for i in range(self.step_index + 1): colors = self.steps[i] for id in colors: if id in self.nodes.keys(): self.nodes[id].color = colors[id] elif id in self.edges.keys(): self.edges[id].color = colors[id] self.repaint()
class UI(): """The UI class manages the buttons, map and tiles. The latter two are visual depictions of the world and cells respectively """ def __init__(self, master, app, frame): """Create the window.""" self.master = master self.app = app self.frame = frame self.world = self.app.simulation.world self.add_buttons() self.add_other_widgets() self.add_map() log(">> Creating tiles") self.create_tiles() log(">> Painting tiles") self.paint_tiles() def add_buttons(self): """Add buttons to the frame.""" ground_button = Button(self.frame, text="TERRA", fg="red", command=self.draw_terrain) ground_button.grid(row=1, column=0, sticky=W+E) water_button = Button(self.frame, text="WATER", fg="red", command=self.toggle_water) water_button.grid(row=1, column=1, sticky=W+E) heat_button = Button(self.frame, text="HEAT", fg="red", command=self.draw_heat) heat_button.grid(row=1, column=2, sticky=W+E) def add_other_widgets(self): """Add other widgets to the frame.""" self.time_rate = StringVar() self.rate_label = Label(self.frame, textvariable=self.time_rate) self.rate_label.grid(row=0, column=0, sticky=W, columnspan=2) self.time_stamp = StringVar() self.time_label = Label(self.frame, textvariable=self.time_stamp) self.time_label.grid(row=0, column=2, columnspan=8) self.update_time_label(0) def add_map(self): """Add a blank map.""" self.map = Canvas(self.master, width=settings.map_width + 2*settings.map_border, height=settings.map_height + 2*settings.map_border, bg="black", highlightthickness=0) self.map.grid(columnspan=12) for c in range(12): self.frame.grid_columnconfigure(c, minsize=settings.map_width/12) def create_tiles(self): """Create blank tiles.""" self.map.delete("all") self.tiles = [] for cell in self.world.cells: n_in_row = len([c for c in self.world.cells if c.latitude == cell.latitude]) x_start = ((settings.map_width/2.0) - (n_in_row/2.0)*settings.tile_width) y_start = ((cell.latitude/settings.cell_degree_width) * settings.tile_height) self.tiles.append(self.map.create_rectangle( (x_start + (cell.longitude/360.0) * n_in_row * settings.tile_width), y_start, (x_start + settings.tile_width + 1 + (cell.longitude/360.0) * n_in_row * settings.tile_width), y_start + settings.tile_height, fill="yellow", outline="")) for x in range(len(self.tiles)): self.map.tag_bind(self.tiles[x], "<ButtonPress-1>", lambda event, arg=x: self.left_click_tile(arg)) self.map.tag_bind(self.tiles[x], "<ButtonPress-2>", lambda event, arg=x: self.right_click_tile(arg)) def left_click_tile(self, x): """Tell world to raise terrain at cell x.""" self.world.raise_cell(x, 1000) self.paint_tiles() def right_click_tile(self, x): """Tell world to raise terrain at cell x.""" self.world.raise_cell(x, -1000) self.paint_tiles() def paint_tiles(self): """Color the tiles.""" for x in range(len(self.tiles)): self.map.itemconfigure(self.tiles[x], fill=self.cell_color(self.world.cells[x])) def update_time_label(self, time): """Update the UI time label.""" year = time / (60*60*24*365) time -= year*(60*60*24*365) day = time / (60*60*24) time -= day * (60*60*24) hour = time / (60*60) time -= hour*(60*60) minute = time / 60 time -= minute*60 second = time year = format(year, ",d") hour = "%02d" % (hour, ) minute = "%02d" % (minute, ) second = "%02d" % (second, ) self.time_stamp.set("{}:{}:{}, day {}, year {}." .format(hour, minute, second, day, year)) self.time_rate.set("x{}".format(settings.time_step_description)) def cell_color(self, cell): """Work out what color a tile should be. The color depends on the cell and the draw_mode parameter. """ if settings.draw_mode == "terrain": if cell.water.depth == 0.0 or settings.draw_water is False: col_min = [50, 20, 4] col_max = [255, 255, 255] p = ((cell.land.height - settings.min_ground_height) / (settings.max_ground_height - settings.min_ground_height)) else: col_min = [153, 204, 255] col_max = [20, 20, 80] p = cell.water.depth/6000.0 if p > 1: p = 1 elif settings.draw_mode == "heat": if settings.draw_water is True: temp = cell.surface_temperature else: temp = cell.land.temperature if temp < 223: col_min = [0, 0, 0] col_max = [82, 219, 255] p = max(min((temp)/223.0, 1), 0) elif temp < 273: col_min = [82, 219, 255] col_max = [255, 255, 255] p = max(min((temp-223.0)/50.0, 1), 0) elif temp < 313: col_min = [255, 255, 255] col_max = [255, 66, 0] p = max(min((temp-273.0)/40.0, 1), 0) else: col_min = [255, 66, 0] col_max = [0, 0, 0] p = max(min((temp-313.0)/100.0, 1), 0) elif settings.draw_mode == "wind": col_min = [0, 0, 0] col_max = [255, 255, 255] p = min(cell.wind_speed, 10)/10 q = 1-p col = [int(q*col_min[0] + p*col_max[0]), int(q*col_min[1] + p*col_max[1]), int(q*col_min[2] + p*col_max[2])] return '#%02X%02X%02X' % (col[0], col[1], col[2]) def draw_terrain(self): """Paint map by altitude.""" settings.draw_mode = "terrain" self.paint_tiles() def draw_heat(self): """Paint map by land temperature.""" settings.draw_mode = "heat" self.paint_tiles() def toggle_water(self): """Toggle whether water is shown in terrain mode.""" settings.draw_water = not settings.draw_water self.paint_tiles()
canvas = Canvas(root, height=h) canvas.pack(fill=BOTH) field_height = h / cell_size field_width = w / cell_size cell_matrix = [] for i in range(field_height): for j in range(field_width): square = canvas.create_rectangle(2 + cell_size * j, 2 + cell_size * i, cell_size + cell_size * j - 2, cell_size + cell_size * i - 2, fill="green") canvas.itemconfigure(square, state=HIDDEN, tags=('hid', '0')) cell_matrix.append(square) fict_square = canvas.create_rectangle(0, 0, 0, 0, state=HIDDEN, tags=('hid', '0')) cell_matrix.append(fict_square) frame = Frame(root) bt1 = Button(frame, text='Eval', command=step) bt2 = Button(frame, text='Clear', command=clear) bt1.pack(side='left') bt2.pack(side='right') frame.pack(side='bottom')
class GridObj(Frame): """The GridObj class is a UI element for a cell in a grid of carts.""" _cart = None _key = None _is_playing = False _rect = None _title = None _issuer = None _length = None _on_left_click = None _on_right_click = None _on_cart_end = None def __init__(self, parent, key, on_left_click, on_right_click, on_cart_end): """Construct a grid object. :param parent :param on_left_click: callback for left click :param on_right_click: callback for right click :param on_cart_end: callback for when a cart ends """ Frame.__init__(self, parent.master, bd=1, relief=Tkinter.SUNKEN, bg=COLOR_DEFAULT, width=CART_WIDTH, height=CART_HEIGHT) self._key = key self._on_left_click = on_left_click self._on_right_click = on_right_click self._on_cart_end = on_cart_end self._rect = Canvas(self, width=CART_WIDTH, height=CART_HEIGHT, bg=COLOR_DEFAULT) self._title = self._rect.create_text(5, 5, width=CART_WIDTH, anchor=Tkinter.NW, font=FONT, fill=COLOR_TITLE, text="") self._issuer = self._rect.create_text(CART_WIDTH / 2, 25, width=CART_WIDTH, anchor=Tkinter.N, font=FONT, fill=COLOR_ISSUER, text="") self._length = self._rect.create_text(CART_WIDTH / 2, CART_HEIGHT - 15, anchor=Tkinter.S, font=FONT, fill=COLOR_LENGTH, text="") self._rect.bind("<ButtonPress-1>", self._left_click) self._rect.bind("<Button-2>", self._right_click) self._rect.bind("<Button-3>", self._right_click) self._rect.pack() def has_cart(self): """Get whether the grid object has a cart.""" return self._cart is not None def get_cart(self): """Get the cart of the grid object.""" return self._cart def set_cart(self, cart): """Set a cart for the grid object. :param cart """ self._cart = cart length = self._cart.get_meter_data()[1] / 1000 self._rect.itemconfigure(self._title, text=self._cart.title) self._rect.itemconfigure(self._issuer, text=(self._cart.issuer + " " + self._cart.cart_id)) self._rect.itemconfigure(self._length, text=get_fmt_time(length)) self._rect["bg"] = COLOR_TYPES_NEW[self._cart.cart_type] def remove_cart(self): """Remove a cart from the grid object.""" self._cart = None self._rect.itemconfigure(self._title, text="") self._rect.itemconfigure(self._issuer, text="") self._rect.itemconfigure(self._length, text="") self._rect["bg"] = COLOR_DEFAULT def is_playing(self): """Get whether the cart is playing.""" return self._is_playing def start(self): """Start the grid object.""" self._is_playing = True self._rect["bg"] = COLOR_PLAYING self._cart.start(self._cart_end) database.log_cart(self._cart.cart_id) def stop(self): """Stop the grid object.""" self._is_playing = False self._rect["bg"] = COLOR_TYPES_PLAYED[self._cart.cart_type] self._cart.stop() def _left_click(self, *args): """Respond to a left click.""" self._on_left_click(self, self._key) def _right_click(self, *args): """Respond to a right click.""" self._on_right_click(self) def _cart_end(self): """Respond to the end of the cart.""" self._on_cart_end(self._key)
class Screen(Observer): def __init__(self, parent, model): self.parent = parent self.model = model self.canvas = Canvas(parent) self.curve_id = -1 self.control_points_id = [] self.control_point_index = -1 def set_canvas(self, canvas): self.canvas = canvas def get_canvas(self): return self.canvas # View : update() the Bezier curve def update(self, subject): curve = subject.get_curve() self.canvas.delete(self.curve_id) self.curve_id = self.canvas.create_line(curve, width=3, fill='gray40') # View : control points visualisation def update_control_points(self, model): control_points = model.get_control_points() # self.canvas.delete('ctrl_pts') del self.control_points_id[:] i = 0 while i < len(control_points): x, y = control_points[i] self.control_points_id.append( self.canvas.create_oval(x, y, x + 10, y + 10, outline='black', fill='green')) i = i + 1 # Controler : control point interaction to update the Bezier curve def select_point(self, event, model): control_points = model.get_control_points() # selection of a control point i = 0 while i < len(control_points): x, y = control_points[i] if x - 10 < event.x < x + 10 and y - 10 < event.y < y + 10: self.control_point_index = i self.canvas.itemconfigure( self.control_points_id[self.control_point_index], fill='red') break i = i + 1 # insertion of a control point if self.control_point_index == -1: i = 0 while i < len(control_points) - 1: x1, y1 = control_points[i] x2, y2 = control_points[i + 1] print(event.x, event.y) if (x1 < event.x < x2 or x2 < event.x < x1) and (y1 < event.y < y2 or y2 < event.y < y1): control_points.insert(i, (event.x, event.y)) model.set_control_points(control_points) self.update_control_points(model) break i = i + 1 self.update_control_points(model) def move_point(self, event, model): if 0 <= self.control_point_index < len(self.control_points_id): coords = self.canvas.coords( self.control_points_id[self.control_point_index]) x1, y1 = coords[0], coords[1] x1, y1 = event.x - x1, event.y - y1 control_points = model.get_control_points() control_points[self.control_point_index] = event.x, event.y model.set_control_points(control_points) self.canvas.move(self.control_points_id[self.control_point_index], x1, y1) model.compute_curve() def release_point(self, event): self.canvas.itemconfigure( self.control_points_id[self.control_point_index], fill='green') self.control_point_index = -1 def packing(self): self.canvas.pack(fill='both', expand=True)
class TkProgessBar(Frame): """ TkListboxMulticolumn component which can display multi-sortable listbox """ def __init__(self, master, cnf={}, **kw): """ Construct a listbox widget with one or many column and label field for header Valid resource names: background, bd, bg, borderwidth, class, colormap, fg, font, foreground, height, highlightbackground, """ Frame.__init__(self, master) self._value = kw.get('value', 0.0) # Create canvas for drawing in self._canvas = Canvas( self, bg=kw.get('bg', 'white'), width=kw.get('width', 300), height=kw.get('height', 20), relief=kw.get('relief', 'sunken'), border=kw.get('border', 1) ) self._canvas.pack(fill='both', expand='yes') # Drawing a rectangle self._rect = self._canvas.create_rectangle( 0, 0, 0, self._canvas.winfo_reqheight(), fill=kw.get('fillcolor', 'blue'), width=0 ) # Drawing a text area self._text = self._canvas.create_text( self._canvas.winfo_reqwidth()/2, self._canvas.winfo_reqheight()/2, text='', fill=kw.get('textcolor', 'gray') ) self.bind('<Configure>', self._update_coords) def _update_coords(self, event): '''Updates the position of the text and rectangle inside the canvas when the size of the widget gets changed.''' # looks like we have to call update_idletasks() twice to make sure # to get the results we expect self._canvas.update_idletasks() self._canvas.coords(self._text, self._canvas.winfo_width()/2, self._canvas.winfo_height()/2) self._canvas.coords(self._rect, 0, 0, self._canvas.winfo_width()*self._value, self._canvas.winfo_height()) self._canvas.update_idletasks() def get(self, first, last=None): """ return percent and text value """ return self._value, self._canvas.itemcget(self._text, 'text') def set(self, value=0.0, text=None): ''' Set different values. ''' #make the value failsafe: if value < 0.0: value = 0.0 elif value > 1.0: value = 1.0 self._value = value if text == None: #if no text is specified use the default percentage string: text = str(int(round(100 * value))) + ' %' self._canvas.coords(self._rect, 0, 0, self._canvas.winfo_width()*value, self._canvas.winfo_height()) self._canvas.itemconfigure(self._text, text=text) self._canvas.update_idletasks()
class Scrolling_Area(Frame, object): def __init__(self, master, width=None, anchor=N, height=None, mousewheel_speed = 2, scroll_horizontally=True, xscrollbar=None, scroll_vertically=True, yscrollbar=None, background=None, inner_frame=Frame, **kw): Frame.__init__(self, master, class_="Scrolling_Area", background=background) self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1) self._width = width self._height = height self.canvas = Canvas(self, background=background, highlightthickness=0, width=width, height=height) self.canvas.grid(row=0, column=0, sticky=N+E+W+S) if scroll_vertically: if yscrollbar is not None: self.yscrollbar = yscrollbar else: self.yscrollbar = Scrollbar(self, orient=VERTICAL) self.yscrollbar.grid(row=0, column=1,sticky=N+S) self.canvas.configure(yscrollcommand=self.yscrollbar.set) self.yscrollbar['command']=self.canvas.yview else: self.yscrollbar = None if scroll_horizontally: if xscrollbar is not None: self.xscrollbar = xscrollbar else: self.xscrollbar = Scrollbar(self, orient=HORIZONTAL) self.xscrollbar.grid(row=1, column=0, sticky=E+W) self.canvas.configure(xscrollcommand=self.xscrollbar.set) self.xscrollbar['command']=self.canvas.xview else: self.xscrollbar = None self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) self.innerframe = inner_frame(self.canvas, **kw) self.innerframe.pack(anchor=anchor) self.canvas.create_window(0, 0, window=self.innerframe, anchor='nw', tags="inner_frame") self.canvas.bind('<Configure>', self._on_canvas_configure) Mousewheel_Support(self).add_support_to(self.canvas, xscrollbar=self.xscrollbar, yscrollbar=self.yscrollbar) @property def width(self): return self.canvas.winfo_width() @width.setter def width(self, width): self.canvas.configure(width= width) @property def height(self): return self.canvas.winfo_height() @height.setter def height(self, height): self.canvas.configure(height = height) def set_size(self, width, height): self.canvas.configure(width=width, height = height) def _on_canvas_configure(self, event): width = max(self.innerframe.winfo_reqwidth(), event.width) height = max(self.innerframe.winfo_reqheight(), event.height) self.canvas.configure(scrollregion="0 0 %s %s" % (width, height)) self.canvas.itemconfigure("inner_frame", width=width, height=height) def update_viewport(self): self.update() window_width = self.innerframe.winfo_reqwidth() window_height = self.innerframe.winfo_reqheight() if self._width is None: canvas_width = window_width else: canvas_width = min(self._width, window_width) if self._height is None: canvas_height = window_height else: canvas_height = min(self._height, window_height) self.canvas.configure(scrollregion="0 0 %s %s" % (window_width, window_height), width=canvas_width, height=canvas_height) self.canvas.itemconfigure("inner_frame", width=window_width, height=window_height)
class Grid(Frame): #Establishes connection to server and defines #local variables def __init__(self, parent): self.sock = socket.socket() self.host = '' self.buf = 1024 self.port = 8888 self.sock.connect((self.host, self.port)) self.purple = '#130d38' self.green = '#239d60' self.sock.send('Let me come play!') self.message = self.sock.recv(self.buf) if self.message: print 'Client got:', self.message self.icon = self.message Frame.__init__(self, parent, background='white') self.parent = parent self.dimension = 100 self.cells = {} self.used = list() for i in range(9): self.used.append('n') self.lastTimestamp = 0 self.initUI() #Sets up the GUI def initUI(self): self.parent.title('Tic-Tac-Toe') self.pack(fill=BOTH, expand=1) self.canvas = Canvas(self) for row in range(3): for column in range(3): x1 = column*self.dimension y1 = row*self.dimension x2 = x1 + self.dimension y2 = y1 + self.dimension self.cells[row, column] = self.canvas.create_rectangle(x1, y1, x2, y2, outline=self.purple) self.clickId = self.canvas.bind('<ButtonRelease-1>', self.cellClick) self.canvas.pack(fill=BOTH, expand=1) if self.icon == 'O': self.recvMove() #Responds to click on a cell def cellClick(self, event): print 'click' row = event.y/self.dimension column = event.x/self.dimension print ('%d %d' %(row, column)) self.sendMove(3*row + column) #Sends move to server def sendMove(self, index): print 'sending' self.sock.send('%d %s' %(index, self.icon)) info = self.sock.recv(self.buf).split() print 'Client received:', info index = int(info[0]) self.update(index/3, index%3, info[1], info[2]) #Receives move from server def recvMove(self): print 'listening' info = self.sock.recv(self.buf).split() print 'Client received:', info index = int(info[0]) self.update(index/3, index%3, info[1], info[2]) #Updates data and interface after receiving information def update(self, row, column, icon, timestamp): if float(timestamp) - self.lastTimestamp > 2: x = column*self.dimension + self.dimension/2 y = row*self.dimension + self.dimension/2 if self.used[3*row + column] == 'n': self.canvas.create_text(x, y, text=icon, fill=self.purple, font='Verdana 18 bold italic') self.used[3*row + column] = icon self.checkWin(3*row + column) self.canvas.update_idletasks() print 'Used:', self.used self.lastTimestamp = float(timestamp) print 'time: %s' %self.lastTimestamp if self.icon == icon: print 'was my move...now waiting' self.recvMove() else: print 'not updating' self.lastTimestamp = float(timestamp) print 'time: %s' %self.lastTimestamp if self.icon != icon: self.recvMove() #Checks if the last move resulted in a win def checkWin(self, cell): win = False winCells = list() #Top row if cell <= 2: if self.used[0] == self.used[1] and self.used[0] == self.used[2]: print 'top row win' for i in range(3): winCells.append(i) win = True #Middle row if cell >= 3 and cell <=5: if self.used[3] == self.used[4] and self.used[3] == self.used[5]: print 'middle row win' for i in range(3, 6): winCells.append(i) win = True #Bottom row if cell >= 6: if self.used[6] == self.used[7] and self.used[6] == self.used[8]: print 'bottom row win' for i in range(6, 9): winCells.append(i) win = True #Left column if cell%3 == 0: if self.used[0] == self.used[3] and self.used[0] == self.used[6]: print 'left column win' for i in range(0, 7, 3): winCells.append(i) win = True #Middle column if cell%3 == 1: if self.used[1] == self.used[4] and self.used[1] == self.used[7]: print 'middle column win' for i in range(1, 8, 3): winCells.append(i) win = True #Right column if cell%3 == 2: if self.used[2] == self.used[5] and self.used[2] == self.used[8]: print 'right column win' for i in range(2, 9, 3): winCells.append(i) win = True #Top-left diagonal if cell%4 == 0: if self.used[0] == self.used[4] and self.used[0] == self.used[8]: print 'top-left diagonal win' for i in range(0, 9, 4): winCells.append(i) win = True #Top-right diagonal if cell == 2 or cell == 4 or cell == 6: if self.used[2] == self.used[4] and self.used[2] == self.used[6]: print 'top-right diagonal win' for i in range(2, 7, 2): winCells.append(i) win = True if win: self.markWin(winCells) self.endGame(self.used[cell]) #Indicates winning cells in the GUI def markWin(self, *winCells): cellList = winCells[0] print winCells print cellList for cell in cellList: print cell self.canvas.itemconfigure(self.cells[cell/3, cell%3], fill=self.green) #Creates dialog to declare the winner and closes the connection def endGame(self, winningIcon): tkMessageBox.showinfo('Game Over!', 'Player %s wins!' %winningIcon) self.sock.close()
class UI(): """The UI class manages the buttons, map and tiles. The latter two are visual depictions of the world and cells respectively """ def __init__(self, master, app, frame): """Create the window.""" self.master = master self.app = app self.frame = frame self.world = self.app.simulation.world self.add_buttons() self.add_other_widgets() self.add_map() log(">> Creating tiles") self.create_tiles() log(">> Painting tiles") self.paint_tiles() def add_buttons(self): """Add buttons to the frame.""" ground_button = Button(self.frame, text="TERRA", fg="red", command=self.draw_terrain) ground_button.grid(row=1, column=0, sticky=W + E) water_button = Button(self.frame, text="WATER", fg="red", command=self.toggle_water) water_button.grid(row=1, column=1, sticky=W + E) heat_button = Button(self.frame, text="HEAT", fg="red", command=self.draw_heat) heat_button.grid(row=1, column=2, sticky=W + E) def add_other_widgets(self): """Add other widgets to the frame.""" self.time_rate = StringVar() self.rate_label = Label(self.frame, textvariable=self.time_rate) self.rate_label.grid(row=0, column=0, sticky=W, columnspan=2) self.time_stamp = StringVar() self.time_label = Label(self.frame, textvariable=self.time_stamp) self.time_label.grid(row=0, column=2, columnspan=8) self.update_time_label(0) def add_map(self): """Add a blank map.""" self.map = Canvas(self.master, width=settings.map_width + 2 * settings.map_border, height=settings.map_height + 2 * settings.map_border, bg="black", highlightthickness=0) self.map.grid(columnspan=12) for c in range(12): self.frame.grid_columnconfigure(c, minsize=settings.map_width / 12) def create_tiles(self): """Create blank tiles.""" self.map.delete("all") self.tiles = [] for cell in self.world.cells: n_in_row = len( [c for c in self.world.cells if c.latitude == cell.latitude]) x_start = ((settings.map_width / 2.0) - (n_in_row / 2.0) * settings.tile_width) y_start = ((cell.latitude / settings.cell_degree_width) * settings.tile_height) self.tiles.append( self.map.create_rectangle(( x_start + (cell.longitude / 360.0) * n_in_row * settings.tile_width), y_start, (x_start + settings.tile_width + 1 + (cell.longitude / 360.0) * n_in_row * settings.tile_width), y_start + settings.tile_height, fill="yellow", outline="")) for x in range(len(self.tiles)): self.map.tag_bind(self.tiles[x], "<ButtonPress-1>", lambda event, arg=x: self.left_click_tile(arg)) self.map.tag_bind(self.tiles[x], "<ButtonPress-2>", lambda event, arg=x: self.right_click_tile(arg)) def left_click_tile(self, x): """Tell world to raise terrain at cell x.""" self.world.raise_cell(x, 1000) self.paint_tiles() def right_click_tile(self, x): """Tell world to raise terrain at cell x.""" self.world.raise_cell(x, -1000) self.paint_tiles() def paint_tiles(self): """Color the tiles.""" for x in range(len(self.tiles)): self.map.itemconfigure(self.tiles[x], fill=self.cell_color(self.world.cells[x])) def update_time_label(self, time): """Update the UI time label.""" year = time / (60 * 60 * 24 * 365) time -= year * (60 * 60 * 24 * 365) day = time / (60 * 60 * 24) time -= day * (60 * 60 * 24) hour = time / (60 * 60) time -= hour * (60 * 60) minute = time / 60 time -= minute * 60 second = time year = format(year, ",d") hour = "%02d" % (hour, ) minute = "%02d" % (minute, ) second = "%02d" % (second, ) self.time_stamp.set("{}:{}:{}, day {}, year {}.".format( hour, minute, second, day, year)) self.time_rate.set("x{}".format(settings.time_step_description)) def cell_color(self, cell): """Work out what color a tile should be. The color depends on the cell and the draw_mode parameter. """ if settings.draw_mode == "terrain": if cell.water.depth == 0.0 or settings.draw_water is False: col_min = [50, 20, 4] col_max = [255, 255, 255] p = ((cell.land.height - settings.min_ground_height) / (settings.max_ground_height - settings.min_ground_height)) else: col_min = [153, 204, 255] col_max = [20, 20, 80] p = cell.water.depth / 6000.0 if p > 1: p = 1 elif settings.draw_mode == "heat": if settings.draw_water is True: temp = cell.surface_temperature else: temp = cell.land.temperature if temp < 223: col_min = [0, 0, 0] col_max = [82, 219, 255] p = max(min((temp) / 223.0, 1), 0) elif temp < 273: col_min = [82, 219, 255] col_max = [255, 255, 255] p = max(min((temp - 223.0) / 50.0, 1), 0) elif temp < 313: col_min = [255, 255, 255] col_max = [255, 66, 0] p = max(min((temp - 273.0) / 40.0, 1), 0) else: col_min = [255, 66, 0] col_max = [0, 0, 0] p = max(min((temp - 313.0) / 100.0, 1), 0) elif settings.draw_mode == "wind": col_min = [0, 0, 0] col_max = [255, 255, 255] p = min(cell.wind_speed, 10) / 10 q = 1 - p col = [ int(q * col_min[0] + p * col_max[0]), int(q * col_min[1] + p * col_max[1]), int(q * col_min[2] + p * col_max[2]) ] return '#%02X%02X%02X' % (col[0], col[1], col[2]) def draw_terrain(self): """Paint map by altitude.""" settings.draw_mode = "terrain" self.paint_tiles() def draw_heat(self): """Paint map by land temperature.""" settings.draw_mode = "heat" self.paint_tiles() def toggle_water(self): """Toggle whether water is shown in terrain mode.""" settings.draw_water = not settings.draw_water self.paint_tiles()
class TrailUI: def __init__(self, parent, trail=None): self.parent = parent self.trail = trail self.alpha_reflection = trail.alpha_reflection self.states = [] self.probabilitylabels = {} ## scrollbar # create a canvas object and a vertical scrollbar for scrolling it self.scrollframe = Frame(parent) self.hsb = Scrollbar(self.scrollframe, orient=Tkinter.HORIZONTAL) self.hsb.pack(fill=Tkinter.X, side=BOTTOM, expand=Tkinter.FALSE) self.scrollcanvas = Canvas(self.scrollframe, bd=0, highlightthickness=0, xscrollcommand=self.hsb.set) self.scrollcanvas.pack(side=LEFT, fill=BOTH, expand=Tkinter.TRUE) self.hsb.config(command=self.scrollcanvas.xview) # reset the view self.scrollcanvas.xview_moveto(0) self.scrollcanvas.yview_moveto(0) # put trailframe into scrollframe and assign configs self.trailframe = interior = Frame(self.scrollcanvas) self.interior_id = self.scrollcanvas.create_window(10, 0, window=interior, anchor=Tkinter.NW) interior.bind('<Configure>', self._configure_interior) self.scrollcanvas.bind('<Configure>', self._configure_canvas) self.scrollframe.pack(fill=Tkinter.X, expand=1) self.infoframe = Frame(parent) self.infoframe.pack(fill=Tkinter.X, expand=1, side=BOTTOM) self.canvas = Canvas(self.infoframe, width=1000, height=200) self.canvas.pack() self.b = Button(self.infoframe, text='Disable Propagation', command=self.__toggle_prop) self.b.pack() self.b2 = Button(self.infoframe, text='Make active only', command=self.__activeonly) self.b2.pack() self.parent.title("ClusterF**k") self.enable_propagation = True self.trail.updateColorList() self.maxgridcol = -1 self.trail.initUI(self) # Multi Cell Selection self.multiselection_pressed = False self.dynamicselection_pressed = False self.selectedcells = [] self.parent.bind("<Control_L>", self.__selection_start) self.parent.bind("<KeyRelease-Control_L>", self.__selection_end) self.parent.bind("<Shift_L>", self.__dynamic_selection_start) self.parent.bind("<KeyRelease-Shift_L>", self.__dynamic_selection_end) self.parent.bind("<Escape>", lambda event: self._clear_selection()) self.parent.bind("<Return>", lambda event: self.open_cell_dialogue()) # track changes to the canvas and frame width and sync them, # also updating the scrollbar # taken from https://gist.github.com/EugeneBakin/76c8f9bcec5b390e45df def _configure_interior(self, event): # update the scrollbars to match the size of the inner frame size = (self.trailframe.winfo_reqwidth(), self.trailframe.winfo_reqheight()) self.scrollcanvas.config(scrollregion="0 0 %s %s" % size) if self.trailframe.winfo_reqwidth() != self.scrollcanvas.winfo_width(): # update the canvas's width to fit the inner frame self.scrollcanvas.config(width=self.trailframe.winfo_reqwidth()) def _configure_canvas(self, event): if self.trailframe.winfo_reqwidth() != self.scrollcanvas.winfo_width(): # update the inner frame's width to fill the canvas self.scrollcanvas.itemconfigure( self.trailframe, width=self.scrollcanvas.winfo_width()) def __selection_start(self, event): print "Selection start/continue" self.multiselection_pressed = True def __dynamic_selection_start(self, event): print "Dynamic selection start" self.dynamicselection_pressed = True def __selection_end(self, event): print "Selection end" self.multiselection_pressed = False def __dynamic_selection_end(self, event): print "Dynamic selection end" self.dynamicselection_pressed = False def open_cell_dialogue(self): if len(self.selectedcells) is 0: return # oldstate = self.__clickedcells[0]["oldstate"] # oldstatestr = ",".join(["{:x}".format(x) for x in oldstate]) oldstatestr = "" dialog = StatePopup( self, oldstatestr, self.selectedcells[0]["state_probs"]) # TODO add probs self.trailframe.wait_window(dialog.top) newstate = dialog.value # set each cell of the selection to the new state if newstate is not None: for i, cell in enumerate(self.selectedcells): cell["stateUI"].state.set(cell["row"], cell["col"], set(newstate)) # self._clear_selection() self.redraw_all() self.redraw_selection() def _clear_selection(self): for cell in self.selectedcells: cell["stateUI"].undraw_selection(cell) self.selectedcells = [] def __toggle_prop(self): self.enable_propagation = not self.enable_propagation if self.enable_propagation: self.b.config(text="Disable Propagation") self.redraw_all() else: self.b.config(text="Enable Propagation") def __activeonly(self): self.trail.makeActiveOnly() self.redraw_all() def get_stateui_at(self, row, col): # retrieve state from specific grid position for state in self.states: if state._row is row and state._col is col: return state return self.get_stateui_at(row, col - 1) def redraw_selection(self): for cell in self.selectedcells: cell["stateUI"].draw_selection(cell) def redraw_all(self): if self.enable_propagation: self.trail.propagate() self.trail.getProbability(verbose=True) self.redrawColorList() self.redraw_states() self.redraw_selection() if self.enable_propagation: self.redraw_probablities() def redraw_states(self): for state in self.states: state.redraw_state() if PRINT_PROPS is True: for state in self.states: state.redraw_propagation() def redraw_probablities(self): if self.alpha_reflection is True: for i, prob in enumerate(self.trail.probabilities): overallprob, sboxprob, mixcolprob = prob.getProbability() if i < self.trail.rounds: self.probabilitylabels["S" + str(i)].textvar.set( "2^{0:.2f}".format(math.log(sboxprob, 2))) self.probabilitylabels["M" + str(i + 1)].textvar.set( "2^{0:.2f}".format(math.log(mixcolprob, 2))) elif i >= self.trail.rounds + 1: self.probabilitylabels["S" + str(i + 2)].textvar.set( "2^{0:.2f}".format(math.log(sboxprob, 2))) self.probabilitylabels["M" + str(i + 1)].textvar.set( "2^{0:.2f}".format(math.log(mixcolprob, 2))) else: # inner round self.probabilitylabels["I"].textvar.set("2^{0:.2f}".format( math.log(overallprob, 2))) else: for i, prob in enumerate(self.trail.probabilities): overallprob, sboxprob, mixcolprob = prob.getProbability() self.probabilitylabels["S" + str(i + 1)].textvar.set( "2^{0:.2f}".format(math.log(sboxprob, 2))) self.probabilitylabels["M" + str(i + 1)].textvar.set( "2^{0:.2f}".format(math.log(mixcolprob, 2))) def redrawColorList(self): self.canvas.delete("colorlist") self.trail.updateColorList() for i, (state, color) in enumerate(self.trail.colorlist.items()): statestr = ",".join(["{:x}".format(x) for x in state]) x = 15 + int(i / 5) * 250 y = 15 + (i % 5) * 40 self.canvas.create_rectangle(x, y, x + 25, y + 25, fill=color, tags="colorlist") textx = x + 40 texty = y + 12 self.canvas.create_text(textx, texty, text=statestr, tags="colorlist", fill="black", anchor="w") def cleanup(self): self.infoframe.destroy() self.trailframe.destroy()
class Plotter(GenericPlotter): def __init__(self, windowTitle='TopoVis', params=None): GenericPlotter.__init__(self, params) self.nodes = {} self.links = {} self.nodeLinks = {} self.lineStyles = {} self.shapes = {} self.windowTitle = windowTitle self.prepareCanvas() self.lastShownTime = 0 ################### def prepareCanvas(self): self.tk = Tk() self.tk.title(self.windowTitle) self.canvas = Canvas(self.tk, width=850, height=850) self.canvas.pack(fill=BOTH, expand=YES) self.createText('time', 0, 0, text="time=0.0 seconds") ################### def setTime(self, time): if time - self.lastShownTime > 0.00001: self.updateText('time', text='Time: %.5f seconds' % time) self.lastShownTime = time ################### def updateNodePosAndSize(self, ident): p = self.params c = self.canvas if ident not in self.nodes.keys(): node_tag = c.create_oval(0, 0, 0, 0) label_tag = c.create_text(0, 0, text=str(ident)) self.nodes[ident] = (node_tag, label_tag) else: (node_tag, label_tag) = self.nodes[ident] node = self.scene.nodes[ident] nodesize = node.scale * p.nodesize x1 = node.pos[0] - nodesize y1 = node.pos[1] - nodesize (x2, y2) = (x1 + nodesize * 2, y1 + nodesize * 2) c.coords(node_tag, x1, y1, x2, y2) c.coords(label_tag, node.pos) for link in self.nodeLinks[ident]: self.updateLink(*link) ################### def configLine(self, tagOrId, style): config = {} config['fill'] = colorStr(style.color) config['width'] = style.width config['arrow'] = arrowMap[style.arrow] config['dash'] = style.dash self.canvas.itemconfigure(tagOrId, **config) ################### def configPolygon(self, tagOrId, lineStyle, fillStyle): config = {} config['outline'] = colorStr(lineStyle.color) config['width'] = lineStyle.width config['dash'] = lineStyle.dash config['fill'] = colorStr(fillStyle.color) self.canvas.itemconfigure(tagOrId, **config) ################### def createLink(self, src, dst, style): if src == dst: raise RuntimeError('Source and destination are the same node') p = self.params c = self.canvas (x1, y1, x2, y2) = computeLinkEndPoints(self.scene.nodes[src], self.scene.nodes[dst], p.nodesize) link_obj = c.create_line(x1, y1, x2, y2, tags='link') self.configLine(link_obj, self.scene.lineStyles[style]) return link_obj ################### def updateLink(self, src, dst, style): p = self.params c = self.canvas link_obj = self.links[(src, dst, style)] (x1, y1, x2, y2) = computeLinkEndPoints(self.scene.nodes[src], self.scene.nodes[dst], p.nodesize) c.coords(link_obj, x1, y1, x2, y2) ################### def node(self, ident, x, y): self.nodeLinks[ident] = [] self.updateNodePosAndSize(ident) self.tk.update() ################### def nodemove(self, ident, x, y): self.updateNodePosAndSize(ident) self.tk.update() ################### def nodecolor(self, ident, r, g, b): (node_tag, label_tag) = self.nodes[ident] self.canvas.itemconfig(node_tag, outline=colorStr((r, g, b))) self.canvas.itemconfigure(label_tag, fill=colorStr((r, g, b))) self.tk.update() ################### def nodewidth(self, ident, width): (node_tag, label_tag) = self.nodes[ident] self.canvas.itemconfig(node_tag, width=width) self.tk.update() ################### def nodescale(self, ident, scale): # scale attribute has been set by TopoVis # just update the node self.updateNodePosAndSize(ident) self.tk.update() ################### def nodelabel(self, ident, label): (node_tag, label_tag) = self.nodes[ident] self.canvas.itemconfigure(label_tag, text=self.scene.nodes[ident].label) self.tk.update() ################### def addlink(self, src, dst, style): self.nodeLinks[src].append((src, dst, style)) self.nodeLinks[dst].append((src, dst, style)) self.links[(src, dst, style)] = self.createLink(src, dst, style) self.tk.update() ################### def dellink(self, src, dst, style): self.nodeLinks[src].remove((src, dst, style)) self.nodeLinks[dst].remove((src, dst, style)) self.canvas.delete(self.links[(src, dst, style)]) del self.links[(src, dst, style)] self.tk.update() ################### def clearlinks(self): self.canvas.delete('link') self.links.clear() for n in self.nodes: self.nodeLinks[n] = [] self.tk.update() ################### def circle(self, x, y, r, ident, linestyle, fillstyle): if ident in self.shapes.keys(): self.canvas.delete(self.shapes[ident]) del self.shapes[ident] self.shapes[ident] = self.canvas.create_oval(x - r, y - r, x + r, y + r) self.configPolygon(self.shapes[ident], linestyle, fillstyle) self.tk.update() ################### def line(self, x1, y1, x2, y2, ident, linestyle): if ident in self.shapes.keys(): self.canvas.delete(self.shapes[ident]) del self.shapes[ident] self.shapes[ident] = self.canvas.create_line(x1, y1, x2, y2) self.configLine(self.shapes[ident], linestyle) self.tk.update() ################### def rect(self, x1, y1, x2, y2, ident, linestyle, fillstyle): if ident in self.shapes.keys(): self.canvas.delete(self.shapes[ident]) del self.shapes[ident] self.shapes[ident] = self.canvas.create_rectangle(x1, y1, x2, y2) self.configPolygon(self.shapes[ident], linestyle, fillstyle) self.tk.update() ################### def createText(self, ident, *args, **kwargs): self.shapes[ident] = self.canvas.create_text(*args, anchor=NW, **kwargs) ################### def updateText(self, ident, text): self.canvas.itemconfigure(self.shapes[ident], text=text) ################### def delshape(self, ident): if ident in self.shapes.keys(): self.canvas.delete(self.shapes[ident]) self.tk.update()
class Scrolling_Area(Frame, object): def __init__(self, master, width=None, anchor=N, height=None, mousewheel_speed = 2, scroll_horizontally=True, xscrollbar=None, scroll_vertically=True, yscrollbar=None, outer_background=None, inner_frame=Frame, **kw): Frame.__init__(self, master, class_=self.__class__) if outer_background: self.configure(background=outer_background) self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1) self._width = width self._height = height self.canvas = Canvas(self, background=outer_background, highlightthickness=0, width=width, height=height) self.canvas.grid(row=0, column=0, sticky=N+E+W+S) if scroll_vertically: if yscrollbar is not None: self.yscrollbar = yscrollbar else: self.yscrollbar = Scrollbar(self, orient=VERTICAL) self.yscrollbar.grid(row=0, column=1,sticky=N+S) self.canvas.configure(yscrollcommand=self.yscrollbar.set) self.yscrollbar['command']=self.canvas.yview else: self.yscrollbar = None if scroll_horizontally: if xscrollbar is not None: self.xscrollbar = xscrollbar else: self.xscrollbar = Scrollbar(self, orient=HORIZONTAL) self.xscrollbar.grid(row=1, column=0, sticky=E+W) self.canvas.configure(xscrollcommand=self.xscrollbar.set) self.xscrollbar['command']=self.canvas.xview else: self.xscrollbar = None self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) self.innerframe = inner_frame(self.canvas, **kw) self.innerframe.pack(anchor=anchor) self.canvas.create_window(0, 0, window=self.innerframe, anchor='nw', tags="inner_frame") self.canvas.bind('<Configure>', self._on_canvas_configure) Mousewheel_Support(self).add_support_to(self.canvas, xscrollbar=self.xscrollbar, yscrollbar=self.yscrollbar) @property def width(self): return self.canvas.winfo_width() @width.setter def width(self, width): self.canvas.configure(width= width) @property def height(self): return self.canvas.winfo_height() @height.setter def height(self, height): self.canvas.configure(height = height) def set_size(self, width, height): self.canvas.configure(width=width, height = height) def _on_canvas_configure(self, event): width = max(self.innerframe.winfo_reqwidth(), event.width) height = max(self.innerframe.winfo_reqheight(), event.height) self.canvas.configure(scrollregion="0 0 %s %s" % (width, height)) self.canvas.itemconfigure("inner_frame", width=width, height=height) def update_viewport(self): self.update() window_width = self.innerframe.winfo_reqwidth() window_height = self.innerframe.winfo_reqheight() if self._width is None: canvas_width = window_width else: canvas_width = min(self._width, window_width) if self._height is None: canvas_height = window_height else: canvas_height = min(self._height, window_height) self.canvas.configure(scrollregion="0 0 %s %s" % (window_width, window_height), width=canvas_width, height=canvas_height) self.canvas.itemconfigure("inner_frame", width=window_width, height=window_height)
class Application(Frame, object): """The application main class.""" WIDTH, HEIGHT = 1280, 720 BG = 'white' FONT = 'Verdana' FILE_OPEN_OPTIONS = { 'mode': 'rb', 'title': 'Choose *.json file', 'defaultextension': '.json', 'filetypes': [('JSON file', '*.json')] } DEFAULTS = 'default_settings.yaml' def __init__(self, master=None): """Creates application main window with sizes self.WIDTH and self.HEIGHT. :param master: instance - Tkinter.Tk instance """ super(Application, self).__init__(master) self.master.title('Engine Game') self.master.geometry('{}x{}'.format(self.WIDTH, self.HEIGHT)) self.master.protocol('WM_DELETE_WINDOW', self.exit) self.source = None self._map = None self.points = None self.lines = None self.captured_point = None self.x0 = None self.y0 = None self.scale_x = None self.scale_y = None self.font_size = None self.coordinates = {} self.captured_lines = {} self.canvas_obj = AttrDict() self.icons = { 0: PhotoImage(file=join('icons', 'player_city.png')), 1: PhotoImage(file=join('icons', 'city.png')), 2: PhotoImage(file=join('icons', 'market.png')), 3: PhotoImage(file=join('icons', 'store.png')), 4: PhotoImage(file=join('icons', 'point.png')), 5: PhotoImage(file=join('icons', 'player_train.png')), 6: PhotoImage(file=join('icons', 'train.png')), 7: PhotoImage(file=join('icons', 'crashed_train.png')), 8: PhotoImage(file=join('icons', 'collision.png')), 9: PhotoImage(file=join('icons', 'play.png')), 10: PhotoImage(file=join('icons', 'play_pressed.png')), 11: PhotoImage(file=join('icons', 'stop.png')), 12: PhotoImage(file=join('icons', 'stop_pressed.png')) } self.queue_requests = { 0: self.set_status_bar, 1: self.set_player_idx, 2: self.build_map, 3: self.refresh_map, 4: self.set_available_games, 99: self.bot_control } self.settings_window = None if exists(expanduser(self.DEFAULTS)): with open(expanduser(self.DEFAULTS), 'r') as cfg: defaults = DefaultsDict.from_yaml(cfg) self.host = None if not defaults.host else str(defaults.host) self.port = None if not defaults.port else int(defaults.port) self.timeout = None if not defaults.timeout else int(defaults.timeout) self.username = None if not defaults.username else str(defaults.username) self.password = None if not defaults.password else str(defaults.password) else: self.host, self.port, self.timeout, self.username, self.password = None, None, None, None, None self.player_idx = None self.posts = {} self.trains = {} self.select_game_window = False self.available_games = None self.game = None self.num_players = None self.num_turns = None self.bot = Bot() self.bot_thread = None self.menu = Menu(self) filemenu = Menu(self.menu) filemenu.add_command(label='Open file', command=self.file_open) filemenu.add_command(label='Server settings', command=self.open_server_settings) filemenu.add_command(label='Select game', command=self.select_game) filemenu.add_command(label='Exit', command=self.exit) self.menu.add_cascade(label='Menu', menu=filemenu) master.config(menu=self.menu) self._status_bar = StringVar() self.label = Label(master, textvariable=self._status_bar) self.label.pack() self.frame = Frame(self) self.frame.bind('<Configure>', self._resize_frame) self.canvas = Canvas(self.frame, bg=self.BG, scrollregion=(0, 0, self.winfo_width(), self.winfo_height())) self.canvas.bind('<Button-1>', self._capture_point) self.canvas.bind('<Motion>', self._move_point) self.canvas.bind('<B1-ButtonRelease>', self._release_point) self.canvas.bind('<Configure>', self._resize_canvas) hbar = Scrollbar(self.frame, orient=HORIZONTAL) hbar.pack(side=BOTTOM, fill=X) hbar.config(command=self.canvas.xview) vbar = Scrollbar(self.frame, orient=VERTICAL) vbar.pack(side=RIGHT, fill=Y) vbar.config(command=self.canvas.yview) self.canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set) self.canvas.pack(fill=BOTH, expand=True) self.play = Label(self.canvas, bg='white') self.play.configure(image=self.icons[9]) self.play.bind('<Button-1>', self._play_press) self.play.bind('<B1-ButtonRelease>', self._play_release) self.stop = Label(self.canvas, bg='white') self.stop.configure(image=self.icons[11]) self.stop.bind('<Button-1>', self._stop_press) self.stop.bind('<B1-ButtonRelease>', self._stop_release) self.frame.pack(fill=BOTH, expand=True) self.weighted = IntVar(value=1) self.weighted_check = Checkbutton(self, text='Proportionally to length', variable=self.weighted, command=self._proportionally) self.weighted_check.pack(side=LEFT) self.show_weight = IntVar() self.show_weight_check = Checkbutton(self, text='Show length', variable=self.show_weight, command=self.show_weights) self.show_weight_check.pack(side=LEFT) self.pack(fill=BOTH, expand=True) self.requests_executor() self.get_available_games() self.set_status_bar('Click Play to start the game') self.play.place(rely=0.5, relx=0.5, anchor=CENTER) @property def map(self): """Returns the actual map.""" return self._map @map.setter def map(self, value): """Clears previously drawn map and assigns a new map to self._map.""" self.clear_map() self.canvas.configure(scrollregion=(0, 0, self.canvas.winfo_width(), self.canvas.winfo_height())) self.x0, self.y0 = self.canvas.winfo_width() / 2, self.canvas.winfo_height() / 2 self._map = value @staticmethod def midpoint(x_start, y_start, x_end, y_end): """Calculates a midpoint coordinates between two points. :param x_start: int - x coordinate of the start point :param y_start: int - y coordinate of the start point :param x_end: int - x coordinate of the end point :param y_end: int - y coordinate of the end point :return: 2-tuple of a midpoint coordinates """ return (x_start + x_end) / 2, (y_start + y_end) / 2 def _resize_frame(self, event): """Calculates new font size each time frame size changes. :param event: Tkinter.Event - Tkinter.Event instance for Configure event :return: None """ self.font_size = int(0.0125 * min(event.width, event.height)) def _resize_canvas(self, event): """Redraws map each time Canvas size changes. Scales map each time visible part of Canvas is enlarged. :param event: Tkinter.Event - Tkinter.Event instance for Configure event :return: None """ if self.map: k = min(float(event.width) / float(self.x0 * 2), float(event.height) / float(self.y0 * 2)) self.scale_x, self.scale_y = self.scale_x * k, self.scale_y * k self.x0, self.y0 = self.x0 * k, self.y0 * k self.redraw_map() self.redraw_trains() x_start, y_start, x_end, y_end = self.canvas.bbox('all') x_start = 0 if x_start > 0 else x_start y_start = 0 if y_start > 0 else y_start self.canvas.configure(scrollregion=(x_start, y_start, x_end, y_end)) def _proportionally(self): """Rebuilds map and redraws trains.""" self.build_map() self.redraw_trains() def _capture_point(self, event): """Stores captured point and it's lines. :param event: Tkinter.Event - Tkinter.Event instance for ButtonPress event :return: None """ x, y = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y) obj_ids = self.canvas.find_overlapping(x - 5, y - 5, x + 5, y + 5) if not obj_ids: return for obj_id in obj_ids: if obj_id in self.canvas_obj.point.keys(): self.captured_point = obj_id point_idx = self.canvas_obj.point[obj_id]['idx'] self.captured_lines = {} for line_id, attr in self.canvas_obj.line.items(): if attr['start_point'] == point_idx: self.captured_lines[line_id] = 'start_point' if attr['end_point'] == point_idx: self.captured_lines[line_id] = 'end_point' if self.weighted.get(): self.weighted.set(0) def _release_point(self, event): """Writes new coordinates for a moved point and resets self.captured_point and self.captured_lines. :param event: Tkinter.Event - Tkinter.Event instance for ButtonRelease event :return: None """ if self.captured_point: idx = self.canvas_obj.point[self.captured_point]['idx'] x, y = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y) self.coordinates[idx] = (x, y) self.points[idx]['x'], self.points[idx]['y'] = (x - self.x0) / self.scale_x, (y - self.y0) / self.scale_y self.captured_point = None self.captured_lines = {} def _move_point(self, event): """Moves point and its lines. Moves weights if self.show_weight is set to 1. In case some point is moved beyond Canvas border Canvas scrollregion is resized correspondingly. :param event: Tkinter.Event - Tkinter.Event instance for Motion event :return: None """ if self.captured_point: new_x, new_y = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y) self.canvas.coords(self.captured_point, new_x, new_y) indent_y = self.icons[self.canvas_obj.point[self.captured_point]['icon']].height() / 2 + self.font_size if self.canvas_obj.point[self.captured_point]['text_obj']: self.canvas.coords(self.canvas_obj.point[self.captured_point]['text_obj'], new_x, new_y - indent_y) self.coordinates[self.canvas_obj.point[self.captured_point]['idx']] = (new_x, new_y) self.canvas.configure(scrollregion=self.canvas.bbox('all')) for line_id, attr in self.captured_lines.items(): line_attrs = self.canvas_obj.line[line_id] if attr == 'start_point': x, y = self.coordinates[line_attrs['end_point']] self.canvas.coords(line_id, new_x, new_y, x, y) else: x, y = self.coordinates[line_attrs['start_point']] self.canvas.coords(line_id, x, y, new_x, new_y) if self.show_weight.get(): mid_x, mid_y = self.midpoint(new_x, new_y, x, y) self.canvas.coords(line_attrs['weight_obj'][1], mid_x, mid_y) r = self.font_size * len(str(line_attrs['weight'])) self.canvas.coords(line_attrs['weight_obj'][0], mid_x - r, mid_y - r, mid_x + r, mid_y + r) self.redraw_trains() def _play_press(self, _): """Draws play button pressed icon.""" self.play.configure(image=self.icons[10]) def _play_release(self, _): """Draws play button icon and calls bot_control method.""" self.play.configure(image=self.icons[9]) self.bot_control() def _stop_press(self, _): """Draws stop button pressed icon.""" self.stop.configure(image=self.icons[12]) def _stop_release(self, _): """Draws stop buton icon and calls bot_control method.""" self.stop.configure(image=self.icons[11]) self.bot_control() def set_player_idx(self, value): """Sets a player idx value.""" self.player_idx = value def file_open(self): """Opens file dialog and builds and draws a map once a file is chosen. Stops bot if its started.""" path = tkFileDialog.askopenfile(parent=self.master, **self.FILE_OPEN_OPTIONS) if path: if self.bot_thread: self.bot_control() self.posts, self.trains = {}, {} self.source = path.name self.weighted_check.configure(state=NORMAL) self.build_map() def open_server_settings(self): """Opens server settings window.""" ServerSettings(self, title='Server settings') def select_game(self): """Opens select game window.""" self.select_game_window = True SelectGame(self, title='Select game') self.select_game_window = False self.set_status_bar('Click Play to start the game') def exit(self): """Closes application and stops bot if its started.""" if self.bot_thread: self.bot_control() self.master.destroy() def bot_control(self): """Starts bot for playing the game or stops it if it is started.""" if not self.bot_thread: self.bot_thread = Thread(target=self.bot.start, kwargs={ 'host': self.host, 'port': self.port, 'time_out': self.timeout, 'username': self.username, 'password': self.password, 'game': self.game, 'num_players': self.num_players, 'num_turns': self.num_turns}) self.bot_thread.start() else: self.bot.stop() self.bot_thread.join() self.bot_thread = None def get_available_games(self): """Requests a list of available games.""" if self.select_game_window: self.bot.get_available_games(host=self.host, port=self.port, time_out=self.timeout) self.after(1000, self.get_available_games) def set_available_games(self, games): """Sets new value for available games list.""" self.available_games = games def set_status_bar(self, value): """Assigns new status bar value and updates it. :param value: string - status bar string value :return: None """ self._status_bar.set(value) self.label.update() def build_map(self, source=None): """Builds and draws new map. :param source: string - source string; could be JSON string or path to *.json file. :return: None """ if source: self.source = source if self.source: self.map = Graph(self.source, weighted=self.weighted.get()) self.set_status_bar('Map title: {}'.format(self.map.name)) self.points, self.lines = self.map.get_coordinates() self.draw_map() def draw_map(self): """Draws map by prepared coordinates.""" self.draw_lines() self.draw_points() def clear_map(self): """Clears previously drawn map and resets coordinates and scales.""" self.canvas.delete('all') self.scale_x, self.scale_y = None, None self.coordinates = {} def redraw_map(self): """Redraws existing map by existing coordinates.""" if self.map: self.coordinates = {} for obj_id in self.canvas_obj.line: self.canvas.delete(obj_id) self.draw_lines() self.redraw_points() def redraw_points(self): """Redraws map points by existing coordinates.""" if self.map: for obj_id, attrs in self.canvas_obj.point.items(): if attrs['text_obj']: self.canvas.delete(attrs['text_obj']) self.canvas.delete(obj_id) self.draw_points() def redraw_trains(self): """Redraws existing trains.""" if self.trains and hasattr(self.canvas_obj, 'train'): for obj_id, attrs in self.canvas_obj.train.items(): self.canvas.delete(attrs['text_obj']) self.canvas.delete(obj_id) self.draw_trains() @prepare_coordinates def draw_points(self): """Draws map points by prepared coordinates.""" point_objs = {} captured_point_idx = self.canvas_obj.point[self.captured_point]['idx'] if self.captured_point else None for idx in self.points.keys(): x, y = self.coordinates[idx] if self.posts and idx in self.posts.keys(): post_type = self.posts[idx]['type'] if post_type == 1: status = '{}/{} {}/{} {}/{}'.format(self.posts[idx]['population'], self.posts[idx]['population_capacity'], self.posts[idx]['product'], self.posts[idx]['product_capacity'], self.posts[idx]['armor'], self.posts[idx]['armor_capacity']) elif post_type == 2: status = '{}/{}'.format(self.posts[idx]['product'], self.posts[idx]['product_capacity']) else: status = '{}/{}'.format(self.posts[idx]['armor'], self.posts[idx]['armor_capacity']) image_id = 0 if post_type == 1 and self.posts[idx]['player_idx'] == self.player_idx else post_type point_id = self.canvas.create_image(x, y, image=self.icons[image_id]) y -= (self.icons[post_type].height() / 2) + self.font_size text_id = self.canvas.create_text(x, y, text=status, font="{} {}".format(self.FONT, self.font_size)) else: post_type = 4 point_id = self.canvas.create_image(x, y, image=self.icons[post_type]) text_id = None point_objs[point_id] = {'idx': idx, 'text_obj': text_id, 'icon': post_type} self.captured_point = point_id if idx == captured_point_idx else self.captured_point self.canvas_obj['point'] = point_objs @prepare_coordinates def draw_lines(self): """Draws map lines by prepared coordinates and shows their weights if self.show_weight is set to 1.""" line_objs, captured_lines_idx = {}, {} if self.captured_lines: for line_id in self.captured_lines.keys(): captured_lines_idx[self.canvas_obj.line[line_id]['idx']] = line_id for idx, attrs in self.lines.items(): x_start, y_start = self.coordinates[attrs['start_point']] x_stop, y_stop = self.coordinates[attrs['end_point']] line_id = self.canvas.create_line(x_start, y_start, x_stop, y_stop) line_objs[line_id] = {'idx': idx, 'weight': attrs['weight'], 'start_point': attrs['start_point'], 'end_point': attrs['end_point'], 'weight_obj': ()} if idx in captured_lines_idx.keys(): self.captured_lines[line_id] = self.captured_lines.pop(captured_lines_idx[idx]) self.canvas_obj['line'] = line_objs self.show_weights() @prepare_coordinates def draw_trains(self): """Draws trains by prepared coordinates.""" trains = {} for train in self.trains.values(): start_point = self.lines[train['line_idx']]['start_point'] end_point = self.lines[train['line_idx']]['end_point'] weight = self.lines[train['line_idx']]['weight'] position = train['position'] x_start, y_start = self.coordinates[start_point] x_end, y_end = self.coordinates[end_point] delta_x, delta_y = int((x_start - x_end) / weight) * position, int((y_start - y_end) / weight) * position x, y = x_start - delta_x, y_start - delta_y if train['cooldown'] > 0: icon = 7 status = None else: icon = 5 if train['player_idx'] == self.player_idx else 6 status = '{}/{}'.format(train['goods'], train['goods_capacity']) indent_y = self.icons[icon].height() / 2 train_id = self.canvas.create_image(x, y - indent_y, image=self.icons[icon]) text_id = self.canvas.create_text(x, y - (2 * indent_y + self.font_size), text=status, font="{} {}".format(self.FONT, self.font_size)) if status else None trains[train_id] = {'icon': icon, 'text_obj': text_id} self.canvas_obj['train'] = trains def show_weights(self): """Shows line weights when self.show_weight is set to 1 and hides them when it is set to 0.""" if not self.canvas_obj: return if self.show_weight.get(): for line in self.canvas_obj.line.values(): if line['weight_obj']: for obj in line['weight_obj']: self.canvas.itemconfigure(obj, state='normal') else: x_start, y_start = self.coordinates[line['start_point']] x_end, y_end = self.coordinates[line['end_point']] x, y = self.midpoint(x_start, y_start, x_end, y_end) value = line['weight'] size = self.font_size r = int(size) * len(str(value)) oval_id = self.canvas.create_oval(x - r, y - r, x + r, y + r, fill=self.BG, width=0) text_id = self.canvas.create_text(x, y, text=value, font="{} {}".format(self.FONT, str(size))) line['weight_obj'] = (oval_id, text_id) else: for line in self.canvas_obj.line.values(): if line['weight_obj']: for obj in line['weight_obj']: self.canvas.itemconfigure(obj, state='hidden') def requests_executor(self): """Dequeues and executes requests. Assigns corresponding label to bot control button.""" if not self.bot.queue.empty(): request_type, request_body = self.bot.queue.get_nowait() if request_type == 99 and request_body: self.open_server_settings() request_body = None if request_body is not None: self.queue_requests[request_type](request_body) else: self.queue_requests[request_type]() if self.bot_thread and self.bot_thread.is_alive(): if self.play.place_info(): self.play.place_forget() self.stop.place(rely=0.99, relx=0.995, anchor=SE) else: if self.stop.place_info(): self.stop.place_forget() self.play.place(rely=0.5, relx=0.5, anchor=CENTER) self.after(50, self.requests_executor) def refresh_map(self, dynamic_objects): """Refreshes map with passed dynamic objects. :param dynamic_objects: dict - dict of dynamic objects :return: None """ for post in dynamic_objects['posts']: self.posts[post['point_idx']] = post for train in dynamic_objects['trains']: self.trains[train['idx']] = train self.redraw_points() self.redraw_trains()