Example #1
0
def main():
    root = Tk()
    # w, h = root.winfo_screenwidth(), root.winfo_screenheight()
    w, h = 960, 540
    # get value from arduino
    # ser = serial.Serial('/dev/tty.usbserial', 9600)
    pos = 0
    root.overrideredirect(1)
    root.focus_set()
    root.bind("<Escape>", lambda e: e.widget.quit())
    root.geometry("%dx%d+300+300" % (w, h))
    canvas = Canvas(root, width=w, height=h, background="black")
    rect0 = canvas.create_rectangle(w/2-75, h/2-20, w/2+75, h/2+20, fill="#05f", outline="#05f")
    rect1 = canvas.create_rectangle(w/2-20, h/2-75, w/2+20, h/2+75, fill="#05f", outline="#05f")
    canvas.pack() 
    
    while (True):
        # gets angle and moves accordingly
        # pos = ser.readline()
        canvas.move(rect0, 1, 0)
        canvas.move(rect1, 1, 0)
        root.update()
        root.after(30)
      
    app = App(root)
    time.sleep(0.5)
    root.mainloop()  
Example #2
0
class Grid(object):
    cell_size = 5

    def __init__(self):
        master = Tk()
        self.canvas = Canvas(master, width=800, height=600, background='black')
        self.canvas.pack()
        self.columns = int(self.canvas['width']) / self.cell_size
        self.rows = int(self.canvas['height']) / self.cell_size

    def put(self, x, y, tags=None):
        self.canvas.create_rectangle(x * self.cell_size,
                                     y*self.cell_size,
                                     x * self.cell_size + self.cell_size,
                                     y*self.cell_size + self.cell_size, 
                                     fill="white", outline="white", tags=tags)

    def move(self, tags, dx, dy):
        self.canvas.move(tags, dx*self.cell_size, dy*self.cell_size)
Example #3
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()
    global scaling_factor
    if event.char == '>':
        scaling_factor = scaling_factor + 0.1
        resize()

    elif event.char == '<':
        scaling_factor = scaling_factor - 0.1
        resize()

    elif event.char == "<Right>":
        x = x + 5
        print x


(x, y) = canvas.coords(zoeid)
canvas.bind("<Right>", lambda event: canvas.move(zoeid, 5, 0))

canvas.bind("<Left>", lambda event: canvas.move(zoeid, -5, 0))

canvas.bind("<Up>", lambda event: canvas.move(zoeid, 0, -5))

canvas.bind("<Down>", lambda event: canvas.move(zoeid, 0, 5))
canvas.focus_set()

canvas.bind("<Key>", key)

scaling_factor = 1.0


def resize():
    global canvas, zoeid, photo1, Zoe, scaling_factor, coorx, coory, x, y
Example #5
0
class GUI(object):
    def __init__(self, logger):
        self.logger = logger
        self.root = Tk()
        self.canvas = Canvas(self.root, width=800, height=800)
        self.canvas.pack()
        self.root.after(33, self.update)
        self.pos = (0,0)
        self.circle = self.canvas.create_oval(-10,-10,10,10,fill='black')
        self.gestures = [
            lambda t,x,y,s: ((sin(t*2*pi*0.5)*300 + 400,
                              abs(cos(t*2*pi*0.2)*300) + 200),
                             s),
            lambda t,x,y,s: ((sin(t*2*pi*1)*300 + 400,
                              cos(t*2*pi*1)*300 + 400),
                             s),
            lambda t,x,y,s: ((sin(t*2*pi*0.75)*300 + 400,
                              -abs(cos(t*2*pi*0.75)*300) + 400),
                             s),
            lambda t,x,y,s: ((x+(s[0] - x)*0.1,
                              y+(s[1] - y)*0.1),
                             (uniform(100,700)*(t%1<0.05) + (t%1>0.05)*s[0],
                              uniform(100,700)*(t%1<0.05) + (t%1>0.05)*s[1])),
            lambda t,x,y,s: ((400, y+s[1] if y < 700 else 700-s[1]),
                             (0, (10 + s[1])*(-0.5 if y>700 else 1))),
            ]
        self.state = [0,0]
        self.current_gesture = -1
        self.last_gesture_time = time.time()
        self.next_gesture(self.last_gesture_time)
        self.waiting = True
        self.root.bind('<space>', self.on_space)
        self.logger.set_tag('waiting')

    def on_space(self, *args):
        self.waiting = False
        self.last_gesture_time = time.time()

    def run(self):
        self.root.mainloop()

    def next_gesture(self, t):
        self.current_gesture += 1
        if self.current_gesture >= len(self.gestures):
            self.root.quit()
            self.logger.set_done()
            return True
        else:
            self.last_gesture_time = t
            gestureID = 'gesture%d'%self.current_gesture
            self.logger.set_tag(gestureID)
            print gestureID

    def update(self):
        if not self.waiting:
            t = time.time()
            if (t - self.last_gesture_time) > SECONDS_PER_GESTURE:
                if self.next_gesture(t):
                    return
            pos, self.state = self.gestures[self.current_gesture](t,self.pos[0],self.pos[1],self.state)
            delta = pos[0] - self.pos[0], pos[1] - self.pos[1]
            self.canvas.move(self.circle, delta[0], delta[1])
            self.pos = pos
        self.root.after(33, self.update)
