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])
Example #2
0
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)
Example #3
0
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)
Example #4
0
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)
Example #5
0
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)
Example #6
0
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)
Example #7
0
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
Example #8
0
    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)
Example #9
0
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()
Example #10
0
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()
Example #11
0
	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')
Example #12
0
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)
Example #13
0
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)
Example #14
0
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()
Example #15
0
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)
Example #16
0
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()
Example #17
0
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()
Example #18
0
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()
Example #19
0
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)
Example #21
0
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()