Example #6
0
    class Breakout(Tk):
        def __init__(self):
            Tk.__init__(self)
            #self.canvas.delete('all')
            self.geometry('790x600')
            self.resizable(
                0, 0
            )  #set both parameters to false and to check whether window is resizable in x and y directions
            self.func()

            # game screen
        def func(self):

            self.canvas = Canvas(self,
                                 bg='skyblue',
                                 width=990,
                                 height=600,
                                 highlightcolor='green')
            self.canvas.pack(
                expand=1, fill=BOTH
            )  #when it is true and widget expands to fill any space

            # ball
            self._initiate_new_ball()
            #self.level=choice([1])

            # paddle
            self.canvas.create_rectangle(375,
                                         975,
                                         525,
                                         585,
                                         fill='red',
                                         tags='paddle')
            self.bind('<Key>', self._move_paddle)

            # bricks
            self.bricks = {}
            brick_coords = [15, 12, 60, 45]
            for i in range(56):
                self.canvas.create_rectangle(brick_coords,
                                             outline='green',
                                             fill=('yellow'),
                                             tags='brick' + str(i))
                self.bricks['brick' + str(i)] = None
                brick_coords[0] += 55
                brick_coords[2] += 55
                if brick_coords[2] > 790:
                    brick_coords[0] = 15
                    brick_coords[2] = 60
                    brick_coords[1] += 55
                    brick_coords[3] += 55

        def _initiate_new_ball(self):
            if self.canvas.find_withtag('ball'):
                self.canvas.delete('ball')
            self.x = 300
            self.y = 350
            self.angle = 240
            self.speed = 10
            self.level = 0
            self.score = 0

            self.canvas.create_oval(self.x,
                                    self.y,
                                    self.x + 10,
                                    self.y + 10,
                                    fill='orange',
                                    outline='red',
                                    tags='ball')

            self.after(2000, self._move_ball)

        def _move_paddle(self, event):
            if event.keysym == 'Left':
                if self.canvas.coords('paddle')[0] > 0:
                    self.canvas.move('paddle', -20, 0)
            elif event.keysym == 'Right':
                if self.canvas.coords('paddle')[2] < 990:
                    self.canvas.move('paddle', +20, 0)

        #def _move_ball1(self):
        #	call1()
        #self._initiate_new_ball1()

        def _move_ball(self):

            # variables to determine where ball is in relation to other objects
            ball = self.canvas.find_withtag('ball')[0]
            bounds = self.canvas.find_overlapping(0, 0, 790, 600)
            paddle = self.canvas.find_overlapping(
                *self.canvas.coords('paddle'))
            for brick in self.bricks.iterkeys():
                self.bricks[brick] = self.canvas.find_overlapping(
                    *self.canvas.bbox(brick))

            # calculate change in x,y values of ball
            angle = self.angle - 120  # correct for quadrant IV
            increment_x = cos(radians(angle)) * self.speed
            increment_y = sin(radians(angle)) * self.speed
            #self.level += choice([1])
            #score=self.score
            #score=0
            # finite state machine to set ball state

            if ball in bounds:
                self.ball_state = 'moving'
                for brick, hit in self.bricks.iteritems():
                    if ball in hit:
                        self.ball_state = 'hit_brick'
                        delete_brick = brick
                    elif ball in paddle:
                        self.ball_state = 'hit_wall'
                    elif (self.score) // 3 == 56:
                        self.canvas.create_text(
                            WIDTH / 4,
                            HEIGHT / 2.3,
                            text="CONGRATS!! GAME COMPLETED!",
                            font=("Helvetica", 20),
                            fill="orange")

                        self.canvas.create_text(WIDTH / 4,
                                                HEIGHT / 2,
                                                text=(self.score // 3),
                                                font=("Helvetica", 20),
                                                fill="red")
                        self.canvas.create_text(WIDTH / 4,
                                                HEIGHT / 1.7,
                                                text="YOUR SCORE ",
                                                font=("Helvetica", 20),
                                                fill="darkorange")
                        #image()
                        quit_to_exit()

                        call()

            elif ball not in bounds:
                if self.canvas.coords('ball')[1] < 600:
                    self.ball_state = 'hit_wall'
                else:
                    self.ball_state = 'out_of_bounds'

                    #self.level += choice([1])

                    self.canvas.create_text(
                        WIDTH / 2.5,
                        HEIGHT / 2.3,
                        text="GAME OVER !!PLEASE CLOSE THE WINDOW TO RESTART!",
                        tag="cr2",
                        font=("Helvetica", 20),
                        fill="orange")
                    self.canvas.create_text(WIDTH / 4,
                                            HEIGHT / 2,
                                            text="YOUR SCORE IS",
                                            tag="cr1",
                                            font=("Helvetica", 20),
                                            fill="orange")
                    self.canvas.create_text(WIDTH / 4,
                                            HEIGHT / 1.7,
                                            text=(self.score // 3) + 1,
                                            tag="cr",
                                            font=("Helvetica", 20),
                                            fill="red")
                    quit_to_exit()
                    call()

                    self._initiate_new_ball()

                    #self.bind('<key>',self.game_over)
                    #game = Breakout()
                    #game.mainloop()

            # handler for ball state
            if self.ball_state is 'moving':
                self.canvas.move('ball', increment_x, increment_y)
                self.after(35, self._move_ball)
#		        self.level +=choice([1])

            elif self.ball_state is 'hit_brick' or self.ball_state is 'hit_wall':
                if self.ball_state == 'hit_brick':
                    self.canvas.delete(delete_brick)
                    del self.bricks[delete_brick]
                self.canvas.move('ball', -increment_x, -increment_y)
                #		        self.level += choice([1])
                self.score += choice([1])
                self.angle += choice([135])
                self.canvas.delete("cr")
                self.canvas.delete("cr1")
                self.canvas.delete("cr2")
                #canvas.create_text(WIDTH/4,HEIGHT/5,text="GAME OVER!")
                self._move_ball()
Example #7
0
class GUI(object):
    def __init__(self, logger):
        self.logger = logger
        self.root = Tk()
        self.canvas = Canvas(self.root, width=800, height=800)
        self.canvas.pack()
        self.root.after(33, self.update)
        self.pos = (0, 0)
        self.circle = self.canvas.create_oval(-10, -10, 10, 10, fill='black')
        self.gestures = [
            lambda t, x, y, s: ((sin(t * 2 * pi * 0.5) * 300 + 400,
                                 abs(cos(t * 2 * pi * 0.2) * 300) + 200), s),
            lambda t, x, y, s: ((sin(t * 2 * pi * 1) * 300 + 400,
                                 cos(t * 2 * pi * 1) * 300 + 400), s),
            lambda t, x, y, s: ((sin(t * 2 * pi * 0.75) * 300 + 400, -abs(
                cos(t * 2 * pi * 0.75) * 300) + 400), s),
            lambda t, x, y, s: ((x + (s[0] - x) * 0.1, y + (s[1] - y) * 0.1),
                                (uniform(100, 700) * (t % 1 < 0.05) +
                                 (t % 1 > 0.05) * s[0], uniform(100, 700) *
                                 (t % 1 < 0.05) + (t % 1 > 0.05) * s[1])),
            lambda t, x, y, s: ((400, y + s[1] if y < 700 else 700 - s[1]),
                                (0, (10 + s[1]) * (-0.5 if y > 700 else 1))),
        ]
        self.state = [0, 0]
        self.current_gesture = -1
        self.last_gesture_time = time.time()
        self.next_gesture(self.last_gesture_time)
        self.waiting = True
        self.root.bind('<space>', self.on_space)
        self.logger.set_tag('waiting')

    def on_space(self, *args):
        self.waiting = False
        self.last_gesture_time = time.time()

    def run(self):
        self.root.mainloop()

    def next_gesture(self, t):
        self.current_gesture += 1
        if self.current_gesture >= len(self.gestures):
            self.root.quit()
            self.logger.set_done()
            return True
        else:
            self.last_gesture_time = t
            gestureID = 'gesture%d' % self.current_gesture
            self.logger.set_tag(gestureID)
            print gestureID

    def update(self):
        if not self.waiting:
            t = time.time()
            if (t - self.last_gesture_time) > SECONDS_PER_GESTURE:
                if self.next_gesture(t):
                    return
            pos, self.state = self.gestures[self.current_gesture](t,
                                                                  self.pos[0],
                                                                  self.pos[1],
                                                                  self.state)
            delta = pos[0] - self.pos[0], pos[1] - self.pos[1]
            self.canvas.move(self.circle, delta[0], delta[1])
            self.pos = pos
        self.root.after(33, self.update)
class Breakout(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.geometry('400x400')
        self.resizable(0,0)

        # game screen
        self.canvas = Canvas(self, bg='black', width=400, height=400)
        self.canvas.pack(expand=1, fill=BOTH)

        # ball
        self._initiate_new_ball()

        # paddle
        self.canvas.create_rectangle(175,375,225,385, fill='black',
                                     outline='white', tags='paddle')
        self.bind('<Key>', self._move_paddle)

        # bricks
        self.bricks = {}
        brick_coords = [5,5,35,15]
        for i in range(39):
            self.canvas.create_rectangle(*brick_coords, outline='white',
                                         fill=('#{}'.format(randint(100000,999999))),
                                         tags='brick' + str(i))
            self.bricks['brick' + str(i)] = None
            brick_coords[0] += 30; brick_coords[2] += 30
            if brick_coords[2] > 395:
                brick_coords[0] = 5; brick_coords[2] = 35
                brick_coords[1] += 10; brick_coords[3] += 10

    def _initiate_new_ball(self):
        if self.canvas.find_withtag('ball'):
            self.canvas.delete('ball')
        self.x = 60; self.y = 100
        self.angle = 140; self.speed = 5
        self.canvas.create_oval(self.x,self.y,self.x+10,self.y+10,
                                fill='lawn green', outline='white', tags='ball')
        self.after(1000, self._move_ball)
        
    def _move_paddle(self, event):
        if event.keysym == 'Left':
            if self.canvas.coords('paddle')[0] > 0:
                self.canvas.move('paddle', -10, 0)
        elif event.keysym == 'Right':
            if self.canvas.coords('paddle')[2] < 400:
                self.canvas.move('paddle', +10, 0)

    def _move_ball(self):

        # variables to determine where ball is in relation to other objects
        ball = self.canvas.find_withtag('ball')[0]
        bounds = self.canvas.find_overlapping(0,0,400,400)
        paddle = self.canvas.find_overlapping(*self.canvas.coords('paddle'))
        for brick in self.bricks.iterkeys():
            self.bricks[brick] = self.canvas.find_overlapping(*self.canvas.bbox(brick))

        # calculate change in x,y values of ball
        angle = self.angle - 90 # correct for quadrant IV
        increment_x = cos(radians(angle)) * self.speed
        increment_y = sin(radians(angle)) * self.speed

        # finite state machine to set ball state
        if ball in bounds:
            self.ball_state = 'moving'
            for brick, hit in self.bricks.iteritems():
                if ball in hit:
                    self.ball_state = 'hit_brick'
                    delete_brick = brick
                elif ball in paddle:
                    self.ball_state = 'hit_wall'
        elif ball not in bounds:
            if self.canvas.coords('ball')[1] < 400:
                self.ball_state = 'hit_wall'
            else:
                self.ball_state = 'out_of_bounds'
                self._initiate_new_ball()

        # handler for ball state
        if self.ball_state is 'moving':
            self.canvas.move('ball', increment_x, increment_y)
            self.after(15, self._move_ball)
        elif self.ball_state is 'hit_brick' or self.ball_state is 'hit_wall':
            if self.ball_state == 'hit_brick':
                self.canvas.delete(delete_brick)
                del self.bricks[delete_brick]
            self.canvas.move('ball', -increment_x, -increment_y)
            self.angle += choice([119, 120, 121])
            self._move_ball()
Example #9
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 #10
0
class Game():
    WIDTH = 300
    HEIGHT = 500

    def start(self):
        
        self.level = 1
        self.score = 0
        self.speed = 500
        self.counter = 0
        self.create_new_game = True

        self.root = Tk()
        self.root.title("Tetris")

        self.status_var = StringVar() 
        self.status_var.set("Level: 1, Score: 0")
        self.status = Label(self.root, 
                textvariable=self.status_var, 
                font=("Helvetica", 10, "bold"))
        self.status.pack()
        
        self.canvas = Canvas(
                self.root, 
                width=Game.WIDTH, 
                height=Game.HEIGHT)
        self.canvas.pack()

        self.root.bind("<Key>", self.handle_events)
        self.timer()
        self.root.mainloop()
    
    def timer(self):
        if self.create_new_game == True:
            self.current_shape = Shape(self.canvas)
            self.create_new_game = False

        if not self.current_shape.fall():
            lines = self.remove_complete_lines()
            if lines:
                self.score += 10 * self.level**2 * lines**2
                self.status_var.set("Level: %d, Score: %d" % 
                        (self.level, self.score))

            self.current_shape = Shape(self.canvas)
            if self.is_game_over():
                self.create_new_game = True
                self.game_over()

            self.counter += 1
            if self.counter == 5:
                self.level += 1
                self.speed -= 20
                self.counter = 0
                self.status_var.set("Level: %d, Score: %d" % 
                        (self.level, self.score))
        
        self.root.after(self.speed, self.timer)

    def handle_events(self, event):
        
        if event.keysym == "Left": self.current_shape.move(-1, 0)
        if event.keysym == "Right": self.current_shape.move(1, 0)
        if event.keysym == "Down": self.current_shape.move(0, 1)
        if event.keysym == "Up": self.current_shape.rotate()

    def is_game_over(self):
        
        for box in self.current_shape.boxes:
            if not self.current_shape.can_move_box(box, 0, 1):
                return True
        return False

    def remove_complete_lines(self):
        shape_boxes_coords = [self.canvas.coords(box)[3] for box 
                in self.current_shape.boxes]
        all_boxes = self.canvas.find_all()
        all_boxes_coords = {k : v for k, v in 
                zip(all_boxes, [self.canvas.coords(box)[3] 
                    for box in all_boxes])}
        lines_to_check = set(shape_boxes_coords)
        boxes_to_check = dict((k, v) for k, v in all_boxes_coords.iteritems()
                if any(v == line for line in lines_to_check))
        counter = Counter()
        for box in boxes_to_check.values(): counter[box] += 1
        complete_lines = [k for k, v in counter.iteritems() 
                if v == (Game.WIDTH/Shape.BOX_SIZE)]
 
        if not complete_lines: return False

        for k, v in boxes_to_check.iteritems():
            if v in complete_lines:
                self.canvas.delete(k)
                del all_boxes_coords[k]
                
        for (box, coords) in all_boxes_coords.iteritems():
            for line in complete_lines:
                if coords < line:
                    self.canvas.move(box, 0, Shape.BOX_SIZE)
        return len(complete_lines)

    def game_over(self):
            self.canvas.delete(Tkinter.ALL)
            tkMessageBox.showinfo(
                    "Game Over", 
                    "You scored %d points." % self.score)
Example #11
0
class Game():
    WIDTH = 300
    HEIGHT = 500

    def start(self):
        '''Starts the game.

        Creates a window, a canvas, and a first shape. Binds the event handler.
        Then starts a GUI timer of ms interval self.speed and starts the GUI main 
        loop.

        '''
        #TODO start() needs to be refactored so that the creation of the
        # window, label, and canvas are independent from setting them to
        # defaults and starting the game.
        #
        # There should also be a way for the user to restart and pause
        # the game if he or she wishes.
        #
        # It's a little weird that level is based only on time and that
        # as a result it increases faster and faster. Wouldn't it make
        # more sense for level to be a result of completed lines?
        self.level = 1
        self.score = 0
        self.speed = 500
        self.counter = 0
        self.create_new_game = True

        self.root = Tk()
        self.root.title("Tetris")

        self.status_var = StringVar()
        self.status_var.set("Level: 1, Score: 0")
        self.status = Label(self.root,
                            textvariable=self.status_var,
                            font=("Helvetica", 10, "bold"))
        self.status.pack()

        self.canvas = Canvas(self.root, width=Game.WIDTH, height=Game.HEIGHT)
        self.canvas.pack()

        self.root.bind("<Key>", self.handle_events)
        self.timer()
        self.root.mainloop()

    def timer(self):
        '''Every self.speed ms, attempt to cause the current_shape to fall().

        If fall() returns False, create a new shape and check if it can fall.
        If it can't, then the game is over.
        
        '''
        if self.create_new_game == True:
            self.current_shape = Shape(self.canvas)
            self.create_new_game = False

        if not self.current_shape.fall():
            lines = self.remove_complete_lines()
            if lines:
                self.score += 10 * self.level**2 * lines**2
                self.status_var.set("Level: %d, Score: %d" %
                                    (self.level, self.score))

            self.current_shape = Shape(self.canvas)
            if self.is_game_over():
                #TODO This is a problem. You rely on the timer method to
                # create a new game rather than creating it here. As a
                # result, there is an intermittent error where the user
                # event keypress Down eventually causes can_move_box
                # to throw an IndexError, since the current shape has
                # no boxes. Instead, you need to cleanly start a new
                # game. I think refactoring start() might help a lot
                # here.
                #
                # Furthermore, starting a new game currently doesn't reset
                # the levels. You should place all your starting constants
                # in the same place so it's clear what needs to be reset
                # when.
                self.create_new_game = True
                self.game_over()

            self.counter += 1
            if self.counter == 5:
                self.level += 1
                self.speed -= 20
                self.counter = 0
                self.status_var.set("Level: %d, Score: %d" %
                                    (self.level, self.score))

        self.root.after(self.speed, self.timer)

    def handle_events(self, event):
        '''Handle all user events.'''
        if event.keysym == "Left": self.current_shape.move(-1, 0)
        if event.keysym == "Right": self.current_shape.move(1, 0)
        if event.keysym == "Down": self.current_shape.move(0, 1)
        if event.keysym == "Up": self.current_shape.rotate()

    def is_game_over(self):
        '''Check if a newly created shape is able to fall.

        If it can't fall, then the game is over.

        '''
        for box in self.current_shape.boxes:
            if not self.current_shape.can_move_box(box, 0, 1):
                return True
        return False

    def remove_complete_lines(self):
        shape_boxes_coords = [
            self.canvas.coords(box)[3] for box in self.current_shape.boxes
        ]
        all_boxes = self.canvas.find_all()
        all_boxes_coords = {
            k: v
            for k, v in zip(all_boxes,
                            [self.canvas.coords(box)[3] for box in all_boxes])
        }
        lines_to_check = set(shape_boxes_coords)
        boxes_to_check = dict((k, v) for k, v in all_boxes_coords.iteritems()
                              if any(v == line for line in lines_to_check))
        counter = Counter()
        for box in boxes_to_check.values():
            counter[box] += 1
        complete_lines = [
            k for k, v in counter.iteritems()
            if v == (Game.WIDTH / Shape.BOX_SIZE)
        ]

        if not complete_lines: return False

        for k, v in boxes_to_check.iteritems():
            if v in complete_lines:
                self.canvas.delete(k)
                del all_boxes_coords[k]

        #TODO Would be cooler if the line flashed or something
        for (box, coords) in all_boxes_coords.iteritems():
            for line in complete_lines:
                if coords < line:
                    self.canvas.move(box, 0, Shape.BOX_SIZE)
        return len(complete_lines)

    def game_over(self):
        self.canvas.delete(Tkinter.ALL)
        tkMessageBox.showinfo("Game Over",
                              "You scored %d points." % self.score)
Example #12
0
class StlFrame(Frame):
	def __init__(self, root, scale=1):
		Frame.__init__(self, root)
		self.app = root
		
		self.gridOffset = 10
		self.arrangeMargin = 2
		self.centerOnLoad = True
		
		self.offsetx = 0
		self.offsety = 0
		self.scale = scale
		self.zoom = 1
		
		self.selection = None
		self.selectable = []
		self.itemMap = {}

		self.canvas = Canvas(self, width=200*self.scale+13, height=200*self.scale+13, bd=2, relief=RIDGE, bg="white")
		self.canvas.config(takefocus="1")
		self.canvas.bind("<Key>", self.keyCanvas)
		self.canvas.bind("<Button-1>", self.clickCanvas)
		self.canvas.bind("<B1-Motion>", self.dragCanvas)
		self.canvas.bind("<MouseWheel>", self.wheelCanvas)
		self.canvas.bind("<Button-4>", self.wheelCanvas)
		self.canvas.bind("<Button-5>", self.wheelCanvas)

		self.root = root
		self.buildarea = [200, 200]

		self.canvas.grid(row=1,column=1,columnspan=5)
		self.drawGrid()	
		
	def keyCanvas(self, event):
		self.app.setModified()
		if event.keysym == "Left":
			self.moveStl(-1, 0)
		elif event.keysym == "Right":
			self.moveStl(1, 0)
		elif event.keysym == "Up":
			if (event.state & SHIFT_MASK) != 0:
				self.rotateStl(1)
			else:
				self.moveStl(0, 1)
		elif event.keysym == "Down":
			if (event.state & SHIFT_MASK) != 0:
				self.rotateStl(-1)
			else:
				self.moveStl(0, -1)
	
	def clickCanvas(self, event):
		self.app.setModified()
		self.canvas.focus_set()
		self.startx = event.x/float(self.scale)
		self.starty = event.y/float(self.scale)
		itemIdList = self.canvas.find_closest(event.x, event.y)
		for itemId in itemIdList:
			if itemId in self.selectable:
				self.setSelection(itemId)
				self.app.setSelection(self.itemMap[itemId])
				return

	def dragCanvas(self, event):
		self.app.setModified()
		self.canvas.focus_set()
		x = event.x/float(self.scale)
		y = event.y/float(self.scale)
		self.moveStl((x - self.startx), (self.starty - y))
		self.startx = x
		self.starty = y
		
	def wheelCanvas(self, event):
		self.app.setModified()
		if event.num == 4 or event.delta == 120:
			self.rotateStl(1)
		elif event.num == 5 or event.delta == -120:
			self.rotateStl(-1)
			
	def moveStl(self, dx, dy):
		if self.selection is None:
			return
		self.canvas.move(self.selection, dx*self.scale, -dy*self.scale)
		stlObj = self.itemMap[self.selection]
		stlObj.deltaTranslation(dx, dy)
			
	def rotateStl(self, angle):
		if self.selection is None:
			return
		#self.canvas.move(self.selection, dx, -dy)
		stlObj = self.itemMap[self.selection]
		rads = math.radians(angle+stlObj.rotation)
		cos = math.cos(rads)
		sin = math.sin(rads)
		
		d = []
		xMin = yMin = 99999
		xMax = yMax = -99999
		for x,y in stlObj.hull:
			xp = (x-stlObj.hxCenter)*cos - (y-stlObj.hyCenter)*sin + stlObj.hxCenter
			if xp < xMin: xMin=xp
			if xp > xMax: xMax=xp
			xp += stlObj.translatex
			
			yp = (x-stlObj.hxCenter)*sin + (y-stlObj.hyCenter)*cos + stlObj.hyCenter
			if yp < yMin: yMin=yp
			if yp > yMax: yMax=yp
			yp += stlObj.translatey
			d.extend(self.transform(xp,self.buildarea[1]-yp))

		self.canvas.delete(stlObj.name)
		self.selectable.remove(self.selection)
		del self.itemMap[self.selection]
			
		itemId = self.canvas.create_polygon(d, fill=hilite, outline="black", tag=stlObj.name, width=3)
		self.selectable.append(itemId)
		self.itemMap[itemId] = stlObj
		self.setSelection(itemId)

		stlObj.deltaRotation(angle)
		stlObj.hxSize = xMax-xMin
		stlObj.hySize = yMax-yMin
		stlObj.hArea = stlObj.hxSize * stlObj.hySize

		
	def setSelection(self, itemId):
		if itemId not in self.selectable:
			return
		
		if self.selection is not None:
			self.canvas.itemconfig(self.selection, fill=gray)
			
		self.canvas.itemconfig(itemId, fill=hilite)
		self.selection = itemId
		
	def setSelectionByName(self, name):
		for i in self.itemMap.keys():
			if self.itemMap[i].name == name:
				self.setSelection(i)
				return
		
	def getSelection(self):
		return self.selection
	
	def getSelectedStl(self):
		if self.selection is None:
			return None
		
		return self.itemMap[self.selection]

	def drawGrid(self):
		self.canvas.delete("GRID")
		ltGray = "#C0C0C0"
		dkGray = "#808080"
		
		yleft = 0

		yright = self.buildarea[1]*self.zoom*self.scale
		if yright > self.buildarea[1]*self.scale: yright = self.buildarea[1]*self.scale

		for x in range(0, self.buildarea[0]+1, 10):
			if x%50 == 0:
				c = dkGray
			else:
				c = ltGray
			x = x*self.zoom*self.scale
			if x >= 0 and x <= self.buildarea[0]*self.scale:
				self.canvas.create_line(x+self.gridOffset, yleft+self.gridOffset, x+self.gridOffset, yright+self.gridOffset, fill=c, tags="GRID")
			
		xtop = 0

		xbottom = self.buildarea[0]*self.zoom*self.scale
		if xbottom > self.buildarea[0]*self.scale: xbottom = self.buildarea[0]*self.scale

		for y in range(0, self.buildarea[1]+1, 10):
			if y%50 == 0:
				c = dkGray
			else:
				c = ltGray
			y = y*self.zoom*self.scale
			if y >= 0 and y <= self.buildarea[1]*self.scale:
				self.canvas.create_line(xtop+self.gridOffset, y+self.gridOffset, xbottom+self.gridOffset, y+self.gridOffset, fill=c, tags="GRID")
			
	def addStl(self, stlObject, highlight=False, process=True):
		self.canvas.delete(stlObject.name)
		if highlight:
			col = hilite
		else:
			col = gray
			
		if self.centerOnLoad and process:
			dx = (self.buildarea[0]/2) - stlObject.hxCenter
			dy = (self.buildarea[1]/2) - stlObject.hyCenter
			stlObject.deltaTranslation(dx, dy)
			stlObject.applyDeltas()
		
		d = []
		for x,y in stlObject.hull:
			d.extend(self.transform(x,self.buildarea[1]-y))
			
		itemId = self.canvas.create_polygon(d, fill=col, outline="black", tag=stlObject.name, width=3)
		self.selectable.append(itemId)
		self.itemMap[itemId] = stlObject
		if highlight:
			self.setSelection(itemId)
			
	def delStl(self):
		if self.selection is None:
			return

		stlObj = self.itemMap[self.selection]
		self.canvas.delete(stlObj.name)
		self.selectable.remove(self.selection)
		del self.itemMap[self.selection]
		self.selection = None
		
	def delAll(self):
		objs = self.itemMap.values()
		for o in objs:
			self.canvas.delete(o.name)
		self.selectable = []
		self.itemMap = {}
		self.selection = None
		
	def commit(self):
		if self.selection is not None:
			o = self.itemMap[self.selection]
			name = o.name
		else:
			name = ""
			
		objs = self.itemMap.values()
		self.selectable = []
		self.itemMap = {}
		
		for o in objs:
			self.canvas.delete(o.name)
			o.applyDeltas()
			self.addStl(o, highlight=(o.name == name), process=False)
			
	def getItemIdFromObject(self, obj):
		for itemId in self.itemMap.keys():
			if obj.name == self.itemMap[itemId].name:
				return itemId
			
		return None
			
	def arrange(self):
		def cmpobj(a, b):
			return cmp(b.hArea, a.hArea)
		
		omap = Map(self.buildarea)
		maxx = maxy = -99999
		minx = miny = 99999
		
		objs = sorted(self.itemMap.values(), cmpobj)
		for o in objs:
			itemId = self.getItemIdFromObject(o)
			if itemId is None: continue
			
			x, y = omap.find(o.hxSize+self.arrangeMargin*2, o.hySize+self.arrangeMargin*2)
			if x is None or y is None:
				showinfo("Plate full",  "Object %s does not fit" % o.name, parent=self)
			else:
				dx = x - o.hxCenter - o.translatex + o.hxSize/2 + self.arrangeMargin
				dy = y - o.hyCenter - o.translatey + o.hySize/2 + self.arrangeMargin
				
				self.setSelection(itemId)
				self.app.setSelection(o)
				self.moveStl(dx, dy)
				deltax = o.hxSize+self.arrangeMargin*2
				deltay = o.hySize+self.arrangeMargin*2
				omap.mark(x, y, deltax, deltay)
				if x < minx: minx=x
				if x+deltax > maxx: maxx=x+deltax
				if y < miny: miny=y
				if y+deltay > maxy: maxy=y+deltay
				
		dx = self.buildarea[0]/2-(maxx+minx)/2
		dy = self.buildarea[1]/2-(maxy+miny)/2

		for o in objs:
			itemId = self.getItemIdFromObject(o)
			if itemId is None: continue
			
			self.setSelection(itemId)
			self.app.setSelection(o)
			self.moveStl(dx, dy)
			
	def getStls(self):
		return self.itemMap.values()
			
	def countObjects(self):
		return len(self.selectable)

	def transform(self, ptx, pty):
		x = (ptx+self.offsetx)*self.zoom*self.scale+self.gridOffset
		y = (pty-self.offsety)*self.zoom*self.scale+self.gridOffset
		return (x, y)
	
	def triangulate(self, p1, p2):
		dx = p2[0] - p1[0]
		dy = p2[1] - p1[1]
		d = math.sqrt(dx*dx + dy*dy)
		return d
Example #13
0
class Simulator(object):
    def __init__(self):
        tk=Tk()
        tk.title = "T da B's Gravity Simulator"
        self.width = 1900
        self.height = 1000

        self.canvas=Canvas(tk, width=self.width, height=self.height, bg='black')
        self.masses = list()
        self.new_masses = list()
        for _ in range(20):
            size = randint(3, 7)
            m = MassiveObject(
                size * 10**16,
                size,
                randint(100, self.width - 100),
                randint(100, self.height - 100),
                randint(-15, 15),
                randint(-15, 15),
                random_color()
                )
            m.canvas_id = self.canvas.create_oval(m.x - m.radius,
                                               m.y - m.radius,
                                               m.x + m.radius,
                                               m.y + m.radius,
                                               outline=m.color,
                                               fill=m.color)
            self.masses.append(m)
        self.canvas.pack()

        self.draw()
        tk.mainloop()

    def draw(self):
        """
        Main loop
        """
        for m in self.masses:
            #if m.is_deleted is True:
            #    self.masses.remove(m)
            #    continue
            for m2 in self.masses:
                if m2 == m:
                    continue
                else:
                    self.update(m, m2)
            #m.draw_accel_vector()
            #m.draw_vel_vector()
        self.masses += self.new_masses
        self.new_masses = list()
        self.canvas.after(10, self.draw)

    def update(self, m1, m2):
        """
        Update MassiveObject m1 with respect to m2
        """
        #if ( distance(m1, m2) < m1.radius + m2.radius ):
        #    logger.info("%s and %s collided!" % (m1.color, m2.color))
        #    self.canvas.delete(m1.canvas_id, m2.canvas_id)

        #    text = self.canvas.create_text((m1.x + m2.x) / 2,
        #                                 (m1.y + m2.y) / 2,
        #                                 text="COLLISION!",
        #                                 fill='red')
        #    self.canvas.after(1000, self.canvas.delete, text)
        #    m1.is_deleted = True
        #    m2.is_deleted = True
        if ( distance(m1, m2) < m1.radius + m2.radius ):
            self.canvas.delete(m1.canvas_id, m2.canvas_id)

            '''
            text = self.canvas.create_text((m1.x + m2.x) / 2,
                                         (m1.y + m2.y) / 2,
                                         text="COLLISION!",
                                         fill='red')
            self.canvas.after(1000, self.canvas.delete, text)
            '''

            self.masses.remove(m1)
            self.masses.remove(m2)
            mid_x = (m1.x + m2.x) / 2
            mid_y = (m1.y + m2.y) / 2
            c1 = m1.mass / (m1.mass + m2.mass)
            c2 = m2.mass / (m1.mass + m2.mass)
            v_x = c1 * m1.v_x + c2 * m2.v_x
            v_y = c1 * m1.v_y + c2 * m2.v_y

            new_m = MassiveObject(
                m1.mass + m2.mass,
                m1.radius + m2.radius,
                mid_x,
                mid_y,
                v_x,
                v_y,
                avg_color(m1.color, m2.color)
                )
            new_m.canvas_id = self.canvas.create_oval(new_m.x - new_m.radius,
                                                   new_m.y - new_m.radius,
                                                   new_m.x + new_m.radius,
                                                   new_m.y + new_m.radius,
                                                   outline=new_m.color,
                                                   fill=new_m.color)
            self.new_masses.append(new_m)
            return

        old_x = m1.x
        old_y = m1.y
        g_x, g_y = grav_force(m1, m2)
        m1.a_x = g_x / m1.mass
        m1.a_y = g_y / m1.mass
        m1.t += m1.timestep
        m1.x += m1.timestep * (m1.v_x + .5*(m1.timestep * m1.a_x))
        m1.y += m1.timestep * (m1.v_y + .5*(m1.timestep * m1.a_y))
        g_x, g_y = grav_force(m1, m2)
        new_a_x, new_a_y = g_x / m1.mass, g_y / m1.mass
        m1.v_x += m1.timestep * .5 * (m1.a_x + new_a_x)
        m1.v_y += m1.timestep * .5 * (m1.a_y + new_a_y)

        self.canvas.move(m1.canvas_id, m1.x - old_x, m1.y - old_y)
        logger.info("Updated %s from (%s, %s) to (%s, %s)" % (m1.color, old_x, old_y, m1.x, m1.y))

    def draw_accel_vector(self):
        m = mag(self.x, self.y, self.x + self.a_x, self.y + self.a_y)
        if m > 1:
            line = self.canvas.create_line(self.x,
                                           self.y,
                                           self.x + self.a_x,
                                           self.y + self.a_y,
                                           fill='yellow',
                                           arrow='last')

            text = self.canvas.create_text(self.x + 1.2 * self.a_x,
                                           self.y + 1.2 * self.a_y,
                                           text=str(int(m)),
                                           fill='yellow')
            self.canvas.after(int(self.timestep * 1000), self.canvas.delete, line, text)

    def draw_vel_vector(self):
        m = mag(self.x, self.y, self.x + self.v_x, self.y + self.v_y)
        if m > 1:
            line = self.canvas.create_line(self.x,
                                           self.y,
                                           self.x + self.v_x,
                                           self.y + self.v_y,
                                           fill='red',
                                           arrow='last')

            text = self.canvas.create_text(self.x + 1.2 * self.v_x,
                                           self.y + 1.2 * self.v_y,
                                           text=str(int(m)),
                                           fill='red')
            self.canvas.after(int(self.timestep * 1000), self.canvas.delete, line, text)
Example #14
0
class Breakout(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.geometry('400x400')
        self.resizable(0, 0)

        # game screen
        self.canvas = Canvas(self, bg='black', width=400, height=400)
        self.canvas.pack(expand=1, fill=BOTH)

        # ball
        self._initiate_new_ball()

        # paddle
        self.canvas.create_rectangle(175,
                                     375,
                                     225,
                                     385,
                                     fill='black',
                                     outline='white',
                                     tags='paddle')
        self.bind('<Key>', self._move_paddle)

        # bricks
        self.bricks = {}
        brick_coords = [5, 5, 35, 15]
        for i in range(39):
            self.canvas.create_rectangle(*brick_coords,
                                         outline='white',
                                         fill=('#{}'.format(
                                             randint(100000, 999999))),
                                         tags='brick' + str(i))
            self.bricks['brick' + str(i)] = None
            brick_coords[0] += 30
            brick_coords[2] += 30
            if brick_coords[2] > 395:
                brick_coords[0] = 5
                brick_coords[2] = 35
                brick_coords[1] += 10
                brick_coords[3] += 10

    def _initiate_new_ball(self):
        if self.canvas.find_withtag('ball'):
            self.canvas.delete('ball')
        self.x = 60
        self.y = 100
        self.angle = 140
        self.speed = 5
        self.canvas.create_oval(self.x,
                                self.y,
                                self.x + 10,
                                self.y + 10,
                                fill='lawn green',
                                outline='white',
                                tags='ball')
        self.after(1000, self._move_ball)

    def _move_paddle(self, event):
        if event.keysym == 'Left':
            if self.canvas.coords('paddle')[0] > 0:
                self.canvas.move('paddle', -10, 0)
        elif event.keysym == 'Right':
            if self.canvas.coords('paddle')[2] < 400:
                self.canvas.move('paddle', +10, 0)

    def _move_ball(self):

        # variables to determine where ball is in relation to other objects
        ball = self.canvas.find_withtag('ball')[0]
        bounds = self.canvas.find_overlapping(0, 0, 400, 400)
        paddle = self.canvas.find_overlapping(*self.canvas.coords('paddle'))
        for brick in self.bricks.iterkeys():
            self.bricks[brick] = self.canvas.find_overlapping(
                *self.canvas.bbox(brick))

        # calculate change in x,y values of ball
        angle = self.angle - 90  # correct for quadrant IV
        increment_x = cos(radians(angle)) * self.speed
        increment_y = sin(radians(angle)) * self.speed

        # finite state machine to set ball state
        if ball in bounds:
            self.ball_state = 'moving'
            for brick, hit in self.bricks.iteritems():
                if ball in hit:
                    self.ball_state = 'hit_brick'
                    delete_brick = brick
                elif ball in paddle:
                    self.ball_state = 'hit_wall'
        elif ball not in bounds:
            if self.canvas.coords('ball')[1] < 400:
                self.ball_state = 'hit_wall'
            else:
                self.ball_state = 'out_of_bounds'
                self._initiate_new_ball()

        # handler for ball state
        if self.ball_state is 'moving':
            self.canvas.move('ball', increment_x, increment_y)
            self.after(15, self._move_ball)
        elif self.ball_state is 'hit_brick' or self.ball_state is 'hit_wall':
            if self.ball_state == 'hit_brick':
                self.canvas.delete(delete_brick)
                del self.bricks[delete_brick]
            self.canvas.move('ball', -increment_x, -increment_y)
            self.angle += choice([119, 120, 121])
            self._move_ball()
Example #15
0
class Game():
    WIDTH = 300
    HEIGHT = 500

    def start(self):
        '''Starts the game.

        Creates a window, a canvas, and a first shape. Binds the event handler.
        Then starts a GUI timer of ms interval self.speed and starts the GUI main 
        loop.

        '''
        #TODO start() needs to be refactored so that the creation of the
        # window, label, and canvas are independent from setting them to
        # defaults and starting the game.
        #
        # There should also be a way for the user to restart and pause
        # the game if he or she wishes.
        #
        # It's a little weird that level is based only on time and that
        # as a result it increases faster and faster. Wouldn't it make
        # more sense for level to be a result of completed lines?
        self.level = 1
        self.score = 0
        self.speed = 500
        self.counter = 0
        self.create_new_game = True

        self.root = Tk()
        self.root.title("Tetris")

        self.status_var = StringVar() 
        self.status_var.set("Level: 1, Score: 0")
        self.status = Label(self.root, 
                textvariable=self.status_var, 
                font=("Helvetica", 10, "bold"))
        self.status.pack()
        
        self.canvas = Canvas(
                self.root, 
                width=Game.WIDTH, 
                height=Game.HEIGHT)
        self.canvas.pack()

        self.root.bind("<Key>", self.handle_events)
        self.timer()
        self.root.mainloop()
    
    def timer(self):
        '''Every self.speed ms, attempt to cause the current_shape to fall().

        If fall() returns False, create a new shape and check if it can fall.
        If it can't, then the game is over.
        
        '''
        if self.create_new_game == True:
            self.current_shape = Shape(self.canvas)
            self.create_new_game = False

        if not self.current_shape.fall():
            lines = self.remove_complete_lines()
            if lines:
                self.score += 10 * self.level**2 * lines**2
                self.status_var.set("Level: %d, Score: %d" % 
                        (self.level, self.score))

            self.current_shape = Shape(self.canvas)
            if self.is_game_over(): 
                #TODO This is a problem. You rely on the timer method to
                # create a new game rather than creating it here. As a 
                # result, there is an intermittent error where the user
                # event keypress Down eventually causes can_move_box
                # to throw an IndexError, since the current shape has
                # no boxes. Instead, you need to cleanly start a new
                # game. I think refactoring start() might help a lot
                # here.
                #
                # Furthermore, starting a new game currently doesn't reset
                # the levels. You should place all your starting constants
                # in the same place so it's clear what needs to be reset
                # when.
                self.create_new_game = True
                self.game_over()

            self.counter += 1
            if self.counter == 5:
                self.level += 1
                self.speed -= 20
                self.counter = 0
                self.status_var.set("Level: %d, Score: %d" % 
                        (self.level, self.score))
        
        self.root.after(self.speed, self.timer)

    def handle_events(self, event):
        '''Handle all user events.'''
        if event.keysym == "Left": self.current_shape.move(-1, 0)
        if event.keysym == "Right": self.current_shape.move(1, 0)
        if event.keysym == "Down": self.current_shape.move(0, 1)
        if event.keysym == "Up": self.current_shape.rotate()

    def is_game_over(self):
        '''Check if a newly created shape is able to fall.

        If it can't fall, then the game is over.

        '''
        for box in self.current_shape.boxes:
            if not self.current_shape.can_move_box(box, 0, 1):
                return True
        return False

    def remove_complete_lines(self):
        shape_boxes_coords = [self.canvas.coords(box)[3] for box 
                in self.current_shape.boxes]
        all_boxes = self.canvas.find_all()
        all_boxes_coords = {k : v for k, v in 
                zip(all_boxes, [self.canvas.coords(box)[3] 
                    for box in all_boxes])}
        lines_to_check = set(shape_boxes_coords)
        boxes_to_check = dict((k, v) for k, v in all_boxes_coords.iteritems()
                if any(v == line for line in lines_to_check))
        counter = Counter()
        for box in boxes_to_check.values(): counter[box] += 1
        complete_lines = [k for k, v in counter.iteritems() 
                if v == (Game.WIDTH/Shape.BOX_SIZE)]
 
        if not complete_lines: return False

        for k, v in boxes_to_check.iteritems():
            if v in complete_lines:
                self.canvas.delete(k)
                del all_boxes_coords[k]
                
        #TODO Would be cooler if the line flashed or something
        for (box, coords) in all_boxes_coords.iteritems():
            for line in complete_lines:
                if coords < line:
                    self.canvas.move(box, 0, Shape.BOX_SIZE)
        return len(complete_lines)

    def game_over(self):
            self.canvas.delete(Tkinter.ALL)
            tkMessageBox.showinfo(
                    "Game Over", 
                    "You scored %d points." % self.score)
Example #16
0
class histogramWidget:
    BACKGROUND = "#222222"
    EDGE_HISTOGRAM_COLOR = "#999999"
    NODE_HISTOGRAM_COLOR = "#555555"
    TOOLTIP_COLOR="#FFFF55"
    
    PADDING = 8
    CENTER_WIDTH = 1
    CENTER_COLOR = "#444444"
    ZERO_GAP = 1
    UPDATE_WIDTH = 9
    UPDATE_COLOR = "#FFFFFF"
    HANDLE_WIDTH = 5
    HANDLE_COLOR = "#FFFFFF"
    HANDLE_LENGTH = (HEIGHT-2*PADDING)
    TICK_COLOR = "#FFFFFF"
    TICK_WIDTH = 10
    TICK_FACTOR = 2
    
    LOG_BASE = 10.0
    
    def __init__(self, parent, x, y, width, height, data, logScale=False, callback=None):
        self.canvas = Canvas(parent,background=histogramWidget.BACKGROUND, highlightbackground=histogramWidget.BACKGROUND,width=width,height=height)
        self.canvas.place(x=x,y=y,width=width,height=height,bordermode="inside")
        
        self.logScale = logScale
        
        self.callback = callback
        
        self.edgeBars = []
        self.nodeBars = []
        
        self.binValues = []
        self.numBins = len(data) - 1
        
        self.currentBin = self.numBins     # start the slider at the highest bin
        
        edgeRange = 0.0
        nodeRange = 0.0
        
        for values in data.itervalues():
            if values[0] > edgeRange:
                edgeRange = values[0]
            if values[1] > nodeRange:
                nodeRange = values[1]
        
        edgeRange = float(edgeRange)    # ensure that it will yield floats when used in calculations...
        nodeRange = float(nodeRange)
        
        if logScale:
            edgeRange = math.log(edgeRange,histogramWidget.LOG_BASE)
            nodeRange = math.log(nodeRange,histogramWidget.LOG_BASE)
        
        # calculate the center line - but don't draw it yet
        self.center_x = histogramWidget.PADDING
        if self.logScale:
            self.center_x += histogramWidget.TICK_WIDTH+histogramWidget.PADDING
        self.center_y = height/2
        self.center_x2 = width-histogramWidget.PADDING
        self.center_y2 = self.center_y + histogramWidget.CENTER_WIDTH
        
        # draw the histograms with background-colored baseline rectangles (these allow tooltips to work on very short bars with little area)
        self.bar_interval = float(self.center_x2 - self.center_x) / (self.numBins+1)
        bar_x = self.center_x
        edge_y2 = self.center_y-histogramWidget.PADDING
        edge_space = edge_y2-histogramWidget.PADDING
        node_y = self.center_y2+histogramWidget.PADDING
        node_space = (height-node_y)-histogramWidget.PADDING
        
        thresholds = sorted(data.iterkeys())
        for threshold in thresholds:
            self.binValues.append(threshold)
            edgeWeight = data[threshold][0]
            nodeWeight = data[threshold][1]
            if logScale:
                if edgeWeight > 0:
                    edgeWeight = math.log(edgeWeight,histogramWidget.LOG_BASE)
                else:
                    edgeWeight = 0
                if nodeWeight > 0:
                    nodeWeight = math.log(nodeWeight,histogramWidget.LOG_BASE)
                else:
                    nodeWeight = 0
            
            bar_x2 = bar_x + self.bar_interval
            
            edge_y = histogramWidget.PADDING + int(edge_space*(1.0-edgeWeight/edgeRange))
            edge = self.canvas.create_rectangle(bar_x,edge_y,bar_x2,edge_y2,fill=histogramWidget.EDGE_HISTOGRAM_COLOR,width=0)
            baseline = self.canvas.create_rectangle(bar_x,edge_y2+histogramWidget.ZERO_GAP,bar_x2,edge_y2+histogramWidget.PADDING,fill=histogramWidget.BACKGROUND,width=0)
            self.canvas.addtag_withtag("Threshold: %f" % threshold,edge)
            self.canvas.addtag_withtag("No. Edges: %i" % data[threshold][0],edge)
            self.canvas.tag_bind(edge,"<Enter>",self.updateToolTip)
            self.canvas.tag_bind(edge,"<Leave>",self.updateToolTip)
            self.edgeBars.append(edge)
            self.canvas.addtag_withtag("Threshold: %f" % threshold,baseline)
            self.canvas.addtag_withtag("No. Edges: %i" % data[threshold][0],baseline)
            self.canvas.tag_bind(baseline,"<Enter>",self.updateToolTip)
            self.canvas.tag_bind(baseline,"<Leave>",self.updateToolTip)
            
            node_y2 = node_y + int(node_space*(nodeWeight/nodeRange))
            node = self.canvas.create_rectangle(bar_x,node_y,bar_x2,node_y2,fill=histogramWidget.NODE_HISTOGRAM_COLOR,width=0)
            baseline = self.canvas.create_rectangle(bar_x,node_y-histogramWidget.PADDING,bar_x2,node_y-histogramWidget.ZERO_GAP,fill=histogramWidget.BACKGROUND,width=0)
            self.canvas.addtag_withtag("Threshold: %f" % threshold,node)
            self.canvas.addtag_withtag("No. Nodes: %i" % data[threshold][1],node)
            self.canvas.tag_bind(node,"<Enter>",self.updateToolTip)
            self.canvas.tag_bind(node,"<Leave>",self.updateToolTip)
            self.nodeBars.append(node)
            self.canvas.addtag_withtag("Threshold: %f" % threshold,baseline)
            self.canvas.addtag_withtag("No. Nodes: %i" % data[threshold][1],baseline)
            self.canvas.tag_bind(baseline,"<Enter>",self.updateToolTip)
            self.canvas.tag_bind(baseline,"<Leave>",self.updateToolTip)
            
            bar_x = bar_x2
        
        # now draw the center line
        self.centerLine = self.canvas.create_rectangle(self.center_x,self.center_y,self.center_x2,self.center_y2,fill=histogramWidget.CENTER_COLOR,width=0)
        
        # draw the tick marks if logarithmic
        if self.logScale:
            tick_x = histogramWidget.PADDING
            tick_x2 = histogramWidget.PADDING+histogramWidget.TICK_WIDTH
            
            start_y = edge_y2
            end_y = histogramWidget.PADDING
            dist = start_y-end_y
            while dist > 1:
                dist /= histogramWidget.TICK_FACTOR
                self.canvas.create_rectangle(tick_x,end_y+dist-1,tick_x2,end_y+dist,fill=histogramWidget.TICK_COLOR,width=0)
            
            start_y = node_y
            end_y = height-histogramWidget.PADDING
            dist = end_y-start_y
            while dist > 1:
                dist /= histogramWidget.TICK_FACTOR
                self.canvas.create_rectangle(tick_x,end_y-dist,tick_x2,end_y-dist+1,fill=histogramWidget.TICK_COLOR,width=0)
        
        # draw the update bar
        bar_x = self.currentBin*self.bar_interval + self.center_x
        bar_x2 = self.center_x2
        bar_y = self.center_y-histogramWidget.UPDATE_WIDTH/2
        bar_y2 = bar_y+histogramWidget.UPDATE_WIDTH
        self.updateBar = self.canvas.create_rectangle(bar_x,bar_y,bar_x2,bar_y2,fill=histogramWidget.UPDATE_COLOR,width=0)
        
        # draw the handle
        handle_x = self.currentBin*self.bar_interval-histogramWidget.HANDLE_WIDTH/2+self.center_x
        handle_x2 = handle_x+histogramWidget.HANDLE_WIDTH
        handle_y = self.center_y-histogramWidget.HANDLE_LENGTH/2
        handle_y2 = handle_y+histogramWidget.HANDLE_LENGTH
        self.handleBar = self.canvas.create_rectangle(handle_x,handle_y,handle_x2,handle_y2,fill=histogramWidget.HANDLE_COLOR,width=0)
        self.canvas.tag_bind(self.handleBar, "<Button-1>",self.adjustHandle)
        self.canvas.tag_bind(self.handleBar, "<B1-Motion>",self.adjustHandle)
        self.canvas.tag_bind(self.handleBar, "<ButtonRelease-1>",self.adjustHandle)
        parent.bind("<Left>",lambda e: self.nudgeHandle(e,-1))
        parent.bind("<Right>",lambda e: self.nudgeHandle(e,1))
        
        # init the tooltip as nothing
        self.toolTipBox = self.canvas.create_rectangle(0,0,0,0,state="hidden",fill=histogramWidget.TOOLTIP_COLOR,width=0)
        self.toolTip = self.canvas.create_text(0,0,state="hidden",anchor="nw")
        self.canvas.bind("<Enter>",self.updateToolTip)
        self.canvas.bind("<Leave>",self.updateToolTip)
    
    def adjustHandle(self, event):
        newBin = int(self.numBins*(event.x-self.center_x)/float(self.center_x2-self.center_x)+0.5)
        if newBin == self.currentBin or newBin < 0 or newBin > self.numBins:
            return
        
        self.canvas.move(self.handleBar,(newBin-self.currentBin)*self.bar_interval,0)
        self.currentBin = newBin
        if self.callback != None:
            self.callback(self.binValues[newBin])
    
    def nudgeHandle(self, event, distance):
        temp = self.currentBin+distance
        if temp < 0 or temp > self.numBins:
            return
        
        self.canvas.move(self.handleBar,distance*self.bar_interval,0)
        self.currentBin += distance
        
        if self.callback != None:
            self.callback(self.binValues[self.currentBin])
    
    def update(self, currentBins):
        currentBar = self.canvas.coords(self.updateBar)
        self.canvas.coords(self.updateBar,currentBins*self.bar_interval+self.center_x,currentBar[1],currentBar[2],currentBar[3])
    
    def updateToolTip(self, event):
        allTags = self.canvas.gettags(self.canvas.find_overlapping(event.x,event.y,event.x+1,event.y+1))
        
        if len(allTags) == 0:
            self.canvas.itemconfig(self.toolTipBox,state="hidden")
            self.canvas.itemconfig(self.toolTip,state="hidden")
            return
        
        outText = ""
        for t in allTags:
            if t == "current":
                continue
            outText += t + "\n"
        
        outText = outText[:-1]  # strip the last return
        
        self.canvas.coords(self.toolTip,event.x+20,event.y)
        self.canvas.itemconfig(self.toolTip,state="normal",text=outText,anchor="nw")
        # correct if our tooltip is off screen
        textBounds = self.canvas.bbox(self.toolTip)
        if textBounds[2] >= WIDTH-2*histogramWidget.PADDING:
            self.canvas.itemconfig(self.toolTip, anchor="ne")
            self.canvas.coords(self.toolTip,event.x-20,event.y)
            if textBounds[3] >= HEIGHT-2*histogramWidget.PADDING:
                self.canvas.itemconfig(self.toolTip, anchor="se")
        elif textBounds[3] >= HEIGHT-2*histogramWidget.PADDING:
            self.canvas.itemconfig(self.toolTip, anchor="sw")
        
        # draw the box behind it
        self.canvas.coords(self.toolTipBox,self.canvas.bbox(self.toolTip))
        self.canvas.itemconfig(self.toolTipBox, state="normal")
Example #17
0
class carGUI:

    carDict = {}
    carIDs = []

    def __init__(self, master):
        self.master = master
        master.title("A simple GUI")

        # Initialize Canvas
        self.canv = Canvas(master)
        self.canv.pack(fill='both', expand=True)

        # Initialize X-Lane
        self.xTop = self.canv.create_line(0,
                                          470,
                                          1000,
                                          470,
                                          fill='black',
                                          tags=('top'))
        self.xBottom = self.canv.create_line(0,
                                             510,
                                             1000,
                                             510,
                                             fill='black',
                                             tags=('left'))

        # Initialize Y-Lane
        self.yLeft = self.canv.create_line(470,
                                           0,
                                           470,
                                           1000,
                                           fill='blue',
                                           tags='right')
        self.yRight = self.canv.create_line(510,
                                            0,
                                            510,
                                            1000,
                                            fill='blue',
                                            tags='bottom')

        # Highlight Intersection
        self.rect = self.canv.create_rectangle(470,
                                               470,
                                               510,
                                               510,
                                               fill='green')

        # Show Regulation Lines
        self.xLimit = self.canv.create_line(470 - 40,
                                            450,
                                            470 - 40,
                                            530,
                                            fill="red")
        self.yLimit = self.canv.create_line(450,
                                            470 - 40,
                                            530,
                                            470 - 40,
                                            fill="red")

        # Create button to begin simulation
        b = Button(text="Start Simluation!", command=self.simClickListener)
        b.pack()

        # Create checkbox to differentiate real world sim from autonomous sim
        self.CheckVar = IntVar()
        self.checkConventional = Checkbutton(text="Conventional System", variable=self.CheckVar, \
            onvalue=1, offvalue=0, height=5)
        self.checkConventional.pack()

        # Create text fields to show first in queue cars
        self.carDisplayX = self.canv.create_text(10,
                                                 10,
                                                 anchor="nw",
                                                 fill="red")
        self.carDisplayY = self.canv.create_text(600,
                                                 10,
                                                 anchor="nw",
                                                 fill="black")

    def drawCar(self, lane, ID):

        if (lane == 1):
            # Draw an X car
            self.rect = self.canv.create_rectangle(0,
                                                   485,
                                                   10,
                                                   495,
                                                   fill='black')
        elif (lane == 2):
            # Draw a Y car
            self.rect = self.canv.create_rectangle(485, 0, 495, 10, fill='red')

        self.canv.addtag_below(self.rect, "HELLO")

        # Register the ID of the car
        self.carIDs.append(ID)
        # Ad the key value pair to the car dictionary for the GUI
        self.carDict[ID] = self.rect

    def moveCars(self, carList, timeInterval):

        self.master.update_idletasks()  # THIS UPDATES THE GUI

        for i in range(0, len(carList)):
            self.canv.move(self.carDict[carList[i].ID],
                           carList[i].velocityX * timeInterval,
                           carList[i].velocityY * timeInterval)

    def highlightCar(self, car, color):
        self.canv.itemconfig(self.carDict[car.ID], fill=color)

    def simClickListener(self):
        from Simulation import simulation as sim
        sim(self)

    def updateCarInformationDisplay(self, car):
        carData = "position X = " + str(car.positionX) + "\nposition Y = " + \
            str(car.positionY) + "\nvelocity X = " + str(car.velocityX) + \
            "\nvelocity Y = " + str(car.velocityY)

        if (car.velocityX > 0):
            self.canv.itemconfig(self.carDisplayX, text=carData)

        else:
            self.canv.itemconfig(self.carDisplayY, text=carData)
Example #18
0
class MazePlannerCanvas(Frame):
    """
    MazePlannerCanvas contains the main frontend workhorse functionality of the entire
    application.
    it allows the user to graphically place nodes and define the edges between them
    """
    def __init__(self, parent, status=None, manager=DataStore()):
        """
        Construct an instance of the MazePlannerCanvas

        :param parent:              The parent widget that the mazePlannerCanvas will sit in
        :param status:              The statusbar that will receive mouse updates
        :type manager: DataStore
        :return:
        """
        Frame.__init__(self, parent)
        self._manager = manager
        self._canvas = Canvas(self, bg="grey", cursor="tcross")
        self._canvas.pack(fill=BOTH, expand=1)
        self._commands = {
            (ControlSpecifier.DRAG_NODE,    ExecutionStage.START)       : self._begin_node_drag,
            (ControlSpecifier.CREATE_EDGE,  ExecutionStage.START)       : self._begin_edge,
            (ControlSpecifier.DRAG_NODE,    ExecutionStage.END)         : self._end_node_drag,
            (ControlSpecifier.CREATE_EDGE,  ExecutionStage.END)         : self._end_edge,
            (ControlSpecifier.DRAG_NODE,    ExecutionStage.EXECUTE)     : self._execute_drag,
            (ControlSpecifier.CREATE_EDGE,  ExecutionStage.EXECUTE)     : self._execute_edge,
            (ControlSpecifier.MENU,         ExecutionStage.EXECUTE)     : self._launch_menu,
            (ControlSpecifier.CREATE_NODE,  ExecutionStage.EXECUTE)     : self.create_new_node,
        }
        self._commands = load_controls(self._commands)
        self._edge_cache = \
            {
                "x_start"       : None,
                "y_start"       : None,
                "x_end"         : None,
                "y_end"         : None,
                "item_start"    : None,
                "item_end"      : None,
                "edge"          : None
            }
        self._command_cache = None
        self._cache = \
            {
                "item"  : None,
                "x"     : 0,
                "y"     : 0,
                "event" : None
            }
        self._status = status
        self._edge_bindings = {}
        self._node_listing = {}
        self._object_listing = {}
        self._curr_start = None
        self._construct(parent)

    def _construct(self, parent):
        """
        Construct all of the event bindings and callbacks for mouse events
        """
        self._canvas.focus_set()
        self._canvas.bind("<B1-Motion>", lambda event, m_event=Input_Event.DRAG_M1: self._handle_mouse_events(m_event, event))
        self._canvas.bind("<B2-Motion>", lambda event, m_event=Input_Event.DRAG_M2: self._handle_mouse_events(m_event, event))
        self._canvas.bind("<B3-Motion>", lambda event, m_event=Input_Event.DRAG_M3: self._handle_mouse_events(m_event, event))
        self._canvas.bind("<ButtonPress-2>", lambda event, m_event=Input_Event.CLICK_M2: self._handle_mouse_events(m_event, event))
        self._canvas.bind("<ButtonRelease-2>", lambda event, m_event=Input_Event.RELEASE_M2: self._handle_mouse_events(m_event, event))
        self._canvas.bind("<ButtonPress-1>", lambda event, m_event=Input_Event.CLICK_M1: self._handle_mouse_events(m_event, event))
        self._canvas.bind("<ButtonPress-3>", lambda event, m_event=Input_Event.CLICK_M3: self._handle_mouse_events(m_event, event))
        self._canvas.bind("<ButtonRelease-1>", lambda event, m_event=Input_Event.RELEASE_M1: self._handle_mouse_events(m_event, event))
        self._canvas.bind("<ButtonRelease-3>", lambda event, m_event=Input_Event.RELEASE_M3: self._handle_mouse_events(m_event, event))
        self._canvas.bind("<Return>", lambda event, m_event=Input_Event.RETURN: self._handle_mouse_events(m_event, event))
        self._canvas.bind("<Double-Button-1>", lambda event, m_event=Input_Event.D_CLICK_M1: self._handle_mouse_events(m_event, event))
        self._canvas.bind("<Double-Button-2>", lambda event, m_event=Input_Event.D_CLICK_M2: self._handle_mouse_events(m_event, event))
        self._canvas.bind("<Double-Button-3>", lambda event, m_event=Input_Event.D_CLICK_M3: self._handle_mouse_events(m_event, event))
        self._canvas.bind("<Motion>", lambda event, m_event=None : self._handle_mot(m_event, event))
        self._canvas.bind("<Enter>", lambda event: self._canvas.focus_set())
        self._canvas.bind("<space>", lambda event, m_event=Input_Event.SPACE: self._handle_mouse_events(m_event, event))

    def _handle_mot(self, m_event, event):
        """
        Callback function to handle movement of the mouse

        Function updates the mouse location status bar as well as setting cache values to the current location
        of the mouse

        :m_event:           The specifier for the type of event that has been generated
        :event:             The tk provided event object
        """
        event.x = int(self._canvas.canvasx(event.x))
        event.y = int(self._canvas.canvasy(event.y))
        self._status.set_text("Mouse X:" + str(event.x) + "\tMouse Y:" + str(event.y))
        item = self._get_current_item((event.x, event.y))
        if self._is_node(item):
            Debug.printi("Node: " + str(item), Debug.Level.INFO)
        if self._is_edge(item):
            d_x = self._edge_bindings[item].x_start - self._edge_bindings[item].x_end
            d_y = self._edge_bindings[item].y_start - self._edge_bindings[item].y_end
            square = (d_x * d_x) + (d_y * d_y)
            distance = int(math.sqrt(square))
            Debug.printi("Edge: " + str(item) + " | Source: "
                         + str(self._edge_bindings[item].item_start) + " | Target: "
                         + str(self._edge_bindings[item].item_end) + " | Length: "
                         + str(distance))
        self._cache["x"] = event.x
        self._cache["y"] = event.y

    def _handle_mouse_events(self, m_event, event):
        """
        Function that routes mouse events to the appropriate handlers

        Prints logging and UI information about the state of the mouse and then routes
        the mouse event to the appropriate handler

        :m_event:           The specifier for the tupe of event that has been generated
        :event:             The tk provided event object
        """
        event.x = int(self._canvas.canvasx(event.x))
        event.y = int(self._canvas.canvasy(event.y))
        self._status.set_text("Mouse X:" + str(self._cache["x"]) + "\tMouse Y:" + str(self._cache["y"]))
        Debug.printet(event, m_event, Debug.Level.INFO)
        self._cache["event"] = event
        try:
            self._commands[m_event]((event.x, event.y))
        except KeyError:
            Debug.printi("Warning, no control mapped to " + m_event, Debug.Level.ERROR)
        self._command_cache = m_event


    def _begin_node_drag(self, coords):
        """
        Handles starting operations for dragging a node

        Updates the cache information regarding a node drag event, we will used this cache value
        as the handle on which node to update the information for

        :coords:            The mouse coordinates associated with this event
        """
        # Determine which node has been selected, cache this information
        item = self._get_current_item(coords)
        if item in self._node_listing:
            self._update_cache(item, coords)

    def _end_node_drag(self, coords):
        """
        Performs actions to complete a node drag operation

        Validates node location, and other associated object information and updates the cache
        when a node drag is completed

        :coords:            The coordinates associated with this event
        """
        if self._cache["item"] is None:
            return

        # Obtain the final points
        x = coords[0]
        y = coords[1]
        item = self._cache["item"]
        self._validate_node_position(coords)

        container = self._manager.request(DataStore.DATATYPE.NODE, item)
        container.x_coordinate = x
        container.y_coordinate = y
        self._manager.inform(DataStore.EVENT.NODE_EDIT, container.empty_container(), self._cache["item"])
        Debug.printi("Node " + str(self._cache["item"]) + " has been moved", Debug.Level.INFO)
        # Clean the cache
        self._clear_cache(coords)

    def _validate_node_position(self, coords):
        """
        if x < 0:
            x = 0
        if y < 0:
            y = 0
        if x > self._canvas.winfo_width():
            x = self._canvas.winfo_width()-25
        if y > self._canvas.winfo_height():
            y = self._canvas.winfo_height()-25
        self._canvas.move(item, x, y)
        """
        pass

    def _execute_drag(self, coords):
        """
        Updates object position on canvas when user is dragging a node

        :param coords:          The coordinates associated with this event
        """
        # Abort drag if the item is not a node
        if self._cache["item"] not in self._node_listing:
            return
        # Update the drawing information
        delta_x = coords[0] - self._cache["x"]
        delta_y = coords[1] - self._cache["y"]

        # move the object the appropriate amount as long as the drag event has not been done on the empty canvas
        if not self._cache["item"] is None:
            self._canvas.move(self._cache["item"], delta_x, delta_y)

        # record the new position
        self._cache["x"] = coords[0]
        self._cache["y"] = coords[1]

        self._update_attached_edges(self._cache["item"], coords)
        self._update_attached_objects(self._cache["item"], coords)

    def _update_attached_objects(self, item, coords):
        if item not in self._object_listing:
            return
        container = self._manager.request(DataStore.DATATYPE.OBJECT, item)
        container.x_coordinate = coords[0]
        container.y_coordinate = coords[1]
        self._manager.inform(DataStore.EVENT.OBJECT_EDIT, container.empty_container(), item)

    def _update_attached_edges(self, node, coords):
        """
        Updates all associated edges related to a node drag event

        :param node:            The node that has been dragged
        :param coords:          The mouse coordinates which are the new coordinates of the node
        """
        # Go through dictionary and gather list of all attached edge bindings for a node
        start_bindings = []
        for key, binding in self._edge_bindings.iteritems():
            if binding.item_start == node:
                start_bindings.append(binding)

        end_bindings = []
        for key, binding in self._edge_bindings.iteritems():
            if binding.item_end == node:
                end_bindings.append(binding)

        #  Adjust the bindings with this node as the starting edge
        for binding in start_bindings:
            self._canvas.delete(binding.edge)
            del self._edge_bindings[binding.edge]
            old_edge = binding.edge
            binding.edge = self._canvas.create_line(coords[0], coords[1], binding.x_end,
                                                    binding.y_end, tags="edge", activefill="RoyalBlue1", tag="edge")
            self._edge_bindings[binding.edge] = binding
            self._manager.update_key(DataStore.EVENT.EDGE_EDIT, binding.edge, old_edge)
            binding.x_start = coords[0]
            binding.y_start = coords[1]

        # Adjust the bindings with this node as the ending edge
        for binding in end_bindings:
            self._canvas.delete(binding.edge)
            del self._edge_bindings[binding.edge]
            old_edge = binding.edge
            binding.edge = self._canvas.create_line(binding.x_start, binding.y_start,
                                                    coords[0], coords[1], tags="edge", activefill="RoyalBlue1", tag="edge")
            self._edge_bindings[binding.edge] = binding
            self._manager.update_key(DataStore.EVENT.EDGE_EDIT, binding.edge, old_edge)
            binding.x_end = coords[0]
            binding.y_end = coords[1]

        # Remember to adjust all of the edges so that they sit under the node images
        self._canvas.tag_lower("edge")

    def _launch_menu(self, coords):
        """
        Callback function in response to the pressing of the Return key

        Launches a context menu based on the location of the mouse
        :param coords:
        :return:
        """
        # Configure the "static" menu entries -- they can't be static without seriously destroying readability
        # due to the Python version that is being used -.- so now it has to be not optimal until I find a better
        # solution
        p_menu = Menu(self._canvas)
        item = self._get_current_item((self._cache["x"], self._cache["y"]))
        updated_coords = self._canvas_to_screen((self._cache["x"], self._cache["y"]))
        if item is None:
            # No node is currently selected, create the general menu
            p_menu.add_command(label="Place Room", command=lambda: self.create_new_node((self._cache["x"], self._cache["y"])))
            p_menu.add_command(label="Delete All", command=lambda: self.delete_all())
            p_menu.tk_popup(updated_coords[0], updated_coords[1])
            return

        if self._is_node(item):
            # Create the node specific menu
            p_menu.add_command(label="Place Object", command=lambda: self._mark_object((self._cache["x"], self._cache["y"])))
            p_menu.add_command(label="Edit Room", command=lambda: self._selection_operation((self._cache["x"], self._cache["y"])))
            p_menu.add_command(label="Delete Room", command=lambda: self.delete_node(self._get_current_item((self._cache["x"], self._cache["y"]))))
            p_menu.add_command(label="Mark as start", command=lambda: self._mark_start_node(self._get_current_item((self._cache["x"], self._cache["y"]))))

            if self._is_object(item):
                # Launch the node menu as well as an an added option for selecting stuff to edit an object
                p_menu.add_command(label="Edit Object", command=lambda: self._edit_object(coords))
                p_menu.add_command(label="Delete Object", command=lambda: self._delete_object(self._get_current_item((self._cache["x"], self._cache["y"]))))
                p_menu.delete(0)
            p_menu.tk_popup(updated_coords[0], updated_coords[1])
            return

        if self._is_edge(item):
            p_menu.add_command(label="Edit Corridor", command=lambda: self._selection_operation((self._cache["x"], self._cache["y"])))
            p_menu.add_command(label="Delete Corridor", command=lambda: self.delete_edge(self._get_current_item((self._cache["x"], self._cache["y"]))))
            p_menu.tk_popup(updated_coords[0], updated_coords[1])
            return

        self._clear_cache(coords)

    def _edit_object(self, coords):

        """
        Awkward moment when you find a threading related bug in the Tkinter library, caused by some
        Tcl issue or something like that.
        The below line must be left commented out otherwise the window_wait call in the dialog will crash
        out with a Tcl ponter based issue :/
        item = self._get_current_item((self._cache["x"], self._cache["y"]))
        This means that we can only use the mouse to edit objects
        """

        item = self._get_current_item(coords)

        if item not in self._object_listing:
            Debug.printi("Not a valid object to edit", Debug.Level.ERROR)
            return
        obj = ObjectDialog(self, coords[0] + 10, coords[1] + 10, populator=self._manager.request(DataStore.DATATYPE.OBJECT, item))
        Debug.printi("Editing object " + str(item), Debug.Level.INFO)
        self._manager.inform(DataStore.EVENT.OBJECT_EDIT, obj._entries, item)
        Debug.printi("Editing object " + str(item), Debug.Level.INFO)

    def _delete_object(self, item):
        if item not in self._object_listing:
            Debug.printi("Object does not exist to delete", Debug.Level.ERROR)
            return
        del self._object_listing[item]
        self._manager.inform(DataStore.EVENT.OBJECT_DELETE, data_id=item)
        self._canvas.itemconfig(item, outline="red", fill="black", activeoutline="black", activefill="red")

    def _mark_object(self, coords, prog=False, data=None):
        """
        Mark a node as containing an object
        :param coords:
        :return:
        """
        # Retrieve the item
        item = self._get_current_item(coords)

        if not prog:
            if item not in self._node_listing:
                Debug.printi("Invalid object placement selection", Debug.Level.ERROR)
                return

            if item in self._object_listing:
                Debug.printi("This room already has an object in it", Debug.Level.ERROR)
                return
            # Retrieve its coordinates
            # Launch the object maker dialog
            obj = ObjectDialog(self, coords[0] + 10, coords[1] + 10, populator=Containers.ObjectContainer(key_val={
                "x_coordinate"  :   coords[0],
                "y_coordinate"  :   coords[1],
                "name"          :   "Object_"+str(item),
                "mesh"          :   None,
                "scale"         :   None
            }))
            entries = obj._entries
        else:
            entries = {
                "x_coordinate": coords[0],
                "y_coordinate": coords[1],
                "name": data["name"],
                "mesh": data["mesh"],
                "scale": data["scale"]
            }
        # Save informatoin to the manager
        self._manager.inform(DataStore.EVENT.OBJECT_CREATE, entries, item)
        self._object_listing[item] = item
        self._canvas.itemconfig(item, fill="blue")
        Debug.printi("Object created in room " + str(item), Debug.Level.INFO)

    def _valid_edge_cache(self):
        """
        Return true if the edge cache contains a valid edge descriptor

        A valid edge descriptor is when the edge has a valid starting node, if the
        edge does not contain a valid starting node, this means that the edge was not
        created in the proper manner and should thus be ignored by any edge operations
        """
        valid = not self._edge_cache["item_start"] == (None,)
        return valid

    def _canvas_to_screen(self, coords):
        """
        Convert canvas coordinates into screen coordinates

        :param coords:              The current canvas coordinates
        :return:
        """
        """
        # upper left corner of the visible region
        x0 = self._canvas.winfo_rootx()
        y0 = self._canvas.winfo_rooty()

        # given a canvas coordinate cx/cy, convert it to window coordinates:
        wx0 = x0 + coords[0]
        wy0 = y0 + coords[1]


        # upper left corner of the visible region

        x0 = self._canvas.canvasx(0)
        y0 = self._canvas.canvasy(0)

        # given a canvas coordinate cx/cy, convert it to window coordinates:
        wx0 = coords[0] - x0
        wy0 = coords[1] - y0
        #"""
        return (self._cache["event"].x_root, self._cache["event"].y_root)

    def _begin_edge(self, coords):
        """
        Begin recording information regarding the placement of an edge

        :param coords:               The coordinates associated with this event
        """
        # Record the starting node
        self._edge_cache["item_start"] = self._get_current_item((self._cache["x"], self._cache["y"]))

        # Abort the operation if the item was not a valid node to be selecting
        if self._edge_cache["item_start"] is None or self._edge_cache["item_start"] not in self._node_listing:
            self._clear_edge_cache()
            return

        self._edge_cache["x_start"] = self._cache["x"]
        self._edge_cache["y_start"] = self._cache["y"]

    def _end_edge(self, coords, prog=False, data=None):
        """
        Perform the operations required to complete an edge creation operation
        :param coords:
        :return:
        """
        # Check if the cursor is over a node, if so continue, else abort
        curr = self._get_current_item((coords[0], coords[1]))
        if not prog:
            if curr is None or not self._valid_edge_cache() or curr not in self._node_listing:
                # Abort the edge creation process
                self._canvas.delete(self._edge_cache["edge"])
                self._clear_edge_cache()
                return

            # Check if this edge already exists in the program
            if self._check_duplicate_edges(self._edge_cache["item_start"], curr):
                self.delete_edge(self._edge_cache["edge"])
                Debug.printi("Multiple edges between rooms not permitted", Debug.Level.ERROR)
                return

            #Ensure that edges arent made between the same room
            if curr == self._edge_cache["item_start"]:
                Debug.printi("Cannot allow paths starting and ending in the same room", Debug.Level.ERROR)
                return

        self._canvas.tag_lower("edge")
        self._edge_cache["item_end"] = curr

        # Note that we use the edge ID as the key
        self._edge_bindings[self._edge_cache["edge"]] = EdgeBind(self._edge_cache)
        self._edge_bindings[self._edge_cache["edge"]].x_end = coords[0]
        self._edge_bindings[self._edge_cache["edge"]].y_end = coords[1]
        # Inform the manager
        if not prog:
            self._manager.inform(
                DataStore.EVENT.EDGE_CREATE,
                    {
                        "source"    :   self._edge_cache["item_start"],
                        "target"    :   self._edge_cache["item_end"],
                        "height"    :   None,
                        "wall1"     :   {
                            "height":Defaults.Edge.WALL_HEIGHT,
                            "textures":{
                                Defaults.Wall.PATH: {
                                    "path":Defaults.Wall.PATH,
                                    "tile_x":Defaults.Wall.TILE_X,
                                    "tile_y":Defaults.Wall.TILE_Y,
                                    "height":None
                                }
                            }
                        } if Defaults.Config.EASY_MAZE else None,
                        "wall2"     : {
                            "height": Defaults.Edge.WALL_HEIGHT,
                            "textures": {
                                Defaults.Wall.PATH: {
                                    "path": Defaults.Wall.PATH,
                                    "tile_x": Defaults.Wall.TILE_X,
                                    "tile_y": Defaults.Wall.TILE_Y,
                                    "height":None
                                }
                            }
                        }
                    } if Defaults.Config.EASY_MAZE else None,
                self._edge_cache["edge"])
        else:
            # We are programmatically adding the edges in
            self._manager.inform(
                DataStore.EVENT.EDGE_CREATE,
                {
                    "source": self._edge_cache["item_start"],
                    "target": self._edge_cache["item_end"],
                    "height": None,
                    "wall1": data["wall1"],
                    "wall2": data["wall2"]
                },
                self._edge_cache["edge"])

        Debug.printi("Edge created between rooms "
                     + str(self._edge_cache["item_start"])
                     + " and "
                     + str(self._edge_cache["item_end"])
                     , Debug.Level.INFO)
        self._clear_edge_cache()
        self._clear_cache(coords)

    def _check_duplicate_edges(self, start_node, end_node):
        for binding in self._edge_bindings.itervalues():
            if ( start_node == binding.item_start and end_node == binding.item_end )\
            or ( start_node == binding.item_end and end_node == binding.item_start):
                return True
        return False

    def _execute_edge(self, coords):
        """
        Perform the operations that occur during the motion of an edge drag

        :param coords:
        :return:
        """
        # Update the line position
        # We will update the line position by deleting and redrawing
        if not self._valid_edge_cache():
            return

        self._canvas.delete(self._edge_cache["edge"])
        self._edge_cache["edge"] = self._canvas.create_line( \
            self._edge_cache["x_start"], self._edge_cache["y_start"],
            coords[0]-1, coords[1]-1, tags="edge", activefill="RoyalBlue1", tag="edge")
        d_x = self._edge_cache["x_start"] - coords[0]
        d_y = self._edge_cache["y_start"] - coords[1]
        square = (d_x * d_x) + (d_y * d_y)
        distance = math.sqrt(square)
        Debug.printi("Current corridor distance: " + str(int(distance)))

    def _update_cache(self, item, coords):
        """
        Update the local cache with the item id and coordinates of the mouse

        :param item:                The item with which to update the cache
        :param coords:              The current event coordinates
        """
        self._cache["item"] = item
        self._cache["x"] = coords[0]
        self._cache["y"] = coords[1]

    def _clear_cache(self, coords):
        """
        Clear the cache

        Set the cache values to the current mouse position and None the item
        :param coords:              The coordinates of the mouse at that event time
        """
        self._cache["item"] = None
        self._cache["x"] = coords[0]
        self._cache["y"] = coords[1]

    def _clear_edge_cache(self):
        """
        Clear the edge cache to None for all values
        :return:
        """
        self._edge_cache["x_start"]       = None,
        self._edge_cache["y_start"]       = None,
        self._edge_cache["x_end"]         = None,
        self._edge_cache["y_end"]         = None,
        self._edge_cache["item_start"]    = None,
        self._edge_cache["item_end"]      = None,
        self._edge_cache["edge"]          = None


    def _get_current_item(self, coords):
        """
        Return the item(if any) that the mouse is currently over
        :param coords:                  The current coordinates of the mouse
        :return:
        """
        item = self._canvas.find_overlapping(coords[0]-1, coords[1]-1, coords[0]+1, coords[1]+1)

        if item is ():
            return None

        # Hacky solution
        # Return the first node that we come across, since they seem to be returned by tkinter
        # in reverse order to their visual positioning, we'll go through the list backwards
        for val in item[::-1]:
            if val in self._node_listing:
                return val

        # Else, just return the first item and be done with it
        return item[0]

    def _is_node(self, obj):
        """
        Returns true if the supplied object is a node
        :param obj:             The object id to id
        :return:
        """
        return obj in self._node_listing

    def _is_edge(self, obj):
        """
        Returns true if the supplied object is an edge

        :param obj:             The object id to id
        :return:
        """
        return obj in self._edge_bindings

    def _is_object(self, obj):
        """
        Returns true if the supplied object is an object

        :param obj:             The object id to id
        :return:
        """
        return obj in self._object_listing

    def _get_obj_type(self, obj):
        """
        Returns the Object type of the supplied object

        :param obj:             The object to identify
        :return:
        """
        if self._is_node(obj):
            return EditableObject.NODE
        if self._is_edge(obj):
            return EditableObject.EDGE
        if self._is_object(obj):
            return EditableObject.OBJECT
        return None

    def _selection_operation(self, coords):
        """
        Contextually create or edit a node
        :param coords:
        :return:
        """
        # Determine the item ID
        item = self._get_current_item(coords)
        self._cache["item"] = item
        true_coords = self._canvas_to_screen((self._cache["x"], self._cache["y"]))

        if self._is_node(item):
            Debug.printi("Node Selected : " + str(item) + " | Launching Editor", Debug.Level.INFO)
            # Make request from object manager using the tag assigned
            populator = self._manager.request(DataStore.DATATYPE.NODE, item)
            updated_node = NodeDialog(self, true_coords[0] + 10, true_coords[1] + 10, populator=populator)
            # post information to object manager, or let the dialog handle it, or whatever
            self._manager.inform(DataStore.EVENT.NODE_EDIT, updated_node._entries, item)
            return

        if self._is_edge(item):
            Debug.printi("Edge Selected : " + str(item) + " | Launching Editor", Debug.Level.INFO)
            # Make a request from the object manager to populate the dialog
            populator = self._manager.request(DataStore.DATATYPE.EDGE, item)
            updated_edge = EdgeDialog(self, true_coords[0] + 10, true_coords[1] + 10, populator=populator)
            # Make sure that information is posted to the object manager
            self._manager.inform(DataStore.EVENT.EDGE_EDIT, updated_edge._entries, item)

            return

        if self._is_object(item):
            self._edit_object(coords)
            return

    def create_new_node(self, coords, prog = False, data=None):
        """
        Creates a new node on the Canvas and adds it to the datastore
        :param coords:
        :return:
        """
        # Create the node on Canvas
        self._cache["item"] = self._canvas.create_rectangle(coords[0], coords[1], coords[0]+25, coords[1]+25,
                                                            outline="red", fill="black", activeoutline="black", activefill="red", tag="node")

        self._node_listing[self._cache["item"]] = self._cache["item"]
        if not prog:
            if not Defaults.Config.EASY_MAZE:

                true_coords = self._canvas_to_screen((self._cache["x"], self._cache["y"]))
                new_node = NodeDialog(self, true_coords[0] + 25, true_coords[1] + 25,
                                      populator=Containers.NodeContainer(
                                          {
                                              "node_id": self._cache["item"],
                                              "x_coordinate": self._cache["x"],
                                              "y_coordinate": self._cache["y"],
                                              "room_texture": None,
                                              "wall_pictures": None
                                          }))
                entries = new_node._entries
            else:
                entries = {
                    "node_id": self._cache["item"],
                    "x_coordinate": self._cache["x"],
                    "y_coordinate": self._cache["y"],
                    "room_texture": Defaults.Node.ROOM_TEXTURE,
                    "wall_pictures": None
                }
        else:
            pics = data[1]
            data = data[0]
            entries = {
                "node_id": data["id"],
                "x_coordinate": data["x"],
                "y_coordinate": data["y"],
                "room_texture": data["texture"],
                "wall_pictures": pics
            }
        # Inform the datastore
        self._manager.inform(DataStore.EVENT.NODE_CREATE, entries, self._cache["item"])
        self._clear_cache(coords)

    def delete_all(self):
        """
        Delete all nodes and associated edges and objects from the canvas
        """
        # Iterate over each node in the node listing and delete it using delete node
        for key in self._node_listing.keys():
            self.delete_node(key)

        # Delete any rouge edge bindings that may exist
        for binding in self._edge_bindings:
            self.delete_edge(binding)

        self._object_listing.clear()

        # Delete any naughty objects that are left
        self._canvas.delete("all")
        self._manager.inform(DataStore.EVENT.DELETE_ALL)

    def delete_node(self, node_id):
        """
        Delete a node and all its associated edges and object from the canvas

        :param node_id:             The tkinter id of the node to be deleted
        """
        # Delete from our internal representations
        if node_id not in self._node_listing:
            return

        del self._node_listing[node_id]
        # Delete from the canvas
        self._canvas.delete(node_id)

        # Iterate through the edge bindings and delete all of those
        for key in self._edge_bindings.keys():
            if self._edge_bindings[key].item_start == node_id or self._edge_bindings[key].item_end == node_id:
                self.delete_edge(key)
        # Inform the object manager that a node as been deleted
        if node_id in self._object_listing:
            self._delete_object(node_id)
        self._manager.inform(DataStore.EVENT.NODE_DELETE, data_id=node_id)

    def delete_edge(self, edge_id):
        """
        Delete the specified edge from the MazeCanvas

        :param edge_id:             The edge to be deleted
        :return:
        """
        # Go through the edge bindings and delete the appropriate edge
        try:
            # try to delete the edge binding if it exists
            del self._edge_bindings[edge_id]
        except KeyError:
            # Terrible I know, but I dont have the time to find the root cause
            pass
        # Delete the edge from the canvas
        self._canvas.delete(edge_id)
        # Inform the object manager that an edge has been deleted
        self._manager.inform(DataStore.EVENT.EDGE_DELETE, data_id=edge_id)

    def _mark_start_node(self, node_id):
        """
        Mark the passed in node as the starting node
        :param node_id:
        :return:
        """
        # Print the debug information
        # Mark as the new starting node on the canvas, first check that it is a node
        if node_id in self._node_listing:
            Debug.printi("Node:" + str(node_id) + " has been marked as the new starting node", Debug.Level.INFO)
            if self._curr_start is not None:
                # Return the old starting node to its normal colour
                self._canvas.itemconfig(self._curr_start, outline="red", fill="black", activeoutline="black", activefill="red")
            self._curr_start = node_id
            self._canvas.itemconfig(node_id, outline="black", fill="green", activeoutline="green", activefill="black")

        # Inform the object manager that there is a new starting node
        environment_container = self._manager.request(DataStore.DATATYPE.ENVIRONMENT)
        environment_container.start_node = node_id
        self._manager.inform(DataStore.EVENT.ENVIRONMENT_EDIT, environment_container)