Example #1
0
def addScrollingFigure(figure, frame):
    global canvas, mplCanvas, interior, interior_id, cwid
    # set up a canvas with scrollbars
    canvas = Canvas(frame)
    canvas.grid(row=1, column=1, sticky=Tkconstants.NSEW)

    xScrollbar = Scrollbar(frame, orient=Tkconstants.HORIZONTAL)
    yScrollbar = Scrollbar(frame)

    xScrollbar.grid(row=2, column=1, sticky=Tkconstants.EW)
    yScrollbar.grid(row=1, column=2, sticky=Tkconstants.NS)

    canvas.config(xscrollcommand=xScrollbar.set)
    xScrollbar.config(command=canvas.xview)
    canvas.config(yscrollcommand=yScrollbar.set)
    yScrollbar.config(command=canvas.yview)

    # plug in the figure
    figAgg = FigureCanvasTkAgg(figure, canvas)
    mplCanvas = figAgg.get_tk_widget()

    # and connect figure with scrolling region
    cwid = canvas.create_window(0, 0, window=mplCanvas, anchor=Tkconstants.NW)
    printBboxes("Init")
    changeSize(figure, 1)
Example #2
0
class ScrolledCanvas(Frame):
    def __init__(self,
                 parent,
                 width=100,
                 height=100,
                 bg="white",
                 scrollregion=(0, 0, 300, 300)):
        Frame.__init__(self, parent)
        self.canvas = Canvas(self,
                             width=width - 20,
                             height=height - 20,
                             bg=bg,
                             scrollregion=scrollregion)
        self.canvas.grid(row=0, column=0)
        scv = Scrollbar(self, orient="vertical", command=self.canvas.yview)
        sch = Scrollbar(self, orient="horizontal", command=self.canvas.xview)
        self.canvas.configure(xscrollcommand=sch.set, yscrollcommand=scv.set)
        scv.grid(row=0, column=1, sticky="ns")
        sch.grid(row=1, column=0, sticky="ew")
        self.bind("<Configure>", self.resize)
        self.config = False
        self.bind("<Configure>", self.resize)

    def get_canvas(self):
        return self.canvas

    def resize(self, event):
        if self.config:
            self.width, self.height = self.winfo_width(), self.winfo_height()
            self.canvas.config(width=self.width - 20, height=self.height - 20)
        else:
            self.config = True
Example #3
0
    def buildDisplay(self):
        winWidth = 1000
        winHeight = 800
        frame = Frame(self.root, width=winWidth, height=winHeight)
        frame.pack(side=TOP, expand=YES, fill=X)

        c = Canvas(frame,
                   width=winWidth,
                   height=winHeight,
                   scrollregion=(0, 0, self.canvasWidth, self.canvasHeight))

        hbar = Scrollbar(frame, orient=HORIZONTAL)
        hbar.pack(side=BOTTOM, fill=X)
        hbar.config(command=c.xview)
        vbar = Scrollbar(frame, orient=VERTICAL)
        vbar.pack(side=RIGHT, fill=Y)
        vbar.config(command=c.yview)

        c.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
        c.pack(side=LEFT, expand=YES, fill=BOTH)
        self.canvas = c

        editFrame = Frame(self.root, width=winWidth, height=0)
        editFrame.pack(side=BOTTOM, fill=X)
        self.editFrame = editFrame
Example #4
0
    def initUI(self):
        self.parent.title("TNN visualization")
        self.pack(fill=BOTH, expand=1)

        canvas = Canvas(self, bg="#000")

        width, height = 500, 500
        canvas.config(width=width, height=height)
        canvas.create_line(400, 0, 0, 400, width=1, fill="#fff")

        data = clusterize_data()

        #for i in range(30):
        #    x, y = randint(1, height), randint(1, height)
        #    canvas.create_oval(x, y, x+4, y+4, outline="#0f0", fill="#0f0")

        min, max = -3, 3
        range_data = max - min
        step = 500.0/range_data

        for d in data:
            x, y = (max - d[0])*step , (max - d[1])*step
            x, y = 500 - x, 500 - y
            canvas.create_oval(x, y, x+4, y+4, outline="#0f0", fill="#0f0")

        canvas.pack(fill=BOTH, expand=1)
Example #5
0
    def initUI(self):
        self.parent.title("TNN visualization")
        self.pack(fill=BOTH, expand=1)

        canvas = Canvas(self, bg="#000")

        width, height = 500, 500
        canvas.config(width=width, height=height)
        canvas.create_line(400, 0, 0, 400, width=1, fill="#fff")

        data = clusterize_data()

        #for i in range(30):
        #    x, y = randint(1, height), randint(1, height)
        #    canvas.create_oval(x, y, x+4, y+4, outline="#0f0", fill="#0f0")

        min, max = -3, 3
        range_data = max - min
        step = 500.0 / range_data

        for d in data:
            x, y = (max - d[0]) * step, (max - d[1]) * step
            x, y = 500 - x, 500 - y
            canvas.create_oval(x, y, x + 4, y + 4, outline="#0f0", fill="#0f0")

        canvas.pack(fill=BOTH, expand=1)
Example #6
0
File: UI.py Project: Alovez/Pyste
class PasteUI:
    def __init__(self):
        self.tk = Tk()
        self.pm = PasteManager()
        self.scrollbar = Scrollbar(self.tk)
        self.scrollbar.pack(side=RIGHT, fill=Y)
        self.canvas = Canvas(self.tk, yscrollcommand=self.scrollbar.set)
        self.render_rows()
        self.canvas.config(width=300, height=300)
        self.tk.mainloop()

    def render_rows(self, table='default'):
        rows = self.pm.get_value(table)
        for k, item in rows.iteritems():
            label = Label(self.canvas,
                          text=item,
                          height=10,
                          width=50,
                          wraplength=400,
                          justify='left')
            label.bind(
                "<Button-1>",
                lambda e, item=item, label=label: self.paste(item, label))
            label.bind("<Enter>", lambda e, label=label: self.on_enter(label))
            label.bind("<Leave>", lambda e, label=label: self.on_leave(label))
            label.pack()
        self.scrollbar.config(command=self.canvas.yview)
        self.canvas.pack()

    def paste(self, text, element):
        print text
        pyperclip.copy(text)
        element.config(fg="red")
        element.pack()
        self.tk.destroy()

    def on_enter(self, element):
        element.config(fg="#4f4f4f")
        element.pack()

    def on_leave(self, element):
        element.config(fg="black")
        element.pack()
Example #7
0
def run():
    """
    Esegue l'emulatore del pdp8
    """
    CD = pdp8()
    principale = Tk()
    principale.title("Pdp8 Emulator : Assembly Editor")
    emulatore = Toplevel()
    emulatore.title("Pdp8 Emulator")
    emulatore.geometry("1015x589")

    edit = Editor(principale, CD)

    scrollbar1 = AutoScrollbar(emulatore)
    scrollbar1.grid(row=0, column=1, sticky=N + S)
    scrollbar2 = AutoScrollbar(emulatore, orient=HORIZONTAL)
    scrollbar2.grid(row=1, column=0, sticky=E + W)

    finestra = Canvas(emulatore,
                      yscrollcommand=scrollbar1.set,
                      xscrollcommand=scrollbar2.set)
    finestra.grid(row=0, column=0, sticky=N + S + E + W)

    scrollbar1.config(command=finestra.yview)
    scrollbar2.config(command=finestra.xview)

    emulatore.grid_rowconfigure(0, weight=1)
    emulatore.grid_columnconfigure(0, weight=1)

    emul = Emulatore(finestra, edit, CD, emulatore)

    finestra.create_window(0, 0, anchor=NW, window=emul.master)

    emul.master.update_idletasks()

    finestra.config(scrollregion=finestra.bbox("all"))

    principale.protocol("WM_DELETE_WINDOW", edit.exit)
    emulatore.protocol("WM_DELETE_WINDOW", emul.exit)

    principale.mainloop()
    emulatore.mainloop()
Example #8
0
def run():
    """
    Esegue l'emulatore del pdp8
    """
    CD = pdp8()
    principale = Tk()
    principale.title("Pdp8 Emulator : Assembly Editor")
    emulatore = Toplevel()
    emulatore.title("Pdp8 Emulator")
    emulatore.geometry("1015x589")

    edit = Editor(principale, CD)

    scrollbar1 = AutoScrollbar(emulatore)
    scrollbar1.grid(row=0, column=1, sticky=N + S)
    scrollbar2 = AutoScrollbar(emulatore, orient=HORIZONTAL)
    scrollbar2.grid(row=1, column=0, sticky=E + W)

    finestra = Canvas(emulatore,
                      yscrollcommand=scrollbar1.set,
                      xscrollcommand=scrollbar2.set)
    finestra.grid(row=0, column=0, sticky=N + S + E + W)

    scrollbar1.config(command=finestra.yview)
    scrollbar2.config(command=finestra.xview)

    emulatore.grid_rowconfigure(0, weight=1)
    emulatore.grid_columnconfigure(0, weight=1)

    emul = Emulatore(finestra, edit, CD, emulatore)

    finestra.create_window(0, 0, anchor=NW, window=emul.master)

    emul.master.update_idletasks()

    finestra.config(scrollregion=finestra.bbox("all"))

    principale.protocol("WM_DELETE_WINDOW", edit.exit)
    emulatore.protocol("WM_DELETE_WINDOW", emul.exit)

    principale.mainloop()
    emulatore.mainloop()
Example #9
0
def display(image_file):

    root = Tk()
    root.title("Dataflow Graph")
    screen_width = root.winfo_screenwidth() * 1.0
    screen_height = root.winfo_screenheight() * 0.875

    image1 = Image.open(image_file)
    width, height = image1.size
    if width > screen_width or height > screen_height:
        factor = max(width / screen_width, height / screen_height)
        image1 = image1.resize((int(width / factor), int(height / factor)),
                               Image.ANTIALIAS)

    frame = Frame(root, width=image1.size[0], height=image1.size[1])
    frame.grid(row=0, column=0)
    canvas = Canvas(frame,
                    bg='#FFFFFF',
                    width=image1.size[0],
                    height=image1.size[1],
                    scrollregion=(0, 0, image1.size[0], image1.size[1]))
    img = ImageTk.PhotoImage(image1)
    canvas.create_image(0, 0, image=img, anchor="nw")

    hbar = Scrollbar(frame, orient=HORIZONTAL)
    hbar.pack(side=BOTTOM, fill=Tkinter.X)
    hbar.config(command=canvas.xview)
    vbar = Scrollbar(frame, orient=VERTICAL)
    vbar.pack(side=RIGHT, fill=Tkinter.Y)
    vbar.config(command=canvas.yview)
    canvas.config(width=image1.size[0], height=image1.size[1])
    canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
    canvas.pack(side=LEFT, expand=True, fill=BOTH)

    frame.pack()
    # added so that the windows pops up (and is not minimized)
    # --> see http://stackoverflow.com/questions/9083687/python-tkinter-gui-always-loads-minimized
    root.attributes('-topmost', 1)
    root.update()
    root.attributes('-topmost', 0)
    mainloop()
Example #10
0
    def __init__(self, parent, *args, **kw):
        Frame.__init__(self, parent, *args, **kw)           

        # create a canvas object and a vertical scrollbar for scrolling it
        vscrollbar = Scrollbar(self, orient=VERTICAL)
        vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
        canvas = Canvas(self, bd=0, highlightthickness=0,
                        yscrollcommand=vscrollbar.set)
        canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
        vscrollbar.config(command=canvas.yview)

        # reset the view
        canvas.xview_moveto(0)
        canvas.yview_moveto(0)

        # create a frame inside the canvas which will be scrolled with it
        self.interior = interior = Frame(canvas)
        interior_id = canvas.create_window(0, 0, window=interior,
                                           anchor=NW)
        # I don't know why this works.  Seems like it is a maximum height for window
        canvas.config(height = 800)

        # track changes to the canvas and frame width and sync them,
        # also updating the scrollbar
        def _configure_interior(event):
            # update the scrollbars to match the size of the inner frame
            size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
            canvas.config(scrollregion="0 0 %s %s" % size)
            if interior.winfo_reqwidth() != canvas.winfo_width():
                # update the canvas's width to fit the inner frame
                canvas.config(width=interior.winfo_reqwidth())
        interior.bind('<Configure>', _configure_interior)

        def _configure_canvas(event):
            if interior.winfo_reqwidth() != canvas.winfo_width():
                # update the inner frame's width to fill the canvas
                canvas.itemconfigure(interior_id, width=canvas.winfo_width())
        canvas.bind('<Configure>', _configure_canvas)
Example #11
0
def display(image_file):
    
    root = Tk()
    root.title("Dataflow Graph")
    screen_width=root.winfo_screenwidth()*1.0
    screen_height=root.winfo_screenheight()*0.875
    
    image1 = Image.open(image_file)
    width,height=image1.size
    if width>screen_width or height>screen_height:
        factor=max(width/screen_width,height/screen_height)
        image1=image1.resize((int(width/factor),int(height/factor)), Image.ANTIALIAS)

    
    frame = Frame(root, width=image1.size[0],height=image1.size[1])
    frame.grid(row=0,column=0)
    canvas=Canvas(frame,bg='#FFFFFF',width=image1.size[0],height=image1.size[1],scrollregion=(0,0,image1.size[0],image1.size[1]))
    img = ImageTk.PhotoImage(image1)
    canvas.create_image(0,0,image=img, anchor="nw")

    hbar=Scrollbar(frame,orient=HORIZONTAL)
    hbar.pack(side=BOTTOM,fill=Tkinter.X)
    hbar.config(command=canvas.xview)
    vbar=Scrollbar(frame,orient=VERTICAL)
    vbar.pack(side=RIGHT,fill=Tkinter.Y)
    vbar.config(command=canvas.yview)
    canvas.config(width=image1.size[0],height=image1.size[1])
    canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
    canvas.pack(side=LEFT,expand=True,fill=BOTH)

    frame.pack()
    # added so that the windows pops up (and is not minimized) 
    # --> see http://stackoverflow.com/questions/9083687/python-tkinter-gui-always-loads-minimized
    root.attributes('-topmost', 1)
    root.update()
    root.attributes('-topmost', 0)    
    mainloop()
Example #12
0
class Application(Frame, object):
    """The application main class."""
    WIDTH, HEIGHT = 1280, 720
    BG = 'white'
    FONT = 'Verdana'
    FILE_OPEN_OPTIONS = {
        'mode': 'rb',
        'title': 'Choose *.json file',
        'defaultextension': '.json',
        'filetypes': [('JSON file', '*.json')]
    }
    DEFAULTS = 'default_settings.yaml'

    def __init__(self, master=None):
        """Creates application main window with sizes self.WIDTH and self.HEIGHT.

        :param master: instance - Tkinter.Tk instance
        """
        super(Application, self).__init__(master)
        self.master.title('Engine Game')
        self.master.geometry('{}x{}'.format(self.WIDTH, self.HEIGHT))
        self.master.protocol('WM_DELETE_WINDOW', self.exit)

        self.source = None
        self._map = None
        self.points = None
        self.lines = None
        self.captured_point = None
        self.x0 = None
        self.y0 = None
        self.scale_x = None
        self.scale_y = None
        self.font_size = None
        self.coordinates = {}
        self.captured_lines = {}
        self.canvas_obj = AttrDict()
        self.icons = {
            0: PhotoImage(file=join('icons', 'player_city.png')),
            1: PhotoImage(file=join('icons', 'city.png')),
            2: PhotoImage(file=join('icons', 'market.png')),
            3: PhotoImage(file=join('icons', 'store.png')),
            4: PhotoImage(file=join('icons', 'point.png')),
            5: PhotoImage(file=join('icons', 'player_train.png')),
            6: PhotoImage(file=join('icons', 'train.png')),
            7: PhotoImage(file=join('icons', 'crashed_train.png')),
            8: PhotoImage(file=join('icons', 'collision.png')),
            9: PhotoImage(file=join('icons', 'play.png')),
            10: PhotoImage(file=join('icons', 'play_pressed.png')),
            11: PhotoImage(file=join('icons', 'stop.png')),
            12: PhotoImage(file=join('icons', 'stop_pressed.png'))
        }
        self.queue_requests = {
            0: self.set_status_bar,
            1: self.set_player_idx,
            2: self.build_map,
            3: self.refresh_map,
            4: self.set_available_games,
            99: self.bot_control
        }

        self.settings_window = None
        if exists(expanduser(self.DEFAULTS)):
            with open(expanduser(self.DEFAULTS), 'r') as cfg:
                defaults = DefaultsDict.from_yaml(cfg)
            self.host = None if not defaults.host else str(defaults.host)
            self.port = None if not defaults.port else int(defaults.port)
            self.timeout = None if not defaults.timeout else int(defaults.timeout)
            self.username = None if not defaults.username else str(defaults.username)
            self.password = None if not defaults.password else str(defaults.password)
        else:
            self.host, self.port, self.timeout, self.username, self.password = None, None, None, None, None
        self.player_idx = None
        self.posts = {}
        self.trains = {}
        self.select_game_window = False
        self.available_games = None
        self.game = None
        self.num_players = None
        self.num_turns = None
        self.bot = Bot()
        self.bot_thread = None

        self.menu = Menu(self)
        filemenu = Menu(self.menu)
        filemenu.add_command(label='Open file', command=self.file_open)
        filemenu.add_command(label='Server settings', command=self.open_server_settings)
        filemenu.add_command(label='Select game', command=self.select_game)
        filemenu.add_command(label='Exit', command=self.exit)
        self.menu.add_cascade(label='Menu', menu=filemenu)
        master.config(menu=self.menu)

        self._status_bar = StringVar()
        self.label = Label(master, textvariable=self._status_bar)
        self.label.pack()

        self.frame = Frame(self)
        self.frame.bind('<Configure>', self._resize_frame)
        self.canvas = Canvas(self.frame, bg=self.BG, scrollregion=(0, 0, self.winfo_width(), self.winfo_height()))
        self.canvas.bind('<Button-1>', self._capture_point)
        self.canvas.bind('<Motion>', self._move_point)
        self.canvas.bind('<B1-ButtonRelease>', self._release_point)
        self.canvas.bind('<Configure>', self._resize_canvas)
        hbar = Scrollbar(self.frame, orient=HORIZONTAL)
        hbar.pack(side=BOTTOM, fill=X)
        hbar.config(command=self.canvas.xview)
        vbar = Scrollbar(self.frame, orient=VERTICAL)
        vbar.pack(side=RIGHT, fill=Y)
        vbar.config(command=self.canvas.yview)
        self.canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
        self.canvas.pack(fill=BOTH, expand=True)
        self.play = Label(self.canvas, bg='white')
        self.play.configure(image=self.icons[9])
        self.play.bind('<Button-1>', self._play_press)
        self.play.bind('<B1-ButtonRelease>', self._play_release)
        self.stop = Label(self.canvas, bg='white')
        self.stop.configure(image=self.icons[11])
        self.stop.bind('<Button-1>', self._stop_press)
        self.stop.bind('<B1-ButtonRelease>', self._stop_release)
        self.frame.pack(fill=BOTH, expand=True)

        self.weighted = IntVar(value=1)
        self.weighted_check = Checkbutton(self, text='Proportionally to length', variable=self.weighted,
                                          command=self._proportionally)
        self.weighted_check.pack(side=LEFT)

        self.show_weight = IntVar()
        self.show_weight_check = Checkbutton(self, text='Show length', variable=self.show_weight,
                                             command=self.show_weights)
        self.show_weight_check.pack(side=LEFT)

        self.pack(fill=BOTH, expand=True)
        self.requests_executor()
        self.get_available_games()
        self.set_status_bar('Click Play to start the game')
        self.play.place(rely=0.5, relx=0.5, anchor=CENTER)

    @property
    def map(self):
        """Returns the actual map."""
        return self._map

    @map.setter
    def map(self, value):
        """Clears previously drawn map and assigns a new map to self._map."""
        self.clear_map()
        self.canvas.configure(scrollregion=(0, 0, self.canvas.winfo_width(), self.canvas.winfo_height()))
        self.x0, self.y0 = self.canvas.winfo_width() / 2, self.canvas.winfo_height() / 2
        self._map = value

    @staticmethod
    def midpoint(x_start, y_start, x_end, y_end):
        """Calculates a midpoint coordinates between two points.

        :param x_start: int - x coordinate of the start point
        :param y_start: int - y coordinate of the start point
        :param x_end: int - x coordinate of the end point
        :param y_end: int - y coordinate of the end point
        :return: 2-tuple of a midpoint coordinates
        """
        return (x_start + x_end) / 2, (y_start + y_end) / 2

    def _resize_frame(self, event):
        """Calculates new font size each time frame size changes.

        :param event: Tkinter.Event - Tkinter.Event instance for Configure event
        :return: None
        """
        self.font_size = int(0.0125 * min(event.width, event.height))

    def _resize_canvas(self, event):
        """Redraws map each time Canvas size changes. Scales map each time visible part of Canvas is enlarged.

        :param event: Tkinter.Event - Tkinter.Event instance for Configure event
        :return: None
        """
        if self.map:
            k = min(float(event.width) / float(self.x0 * 2), float(event.height) / float(self.y0 * 2))
            self.scale_x, self.scale_y = self.scale_x * k, self.scale_y * k
            self.x0, self.y0 = self.x0 * k, self.y0 * k
            self.redraw_map()
            self.redraw_trains()
            x_start, y_start, x_end, y_end = self.canvas.bbox('all')
            x_start = 0 if x_start > 0 else x_start
            y_start = 0 if y_start > 0 else y_start
            self.canvas.configure(scrollregion=(x_start, y_start, x_end, y_end))

    def _proportionally(self):
        """Rebuilds map and redraws trains."""
        self.build_map()
        self.redraw_trains()

    def _capture_point(self, event):
        """Stores captured point and it's lines.

        :param event: Tkinter.Event - Tkinter.Event instance for ButtonPress event
        :return: None
        """
        x, y = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y)
        obj_ids = self.canvas.find_overlapping(x - 5, y - 5, x + 5, y + 5)
        if not obj_ids:
            return
        for obj_id in obj_ids:
            if obj_id in self.canvas_obj.point.keys():
                self.captured_point = obj_id
                point_idx = self.canvas_obj.point[obj_id]['idx']
                self.captured_lines = {}
                for line_id, attr in self.canvas_obj.line.items():
                    if attr['start_point'] == point_idx:
                        self.captured_lines[line_id] = 'start_point'
                    if attr['end_point'] == point_idx:
                        self.captured_lines[line_id] = 'end_point'
        if self.weighted.get():
            self.weighted.set(0)

    def _release_point(self, event):
        """Writes new coordinates for a moved point and resets self.captured_point and self.captured_lines.

        :param event: Tkinter.Event - Tkinter.Event instance for ButtonRelease event
        :return: None
        """
        if self.captured_point:
            idx = self.canvas_obj.point[self.captured_point]['idx']
            x, y = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y)
            self.coordinates[idx] = (x, y)
            self.points[idx]['x'], self.points[idx]['y'] = (x - self.x0) / self.scale_x, (y - self.y0) / self.scale_y
            self.captured_point = None
            self.captured_lines = {}

    def _move_point(self, event):
        """Moves point and its lines. Moves weights if self.show_weight is set to 1.

        In case some point is moved beyond Canvas border Canvas scrollregion is resized correspondingly.
        :param event: Tkinter.Event - Tkinter.Event instance for Motion event
        :return: None
        """
        if self.captured_point:
            new_x, new_y = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y)
            self.canvas.coords(self.captured_point, new_x, new_y)
            indent_y = self.icons[self.canvas_obj.point[self.captured_point]['icon']].height() / 2 + self.font_size
            if self.canvas_obj.point[self.captured_point]['text_obj']:
                self.canvas.coords(self.canvas_obj.point[self.captured_point]['text_obj'], new_x, new_y - indent_y)
            self.coordinates[self.canvas_obj.point[self.captured_point]['idx']] = (new_x, new_y)
            self.canvas.configure(scrollregion=self.canvas.bbox('all'))

            for line_id, attr in self.captured_lines.items():
                line_attrs = self.canvas_obj.line[line_id]
                if attr == 'start_point':
                    x, y = self.coordinates[line_attrs['end_point']]
                    self.canvas.coords(line_id, new_x, new_y, x, y)
                else:
                    x, y = self.coordinates[line_attrs['start_point']]
                    self.canvas.coords(line_id, x, y, new_x, new_y)
                if self.show_weight.get():
                    mid_x, mid_y = self.midpoint(new_x, new_y, x, y)
                    self.canvas.coords(line_attrs['weight_obj'][1], mid_x, mid_y)
                    r = self.font_size * len(str(line_attrs['weight']))
                    self.canvas.coords(line_attrs['weight_obj'][0], mid_x - r, mid_y - r, mid_x + r, mid_y + r)

            self.redraw_trains()

    def _play_press(self, _):
        """Draws play button pressed icon."""
        self.play.configure(image=self.icons[10])

    def _play_release(self, _):
        """Draws play button icon and calls bot_control method."""
        self.play.configure(image=self.icons[9])
        self.bot_control()

    def _stop_press(self, _):
        """Draws stop button pressed icon."""
        self.stop.configure(image=self.icons[12])

    def _stop_release(self, _):
        """Draws stop buton icon and calls bot_control method."""
        self.stop.configure(image=self.icons[11])
        self.bot_control()

    def set_player_idx(self, value):
        """Sets a player idx value."""
        self.player_idx = value

    def file_open(self):
        """Opens file dialog and builds and draws a map once a file is chosen. Stops bot if its started."""
        path = tkFileDialog.askopenfile(parent=self.master, **self.FILE_OPEN_OPTIONS)
        if path:
            if self.bot_thread:
                self.bot_control()
            self.posts, self.trains = {}, {}
            self.source = path.name
            self.weighted_check.configure(state=NORMAL)
            self.build_map()

    def open_server_settings(self):
        """Opens server settings window."""
        ServerSettings(self, title='Server settings')

    def select_game(self):
        """Opens select game window."""
        self.select_game_window = True
        SelectGame(self, title='Select game')
        self.select_game_window = False
        self.set_status_bar('Click Play to start the game')

    def exit(self):
        """Closes application and stops bot if its started."""
        if self.bot_thread:
            self.bot_control()
        self.master.destroy()

    def bot_control(self):
        """Starts bot for playing the game or stops it if it is started."""
        if not self.bot_thread:
            self.bot_thread = Thread(target=self.bot.start, kwargs={
                'host': self.host,
                'port': self.port,
                'time_out': self.timeout,
                'username': self.username,
                'password': self.password,
                'game': self.game,
                'num_players': self.num_players,
                'num_turns': self.num_turns})
            self.bot_thread.start()
        else:
            self.bot.stop()
            self.bot_thread.join()
            self.bot_thread = None

    def get_available_games(self):
        """Requests a list of available games."""
        if self.select_game_window:
            self.bot.get_available_games(host=self.host, port=self.port, time_out=self.timeout)
        self.after(1000, self.get_available_games)

    def set_available_games(self, games):
        """Sets new value for available games list."""
        self.available_games = games

    def set_status_bar(self, value):
        """Assigns new status bar value and updates it.

        :param value: string - status bar string value
        :return: None
        """
        self._status_bar.set(value)
        self.label.update()

    def build_map(self, source=None):
        """Builds and draws new map.

        :param source: string - source string; could be JSON string or path to *.json file.
        :return: None
        """
        if source:
            self.source = source
        if self.source:
            self.map = Graph(self.source, weighted=self.weighted.get())
            self.set_status_bar('Map title: {}'.format(self.map.name))
            self.points, self.lines = self.map.get_coordinates()
            self.draw_map()

    def draw_map(self):
        """Draws map by prepared coordinates."""
        self.draw_lines()
        self.draw_points()

    def clear_map(self):
        """Clears previously drawn map and resets coordinates and scales."""
        self.canvas.delete('all')
        self.scale_x, self.scale_y = None, None
        self.coordinates = {}

    def redraw_map(self):
        """Redraws existing map by existing coordinates."""
        if self.map:
            self.coordinates = {}
            for obj_id in self.canvas_obj.line:
                self.canvas.delete(obj_id)
            self.draw_lines()
        self.redraw_points()

    def redraw_points(self):
        """Redraws map points by existing coordinates."""
        if self.map:
            for obj_id, attrs in self.canvas_obj.point.items():
                if attrs['text_obj']:
                    self.canvas.delete(attrs['text_obj'])
                self.canvas.delete(obj_id)
            self.draw_points()

    def redraw_trains(self):
        """Redraws existing trains."""
        if self.trains and hasattr(self.canvas_obj, 'train'):
            for obj_id, attrs in self.canvas_obj.train.items():
                self.canvas.delete(attrs['text_obj'])
                self.canvas.delete(obj_id)
        self.draw_trains()

    @prepare_coordinates
    def draw_points(self):
        """Draws map points by prepared coordinates."""
        point_objs = {}
        captured_point_idx = self.canvas_obj.point[self.captured_point]['idx'] if self.captured_point else None
        for idx in self.points.keys():
            x, y = self.coordinates[idx]
            if self.posts and idx in self.posts.keys():
                post_type = self.posts[idx]['type']
                if post_type == 1:
                    status = '{}/{} {}/{} {}/{}'.format(self.posts[idx]['population'],
                                                        self.posts[idx]['population_capacity'],
                                                        self.posts[idx]['product'],
                                                        self.posts[idx]['product_capacity'],
                                                        self.posts[idx]['armor'],
                                                        self.posts[idx]['armor_capacity'])
                elif post_type == 2:
                    status = '{}/{}'.format(self.posts[idx]['product'], self.posts[idx]['product_capacity'])
                else:
                    status = '{}/{}'.format(self.posts[idx]['armor'], self.posts[idx]['armor_capacity'])
                image_id = 0 if post_type == 1 and self.posts[idx]['player_idx'] == self.player_idx else post_type
                point_id = self.canvas.create_image(x, y, image=self.icons[image_id])
                y -= (self.icons[post_type].height() / 2) + self.font_size
                text_id = self.canvas.create_text(x, y, text=status, font="{} {}".format(self.FONT, self.font_size))
            else:
                post_type = 4
                point_id = self.canvas.create_image(x, y, image=self.icons[post_type])
                text_id = None
            point_objs[point_id] = {'idx': idx, 'text_obj': text_id, 'icon': post_type}
            self.captured_point = point_id if idx == captured_point_idx else self.captured_point
        self.canvas_obj['point'] = point_objs

    @prepare_coordinates
    def draw_lines(self):
        """Draws map lines by prepared coordinates and shows their weights if self.show_weight is set to 1."""
        line_objs, captured_lines_idx = {}, {}
        if self.captured_lines:
            for line_id in self.captured_lines.keys():
                captured_lines_idx[self.canvas_obj.line[line_id]['idx']] = line_id
        for idx, attrs in self.lines.items():
            x_start, y_start = self.coordinates[attrs['start_point']]
            x_stop, y_stop = self.coordinates[attrs['end_point']]
            line_id = self.canvas.create_line(x_start, y_start, x_stop, y_stop)
            line_objs[line_id] = {'idx': idx, 'weight': attrs['weight'], 'start_point': attrs['start_point'],
                                  'end_point': attrs['end_point'], 'weight_obj': ()}
            if idx in captured_lines_idx.keys():
                self.captured_lines[line_id] = self.captured_lines.pop(captured_lines_idx[idx])
        self.canvas_obj['line'] = line_objs
        self.show_weights()

    @prepare_coordinates
    def draw_trains(self):
        """Draws trains by prepared coordinates."""
        trains = {}
        for train in self.trains.values():
            start_point = self.lines[train['line_idx']]['start_point']
            end_point = self.lines[train['line_idx']]['end_point']
            weight = self.lines[train['line_idx']]['weight']
            position = train['position']
            x_start, y_start = self.coordinates[start_point]
            x_end, y_end = self.coordinates[end_point]
            delta_x, delta_y = int((x_start - x_end) / weight) * position, int((y_start - y_end) / weight) * position
            x, y = x_start - delta_x, y_start - delta_y
            if train['cooldown'] > 0:
                icon = 7
                status = None
            else:
                icon = 5 if train['player_idx'] == self.player_idx else 6
                status = '{}/{}'.format(train['goods'], train['goods_capacity'])
            indent_y = self.icons[icon].height() / 2
            train_id = self.canvas.create_image(x, y - indent_y, image=self.icons[icon])
            text_id = self.canvas.create_text(x, y - (2 * indent_y + self.font_size), text=status,
                                              font="{} {}".format(self.FONT, self.font_size)) if status else None
            trains[train_id] = {'icon': icon, 'text_obj': text_id}
        self.canvas_obj['train'] = trains

    def show_weights(self):
        """Shows line weights when self.show_weight is set to 1 and hides them when it is set to 0."""
        if not self.canvas_obj:
            return
        if self.show_weight.get():
            for line in self.canvas_obj.line.values():
                if line['weight_obj']:
                    for obj in line['weight_obj']:
                        self.canvas.itemconfigure(obj, state='normal')
                else:
                    x_start, y_start = self.coordinates[line['start_point']]
                    x_end, y_end = self.coordinates[line['end_point']]
                    x, y = self.midpoint(x_start, y_start, x_end, y_end)
                    value = line['weight']
                    size = self.font_size
                    r = int(size) * len(str(value))
                    oval_id = self.canvas.create_oval(x - r, y - r, x + r, y + r, fill=self.BG, width=0)
                    text_id = self.canvas.create_text(x, y, text=value, font="{} {}".format(self.FONT, str(size)))
                    line['weight_obj'] = (oval_id, text_id)
        else:
            for line in self.canvas_obj.line.values():
                if line['weight_obj']:
                    for obj in line['weight_obj']:
                        self.canvas.itemconfigure(obj, state='hidden')

    def requests_executor(self):
        """Dequeues and executes requests. Assigns corresponding label to bot control button."""
        if not self.bot.queue.empty():
            request_type, request_body = self.bot.queue.get_nowait()
            if request_type == 99 and request_body:
                self.open_server_settings()
                request_body = None
            if request_body is not None:
                self.queue_requests[request_type](request_body)
            else:
                self.queue_requests[request_type]()
        if self.bot_thread and self.bot_thread.is_alive():
            if self.play.place_info():
                self.play.place_forget()
                self.stop.place(rely=0.99, relx=0.995, anchor=SE)
        else:
            if self.stop.place_info():
                self.stop.place_forget()
                self.play.place(rely=0.5, relx=0.5, anchor=CENTER)
        self.after(50, self.requests_executor)

    def refresh_map(self, dynamic_objects):
        """Refreshes map with passed dynamic objects.

        :param dynamic_objects: dict - dict of dynamic objects
        :return: None
        """
        for post in dynamic_objects['posts']:
            self.posts[post['point_idx']] = post
        for train in dynamic_objects['trains']:
            self.trains[train['idx']] = train
        self.redraw_points()
        self.redraw_trains()
Example #13
0
class Troop:
    @classmethod
    def init_troop(cls, name, nation):
        strength = random.randint(1, 3)
        health = random.randint(1, 3)
        ranged = random.choice([False, True]) #Starting troops are always melee random.choice([False, True])

        speed = random.randint(2, 4)

        discipline = random.randint(1, 2)

        rank_size = random.randint(4, 15)
        ranks = random.randint(4, 6)

        elite = random.randint(2, 6)

        if ranged:
            weapons = [random.choice(nation.basic_ranged_weapon_list), random.choice(nation.sidearm_list)]
        else:
            weapons = [random.choice(nation.basic_weapon_list), random.choice(nation.basic_weapon_list)]

        #weapons = [random.choice(nation.ranged_weapon_list), random.choice(nation.sidearm_list)]

        armor = random.choice(nation.basic_armor_list)

        mount = nation.mount_none

        if random.randint(0, 100) < elite + 5:
            mount = random.choice(nation.basic_mount_list)


        tier = 1

        # print "Unknown nation has created a new unit: " + str(name) + ", armed with: " + str(weapons[0].name) +", " + str(weapons[1].name) + ", "+str(armor.name)+", "+str(mount.name)+" elite: "+str(elite)

        return cls(name, strength, health, 0, ranged, speed, discipline, rank_size, ranks, weapons, armor, elite, tier, [], mount, troop_nation=nation)

    def __init__(self, name, strength, health, number, ranged, speed, discipline, rank_size, ranks, weapons, armor, elite, tier, upgrades, mount,
                 stats_history=None, arms_history=None, troop_nation=None):
        if arms_history is None:
            arms_history = []
        if stats_history is None:
            stats_history = []
        self.name = name
        self.strength = strength
        self.health = health
        self.number = number

        self.speed = speed

        self.originally_ranged = ranged #This one won't change when the unit swiches to melee mode.
        self.ranged = ranged

        self.discipline = discipline

        self.rank_size = rank_size
        self.ranks = ranks

        self.weapons = weapons
        self.armor = armor
        self.mount = mount

        self.upgrades = upgrades

        self.elite = elite

        self.tier = tier

        self.nation = troop_nation

        if not arms_history:
            self.arms_history = [(self.weapons, self.armor)]
        else:
            self.arms_history = arms_history

        if not stats_history:
            self.stats_history = [utility.base_soldier_stats()]
        else:
            self.stats_history = stats_history

        self.quality = 0

        if self.nation is not None:
            self.nation.troop_tree.append(self)

        self.experience = 1

    #Creates another troop to add to the troop tree
    @classmethod
    def new_troop(cls, self, nation):
        name = nation.language.make_word(nation.language.name_length, True)

        ranged = random.choice([False, True])

        strength = self.strength + random.randint(1, 10 if not ranged else 5)
        health = self.health + random.randint(1, 4 if not ranged else 2)
        discipline = self.discipline + random.randint(0, 1)

        speed = self.speed + random.randint(1, 2)

        rank_size = random.randint(3, 15)
        ranks = random.randint(3, 5)

        if ranged:
            weapons = [random.choice(nation.ranged_weapon_list), random.choice(nation.sidearm_list)]
        else:
            weapons = [random.choice(nation.weapon_list), random.choice(nation.sidearm_list)]

        armor = random.choice(nation.armor_list)

        mount = nation.mount_none

        elite = random.randint(2, 6)

        if random.randint(0, 100) < (elite * 2) + 5:
            mount = random.choice(nation.mount_list)

        # print str(nation.name) + " created a new unit: " + str(name) + ", armed with: " + str(weapons[0].name) +", " + str(weapons[1].name) + ", "+str(armor.name)+", "+str(mount.name)
        #e.append(events.EventTroopCreated('TroopCreated', {'nation_a': nation.name, 'army_a': name, 'equip_a':weapons, 'armor_a':armor}, s_parent.get_current_date()))

        return cls(name, strength, health, 0, ranged, speed, discipline, rank_size, ranks, weapons, armor, elite, self.tier + 1, [], mount, troop_nation=nation)

    def get_info(self):
        res = {}
        res['name'] = self.name
        res['strength'] = self.strength
        res['health'] = self.health
        res['number'] = self.number
        res['speed'] = self.speed
        res['ranged'] = self.ranged
        res['discipline'] = self.discipline
        res['rank_size'] = self.rank_size
        res['ranks'] = self.ranks
        res['weapons'] = map(lambda eqp: eqp.get_info(), self.weapons)
        res['armor'] = self.armor.get_info()
        res['elite'] = self.elite
        res['tier'] = self.tier
        res['mount'] = self.mount

        res['upgrades'] = []
        for upgrade in self.upgrades:
            res['upgrades'].append(upgrade.get_info())

        res['arms_history'] = []
        for weapons, armor in self.arms_history:
            res['arms_history'].append((map(lambda eqp: eqp.get_info(), weapons), armor.get_info()))

        res['stats_history'] = self.stats_history

        return res

    # TODO: Make these actually do something
    def train(self, amount):
        return 0
        #self.elite += random.randint(0, amount)
        #print self.elite

    def upgrade_gear(self):
        return 0
        # if self.quality > 6:
        #     return

        # self.quality += 1

        # #print "upgrading " + str(self.weapons[0].attack)

        # self.weapons[0].upgrade(1)
        # self.weapons[0].upgrade_skill(1)

        # #Sprint "upgrading to" + str(self.weapons[0].attack)

        # self.weapons[1].upgrade(1)
        # self.weapons[1].upgrade_skill(1)

        # self.armor.upgrade(1)
        # self.armor.upgrade_skill(1)

    def save(self, path):
        with open(path + 'army_structure.txt', 'w') as f:
            f.write(str(self.get_info()))

    def handle_battle_end(self, stats):
        self.stats_history[-1] = utility.zip_dict_with(lambda a,b: a + b, self.stats_history[-1], stats)

    def do_rearm(self, nation):
        if self.tier == 1:
            if self.ranged:
                weapons = [random.choice(nation.basic_ranged_weapon_list), random.choice(nation.sidearm_list)]
            else:
                weapons = [random.choice(nation.basic_weapon_list), random.choice(nation.basic_weapon_list)]

            armor = random.choice(nation.basic_armor_list)

            mount = nation.mount_none

            if random.randint(0, 100) < self.elite + 5:
                mount = random.choice(nation.basic_mount_list)
        else:
            if self.ranged:
                weapons = [random.choice(nation.ranged_weapon_list), random.choice(nation.sidearm_list)]
            else:
                weapons = [random.choice(nation.weapon_list), random.choice(nation.sidearm_list)]

            armor = random.choice(nation.armor_list)

            mount = nation.mount_none

            if random.randint(0, 100) < (self.elite * 2) + 5:
                mount = random.choice(nation.mount_list)

        self.weapons = weapons
        self.armor = armor
        self.mount = mount

        self.arms_history.append((self.weapons, self.armor, self.mount))
        self.stats_history.append(utility.base_soldier_stats())

        return self

    def rearm(self, name, new_weapons, new_armor, new_mount):
        if self.name == name:
            self.weapons = new_weapons
            self.armor = new_armor
            self.mount = new_mount
        else:
            for upgrade in self.upgrades:
                upgrade.rearm(name, new_weapons, new_armor, new_mount)

    def show_information_gui(self):
        self.gui_window = Tk()
        self.gui_window.title(self.name)
        self.gui_window.geometry("400x625+0+0")
        self.gui_window.config(background='white')

        self.ranged_label = gui.Label(self.gui_window, text='Is ranged: {}'.format(self.ranged))
        self.ranged_label.grid(row=0, sticky=W)

        self.mount_label = gui.Label(self.gui_window, text='Mount: {}'.format(self.mount.name))
        self.mount_label.grid(row=1, sticky=W)

        self.strength_label = gui.Label(self.gui_window, text='Strength: {}'.format(self.strength))
        self.strength_label.grid(row=2, sticky=W)

        self.health_label = gui.Label(self.gui_window, text='Health: {}'.format(self.health))
        self.health_label.grid(row=3, sticky=W)

        self.discipline_label = gui.Label(self.gui_window, text='Discipline: {}'.format(self.discipline))
        self.discipline_label.grid(row=4, sticky=W)


        self.discipline_label = gui.Label(self.gui_window, text='Cost: {}'.format(self.get_soldier_cost()))
        self.discipline_label.grid(row=5, sticky=W)

        self.arrangement = gui.Label(self.gui_window, text='Arrangement: {}x{}'.format(self.rank_size, self.ranks))
        self.arrangement.grid(row=6, sticky=W)

        self.arrangement_canvas = Canvas(self.gui_window, width = (self.rank_size + 1) * (TROOP_RADIUS + 1), height= (self.ranks + 1) * (TROOP_RADIUS + 1))
        self.arrangement_canvas.config(background='white')
        self.arrangement_canvas.grid(row=7, sticky=W)

        for x in xrange(1, self.rank_size + 1):
            for y in xrange(1, self.ranks + 1):
                base_x, base_y = x * (TROOP_RADIUS + 1), y * (TROOP_RADIUS + 1)
                self.arrangement_canvas.create_oval(base_x, base_y, base_x + TROOP_RADIUS, base_y + TROOP_RADIUS)

        self.upgrade_label = gui.Label(self.gui_window, text='Upgrades:')
        self.upgrade_label.grid(row=8, sticky=W)

        self.upgrade_buttons = []
        for (i, upgrade) in enumerate(self.upgrades):
            new_upgrade_button = gui.Button(self.gui_window, text=upgrade.name, command=upgrade.show_information_gui)
            new_upgrade_button.grid(row=9, column=i, sticky=W)

            self.upgrade_buttons.append(new_upgrade_button)

        self.history_choice = StringVar()
        self.history_choice.set(self.stringify_history(0))

        self.stats_label = gui.Label(self.gui_window, text='Stats:')
        self.stats_label.grid(row=10, column=0, sticky=W)

        self.stats_choice = OptionMenu(self.gui_window, self.history_choice, *map(self.stringify_history, range(len(self.arms_history))))
        self.stats_choice.config(background='white')
        self.stats_choice['menu'].config(background='white')
        self.stats_choice.grid(row=10, column=1, sticky=W)

        self.stats_select = gui.Button(self.gui_window, text='Select', command=self.select_history)
        self.stats_select.grid(row=10, column=2, sticky=W)

        self.stats_display = Listbox(self.gui_window)
        self.stats_display.grid(row=11, column=0, columnspan=3, sticky=W+E)

        self.select_history()

    def get_soldier_cost(self):
        amount = 0
        for weapon in self.weapons:
            amount += weapon.cost

        amount += self.armor.cost
        amount += self.mount.cost

        return amount

    def stringify_history(self, i):
        weapon_str = ', '.join(map(lambda i: i.name, self.arms_history[i][0]))
        armor_str = self.arms_history[i][1].name
        mount_str = self.mount.name
        return '{}: ({}, {}), {}'.format(i, weapon_str, armor_str, mount_str)

    def select_history(self):
        history_index = int(self.history_choice.get().split(':')[0])

        self.stats_display.delete(0, END)
        for stat in self.stats_history[history_index]:
            self.stats_display.insert(END, '{}: {}'.format(utility.displayify_text(stat), self.stats_history[history_index][stat]))

    def add_number(self, number, nation):
        self.number += number
        #e.append(events.EventArmyRaised('ArmyRaised', {'nation_a': nation.name, 'army_a': self.name, 'raised_a':number}, s_parent.get_current_date()))

        if self.number > self.elite** math.sqrt(self.tier): #If we have enough troops, we will create another, better, rank of troops
            if len(self.upgrades) < 3:
                self.upgrades.append(Troop.new_troop(self, nation))

                self.upgrades[-1].upgrades = [] #Because it wants to put itself as an upgrade, for some reason. TODO

        if self.number < 0:
            self.number = 0

        #Upgrade troops if possible.
        if self.number > (self.elite * self.tier) and len(self.upgrades) > 0:
            upgrading = random.randint(1, self.number // self.elite)
            self.number -= upgrading

            per_upgrade = upgrading // len(self.upgrades)
            for upgrade in self.upgrades:
                total_cost = nation.get_soldier_cost(upgrade)

                if nation.money > total_cost:
                    upgrade.add_number(per_upgrade, nation)
                    #print str(nation.name) + " raised an army of " + str(number) + " " + str(self.name)
                else:
                    self.number += per_upgrade #Add these people back, because they weren't actually upgraded.

        nation.update_tree(self)

        return self

    def reset(self):
        return self.zero().reset_stats()

    def reset_stats(self):
        self.stats_history = [utility.base_soldier_stats()]

        return self

    def zero(self):
        return self.copy().remove_number('', self.size())

    def add_army(self, other):
        self.add_to(other.name, other.number)

        for i in other.upgrades:
            self.add_army(i)

    def add_to(self, type, number):
        if self.name == type:
            self.number += number

            return self
        else:
            for upgrade in self.upgrades:
                if upgrade.name == type:
                    upgrade.number += number

                    return self

            for upgrade in self.upgrades:
                val = upgrade.add_to(type, number)

                if val is not None:
                    return self

            return None

    #Returns a list of the unit + it's upgrades
    def make_upgrade_list(self):
        return sorted([self] + reduce(lambda a, b: a + b, [i.make_upgrade_list() for i in self.upgrades], []), key=lambda a: a.strength * a.health)

    def copy(self):
        return Troop(self.name, self.strength, self.health, 0, self.ranged, self.speed, self.discipline, self.rank_size, self.ranks, [i.copy() for i in self.weapons], self.armor.copy(), self.elite, self.tier, map(lambda i: i.copy(), self.upgrades), self.mount, stats_history=map(dict, self.stats_history), arms_history=list(self.arms_history))

    def is_empty(self):
        return all(map(lambda i: i.is_empty(), self.upgrades)) and self.number == 0

    def trim_empty(self):
        i = 0
        while i < len(self.upgrades):
            if self.upgrades[i].is_empty():
                self.upgrades.pop(i)
            else:
                self.upgrades[i] = self.upgrades[i].trim_empty()

                i += 1

        return self

    def take_number(self, number):
        upgrade_list = self.make_upgrade_list()

        result = self.copy()

        for upgrade in upgrade_list:
            upgraded_amount = 0

            if upgrade.number > number:
                upgrade.number -= number
                upgraded_amount = number

                number = 0
            else:
                upgraded_amount = upgrade.number
                number -= upgrade.number

                upgrade.number = 0

            result.add_to(upgrade.name, upgraded_amount)

            if number == 0:
                break

        return result.trim_empty()

    def remove_number(self, type, number):
        if type == '':
            upgrade_list = self.make_upgrade_list()

            for upgrade in upgrade_list:
                if upgrade.number > number:
                    upgrade.number -= number

                    number = 0

                    return self
                else:
                    number -= upgrade.number

                    upgrade.number = 0

            return self
        else:
            if type == self.name:
                self.number -= number

                return self.number

            for i in self.upgrades:
                if i.name == type:
                    i.number -= number

                    return i.number

            #If not found in any of them, let's check all the children
            for i in self.upgrades:
                val = i.remove_number(type, number)

                if val >= 0:
                    return val

            return -1

    def size(self):
        return self.number + sum(map(lambda t: t.size(), self.upgrades))

    def merge_all(self, other):
        if self.name == other.name:
            self.number += other.number

            for index, upgrade in enumerate(other.upgrades):
                if not upgrade in self.upgrades:
                    self.upgrades.append(upgrade.copy())

                    self.upgrades[-1] = self.upgrades[-1].merge_all(upgrade)
                else:
                    self_upgrade = self.upgrades.index(upgrade)

                    self.upgrades[self_upgrade] = self.upgrades[self_upgrade].merge_all(upgrade)

            return self

    def merge_structure(self, other):
        result = self.zero()

        if result.name == other.name:
            for index, upgrade in enumerate(other.upgrades):
                if not upgrade in result.upgrades:
                    result.upgrades.append(upgrade.zero())

                    result.upgrades[-1] = result.upgrades[-1].merge_structure(upgrade)
                else:
                    self_upgrade = self.upgrades.index(upgrade)

                    result.upgrades[self_upgrade] = result.upgrades[self_upgrade].merge_structure(upgrade)

        return result

    def __eq__(self, other):
        try:
            return self.name == other.name
        except:
            return False

    def __repr__(self):
        return "{0}({1}, {2}): {3} {4}".format(self.name, self.strength, self.health, self.number, self.upgrades)
Example #14
0
    def displayFrame(self, data):
        root = Tk()
        root.title('Book Bank')
        root.geometry("380x620")
        yscrollbar = Scrollbar(root)
        canvas = Canvas(root,
                        background="cadetblue4",
                        yscrollcommand=yscrollbar.set)  # BG="#D2D2D2"

        yscrollbar.config(command=canvas.yview)
        yscrollbar.pack(side=RIGHT, fill=Y)
        # Create the frame which will hold the widgets
        canvas.pack(fill="both", expand=1)

        # im = PhotoImage(file='/Users/RaMD/PycharmProjects/Exchange_Borrowing_Books/wall2.gif')

        lf = LabelFrame(
            canvas,
            text=unicode("قائمة الكتب", "utf-8"),
            bg='cadetblue4',
            fg='gray99'
        ).grid(row=1, column=1, padx=80,
               pady=50)  # pack(expand=1, padx=20, pady=30, ipadx=20, ipady=18)
        frame = Frame(lf)

        im = Image.open('wall3.jpg')
        img = ImageTk.PhotoImage(image=im)
        # canvas.create_image(0, 0, anchor=NE, image=img)
        Label(canvas, image=img).grid(row=0, column=0)
        Label(root,
              text=unicode("الكتب المتوفرة", "utf-8"),
              bg='black',
              fg="white",
              width=40).place(x=0, y=0)

        # method for book pic botton
        def take(id, tableName):
            root.destroy()
            from Frame4_randa import BOOK_PROGRAM
            BOOK_PROGRAM().show(id + 1, tableName)

        def insert(tableName, tableIndex):
            print('entered ')
            root.destroy()
            from insertFrame import database
            database().show(tableName, tableIndex)

        def back():
            root.destroy()
            from FrameSpecialty import Framespecialty
            Framespecialty().frame1()

        im = list(range(len(data)))

        # this loop place book name image and price thaat gots from database
        for i in range(len(data)):
            #byteImgIO = io.BytesIO(data[i][1])
            #byteImg = Image.open(byteImgIO)

            #file_like = BytesIO(data[i][1])
            #img1 = PIL.Image.open(file_like, mode='r').convert('RGB')

            file_like = cStringIO.StringIO(data[i][1])
            img1 = PIL.Image.open(file_like, mode='r').convert('RGB')
            im1 = img1.resize((150, 150),
                              PIL.Image.ANTIALIAS)  # to chage image size
            im[i] = ImageTk.PhotoImage(im1)

            Button(frame,
                   text=unicode(" اسم الكتاب: ", "utf-8") + str(data[i][0]) +
                   '\n' + unicode(" سعر الكتاب: ", "utf-8") + str(data[i][2]),
                   compound='top',
                   image=im[i],
                   command=lambda i=i: take(i, self.tableName)).pack()

        # استعارة الكتاب

        # seller button
        Button(canvas,
               text=unicode(" اضافة كتاب: ", "utf-8"),
               command=lambda: insert(self.tableName, self.tableindex)).place(
                   x=230,
                   y=300)  # .pack(side=BOTTOM,anchor=SE)#,padx=107,pady=5
        Button(canvas,
               text=unicode(" عودة إلى قائمة التخصصات: ", "utf-8"),
               command=back).place(
                   x=195,
                   y=350)  # .pack(side=BOTTOM,anchor=SW)#,padx=90,pady=5

        root.update()
        canvas.create_window(0, 0, window=frame, anchor=E)
        canvas.config(scrollregion=canvas.bbox("all"))
        root.mainloop()
Example #15
0
class Visualiser(threading.Thread):
    STEPS_PER_FRAME = 1

    # It can work with given scale or given sizes
    SCALE = 0.5

    DYNAMIC_SCALE = True
    SIZE_X = 700
    SIZE_Y = 700

    # Vessel size
    VESSEL_X = 16
    VESSEL_Y = 16

    # For displaying angle
    ANGLE_SIZE = 15

    def __init__(self, area):
        super(Visualiser, self).__init__()
        self.area = area

        # Steps
        self.steps = 0

        # Synchronization
        self.lock = threading.Lock()
        self.lock.acquire()

        # List of subs projected map
        self.objects = []

        self.master = Tk()
        self.w = Canvas(self.master, width=sx(Area.SIZE_X), height=sy(Area.SIZE_Y))
        self.master.protocol("WM_DELETE_WINDOW", self.callback)
        self.w.config(borderwidth=sx(10))
        self.w.pack()

        self.__draw_warning_areas()

        # Now we can start
        self.start()

    def callback(self):
        self.master.quit()

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

    def step(self):
        if self.steps >= Visualiser.STEPS_PER_FRAME:
            self.draw()
            self.steps = 0
        else:
            self.steps += 1

    def draw(self):
        # Code to check steps

        self.__draw_one_frame()
        self.master.update()

    def __draw_one_frame(self):
        # Lock
        # ------ SECTION START
        self.__clear_objects()
        s = Sub(self.area)
        self.__draw_ships()
        # ------ SECTION END

    def __draw_ships(self):
        for s in self.area.vessels:
            self.__draw_ship(s)

    def __draw_ship(self, target):
        # Just for dimensions
        ship_start = scale_ship_start(target.x, target.y)
        ship_end = scale_ship_end(target.x, target.y)
        ship = self.w.create_oval(ship_start[0], ship_start[1], ship_end[0], ship_end[1])
        self.objects.append(ship)
        # TODO: Done quickly, not perfect, new function needed
        text = self.w.create_text(ship_start[0],ship_start[1],text=target.name)
        self.objects.append(text)
        # TODO: Done quickly, not perfect, new function needed
        ship_middle = (sx(target.x),sy(target.y))
        line_end = (sx(target.x+np.cos(target.angle)*self.ANGLE_SIZE),sy(target.y+np.sin(target.angle)*self.ANGLE_SIZE))
        line = self.w.create_line(ship_middle[0], ship_middle[1], line_end[0], line_end[1])
        self.objects.append(line)


    def __clear_objects(self):
        for s in self.objects:
            self.w.delete(s)

    def __draw_warning_areas(self):
        self.__draw_warning_area(0, 0, Area.WARN_X0, Area.SIZE_Y)
        self.__draw_warning_area(0, 0, Area.SIZE_Y, Area.WARN_Y0)
        self.__draw_warning_area(Area.WARN_X1, 0, Area.SIZE_X, Area.SIZE_Y)
        self.__draw_warning_area(0, Area.WARN_Y1, Area.SIZE_X, Area.SIZE_Y)

    def __draw_warning_area(self, start_x, start_y, end_x, end_y):
        self.w.create_rectangle(sx(start_x), sy(start_y), sx(end_x), sy(end_y), fill="orange", outline="orange")
Example #16
0
class View(BaseView):

    TEXT_LABEL_OFFSET = 50
    BOX_START_X = 30
    BOX_START_Y = 45
    BOX_WIDTH = 100
    BOX_HEIGHT = 45
    BOX_VERTICAL_OFFSET = 15

    ANOTHER_GUI_OFF = 30
    GUI_WIDTH = 170

    def __init__(self, tkRoot, app, masterComp, parentNode, logger):
        BaseView.__init__(self, tkRoot, app, logger)
        # master (upper level view) component on which this view was issued
        self.masterComp = masterComp

        self.parentNode = parentNode

        # open detailed window - will go into View class, create Canvas in this window
        self.window = Toplevel(self.tkRoot)

        # self.window.bind("<<close-window>>", self.__onClose) # doesn't work
        self.window.protocol("WM_DELETE_WINDOW", self.__onClose)
        self.window.title("%s" % self.masterComp.name)

        self.canvas = Canvas(self.window, bg=BaseView.CANVAS_BG_COLOR)
        self.canvas.pack(expand=YES, fill=BOTH)

        self.app.addActiveView(self.masterComp.name, self)

    def createContent(self):
        self.__setWindowGeometry()
        self.__setScrollableView()
        self.__createBoxes()

    def __setScrollableView(self):
        """Sets a scrollbar and scroll area corresponding to number of
           boxes the views needs to accommodate.
        """
        oneBoxSpace = View.BOX_HEIGHT + View.BOX_VERTICAL_OFFSET
        vertNeeded = len(
            self.parentNode.children) * oneBoxSpace + View.BOX_START_Y
        if (View.BOX_START_Y + vertNeeded) < conf.GUI_HEIGHT:
            return

        self.logger.debug("View needs to be scrollable, setting ...")
        self._setScrollBar(vertNeeded)

    def _setScrollBar(self, verticalSpace):
        """Derived class RosView calls this method."""
        self.canvas.config(scrollregion=(0, 0, 200, verticalSpace))
        self.canvas.config(highlightthickness=0)  # no pixels to border

        sbar = Scrollbar(self.canvas)
        sbar.config(command=self.canvas.yview)  # xlink sbar and canv
        self.canvas.config(yscrollcommand=sbar.set)  # move one moves other
        sbar.pack(side=RIGHT, fill=Y)  # pack first=clip last
        self.canvas.pack(side=LEFT, expand=YES,
                         fill=BOTH)  # canvas clipped first

    def __createBoxes(self):
        # always be the same as self.masterComp.name (title and label must agree)
        group = self.parentNode.name  # self.masterComp.name

        self.canvas.create_text(View.BOX_START_X + View.TEXT_LABEL_OFFSET,
                                View.BOX_START_Y - View.BOX_VERTICAL_OFFSET,
                                text=group,
                                font=self.bigFont)

        nodeKeys = self.parentNode.children.keys()
        nodeKeys.sort()  # sort the keys alphabetically
        for i in range(len(nodeKeys)):
            node = self.parentNode.children[nodeKeys[i]]
            x0 = View.BOX_START_X
            y0 = (View.BOX_START_Y +
                  (i * (View.BOX_HEIGHT + View.BOX_VERTICAL_OFFSET)))
            x1 = x0 + View.BOX_WIDTH
            y1 = y0 + View.BOX_HEIGHT

            box = RenderableBox(self.masterComp.name, self.canvas, node)
            dch = DoubleClickHandler(box, self)
            idBox = box.create(x0, y0, x1, y1, node.state.color)
            idText = box.text(x0 + View.TEXT_LABEL_OFFSET,
                              y0 + View.BOX_HEIGHT / 2, node.name,
                              self.boxTitleFont)
            # bind both IDs - box and text in the box
            self.canvas.tag_bind(idBox, "<Double-1>", dch)
            self.canvas.tag_bind(idText, "<Double-1>", dch)

            # could even perhaps be list and not a dictionary
            self.compStore.append(box)

    def openDetailedView(self, comp):
        # check if view which is to be open has not been opened already
        if self.app.isViewActive(comp.name):
            m = ("View '%s' is already among active windows, "
                 "not created." % comp.name)
            self.logger.warn(m)
            tkMessageBox.showwarning("Quit", m, parent=self.window)
            return

        try:
            rootNode = self.parentNode.children[comp.name]
        except KeyError:
            self.logger.error("Could not access child node for '%s'" %
                              comp.name)
        else:
            V = rootNode.viewerForChildren
            v = V(self.tkRoot, self.app, comp, rootNode, self.logger)
            v.createContent()
            self.logger.debug("View created: name '%s' root node: "
                              "'%s'" % (comp.name, rootNode.name))

    def __onClose(self):
        self.app.removeActiveView(self.masterComp.name)
        self.window.destroy()

    def __setWindowGeometry(self):
        offsetX = View.ANOTHER_GUI_OFF * self.app.activeViewsCount()
        x = conf.GUI_OFF_X + conf.GUI_WIDTH + offsetX
        geom = "%sx%s+%s+%s" % (View.GUI_WIDTH, conf.GUI_HEIGHT, x,
                                conf.GUI_OFF_Y)
        self.window.geometry(geom)
Example #17
0
class Example(Frame):
    def __init__(self, parent, w_size, kmeans):
        Frame.__init__(self, parent)
        self.parent = parent
        self.pack(fill=BOTH, expand=1)
        self.title = self.parent.title()
        self.w_size = w_size

        # canvas
        self.canvas = Canvas(self, bg="#000")
        self.parent.title("Not convergence")
        self.canvas.pack(side="top", fill="both", expand="true")

        self.kmeans = kmeans
        self.draw(200)

    def draw(self, delay):
        """
        """
        colors = ["#0f0", "#0ff", "#ff0", "#fff"]

        self.title = self.parent.title()

        width, height = self.w_size, self.w_size
        self.canvas.config(width=width, height=height)
        self.canvas.delete("all")

        min, max = -2, 10
        range_data = max - min
        step = float(self.w_size) / range_data

        # draw centroids
        for k, c in enumerate(self.kmeans.centroids):
            x, y = (max - c[0]) * step, (max - c[1]) * step
            x, y = self.w_size - x, self.w_size - y

            self.canvas.create_rectangle(x, y, x + 15, y + 15, fill=colors[k])

        # draw clusters
        for k in self.kmeans.clusters:
            for i in self.kmeans.clusters[k]:

                row = self.kmeans.dataset[i]
                x, y = (max - row[0]) * step, (max - row[1]) * step
                x, y = self.w_size - x, self.w_size - y

                self.canvas.create_oval(x,
                                        y,
                                        x + 3,
                                        y + 3,
                                        outline=colors[k],
                                        fill=colors[k])

        self.kmeans.next()

        if not self.kmeans.convergence:
            self.after(delay, lambda: self.draw(delay))
        else:

            text = self.kmeans.purity_function()
            self.parent.title("Convergence reached - Purity value %s" % text)

            self.after(delay)
Example #18
0
class LeftNavView(Canvas):

    def __init__(self, controller, parent):     # prev: def __init__(self, main_window, player_, left_nav):
        self.controller = controller
        self.parent = parent
        self.app = self.parent.app
        self.enabled = False

    def build(self):

        if self.enabled:
            self.redraw()
        else:
            self.build_left_nav_menu()
            self.enabled = True

    def build_left_nav_menu(self):

        app = self.app
        main_window = self.app.main_controller.view
        player = self.app.game.player

        # global left_nav, left_canvas, left

        left_nav = Frame(main_window, height=main_window.sh, width=200, background=app.conf.left_nav_background)
        left_nav.place(x=0, y=0)

        # left = LeftNav(main_window, player, left_nav)

        self.selected_planet = player.selected_planet
        if isset(player.selected_ship):
            self.selected_ship_name = player.selected_ship.name
        else:
            self.selected_ship_name = ""

        self.main_window = main_window
        self.selected_ship_id = 0

        self.planet_images = []

        self.left_canvas = Canvas(left_nav)
        self.left_canvas.config(background=app.conf.left_nav_background, highlightthickness=0, height=main_window.sh, width=200)
        self.left_canvas.place(x=0, y=0)

        if app.conf.debug_lines == 1:
            self.left_canvas.create_line(0, 0, 200, main_window.sh, fill='red')
            self.left_canvas.create_line(200, 0, 0, main_window.sh, fill='red')

        # left nav values

        self.logo_image = Image.open(app.conf.title_image_path)
        self.logo_image.thumbnail([198, 48], Image.ANTIALIAS)
        self.logo_image_res = ImageTk.PhotoImage(self.logo_image)
        self.new_planet_image = self.logo_image_res
        self.planet_images.append(self.new_planet_image)
        self.label_logo = Label(self.left_canvas, image=self.logo_image_res)
        self.label_logo.config(background=app.conf.left_nav_background)
        self.label_logo.planet_image_res = self.logo_image_res           # keep a reference!
        self.label_logo.place(anchor='n', x=100, y=0)

        # Resources Set
        row = 0
        self.resources_start_y = 55
        self.resources_canvas = Canvas(self.left_canvas)
        self.resources_canvas.config(background=app.conf.left_nav_background,
                                     width=198,
                                     highlightthickness=0,
                                     border=0)
        self.resources_canvas.grid_propagate(False)

        self.resources_canvas.place(anchor='nw', x=0, y=self.resources_start_y)
        self.label_resources = Label(self.resources_canvas, text="Resources:", fg=app.conf.main_text_color)
        self.label_resources.config(background=app.conf.left_nav_background)
        self.label_resources.grid(row=row, column=0, sticky='w')
        row += 1
        self.label_planets = Label(self.resources_canvas, text="Planets:", fg=app.conf.second_text_color)
        self.label_planets.config(background=app.conf.left_nav_background)
        self.label_planets.grid(row=row, column=0, sticky='w')
        self.label_planets_val = Label(self.resources_canvas, text=str(len(player.owned_planets))
                                       , fg=app.conf.second_text_color)
        self.label_planets_val.config(background=app.conf.left_nav_background)
        self.label_planets_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_ships = Label(self.resources_canvas, text="Ships:", fg=app.conf.second_text_color)
        self.label_ships.config(background=app.conf.left_nav_background)
        self.label_ships.grid(row=row, column=0, sticky='w')
        self.label_ships_val = Label(self.resources_canvas, text=len(player.ships), fg=app.conf.second_text_color)
        self.label_ships_val.config(background=app.conf.left_nav_background)
        self.label_ships_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_allies = Label(self.resources_canvas, text="Allies:", fg=app.conf.second_text_color)
        self.label_allies.config(background=app.conf.left_nav_background)
        self.label_allies.grid(row=row, column=0, sticky='w')
        self.label_allies_val = Label(self.resources_canvas, text=len(player.allies), fg=app.conf.second_text_color)
        self.label_allies_val.config(background=app.conf.left_nav_background)
        self.label_allies_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_enemies = Label(self.resources_canvas, text="Enemies:", fg=app.conf.second_text_color)
        self.label_enemies.config(background=app.conf.left_nav_background)
        self.label_enemies.grid(row=row, column=0, sticky='w')
        self.label_enemies_val = Label(self.resources_canvas, text=len(player.enemies), fg=app.conf.second_text_color)
        self.label_enemies_val.config(background=app.conf.left_nav_background)
        self.label_enemies_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_separator = Label(self.resources_canvas, text="", fg=app.conf.left_nav_background, width=24)
        self.label_separator.config(background=app.conf.left_nav_background)
        self.label_separator.grid(row=row, columnspan=2, sticky='e,w')

        # left nav buttons
        self.left_buttons_start_y = main_window.sh-112
        if self.left_buttons_start_y < 500:
            self.left_buttons_start_y = 500

        self.left_buttons_canvas = Canvas(self.left_canvas)
        self.left_buttons_canvas.config(background=app.conf.left_nav_background,
                                        height=200,
                                        width=200,
                                        highlightthickness=0,
                                        border=0)
        self.left_buttons_canvas.place(anchor='n', x=100, y=self.left_buttons_start_y)

        self.button_next_planet = Button(self.left_buttons_canvas, text="Next Planet", padx=60
                                         , highlightbackground=app.conf.left_nav_background)
        self.button_next_ship = Button(self.left_buttons_canvas, text="Next Ship"
                                       , highlightbackground=app.conf.left_nav_background)
        self.button_home_planet = Button(self.left_buttons_canvas, text="Home Planet"
                                         , highlightbackground=app.conf.left_nav_background)
        self.button_end_turn = Button(self.left_buttons_canvas, text="End Turn"
                                      , highlightbackground=app.conf.left_nav_background)
        self.button_next_planet.bind("<Button-1>", self.controller.button_next_planet_clicked)
        self.button_next_ship.bind("<Button-1>", self.controller.button_next_ship_clicked)
        self.button_home_planet.bind("<Button-1>", self.controller.button_home_planet_clicked)
        self.button_end_turn.bind("<Button-1>", self.controller.button_end_turn_clicked)
        self.button_next_planet.grid(row=0, column=0, sticky='w,e')
        self.button_next_ship.grid(row=1, column=0, sticky='w,e')
        self.button_home_planet.grid(row=2, column=0, sticky='w,e')
        self.button_end_turn.grid(row=3, column=0, sticky='w,e')

        # Planet Info Set

        row = 0
        self.planet_info_start_y = self.resources_start_y + 115
        self.planet_info_canvas = Canvas(self.left_canvas)
        self.planet_info_canvas.config(background=app.conf.left_nav_background,
                                       width=198,
                                       highlightthickness=0,
                                       border=0)
        self.planet_info_canvas.grid_propagate(False)
        self.planet_info_canvas.place(anchor='nw', x=0, y=self.planet_info_start_y)
        self.label_planet_info = Label(self.planet_info_canvas, text="Planet Info:", fg=app.conf.main_text_color)
        self.label_planet_info.config(background=app.conf.left_nav_background)
        self.label_planet_info.grid(row=row, column=0, sticky='w')
        row += 1
        self.label_planet_name = Label(self.planet_info_canvas, text="Name:", fg=app.conf.second_text_color)
        self.label_planet_name.config(background=app.conf.left_nav_background)
        self.label_planet_name.grid(row=row, column=0, sticky='w')
        self.label_planet_name_val = Label(self.planet_info_canvas, text=str(player.selected_planet.name)
                                           , fg=app.conf.second_text_color)
        self.label_planet_name_val.config(background=app.conf.left_nav_background)
        self.label_planet_name_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_planet_metals = Label(self.planet_info_canvas, text="Metals:", fg=app.conf.second_text_color)
        self.label_planet_metals.config(background=app.conf.left_nav_background)
        self.label_planet_metals.grid(row=row, column=0, sticky='w')
        self.label_planet_metals_val = Label(self.planet_info_canvas, text=str(player.selected_planet.metals)
                                             , fg=app.conf.second_text_color)
        self.label_planet_metals_val.config(background=app.conf.left_nav_background)
        self.label_planet_metals_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_planet_food = Label(self.planet_info_canvas, text="Food:", fg=app.conf.second_text_color)
        self.label_planet_food.config(background=app.conf.left_nav_background)
        self.label_planet_food.grid(row=row, column=0, sticky='w')
        self.label_planet_food_val = Label(self.planet_info_canvas, text=str(player.selected_planet.food)
                                           , fg=app.conf.second_text_color)
        self.label_planet_food_val.config(background=app.conf.left_nav_background)
        self.label_planet_food_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_planet_terrain = Label(self.planet_info_canvas, text="Terrain:", fg=app.conf.second_text_color)
        self.label_planet_terrain.config(background=app.conf.left_nav_background)
        self.label_planet_terrain.grid(row=row, column=0, sticky='w')
        self.label_planet_terrain_val = Label(self.planet_info_canvas, text=str(get_terrain(player.selected_planet.terrain))
                                              , fg=app.conf.second_text_color)
        self.label_planet_terrain_val.config(background=app.conf.left_nav_background)
        self.label_planet_terrain_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_separator_p = Label(self.planet_info_canvas, text="", fg=app.conf.left_nav_background, width=24)
        self.label_separator_p.config(background=app.conf.left_nav_background)
        self.label_separator_p.grid(row=row, columnspan=2, sticky='e,w')

        # ship info

        row = 0
        self.ship_select_start_y = self.planet_info_start_y + 115
        self.ship_select_canvas = Canvas(self.left_canvas)
        self.ship_select_canvas.config(background=app.conf.left_nav_background,
                                       width=198,
                                       highlightthickness=0,
                                       border=0)
        self.ship_select_canvas.grid_propagate(False)
        self.ship_select_canvas.place(anchor='nw', x=0, y=self.ship_select_start_y)
        self.label_ship_select = Label(self.ship_select_canvas, text="Select Ship:", fg=app.conf.main_text_color)
        self.label_ship_select.config(background=app.conf.left_nav_background)
        self.label_ship_select.grid(row=row, column=0, sticky='w')

        # future implementation

        # if selected_ship.name != '':
        if isset(self.selected_ship_name):

            if app.conf.debug == 1:
                print "Showing Selected Ship (init)"

            current_ship = player.get_ship(self.selected_ship_name)

            row += 1
            self.listbox_ship = Listbox(self.ship_select_canvas, width=198
                                        , background=app.conf.alternate_left_nav_background, borderwidth=1)
            self.listbox_ship.config(selectmode=SINGLE)
            for ship in player.ships:
                self.listbox_ship.insert(END, ship.name)
            self.listbox_ship.selection_set(self.selected_ship_id)
            self.listbox_ship.grid(row=row, columnspan=4, sticky='w,e')
            self.listbox_ship.bind('<<ListboxSelect>>', self.poll_ship_list)

            row = 0
            self.ship_info_start_y = self.ship_select_start_y + 200
            self.ship_info_canvas = Canvas(self.left_canvas)
            self.ship_info_canvas.config(background=app.conf.left_nav_background,
                                         width=198,
                                         highlightthickness=0,
                                         border=0)
            self.ship_info_canvas.grid_propagate(False)
            self.ship_info_canvas.place(anchor='nw', x=0, y=self.ship_info_start_y)
            self.label_ship_info = Label(self.ship_info_canvas, text="Ship Info:", fg=app.conf.main_text_color)
            self.label_ship_info.config(background=app.conf.left_nav_background)
            self.label_ship_info.grid(row=row, column=0, sticky='w')

            row += 1
            self.label_ship_name = Label(self.ship_info_canvas, text="Name:", fg=app.conf.second_text_color)
            self.label_ship_name.config(background=app.conf.left_nav_background)
            self.label_ship_name.grid(row=row, column=0, columnspan=2, sticky='w')
            self.label_ship_name_val = Label(self.ship_info_canvas, text=current_ship.name
                                             , fg=app.conf.second_text_color)
            self.label_ship_name_val.config(background=app.conf.left_nav_background)
            self.label_ship_name_val.grid(row=row, column=2, columnspan=2, sticky='e')

            row += 1
            self.label_ship_attack = Label(self.ship_info_canvas, text="Attack:", fg=app.conf.second_text_color)
            self.label_ship_attack.config(background=app.conf.left_nav_background)
            self.label_ship_attack.grid(row=row, column=0, sticky='w')
            self.label_ship_attack_val = Label(self.ship_info_canvas, text=current_ship.attack
                                             , fg=app.conf.second_text_color)
            self.label_ship_attack_val.config(background=app.conf.left_nav_background)
            self.label_ship_attack_val.grid(row=row, column=1, sticky='e')
            self.label_ship_defense = Label(self.ship_info_canvas, text="Defense:", fg=app.conf.second_text_color)
            self.label_ship_defense.config(background=app.conf.left_nav_background)
            self.label_ship_defense.grid(row=row, column=2, sticky='w')
            self.label_ship_defense_val = Label(self.ship_info_canvas, text=current_ship.defense
                                             , fg=app.conf.second_text_color)
            self.label_ship_defense_val.config(background=app.conf.left_nav_background)
            self.label_ship_defense_val.grid(row=row, column=3, sticky='e')

            row += 1
            self.label_ship_storage = Label(self.ship_info_canvas, text="Storage:", fg=app.conf.second_text_color)
            self.label_ship_storage.config(background=app.conf.left_nav_background)
            self.label_ship_storage.grid(row=row, column=0, columnspan=2, sticky='w')
            self.label_ship_storage_val = Label(self.ship_info_canvas, text=current_ship.storage
                                             , fg=app.conf.second_text_color)
            self.label_ship_storage_val.config(background=app.conf.left_nav_background)
            self.label_ship_storage_val.grid(row=row, column=2, columnspan=2, sticky='e')

            row += 1
            self.label_ship_seats = Label(self.ship_info_canvas, text="Seats:", fg=app.conf.second_text_color)
            self.label_ship_seats.config(background=app.conf.left_nav_background)
            self.label_ship_seats.grid(row=row, column=0, columnspan=2, sticky='w')
            self.label_ship_seats_val = Label(self.ship_info_canvas, text=current_ship.seats
                                             , fg=app.conf.second_text_color)
            self.label_ship_seats_val.config(background=app.conf.left_nav_background)
            self.label_ship_seats_val.grid(row=row, column=2, columnspan=2, sticky='e')

            row += 1
            self.label_separator_s = Label(self.ship_info_canvas, text="", fg=app.conf.left_nav_background, width=24)
            self.label_separator_s.config(background=app.conf.left_nav_background)
            self.label_separator_s.grid(row=row, columnspan=4, sticky='e,w')

        else:

            if app.conf.debug == 1:
                print "No Selected Ship Detected (init)"

            row += 1
            self.listbox_ship = Listbox(self.ship_select_canvas, width=198
                                        , background=app.conf.alternate_left_nav_background, borderwidth=1)
            for ship in player.ships:
                self.listbox_ship.insert(END, ship.name)
            self.listbox_ship.grid(row=row, columnspan=4, sticky='w,e')
            self.listbox_ship.bind('<<ListboxSelect>>', self.poll_ship_list)
            row += 1
            self.label_ship_name = Label(self.ship_select_canvas, text="No Ship Selected", fg=app.conf.second_text_color)
            self.label_ship_name.config(background=app.conf.left_nav_background)
            self.label_ship_name.grid(row=row, columnspan=4, sticky='w')

            row += 1
            self.label_separator_s = Label(self.ship_select_canvas, text="", fg=app.conf.left_nav_background, width=24)
            self.label_separator_s.config(background=app.conf.left_nav_background)
            self.label_separator_s.grid(row=row, columnspan=4, sticky='e,w')

        if app.conf.debug == 1:
            print "CreatedLine:", 0, " ", 0, " ", main_window.sw-200, " ", main_window.sh-200
            print "CreatedLine:", main_window.sw-200, " ", 0, " ", 0, " ", main_window.sh-200
            print "CurrWin0:", convert_coords_x(main_window, 0), convert_coords_y(main_window, 0)

        if app.conf.debug == 1:
            print "Displayed: left_nav,", main_window.sh, ",200"

    def poll_ship_list(self, event):

        w = event.widget
        index = int(w.curselection()[0])
        new_ship_name = w.get(index)
        if isset(self.selected_ship_name):
            if self.selected_ship_name == "":
                if new_ship_name != self.selected_ship_name:
                    self.ship_selction_has_changed(new_ship_name)
                    self.selected_ship_name = new_ship_name
                    self.selected_ship_id = w.curselection()
                    if app.conf.debug == 1:
                        print "SelectedShip:", self.selected_ship_name
                    self.redraw(self.main_window, self.player)
        else:
            self.selected_ship_name = new_ship_name
            self.selected_ship_id = w.curselection()
            self.app.debug(("SelectedShip:", self.selected_ship_name))
            self.redraw()

    def redraw(self):

        app = self.app
        main_window = app.main_controller.view
        player = app.game.player

        self.player = player

        app.debug("Redrawing Left Nav")

        self.label_logo.place(anchor='n', x=100, y=0)
        self.resources_canvas.config(background=app.conf.left_nav_background,
                                     height=main_window.sh-self.resources_start_y-202,
                                     width=198,
                                     highlightthickness=0,
                                     border=0)
        self.resources_canvas.place(anchor='nw', x=0, y=self.resources_start_y)
        row = 0
        self.label_resources.grid(row=row, column=0, sticky='w')
        row += 1
        self.label_planets.grid(row=row, column=0, sticky='w')
        self.label_planets_val.config(text=str(len(player.owned_planets)))
        self.label_planets_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_ships.grid(row=row, column=0, sticky='w')
        self.label_ships_val.config(text=len(player.ships))
        self.label_ships_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_allies.grid(row=row, column=0, sticky='w')
        self.label_allies_val.config(text=len(player.allies))
        self.label_allies_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_enemies.grid(row=row, column=0, sticky='w')
        self.label_enemies_val.config(text=len(player.enemies))
        self.label_enemies_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_separator.grid(row=row, columnspan=2, sticky='e,w')

        # left nav buttons

        self.left_buttons_start_y = main_window.sh-112
        if self.left_buttons_start_y < 500:
            self.left_buttons_start_y = 500
        self.left_buttons_canvas.place(anchor='n', x=100, y=self.left_buttons_start_y)
        self.button_next_planet.grid(row=0, column=0, sticky='w,e')
        self.button_next_ship.grid(row=1, column=0, sticky='w,e')
        self.button_home_planet.grid(row=2, column=0, sticky='w,e')
        self.button_end_turn.grid(row=3, column=0, sticky='w,e')

        app.debug(("Left Buttons Start Y:", self.left_buttons_start_y))

        # Planet Info Set

        row = 0
        self.planet_info_start_y = self.resources_start_y + 115
        self.planet_info_canvas.place(anchor='nw', x=0, y=self.planet_info_start_y)
        self.label_planet_info.grid(row=row, column=0, sticky='w')
        row += 1
        self.label_planet_name.grid(row=row, column=0, sticky='w')
        self.label_planet_name_val.config(text=str(player.selected_planet.name))
        self.label_planet_name_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_planet_metals.grid(row=row, column=0, sticky='w')
        self.label_planet_metals_val.config(text=str(player.selected_planet.metals))
        self.label_planet_metals_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_planet_food.grid(row=row, column=0, sticky='w')
        self.label_planet_food_val.config(text=str(player.selected_planet.food))
        self.label_planet_food_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_planet_terrain.grid(row=row, column=0, sticky='w')
        self.label_planet_terrain_val.config(text=str(get_terrain(player.selected_planet.terrain)))
        self.label_planet_terrain_val.grid(row=row, column=1, sticky='e')
        row += 1
        self.label_separator_p.grid(row=row, columnspan=2, sticky='e,w')

        # prep for ship section

        if isset(self.ship_select_canvas):
            self.ship_select_canvas.destroy()

        # ship info

        row = 0
        self.ship_select_start_y = self.planet_info_start_y + 115
        self.ship_select_canvas = Canvas(self.left_canvas)
        self.ship_select_canvas.config(background=app.conf.left_nav_background,
                                       width=198,
                                       highlightthickness=0,
                                       border=0)
        self.ship_select_canvas.grid_propagate(False)
        self.ship_select_canvas.place(anchor='nw', x=0, y=self.ship_select_start_y)
        self.label_ship_select = Label(self.ship_select_canvas, text="Select Ship:", fg=app.conf.main_text_color)
        self.label_ship_select.config(background=app.conf.left_nav_background)
        self.label_ship_select.grid(row=row, column=0, sticky='w')

        # future implementation

        # if selected_ship.name != '':
        if self.selected_ship_name != "":

            app.debug("Showing Selected Ship (redraw)")

            current_ship = player.get_ship(self.selected_ship_name)

            row += 1
            self.listbox_ship = Listbox(self.ship_select_canvas, width=198
                                        , background=app.conf.alternate_left_nav_background, borderwidth=1)
            self.listbox_ship.config(selectmode=SINGLE)
            for ship in player.ships:
                self.listbox_ship.insert(END, ship.name)
            self.listbox_ship.selection_set(self.selected_ship_id)
            self.listbox_ship.grid(row=row, columnspan=4, sticky='w,e')
            self.listbox_ship.bind('<<ListboxSelect>>', self.poll_ship_list)

            row = 0
            self.ship_info_start_y = self.ship_select_start_y + 200
            self.ship_info_canvas = Canvas(self.left_canvas)
            self.ship_info_canvas.config(background=app.conf.left_nav_background,
                                         width=198,
                                         highlightthickness=0,
                                         border=0)
            self.ship_info_canvas.grid_propagate(False)
            self.ship_info_canvas.place(anchor='nw', x=0, y=self.ship_info_start_y)
            self.label_ship_info = Label(self.ship_info_canvas, text="Ship Info:", fg=app.conf.main_text_color)
            self.label_ship_info.config(background=app.conf.left_nav_background)
            self.label_ship_info.grid(row=row, column=0, sticky='w')

            row += 1
            self.label_ship_name = Label(self.ship_info_canvas, text="Name:", fg=app.conf.second_text_color)
            self.label_ship_name.config(background=app.conf.left_nav_background)
            self.label_ship_name.grid(row=row, column=0, columnspan=2, sticky='w')
            self.label_ship_name_val = Label(self.ship_info_canvas, text=current_ship.name
                                             , fg=app.conf.second_text_color)
            self.label_ship_name_val.config(background=app.conf.left_nav_background)
            self.label_ship_name_val.grid(row=row, column=2, columnspan=2, sticky='e')

            row += 1
            self.label_ship_attack = Label(self.ship_info_canvas, text="Attack:", fg=app.conf.second_text_color)
            self.label_ship_attack.config(background=app.conf.left_nav_background)
            self.label_ship_attack.grid(row=row, column=0, sticky='w')
            self.label_ship_attack_val = Label(self.ship_info_canvas, text=current_ship.attack
                                             , fg=app.conf.second_text_color)
            self.label_ship_attack_val.config(background=app.conf.left_nav_background)
            self.label_ship_attack_val.grid(row=row, column=1, sticky='e')
            self.label_ship_defense = Label(self.ship_info_canvas, text="Defense:", fg=app.conf.second_text_color)
            self.label_ship_defense.config(background=app.conf.left_nav_background)
            self.label_ship_defense.grid(row=row, column=2, sticky='w')
            self.label_ship_defense_val = Label(self.ship_info_canvas, text=current_ship.defense
                                             , fg=app.conf.second_text_color)
            self.label_ship_defense_val.config(background=app.conf.left_nav_background)
            self.label_ship_defense_val.grid(row=row, column=3, sticky='e')

            row += 1
            self.label_ship_storage = Label(self.ship_info_canvas, text="Storage:", fg=app.conf.second_text_color)
            self.label_ship_storage.config(background=app.conf.left_nav_background)
            self.label_ship_storage.grid(row=row, column=0, columnspan=2, sticky='w')
            self.label_ship_storage_val = Label(self.ship_info_canvas, text=current_ship.storage
                                             , fg=app.conf.second_text_color)
            self.label_ship_storage_val.config(background=app.conf.left_nav_background)
            self.label_ship_storage_val.grid(row=row, column=2, columnspan=2, sticky='e')

            row += 1
            self.label_ship_seats = Label(self.ship_info_canvas, text="Seats:", fg=app.conf.second_text_color)
            self.label_ship_seats.config(background=app.conf.left_nav_background)
            self.label_ship_seats.grid(row=row, column=0, columnspan=2, sticky='w')
            self.label_ship_seats_val = Label(self.ship_info_canvas, text=current_ship.seats
                                             , fg=app.conf.second_text_color)
            self.label_ship_seats_val.config(background=app.conf.left_nav_background)
            self.label_ship_seats_val.grid(row=row, column=2, columnspan=2, sticky='e')

            row += 1
            self.label_separator_s = Label(self.ship_info_canvas, text="", fg=app.conf.left_nav_background, width=24)
            self.label_separator_s.config(background=app.conf.left_nav_background)
            self.label_separator_s.grid(row=row, columnspan=4, sticky='e,w')

        else:

            app.debug("No Selected Ship Detected (redraw)")

            row += 1
            self.listbox_ship = Listbox(self.ship_select_canvas, width=198
                                        , background=app.conf.alternate_left_nav_background, borderwidth=1)
            for ship in player.ships:
                self.listbox_ship.insert(END, ship.name)
            self.listbox_ship.grid(row=row, columnspan=2, sticky='w,e')
            self.listbox_ship.bind('<<ListboxSelect>>', self.poll_ship_list)
            row += 1
            self.label_ship_name = Label(self.ship_select_canvas, text="No Ship Selected", fg=app.conf.second_text_color)
            self.label_ship_name.config(background=app.conf.left_nav_background)
            self.label_ship_name.grid(row=row, columnspan=2, sticky='w')

            row += 1
            self.label_separator_s = Label(self.ship_select_canvas, text="", fg=app.conf.left_nav_background, width=24)
            self.label_separator_s.config(background=app.conf.left_nav_background)
            self.label_separator_s.grid(row=row, columnspan=4, sticky='e,w')
Example #19
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 #20
0
class Visualiser(threading.Thread):
    STEPS_PER_FRAME = 1

    # It can work with given scale or given sizes
    SCALE = 0.5

    DYNAMIC_SCALE = True
    SIZE_X = 700
    SIZE_Y = 700

    # Vessel size
    VESSEL_X = 16
    VESSEL_Y = 16

    # For displaying angle
    ANGLE_SIZE = 15

    def __init__(self, area):
        super(Visualiser, self).__init__()
        self.area = area

        # Steps
        self.steps = 0

        # Synchronization
        self.lock = threading.Lock()
        self.lock.acquire()

        # List of subs projected map
        self.objects = []

        self.master = Tk()
        self.w = Canvas(self.master,
                        width=sx(Area.SIZE_X),
                        height=sy(Area.SIZE_Y))
        self.master.protocol("WM_DELETE_WINDOW", self.callback)
        self.w.config(borderwidth=sx(10))
        self.w.pack()

        self.__draw_warning_areas()

        # Now we can start
        self.start()

    def callback(self):
        self.master.quit()

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

    def step(self):
        if self.steps >= Visualiser.STEPS_PER_FRAME:
            self.draw()
            self.steps = 0
        else:
            self.steps += 1

    def draw(self):
        # Code to check steps

        self.__draw_one_frame()
        self.master.update()

    def __draw_one_frame(self):
        # Lock
        # ------ SECTION START
        self.__clear_objects()
        s = Sub(self.area)
        self.__draw_ships()
        # ------ SECTION END

    def __draw_ships(self):
        for s in self.area.vessels:
            self.__draw_ship(s)

    def __draw_ship(self, target):
        # Just for dimensions
        ship_start = scale_ship_start(target.x, target.y)
        ship_end = scale_ship_end(target.x, target.y)
        ship = self.w.create_oval(ship_start[0], ship_start[1], ship_end[0],
                                  ship_end[1])
        self.objects.append(ship)
        # TODO: Done quickly, not perfect, new function needed
        text = self.w.create_text(ship_start[0],
                                  ship_start[1],
                                  text=target.name)
        self.objects.append(text)
        # TODO: Done quickly, not perfect, new function needed
        ship_middle = (sx(target.x), sy(target.y))
        line_end = (sx(target.x + np.cos(target.angle) * self.ANGLE_SIZE),
                    sy(target.y + np.sin(target.angle) * self.ANGLE_SIZE))
        line = self.w.create_line(ship_middle[0], ship_middle[1], line_end[0],
                                  line_end[1])
        self.objects.append(line)

    def __clear_objects(self):
        for s in self.objects:
            self.w.delete(s)

    def __draw_warning_areas(self):
        self.__draw_warning_area(0, 0, Area.WARN_X0, Area.SIZE_Y)
        self.__draw_warning_area(0, 0, Area.SIZE_Y, Area.WARN_Y0)
        self.__draw_warning_area(Area.WARN_X1, 0, Area.SIZE_X, Area.SIZE_Y)
        self.__draw_warning_area(0, Area.WARN_Y1, Area.SIZE_X, Area.SIZE_Y)

    def __draw_warning_area(self, start_x, start_y, end_x, end_y):
        self.w.create_rectangle(sx(start_x),
                                sy(start_y),
                                sx(end_x),
                                sy(end_y),
                                fill="orange",
                                outline="orange")
Example #21
0
class TrailUI:
    def __init__(self, parent, trail=None):
        self.parent = parent
        self.trail = trail
        self.alpha_reflection = trail.alpha_reflection
        self.states = []
        self.probabilitylabels = {}
        ## scrollbar
        # create a canvas object and a vertical scrollbar for scrolling it
        self.scrollframe = Frame(parent)
        self.hsb = Scrollbar(self.scrollframe, orient=Tkinter.HORIZONTAL)
        self.hsb.pack(fill=Tkinter.X, side=BOTTOM, expand=Tkinter.FALSE)
        self.scrollcanvas = Canvas(self.scrollframe,
                                   bd=0,
                                   highlightthickness=0,
                                   xscrollcommand=self.hsb.set)
        self.scrollcanvas.pack(side=LEFT, fill=BOTH, expand=Tkinter.TRUE)
        self.hsb.config(command=self.scrollcanvas.xview)

        # reset the view
        self.scrollcanvas.xview_moveto(0)
        self.scrollcanvas.yview_moveto(0)

        # put trailframe into scrollframe and assign configs
        self.trailframe = interior = Frame(self.scrollcanvas)
        self.interior_id = self.scrollcanvas.create_window(10,
                                                           0,
                                                           window=interior,
                                                           anchor=Tkinter.NW)
        interior.bind('<Configure>', self._configure_interior)
        self.scrollcanvas.bind('<Configure>', self._configure_canvas)

        self.scrollframe.pack(fill=Tkinter.X, expand=1)
        self.infoframe = Frame(parent)
        self.infoframe.pack(fill=Tkinter.X, expand=1, side=BOTTOM)
        self.canvas = Canvas(self.infoframe, width=1000, height=200)
        self.canvas.pack()
        self.b = Button(self.infoframe,
                        text='Disable Propagation',
                        command=self.__toggle_prop)
        self.b.pack()
        self.b2 = Button(self.infoframe,
                         text='Make active only',
                         command=self.__activeonly)
        self.b2.pack()
        self.parent.title("ClusterF**k")
        self.enable_propagation = True
        self.trail.updateColorList()
        self.maxgridcol = -1
        self.trail.initUI(self)

        # Multi Cell Selection
        self.multiselection_pressed = False
        self.dynamicselection_pressed = False
        self.selectedcells = []
        self.parent.bind("<Control_L>", self.__selection_start)
        self.parent.bind("<KeyRelease-Control_L>", self.__selection_end)
        self.parent.bind("<Shift_L>", self.__dynamic_selection_start)
        self.parent.bind("<KeyRelease-Shift_L>", self.__dynamic_selection_end)

        self.parent.bind("<Escape>", lambda event: self._clear_selection())
        self.parent.bind("<Return>", lambda event: self.open_cell_dialogue())

    # track changes to the canvas and frame width and sync them,
    # also updating the scrollbar
    # taken from https://gist.github.com/EugeneBakin/76c8f9bcec5b390e45df
    def _configure_interior(self, event):
        # update the scrollbars to match the size of the inner frame
        size = (self.trailframe.winfo_reqwidth(),
                self.trailframe.winfo_reqheight())
        self.scrollcanvas.config(scrollregion="0 0 %s %s" % size)
        if self.trailframe.winfo_reqwidth() != self.scrollcanvas.winfo_width():
            # update the canvas's width to fit the inner frame
            self.scrollcanvas.config(width=self.trailframe.winfo_reqwidth())

    def _configure_canvas(self, event):
        if self.trailframe.winfo_reqwidth() != self.scrollcanvas.winfo_width():
            # update the inner frame's width to fill the canvas
            self.scrollcanvas.itemconfigure(
                self.trailframe, width=self.scrollcanvas.winfo_width())

    def __selection_start(self, event):
        print "Selection start/continue"
        self.multiselection_pressed = True

    def __dynamic_selection_start(self, event):
        print "Dynamic selection start"
        self.dynamicselection_pressed = True

    def __selection_end(self, event):
        print "Selection end"
        self.multiselection_pressed = False

    def __dynamic_selection_end(self, event):
        print "Dynamic selection end"
        self.dynamicselection_pressed = False

    def open_cell_dialogue(self):
        if len(self.selectedcells) is 0:
            return

        # oldstate = self.__clickedcells[0]["oldstate"]
        # oldstatestr = ",".join(["{:x}".format(x) for x in oldstate])
        oldstatestr = ""

        dialog = StatePopup(
            self, oldstatestr,
            self.selectedcells[0]["state_probs"])  # TODO add probs

        self.trailframe.wait_window(dialog.top)

        newstate = dialog.value
        # set each cell of the selection to the new state
        if newstate is not None:
            for i, cell in enumerate(self.selectedcells):
                cell["stateUI"].state.set(cell["row"], cell["col"],
                                          set(newstate))

        # self._clear_selection()
        self.redraw_all()
        self.redraw_selection()

    def _clear_selection(self):
        for cell in self.selectedcells:
            cell["stateUI"].undraw_selection(cell)

        self.selectedcells = []

    def __toggle_prop(self):
        self.enable_propagation = not self.enable_propagation
        if self.enable_propagation:
            self.b.config(text="Disable Propagation")
            self.redraw_all()
        else:
            self.b.config(text="Enable Propagation")

    def __activeonly(self):
        self.trail.makeActiveOnly()
        self.redraw_all()

    def get_stateui_at(self, row, col):
        # retrieve state from specific grid position
        for state in self.states:
            if state._row is row and state._col is col:
                return state

        return self.get_stateui_at(row, col - 1)

    def redraw_selection(self):
        for cell in self.selectedcells:
            cell["stateUI"].draw_selection(cell)

    def redraw_all(self):
        if self.enable_propagation:
            self.trail.propagate()
            self.trail.getProbability(verbose=True)
        self.redrawColorList()
        self.redraw_states()
        self.redraw_selection()
        if self.enable_propagation:
            self.redraw_probablities()

    def redraw_states(self):
        for state in self.states:
            state.redraw_state()

        if PRINT_PROPS is True:
            for state in self.states:
                state.redraw_propagation()

    def redraw_probablities(self):
        if self.alpha_reflection is True:
            for i, prob in enumerate(self.trail.probabilities):
                overallprob, sboxprob, mixcolprob = prob.getProbability()
                if i < self.trail.rounds:
                    self.probabilitylabels["S" + str(i)].textvar.set(
                        "2^{0:.2f}".format(math.log(sboxprob, 2)))
                    self.probabilitylabels["M" + str(i + 1)].textvar.set(
                        "2^{0:.2f}".format(math.log(mixcolprob, 2)))
                elif i >= self.trail.rounds + 1:
                    self.probabilitylabels["S" + str(i + 2)].textvar.set(
                        "2^{0:.2f}".format(math.log(sboxprob, 2)))
                    self.probabilitylabels["M" + str(i + 1)].textvar.set(
                        "2^{0:.2f}".format(math.log(mixcolprob, 2)))
                else:  # inner round
                    self.probabilitylabels["I"].textvar.set("2^{0:.2f}".format(
                        math.log(overallprob, 2)))
        else:
            for i, prob in enumerate(self.trail.probabilities):
                overallprob, sboxprob, mixcolprob = prob.getProbability()
                self.probabilitylabels["S" + str(i + 1)].textvar.set(
                    "2^{0:.2f}".format(math.log(sboxprob, 2)))
                self.probabilitylabels["M" + str(i + 1)].textvar.set(
                    "2^{0:.2f}".format(math.log(mixcolprob, 2)))

    def redrawColorList(self):
        self.canvas.delete("colorlist")
        self.trail.updateColorList()
        for i, (state, color) in enumerate(self.trail.colorlist.items()):
            statestr = ",".join(["{:x}".format(x) for x in state])
            x = 15 + int(i / 5) * 250
            y = 15 + (i % 5) * 40
            self.canvas.create_rectangle(x,
                                         y,
                                         x + 25,
                                         y + 25,
                                         fill=color,
                                         tags="colorlist")

            textx = x + 40
            texty = y + 12
            self.canvas.create_text(textx,
                                    texty,
                                    text=statestr,
                                    tags="colorlist",
                                    fill="black",
                                    anchor="w")

    def cleanup(self):
        self.infoframe.destroy()
        self.trailframe.destroy()
Example #22
0
class ImageSelectWindow(object):
    def __init__(self):
        self.image_Wid = 300
        self.image_Hei = 300
        self.image_interval = 10
        self.canvas_Wid = 930
        self.canvas_Hei = 600
        self.window_wid = self.canvas_Wid + 160
        self.window_Hei = self.canvas_Hei

        # init state control variable
        self.has_select_root_path = False  # sign has select root path(where the sub-directories save) or not
        self.root_path = ''
        self.group_list = []

        # create main window
        self.mainWin = Tkinter.Tk()
        self.mainWin.geometry(
            str(self.window_wid) + 'x' +
            str(self.window_Hei))  # init the size of window
        self.mainWin.title("image select tool")
        self.mainWin.tk.eval('package require Tix')
        # bind the key press event(space to pass, q to quit)
        self.mainWin.bind('<KeyPress>', self._keyPressEvent)

        # create init image(a black background)
        self.img_path_list = []
        self.photo_img_list = []

        # create Canvas control
        self.max_shown_num = 90
        self.cv = Canvas(self.mainWin,
                         bg='white',
                         width=self.canvas_Wid,
                         height=self.canvas_Hei,
                         scrollregion=(0, 0, self.canvas_Wid,
                                       (self.image_Hei + self.image_interval) *
                                       math.ceil(self.max_shown_num / 3)))
        self.vbar = Scrollbar(self.cv, orient=Tkinter.VERTICAL)
        self.vbar.pack(side=Tkinter.RIGHT, fill=Tkinter.Y)
        self.vbar.config(command=self.cv.yview)
        self.cv.config(yscrollcommand=self.vbar.set)
        self.cv.pack(side=Tkinter.LEFT, expand=True, fill=Tkinter.BOTH)
        # bind the mouse click event
        self.cv.bind('<Button-1>', self._mouseClickEvent)
        # bind the mouse wheel event
        self.cv.bind_all('<MouseWheel>', self._mouseWheelEvent)

        # create total Frame to lay out all components
        self.frame = Frame(self.mainWin, width=250, height=self.window_Hei)
        self.frame.pack(side=Tkinter.LEFT)

        # create text control
        self.save_path = './image_select_result'
        self.entry = Entry(self.frame, state='normal')
        self.entry.pack(side=Tkinter.TOP)
        self.entry.insert(0, self.save_path)

        # create 'START' button
        self.btn_start = Button(self.frame,
                                text='START',
                                command=self._selectPath,
                                activeforeground='blue',
                                activebackground='white',
                                bg='blue',
                                fg='white')
        self.btn_start.pack(side=Tkinter.TOP, pady=30)

        # create data annotation label button
        self.btn_pass = Button(self.frame,
                               text='PASS',
                               command=lambda: self._passCurrentGroup(),
                               activeforeground='black',
                               activebackground='blue',
                               bg='white',
                               fg='black')
        self.btn_pass.pack(side=Tkinter.TOP, pady=30)

        #NumericUpDown控件
        self.num_count = Control(self.frame,
                                 integer=True,
                                 max=-1,
                                 min=-1,
                                 value=-1,
                                 step=1,
                                 label='current Image:',
                                 command=self._showImages)
        self.num_count.label.config(font='Helvetica -14 bold')
        self.num_count.pack(side=Tkinter.TOP, pady=30)

        # create 'QUIT' button
        self.btn_quit = Button(self.frame,
                               text='QUIT',
                               command=self.mainWin.quit,
                               activeforeground='blue',
                               activebackground='white',
                               bg='red',
                               fg='white')
        self.btn_quit.pack(side=Tkinter.BOTTOM, pady=100)

    def _keyPressEvent(self, event):
        if event.keycode == 32:
            self._passCurrentGroup()
        elif event.keycode == 81:
            self.mainWin.destroy()

    def _mouseClickEvent(self, event):
        # get coordinate of x
        x_coordinate = event.x

        # compute coordinate of y
        # get the location of the scrollBar in the scroll range
        scale = self.vbar.get()[0]
        start_y = scale * ((self.image_Hei + self.image_interval) *
                           math.ceil(self.max_shown_num / 3))
        y_coordinate = start_y + event.y
        self._selectOneImage(x_coordinate, y_coordinate)

    def _mouseWheelEvent(self, event):
        self.cv.yview_scroll(-1 * (event.delta / 20), "units")

    def _showImages(self, ev=None):
        if self.has_select_root_path:
            if int(self.num_count['value']) == -1:
                # clear the images draw before first
                for idx in range(len(self.img_path_list)):
                    self.cv.delete(self.img_path_list[idx])

                self.img_path_list = []
                self.photo_img_list = []
                return
            else:
                # clear the images draw before first
                for idx in range(len(self.img_path_list)):
                    self.cv.delete(self.img_path_list[idx])

                # get the current group path and images list
                img_group_path = self.group_list[int(self.num_count['value'])]
                self.img_path_list = self._getImagePathList(img_group_path)
                self.img_path_list = self.img_path_list[:min(
                    len(self.img_path_list), self.max_shown_num)]
                self.photo_img_list = []
                for idx in range(len(self.img_path_list)):
                    # load the current image
                    cur_img_path = self.img_path_list[idx]
                    cur_img = Image.open(cur_img_path).resize(
                        (self.image_Wid, self.image_Hei))
                    self.photo_img_list.append(ImageTk.PhotoImage(cur_img))
                    # draw cur image to the appropriate location by index
                    x_coordinate = (idx % 3) * (self.image_Wid +
                                                self.image_interval)
                    y_coordinate = math.floor(
                        idx / 3) * (self.image_Hei + self.image_interval)
                    self.cv.create_image((x_coordinate, y_coordinate),
                                         anchor=Tkinter.NW,
                                         image=self.photo_img_list[idx],
                                         tags=self.img_path_list[idx])
                    # give a tag is convenient for delete later

    def _passCurrentGroup(self):
        cur_idx = int(self.num_count['value'])
        if cur_idx != -1:
            # check has next group or not
            if cur_idx + 1 < len(self.group_list):
                self.num_count['value'] = str(cur_idx + 1)
            else:
                tkMessageBox.showinfo(
                    title='thanks',
                    message='all the image select mission has finished~')

    def _selectOneImage(self, x_coordinate, y_coordinate):
        cur_idx = int(self.num_count['value'])
        if cur_idx == -1:
            return
        col = math.floor(x_coordinate / (self.image_Wid + self.image_interval))
        row = math.floor(y_coordinate / (self.image_Hei + self.image_interval))
        idx = int(row * 3 + col)
        if idx < len(self.img_path_list):
            img_click_path = self.img_path_list[idx]
            cur_img = Image.open(img_click_path)
            img_name = img_click_path.split('\\')[-1]
            cur_save_path = os.path.join(self.save_path, img_name)
            cur_img.save(cur_save_path)

    def _selectPath(self):
        self.root_path = tkFileDialog.askdirectory()
        self.group_list = self._getGroupPathList()
        if len(self.group_list) > 0:
            self.has_select_root_path = True
            self.num_count.config(max=len(self.group_list) - 1)
            self.num_count['value'] = str(0)
        else:
            self.has_select_root_path = False
            self.num_count['value'] = str(-1)
            self.num_count.config(max=-1)
            tkMessageBox.showwarning(
                'warning',
                'No available sub-directories detected! please re-select root path and start'
            )

    def _getGroupPathList(self):
        group_list = []
        for root, dirs, files in os.walk(self.root_path):
            for dir_name in dirs:
                cur_group_path = os.path.join(root, dir_name)
                group_list.append(cur_group_path)
        return group_list

    def _getImagePathList(self, img_group_path):
        img_path_list = []
        for root, dirs, files in os.walk(img_group_path):
            for file_name in files:
                cur_img_path = os.path.join(img_group_path, file_name)
                img_path_list.append(cur_img_path)
        return img_path_list
Example #23
0
class OriginalImage(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.root = parent

        self.orginal_img = Canvas(self)
        self.orginal_img.grid(row=0, column=0)

        self.orginal_img.bind('<ButtonPress-1>', self.on_mouse_down)
        self.orginal_img.bind('<B1-Motion>', self.on_mouse_drag)
        self.orginal_img.bind('<ButtonRelease-1>', self.on_mouse_up)
        self.orginal_img.bind('<Button-3>', self.on_right_click)

        self._set_variables_initial_state()

    def _set_variables_initial_state(self):
        self.drag_color = CLASS_COLOR[0]
        self.item = None
        self.data_observers = []
        self.coordinates_observers = []

    def get(self):
        try:
            return self.orginal_img.image
        except Exception:
            return None

    def register_data_observers(self, observers):
        self.data_observers.append(observers)

    def register_coordinates_observers(self, observers):
        self.coordinates_observers.append(observers)

    def _notify_data_observers(self, pixel_values):
        for observer in self.data_observers:
            observer.add_samples(pixel_values)

    def _notify_coordinates_observers(self, img_region):
        for observer in self.coordinates_observers:
            observer.add_sample_coordinates(img_region)

    def set_image(self, current_image):
        self.orginal_img.image = current_image

        self.orginal_img.photo = PhotoImage(self.orginal_img.image)

        self.orginal_img.create_image(0,
                                      0,
                                      image=self.orginal_img.photo,
                                      anchor='nw',
                                      tags='img')

        w, h = self.orginal_img.image.size
        self.orginal_img.config(width=w,
                                height=h,
                                scrollregion=self.orginal_img.bbox('all'))

    def set_drag_color(self, color):
        self.drag_color = color

    def reset(self):
        try:
            self.orginal_img.create_image(0,
                                          0,
                                          image=self.orginal_img.photo,
                                          anchor='nw',
                                          tags='img')
            self._set_variables_initial_state()
        except AttributeError:
            # No image was previously opened
            pass

    def on_mouse_down(self, event):
        self.anchor = (event.widget.canvasx(event.x),
                       event.widget.canvasy(event.y))
        self.item = None

    def on_mouse_drag(self, event):
        bbox = self.anchor + (event.widget.canvasx(
            event.x), event.widget.canvasy(event.y))
        if self.item is None:
            self.item = event.widget.create_rectangle(bbox,
                                                      outline=self.drag_color,
                                                      fill=self.drag_color)
        else:
            event.widget.coords(self.item, *bbox)

    def on_mouse_up(self, event):
        if self.item:
            self.on_mouse_drag(event)

            box = tuple(
                (int(round(v)) for v in event.widget.coords(self.item)))
            box = tuple([i if i > 0 else 0 for i in box])

            img_region = self.orginal_img.image.crop(box)
            pixel_values = list(img_region.getdata())

            self._notify_data_observers(pixel_values)
            self._notify_coordinates_observers(box)

    def on_right_click(self, event):
        found = event.widget.find_all()
        for iid in found:
            if event.widget.type(iid) == 'rectangle':
                event.widget.delete(iid)
class tkFileSelector() :
  def __init__(self,master,start_dir=expanduser("~"),filetypes=[],title="Select a music file.",color_1="#000000",color_2="#00c0c0",highlight_color_items="#c9c9c9") :
    '''
    master == root_window == Tk()
   
    use color_1 and color_2 and bg_items and fg_items and highlight_color_items for colors personalisation.
   
    filetypes must "Strictly" be a list of extension beginning with an asterix followed by a point and the extension (in lowercase) or an empty list for no filtering.
    filetypes=["*.mp3","*.wav"] per example. Or insert an, item '*' for all filetype in combination with defined filetypes.
   
    for borderwidth and relief settings look at the code
    '''
   
    # Constrcut GUI for the file selection toplevel.
   
    self.toplevel=Toplevel(master,bg=color_1,borderwidth=1,relief="sunken")
    self.toplevel.resizable(width=False, height=False)
    self.toplevel.title(title)
   
    self.dir_selection_frame=Frame(self.toplevel,bg=color_1,borderwidth=8/2,relief="groove")                                         # Frame container for directory fields.
    self.dir_name_entry=Entry(self.toplevel,justify="center",width=50,bg=color_2,fg=color_1)                                         # This will contains the current directory relative dirname
    self.dir_name_separator=Button(self.toplevel,width=1,relief="sunken",bg=color_1,fg=color_2)                                      # An separator
    self.dir_back_button=Button(self.toplevel,width=6,relief="raised",bg=color_2,fg=color_1,text="Back",command=self.folder_go_back) # Change directory back button.
   
   
    self.canvas_frame=Frame(self.toplevel,borderwidth=8,relief="groove")     # Frame for the file selection window canvas and his scrollbar.
    self.canvas=Canvas(self.canvas_frame,height=20*9,width=18*28,bg=color_2) # File selection window.
    self.canvas_scrollbar=Scrollbar(self.canvas_frame,orient=HORIZONTAL, bg=color_2,troughcolor=color_1,command=self.canvas.xview) # File selection window scrollbar.
    self.canvas.configure(xscrollcommand=self.canvas_scrollbar.set)
   
   
    self.file_selection_frame=Frame(self.toplevel,bg=color_1,borderwidth=8/2,relief="groove")                                        # Frame container for filename fields.
    self.file_name_entry=Entry(self.toplevel,justify="center",width=50,bg=color_2,fg=color_1)                                        # This will contains the basename (relative) of the selected file.
    self.file_name_separator=Button(self.toplevel,width=1,relief="sunken",bg=color_1,fg=color_2)                                     # An separator.
    self.file_filter_menubutton = Menubutton(self.file_selection_frame, text='',relief="groove",width=8,bg=color_2,fg=color_1)       # Menubutton for filetype filter.
   
    self.file_filter_extension=""
   
    if filetypes :
      self.file_filter_menu= Menu(self.file_filter_menubutton,borderwidth=3,relief="groove") # We use a menu for the filetypes filtering.
      i=0
      self.file_filter_var=StringVar(master=None, value=filetypes[i], name=None)             # Control varaible for current filetype and initialize with the first filetype item.
      self.file_filter_menubutton.config(text=filetypes[i])                                 
      self.file_filter_extension=filetypes[i][1::]
      while i < len(filetypes) :
	# Creating radiobutton to change the filetype filter.
	self.file_filter_menu.add_radiobutton(label=filetypes[i], variable=self.file_filter_var,value=filetypes[i],background=color_2,command=self.set_filetype_filter )
        i += 1
     
      self.file_filter_menubutton.configure(menu= self.file_filter_menu)
   
   
    self.buttons_frame=Frame(self.toplevel,bg=color_2,borderwidth=8,relief="groove",height=50,width=18*3) # Frame container for the buttons.
    self.button_cancel=Button(self.buttons_frame,bg=color_2,fg=color_1,text="Quit",borderwidth=8/2,relief="groove",width=8,command=self.item_selection_quit)
    self.button_home=Button(self.buttons_frame,bg=color_2,fg=color_1,text="Home",borderwidth=8/2,relief="groove",width=8,command=self.item_selection_home)
    self.button_ok=Button(self.buttons_frame,bg=color_2,fg=color_1,text=" OK ",borderwidth=8/2,relief="groove",width=8,command=self.item_selection_ok)
   
    
    self.start_dir=start_dir        # Start folder.
    self.curdir=start_dir           # Current folder.
   
    self.last_dir=[]                # Container for the precedent folders we visit.
    self.last_dir.append(start_dir) # Append start folder.
   
    self.select_filepath=""         # Value to return by file selection.
   
    self.dir_name_entry.insert(0,"../"+basename(self.curdir))
   
   
    if not color_2 :
      self.items_bg="#D9D9D9"
    else :
      self.items_bg=color_2
   
    self.items_fg=color_1
    self.highlight_color_items=highlight_color_items
   
   
    self.init_icons()
    self.ls_dir()
    self.update_canvas()
   
   
    self.dir_selection_frame.grid(row=0,column=0,sticky="WE")
    self.dir_name_entry.grid(row=0,column=0,in_=self.dir_selection_frame,sticky="NSEW")
    self.dir_name_separator.grid(row=0,column=1,in_=self.dir_selection_frame,sticky="EW")
    self.dir_back_button.grid(row=0,column=2,in_=self.dir_selection_frame,sticky="EW")
   
    self.canvas_frame.grid(row=1,column=0,sticky="WE")
    self.canvas.grid(row=0,column=0,in_=self.canvas_frame)
    self.canvas_scrollbar.grid(row=1,column=0,in_=self.canvas_frame,sticky="WE")
   
    self.file_selection_frame.grid(row=2,column=0,sticky="WE")
    self.file_name_entry.grid(row=0,column=0,in_=self.file_selection_frame,sticky="NSEW")
    self.file_name_separator.grid(row=0,column=1,in_=self.file_selection_frame,sticky="EW")
    self.file_filter_menubutton.grid(row=0,column=2,in_=self.file_selection_frame,sticky="NS")
   
    self.buttons_frame.grid(row=3,column=0,sticky="NSEW")
    self.button_cancel.grid(row=0,column=2,padx=32+3,pady=4,in_=self.buttons_frame)
    self.button_home.grid(row=0,column=4,padx=32+3,pady=4,in_=self.buttons_frame)
    self.button_ok.grid(row=0,column=6,padx=34+3,pady=4,in_=self.buttons_frame)
   
    self.toplevel.wait_window()
   
   
   
  def init_icons(self) :
    # Folder and file icons, design by me.
    self.image_folder=Image.open("/usr/share/ScreenLocker/Images/file_selector/folder_icon.png")
    self.imagetk_folder=ImageTk.PhotoImage(image=self.image_folder)
   
    self.image_file=Image.open("/usr/share/ScreenLocker/Images/file_selector/file_icon.png")
    self.imagetk_file=ImageTk.PhotoImage(image=self.image_file)
   
  def ls_dir(self) :
    ''' List an directory and split the result in folders and files containers.
        Finally sort the 2 containers.'''
   
    folder_content=listdir(self.curdir)
    self.cur_folder_entries=len(folder_content)
   
    self.cur_folder_list=[]
    self.cur_files_list=[]
   
    folder_content.sort()
   
    for v in folder_content :
      if isdir(self.curdir+"/"+v) :
	self.cur_folder_list.append(unicode(v,encoding='utf-8'))
      elif isfile(self.curdir+"/"+v) :
        self.cur_files_list.append(unicode(v,encoding='utf-8'))
   
    self.cur_folder_list.sort()
    self.cur_files_list.sort() 
     
  def update_canvas(self) :
    ''' Generating the content from the File selection window (an canvas)'''
    self.clear_canvas()
   
    i=0             # global folder and file iterator.
    pos_x=0         # Coordinates for the rows.
    pos_y=0         # Coordinates in the columns.
    max_len=0       # Column max folder|filename length.
    max_len_save=0  # Saved value for filling empty canvas scrollregion.
   
    while i < len(self.cur_folder_list) :
      # Generating the folder items of the current folder
     
      exec(u"folder_icon_{0}=Label(self.canvas,text='{1}',image=self.imagetk_folder,relief='flat',width=17,height=17,bg=self.items_bg)".format(str(i),self.cur_folder_list[i].replace("'","\\'")))
      exec(u"folder_name_{0}=Label(self.canvas,text='{1}',relief='flat',width={2},font='Monospace 9 bold',justify='left',bg=self.items_bg,fg=self.items_fg)".format(str(i),self.cur_folder_list[i].replace("'","\\'"),int(len(" "+self.cur_folder_list[i]))))
     
      if int(len(" "+self.cur_folder_list[i])) > max_len :
	# Update longest folder name in this column.
	max_len=int(len(" "+self.cur_folder_list[i])) # Storing the value for max length of the longest folder name in this column.
	max_len_save=max_len # Value to save for filling if the generating content take minus place as the canvas scrollregion.

      exec("folder_icon_{0}.bind('<Double-1>',self.select_folder)".format(str(i)))
      exec("folder_name_{0}.bind('<Double-1>',self.select_folder)".format(str(i)))
     
    
      exec("folder_name_{0}.bind('<Enter>',self.highlight_item_enter)".format(str(i)))
      exec("folder_name_{0}.bind('<Leave>',self.highlight_item_leave)".format(str(i)))
     
      exec("folder_icon_{0}.pack(side='left',fill=BOTH)".format(str(i)))
      exec("folder_name_{0}.pack(side='right',fill=BOTH)".format(str(i)))
     
      exec("self.canvas.create_window(({1},{2}),anchor='nw',window=folder_icon_{0})".format(str(i),pos_x,pos_y))
      exec("self.canvas.create_window(({1}+17+1,{2}),anchor='nw',window=folder_name_{0})".format(str(i),pos_x,pos_y))
     
      pos_y += 20  # column increment 17 height of an items + 3 pixels padding.
     
     
      if ( i % 9 == 0) and not  i == 0 :
	# An column can contains 9 items and we change column.
	pos_y=0                   # Column position updating.
	pos_x += 17 + (max_len*9) # Update the x coordinates according the maximal length of foldername in this column ( (9 pixels == font size) (17 pixels for the folder item icon) ) .

	max_len=0

      i += 1 # Go to the next item.
     
    ii=0            # Files iterator.
   
    while ii < len(self.cur_files_list) :
      # Generating the files items of the current folder.
      if (self.file_filter_extension and self.cur_files_list[ii].lower().endswith(self.file_filter_extension)) or not self.file_filter_extension :
        # applying filter of no filetype filering.
       
	exec(u"file_icon_{0}=Label(self.canvas,text='{1}',image=self.imagetk_file,relief='flat',width=17,height=17,bg=self.items_bg)".format(str(i),self.cur_files_list[ii].replace("'","\\'")))
	exec(u"file_name_{0}=Label(self.canvas,text='{1}',relief='flat',width={2},font='Monospace 9 normal',justify='left',bg=self.items_bg,fg=self.items_fg)".format(str(i),self.cur_files_list[ii].replace("'","\\'"),int(len(" "+self.cur_files_list[ii]))))

	if int(len(" "+self.cur_files_list[ii])) > max_len :
	  # Update longest filename in this column.
	  max_len=int(len(" "+self.cur_files_list[ii])) # Storing the value for max length of the longest filename in this column.
	  max_len_save=max_len                          # Value to save for filling if the generating content take minus place as the canvas scrollregion.
	 
	exec("file_icon_{0}.bind('<Double-1>',self.select_file)".format(str(i)))
	exec("file_name_{0}.bind('<Double-1>',self.select_file)".format(str(i)))
	 
	exec("file_name_{0}.bind('<Enter>',self.highlight_item_enter)".format(str(i)))
	exec("file_name_{0}.bind('<Leave>',self.highlight_item_leave)".format(str(i)))

	exec("file_icon_{0}.pack(side='left',fill=BOTH)".format(str(i)))
	exec("file_name_{0}.pack(side='right',fill=BOTH)".format(str(i)))

	exec("self.canvas.create_window(({1},{2}),anchor='nw',window=file_icon_{0})".format(str(i),pos_x,pos_y))
	exec("self.canvas.create_window(({1}+17+1,{2}),anchor='nw',window=file_name_{0})".format(str(i),pos_x,pos_y))

	pos_y += 20 # column increment 17 height of an items + 3 pixels padding.
   
	if ( i % 9 == 0) and not  i == 0 :
	  # An column can contains 9 items and we change column.
	  # Note: we check the common file & folder iterator.
	  pos_y=0                   # Column position updating.
	  pos_x += 17 + (max_len*9) # Update the x coordinates according the maximal length of filename in this column ( (9 pixels == font size) (17 pixels for the file item icon) ).
	  max_len=0
	i += 1
      ii += 1
   
    if not pos_x+(max_len_save*9)+17 < 18*28 :
      # items collection greater than the canvas scrollregion.
      self.canvas.config(scrollregion=(0,0,pos_x+(max_len_save*9)+17,0))
    else :
      # items collection littler than the canvas scrollregion.
      self.canvas.config(scrollregion=(0,0,18*28,0))
 
  def clear_canvas(self) :
    for child in self.canvas.children.values() :
      child.destroy()
   
   
  def highlight_item_enter(self,event) :
    event.widget.config(bg=self.highlight_color_items)
 
  def highlight_item_leave(self,event) :
    event.widget.config(bg=self.items_bg)
 
  def select_folder(self,event) :
   
    if isdir(self.curdir+"/"+event.widget.cget("text").lstrip()) : # event.widget.cget("text") return the selected folder. sea the update_canvas() method.
      self.select_filepath=""
      self.file_name_entry.delete(0,END)
     
      if self.curdir.startswith('//') :
	# Bugfix.
	self.curdir=self.curdir[1::]
        self.last_dir.append(self.curdir)
      else :
        self.last_dir.append(self.curdir)
       
      for v in self.last_dir :
	# Bigfix
	if self.last_dir.count(v) > 1 :
	  self.last_dir.remove(v)
     
      try :
	# in case of access right this will fail immediatelly
	listdir(self.curdir+"/"+event.widget.cget("text"))
        self.curdir=self.curdir+"/"+event.widget.cget("text")
     
	self.dir_name_entry.delete(0,END)
	self.dir_name_entry.insert(0,"../"+event.widget.cget("text"))
     
        self.ls_dir()
        self.update_canvas()
      except :
	pass
     
  def select_file(self,event) :
    if isfile(self.curdir+"/"+event.widget.cget("text")) :
      # Set the value to return and fill the file selection field.
      self.select_filepath=self.curdir+"/"+event.widget.cget("text")
      self.file_name_entry.delete(0,END)
      self.file_name_entry.insert(0,event.widget.cget("text"))
     
  def folder_go_back(self) :
    if len(self.last_dir) > 1 :
      self.curdir=self.last_dir.pop(-1) # pop the last value from the visited folder folders
    else :
      # In case we have yet only 1 folder in the visited folder container.
      if self.last_dir[0].rfind("/") :
	# The value of the container is not the root folder ( / ) but not the /home/username folder who can be only visited folder.
	self.last_dir[0]=self.last_dir[0][0:self.last_dir[0].rfind("/")]
	self.curdir=self.last_dir[0]
      elif self.last_dir[0].rfind("/") == 0 :
	# The value of the container is the root folder.
        self.last_dir[0]="/"
        self.curdir=self.last_dir[0]
      else : 
	# The value is the /home/username directory
        self.curdir=self.last_dir[0]
   
    self.file_name_entry.delete(0,END)
    self.select_filepath=""
   
    self.dir_name_entry.delete(0,END)
    self.dir_name_entry.insert(0,"../"+basename(self.curdir))
   
    self.ls_dir()
    self.update_canvas() 
     
  def set_filetype_filter(self) :
    '''Change filetype filter.'''
    self.file_filter_menubutton.config(text=self.file_filter_var.get())
    self.file_filter_extension=self.file_filter_var.get()[1::]          # Contains the selected filetype ( in form '.'+filetype ).
   
    self.file_name_entry.delete(0,END)
    self.select_filepath=""
      
    self.ls_dir()
    self.update_canvas() 
   
  def item_selection_ok(self) :
    '''Return the selected filepath or empty string
       and destroy File_selector instance'''
      
    if self.select_filepath :
      self.toplevel.destroy()
      return True
 
  def item_selection_quit(self) :
    '''destroy File_selector instance'''
    self.toplevel.destroy()
    return False
   
  def item_selection_home(self) :
    '''Change current directory to the /home/username folder'''
    self.curdir=expanduser("~")
    self.select_filepath=""
    self.file_name_entry.delete(0,END)
   
    self.last_dir=[]
    self.last_dir.append(expanduser("~"))
   
    self.dir_name_entry.delete(0,END)
    self.dir_name_entry.insert(0,"../"+basename(self.curdir))   
    self.ls_dir()
    self.update_canvas() 
Example #25
0
class OriginalImage(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.root = parent
        
        self.orginal_img = Canvas(self)
        self.orginal_img.grid(row = 0, column = 0)
        
        self.orginal_img.bind('<ButtonPress-1>', self.on_mouse_down)
        self.orginal_img.bind('<B1-Motion>', self.on_mouse_drag)
        self.orginal_img.bind('<ButtonRelease-1>', self.on_mouse_up)
        self.orginal_img.bind('<Button-3>', self.on_right_click)
        
        self._set_variables_initial_state()
        
    def _set_variables_initial_state(self):
        self.drag_color = CLASS_COLOR[0]
        self.item = None
        self.data_observers = []
        self.coordinates_observers = []

    def get(self):
        try:
            return self.orginal_img.image
        except Exception:
            return None
        
    def register_data_observers(self, observers):
        self.data_observers.append(observers)
        
    def register_coordinates_observers(self, observers):
        self.coordinates_observers.append(observers)
        
    def _notify_data_observers(self, pixel_values):
        for observer in self.data_observers:
            observer.add_samples(pixel_values)
            
    def _notify_coordinates_observers(self, img_region):
        for observer in self.coordinates_observers:
            observer.add_sample_coordinates(img_region)

    def set_image(self, current_image):
        self.orginal_img.image = current_image
        
        self.orginal_img.photo = PhotoImage(self.orginal_img.image)
        
        self.orginal_img.create_image(0, 0, image = self.orginal_img.photo, 
                                      anchor = 'nw', tags = 'img')
        
        w, h = self.orginal_img.image.size
        self.orginal_img.config(width = w, height = h, 
                                scrollregion = self.orginal_img.bbox('all'))    
            
    def set_drag_color(self, color):
        self.drag_color = color
        
    def reset(self):
        try:
            self.orginal_img.create_image(0, 0, image = self.orginal_img.photo, 
                                          anchor = 'nw', tags = 'img')
            self._set_variables_initial_state()
        except AttributeError:
            # No image was previously opened
            pass
        
    def on_mouse_down(self, event):        
        self.anchor = (event.widget.canvasx(event.x),
                       event.widget.canvasy(event.y))
        self.item = None

    def on_mouse_drag(self, event):        
        bbox = self.anchor + (event.widget.canvasx(event.x),
                              event.widget.canvasy(event.y))
        if self.item is None:
            self.item = event.widget.create_rectangle(bbox,
                            outline = self.drag_color, fill = self.drag_color)
        else:
            event.widget.coords(self.item, *bbox)

    def on_mouse_up(self, event):        
        if self.item:
            self.on_mouse_drag(event) 

            box = tuple((int(round(v)) for v in event.widget.coords(self.item)))
            box = tuple([i if i>0 else 0 for i in box])

            img_region = self.orginal_img.image.crop(box)
            pixel_values = list(img_region.getdata())
            
            self._notify_data_observers(pixel_values)
            self._notify_coordinates_observers(box)
            

    def on_right_click(self, event):        
        found = event.widget.find_all()
        for iid in found:
            if event.widget.type(iid) == 'rectangle':
                event.widget.delete(iid)
#顶层窗口
top = Tkinter.Tk()  #创建顶层窗口
top.geometry('400x400')  #初始化窗口大小
top.title("Tkinter exercise")
top.tk.eval('package require Tix')  #引入升级包,这样才能使用升级的组合控件

# 创建一个Canvas
# bg = 'white' 设置其背景色为白色
# scrollregion 设置滚动条控制范围(即使画布更大,你也无法移动到scrollregion设置区域以外的区域)
cv = Canvas(top, bg='white', scrollregion=(0, 0, 600, 1000))

vbar = Scrollbar(cv, orient=Tkinter.VERTICAL)
vbar.pack(side=Tkinter.RIGHT, fill=Tkinter.Y)
vbar.config(command=cv.yview)
#cv.config(width=300,height=650)  # 由于布局的方式,这里设置的宽和高就不起作用了
cv.config(yscrollcommand=vbar.set)
cv.pack(side=Tkinter.LEFT, expand=True, fill=Tkinter.BOTH)

# 在画布中绘制指定的图片
img_path_list = [
    './food/[长眠] (462).jpg', './food/411.jpg', './food/[长眠] (461).jpg'
]
img_path_list = [path.decode('utf-8') for path in img_path_list]
imgs_list = [Image.open(path).resize((200, 200)) for path in img_path_list]
imgs_list = [ImageTk.PhotoImage(img) for img in imgs_list]
for i in range(len(imgs_list)):
    cv.create_image((0, 200 * i), anchor=Tkinter.NW, image=imgs_list[i])
    # 这里要注意,不要使用临时变量对create_image函数的imgae参数赋值
    # 因为Canvas仅仅是维护一个引用,当创建的PhotoImage实例被销毁时,显示会出问题

#标签控件
class PiPresents(object):

    def __init__(self):
        gc.set_debug(gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_INSTANCES|gc.DEBUG_OBJECTS|gc.DEBUG_SAVEALL)
        self.pipresents_issue="1.3"
        self.pipresents_minorissue = '1.3.1g'
        # position and size of window without -f command line option
        self.nonfull_window_width = 0.45 # proportion of width
        self.nonfull_window_height= 0.7 # proportion of height
        self.nonfull_window_x = 0 # position of top left corner
        self.nonfull_window_y=0   # position of top left corner
        self.pp_background='black'

        StopWatch.global_enable=False

        # set up the handler for SIGTERM
        signal.signal(signal.SIGTERM,self.handle_sigterm)
        

# ****************************************
# Initialisation
# ***************************************
        # get command line options
        self.options=command_options()

        # get Pi Presents code directory
        pp_dir=sys.path[0]
        self.pp_dir=pp_dir
        
        if not os.path.exists(pp_dir+"/pipresents.py"):
            if self.options['manager']  is False:
                tkMessageBox.showwarning("Pi Presents","Bad Application Directory:\n{0}".format(pp_dir))
            exit(103)

        
        # Initialise logging and tracing
        Monitor.log_path=pp_dir
        self.mon=Monitor()
        # Init in PiPresents only
        self.mon.init()

        # uncomment to enable control of logging from within a class
        # Monitor.enable_in_code = True # enables control of log level in the code for a class  - self.mon.set_log_level()
        
        # make a shorter list to log/trace only some classes without using enable_in_code.
        Monitor.classes  = ['PiPresents', 'pp_paths',
                            
                            'HyperlinkShow','RadioButtonShow','ArtLiveShow','ArtMediaShow','MediaShow','LiveShow','MenuShow',
                            'PathManager','ControlsManager','ShowManager','PluginManager',
                            'MplayerDriver','OMXDriver','UZBLDriver',
                            'KbdDriver','GPIODriver','TimeOfDay','ScreenDriver','Animate','OSCDriver'
                            ]

        # Monitor.classes=['PiPresents','ArtMediaShow','VideoPlayer','OMXDriver']
        
        # get global log level from command line
        Monitor.log_level = int(self.options['debug'])
        Monitor.manager = self.options['manager']
        # print self.options['manager']
        self.mon.newline(3)    
        self.mon.log (self, "Pi Presents is starting, Version:"+self.pipresents_minorissue)
        # self.mon.log (self," OS and separator:" + os.name +'  ' + os.sep)
        self.mon.log(self,"sys.path[0] -  location of code: "+sys.path[0])
        if os.geteuid() !=0:
            user=os.getenv('USER')
        else:
            user = os.getenv('SUDO_USER')
        self.mon.log(self,'User is: '+ user)
        # self.mon.log(self,"os.getenv('HOME') -  user home directory (not used): " + os.getenv('HOME')) # does not work
        # self.mon.log(self,"os.path.expanduser('~') -  user home directory: " + os.path.expanduser('~'))   # does not work

        # optional other classes used
        self.root=None
        self.ppio=None
        self.tod=None
        self.animate=None
        self.gpiodriver=None
        self.oscdriver=None
        self.osc_enabled=False
        self.gpio_enabled=False
        self.tod_enabled=False
         
        # get home path from -o option
        self.pp_home = pp_paths.get_home(self.options['home'])
        if self.pp_home is None:
            self.end('error','Failed to find pp_home')

        # get profile path from -p option
        # pp_profile is the full path to the directory that contains 
        # pp_showlist.json and other files for the profile
        self.pp_profile = pp_paths.get_profile_dir(self.pp_home, self.options['profile'])
        if self.pp_profile is None:
            self.end('error','Failed to find profile')

        # check profile exists
        if os.path.exists(self.pp_profile):
            self.mon.log(self,"Found Requested profile - pp_profile directory is: " + self.pp_profile)
        else:
            self.mon.err(self,"Failed to find requested profile: "+ self.pp_profile)
            self.end('error','Failed to find profile')

        self.mon.start_stats(self.options['profile'])
        
        # check 'verify' option
        if self.options['verify'] is True:
            val =Validator()
            if  val.validate_profile(None,pp_dir,self.pp_home,self.pp_profile,self.pipresents_issue,False) is  False:
                self.mon.err(self,"Validation Failed")
                self.end('error','Validation Failed')

        # initialise and read the showlist in the profile
        self.showlist=ShowList()
        self.showlist_file= self.pp_profile+ "/pp_showlist.json"
        if os.path.exists(self.showlist_file):
            self.showlist.open_json(self.showlist_file)
        else:
            self.mon.err(self,"showlist not found at "+self.showlist_file)
            self.end('error','showlist not found')

        # check profile and Pi Presents issues are compatible
        if float(self.showlist.sissue()) != float(self.pipresents_issue):
            self.mon.err(self,"Version of profile " + self.showlist.sissue() + " is not  same as Pi Presents, must exit")
            self.end('error','wrong version of profile')


        # get the 'start' show from the showlist
        index = self.showlist.index_of_show('start')
        if index >=0:
            self.showlist.select(index)
            self.starter_show=self.showlist.selected_show()
        else:
            self.mon.err(self,"Show [start] not found in showlist")
            self.end('error','start show not found')

        if self.starter_show['start-show']=='':
             self.mon.warn(self,"No Start Shows in Start Show")       

# ********************
# SET UP THE GUI
# ********************
        # turn off the screenblanking and saver
        if self.options['noblank'] is True:
            call(["xset","s", "off"])
            call(["xset","s", "-dpms"])

        self.root=Tk()   
       
        self.title='Pi Presents - '+ self.pp_profile
        self.icon_text= 'Pi Presents'
        self.root.title(self.title)
        self.root.iconname(self.icon_text)
        self.root.config(bg=self.pp_background)

        self.mon.log(self, 'native screen dimensions are ' + str(self.root.winfo_screenwidth()) + ' x ' + str(self.root.winfo_screenheight()) + ' pixcels')
        if self.options['screensize'] =='':        
            self.screen_width = self.root.winfo_screenwidth()
            self.screen_height = self.root.winfo_screenheight()
        else:
            reason,message,self.screen_width,self.screen_height=self.parse_screen(self.options['screensize'])
            if reason =='error':
                self.mon.err(self,message)
                self.end('error',message)

        self.mon.log(self, 'commanded screen dimensions are ' + str(self.screen_width) + ' x ' + str(self.screen_height) + ' pixcels')
       
        # set window dimensions and decorations
        if self.options['fullscreen'] is False:
            self.window_width=int(self.root.winfo_screenwidth()*self.nonfull_window_width)
            self.window_height=int(self.root.winfo_screenheight()*self.nonfull_window_height)
            self.window_x=self.nonfull_window_x
            self.window_y=self.nonfull_window_y
            self.root.geometry("%dx%d%+d%+d" % (self.window_width,self.window_height,self.window_x,self.window_y))
        else:
            self.window_width=self.screen_width
            self.window_height=self.screen_height
            self.root.attributes('-fullscreen', True)
            os.system('unclutter 1>&- 2>&- &') # Suppress 'someone created a subwindow' complaints from unclutter
            self.window_x=0
            self.window_y=0  
            self.root.geometry("%dx%d%+d%+d"  % (self.window_width,self.window_height,self.window_x,self.window_y))
            self.root.attributes('-zoomed','1')

        # canvs cover the whole screen whatever the size of the window. 
        self.canvas_height=self.screen_height
        self.canvas_width=self.screen_width
  
        # make sure focus is set.
        self.root.focus_set()

        # define response to main window closing.
        self.root.protocol ("WM_DELETE_WINDOW", self.handle_user_abort)

        # setup a canvas onto which will be drawn the images or text
        self.canvas = Canvas(self.root, bg=self.pp_background)


        if self.options['fullscreen'] is True:
            self.canvas.config(height=self.canvas_height,
                               width=self.canvas_width,
                               highlightthickness=0)
        else:
            self.canvas.config(height=self.canvas_height,
                    width=self.canvas_width,
                        highlightthickness=1,
                               highlightcolor='yellow')
            
        self.canvas.place(x=0,y=0)
        # self.canvas.config(bg='black')
        self.canvas.focus_set()


                
# ****************************************
# INITIALISE THE INPUT DRIVERS
# ****************************************

        # each driver takes a set of inputs, binds them to symboic names
        # and sets up a callback which returns the symbolic name when an input event occurs/

        # use keyboard driver to bind keys to symbolic names and to set up callback
        kbd=KbdDriver()
        if kbd.read(pp_dir,self.pp_home,self.pp_profile) is False:
            self.end('error','cannot find or error in keys.cfg')
        kbd.bind_keys(self.root,self.handle_input_event)

        self.sr=ScreenDriver()
        # read the screen click area config file
        reason,message = self.sr.read(pp_dir,self.pp_home,self.pp_profile)
        if reason == 'error':
            self.end('error','cannot find screen.cfg')


        # create click areas on the canvas, must be polygon as outline rectangles are not filled as far as find_closest goes
        # click areas are made on the Pi Presents canvas not the show canvases.
        reason,message = self.sr.make_click_areas(self.canvas,self.handle_input_event)
        if reason == 'error':
            self.mon.err(self,message)
            self.end('error',message)


# ****************************************
# INITIALISE THE APPLICATION AND START
# ****************************************
        self.shutdown_required=False
        self.exitpipresents_required=False
        
        # kick off GPIO if enabled by command line option
        self.gpio_enabled=False
        if os.path.exists(self.pp_profile + os.sep + 'pp_io_config'+os.sep+ 'gpio.cfg'):
            # initialise the GPIO
            self.gpiodriver=GPIODriver()
            reason,message=self.gpiodriver.init(pp_dir,self.pp_home,self.pp_profile,self.canvas,50,self.handle_input_event)
            if reason == 'error':
                self.end('error',message)
            else:
                self.gpio_enabled=True
                # and start polling gpio
                self.gpiodriver.poll()
            
        # kick off animation sequencer
        self.animate = Animate()
        self.animate.init(pp_dir,self.pp_home,self.pp_profile,self.canvas,200,self.handle_output_event)
        self.animate.poll()

        #create a showmanager ready for time of day scheduler and osc server
        show_id=-1
        self.show_manager=ShowManager(show_id,self.showlist,self.starter_show,self.root,self.canvas,self.pp_dir,self.pp_profile,self.pp_home)
        # first time through set callback to terminate Pi Presents if all shows have ended.
        self.show_manager.init(self.canvas,self.all_shows_ended_callback,self.handle_command,self.showlist)
        # Register all the shows in the showlist
        reason,message=self.show_manager.register_shows()
        if reason == 'error':
            self.mon.err(self,message)
            self.end('error',message)

        # Init OSCDriver, read config and start OSC server
        self.osc_enabled=False
        if os.path.exists(self.pp_profile + os.sep + 'pp_io_config'+ os.sep + 'osc.cfg'):
            self.oscdriver=OSCDriver()
            reason,message=self.oscdriver.init(self.pp_profile,self.handle_command,self.handle_input_event,self.e_osc_handle_output_event)
            if reason == 'error':
                self.end('error',message)
            else:
                self.osc_enabled=True
                self.root.after(1000,self.oscdriver.start_server())

        # and run the start shows
        self.run_start_shows()

       # set up the time of day scheduler including catchup         
        self.tod_enabled=False
        if os.path.exists(self.pp_profile + os.sep + 'schedule.json'):
            # kick off the time of day scheduler which may run additional shows
            self.tod=TimeOfDay()
            self.tod.init(pp_dir,self.pp_home,self.pp_profile,self.root,self.handle_command)
            self.tod_enabled = True


        # then start the time of day scheduler
        if self.tod_enabled is True:
            self.tod.poll()

        # start Tkinters event loop
        self.root.mainloop( )


    def parse_screen(self,size_text):
        fields=size_text.split('*')
        if len(fields)!=2:
            return 'error','do not understand --fullscreen comand option',0,0
        elif fields[0].isdigit()  is False or fields[1].isdigit()  is False:
            return 'error','dimensions are not positive integers in ---fullscreen',0,0
        else:
            return 'normal','',int(fields[0]),int(fields[1])
        

# *********************
#  RUN START SHOWS
# ********************   
    def run_start_shows(self):
        self.mon.trace(self,'run start shows')
        # parse the start shows field and start the initial shows       
        show_refs=self.starter_show['start-show'].split()
        for show_ref in show_refs:
            reason,message=self.show_manager.control_a_show(show_ref,'open')
            if reason == 'error':
                self.mon.err(self,message)
                


# *********************
# User inputs
# ********************
    # handles one command provided as a line of text
    def handle_command(self,command_text):
        self.mon.log(self,"command received: " + command_text)
        if command_text.strip()=="":
            return

        if command_text[0]=='/': 
            if self.osc_enabled is True:
                self.oscdriver.send_command(command_text)
            return
        
        fields= command_text.split()
        show_command=fields[0]
        if len(fields)>1:
            show_ref=fields[1]
        else:
            show_ref=''
            
        if show_command in ('open','close'):
            if self.shutdown_required is False:
                reason,message=self.show_manager.control_a_show(show_ref,show_command)
            else:
                return
        elif show_command == 'exitpipresents':
            self.exitpipresents_required=True
            if self.show_manager.all_shows_exited() is True:
                # need root.after to get out of st thread
                self.root.after(1,self.e_all_shows_ended_callback)
                return
            else:
                reason,message= self.show_manager.exit_all_shows()

        elif show_command == 'shutdownnow':
            # need root.after to get out of st thread
            self.root.after(1,self.e_shutdown_pressed)
            return
        else:
            reason='error'
            message = 'command not recognised: '+ show_command
            
        if reason=='error':
            self.mon.err(self,message)
        return

    def e_all_shows_ended_callback(self):
            self.all_shows_ended_callback('normal','no shows running')

    def e_shutdown_pressed(self):
            self.shutdown_pressed('now')


    def e_osc_handle_output_event(self,line):
        #jump  out of server thread
        self.root.after(1, lambda arg=line: self.osc_handle_output_event(arg))

    def  osc_handle_output_event(self,line):
        self.mon.log(self,"output event received: "+ line)
        #osc sends output events as a string
        reason,message,delay,name,param_type,param_values=self.animate.parse_animate_fields(line)
        if reason == 'error':
            self.mon.err(self,message)
            self.end(reason,message)
        self.handle_output_event(name,param_type,param_values,0)

               
    def handle_output_event(self,symbol,param_type,param_values,req_time):
        if self.gpio_enabled is True:
            reason,message=self.gpiodriver.handle_output_event(symbol,param_type,param_values,req_time)
            if reason =='error':
                self.mon.err(self,message)
                self.end(reason,message)
        else:
            self.mon.warn(self,'GPIO not enabled')


    # all input events call this callback with a symbolic name.
    # handle events that affect PP overall, otherwise pass to all active shows
    def handle_input_event(self,symbol,source):
        self.mon.log(self,"event received: "+symbol + ' from '+ source)
        if symbol == 'pp-terminate':
            self.handle_user_abort()
            
        elif symbol == 'pp-shutdown':
            self.shutdown_pressed('delay')
            
        elif symbol == 'pp-shutdownnow':
            # need root.after to grt out of st thread
            self.root.after(1,self.e_shutdown_pressed)
            return
        
        elif symbol == 'pp-exitpipresents':
            self.exitpipresents_required=True
            if self.show_manager.all_shows_exited() is True:
                # need root.after to grt out of st thread
                self.root.after(1,self.e_all_shows_ended_callback)
                return
            reason,message= self.show_manager.exit_all_shows()
        else:
            # events for shows affect the show and could cause it to exit.
            for show in self.show_manager.shows:
                show_obj=show[ShowManager.SHOW_OBJ]
                if show_obj is not None:
                    show_obj.handle_input_event(symbol)



    def shutdown_pressed(self, when):
        if when == 'delay':
            self.root.after(5000,self.on_shutdown_delay)
        else:
            self.shutdown_required=True
            if self.show_manager.all_shows_exited() is True:
               self.all_shows_ended_callback('normal','no shows running')
            else:
                # calls exit method of all shows, results in all_shows_closed_callback
                self.show_manager.exit_all_shows()           


    def on_shutdown_delay(self):
        # 5 second delay is up, if shutdown button still pressed then shutdown
        if self.gpiodriver.shutdown_pressed() is True:
            self.shutdown_required=True
            if self.show_manager.all_shows_exited() is True:
               self.all_shows_ended_callback('normal','no shows running')
            else:
                # calls exit method of all shows, results in all_shows_closed_callback
                self.show_manager.exit_all_shows()


    def handle_sigterm(self,signum,frame):
        self.mon.log(self,'SIGTERM received - '+ str(signum))
        self.terminate()


    def handle_user_abort(self):
        self.mon.log(self,'User abort received')
        self.terminate()

    def terminate(self):
        self.mon.log(self, "terminate received")
        needs_termination=False
        for show in self.show_manager.shows:
            # print  show[ShowManager.SHOW_OBJ], show[ShowManager.SHOW_REF]
            if show[ShowManager.SHOW_OBJ] is not None:
                needs_termination=True
                self.mon.log(self,"Sent terminate to show "+ show[ShowManager.SHOW_REF])
                # call shows terminate method
                # eventually the show will exit and after all shows have exited all_shows_callback will be executed.
                show[ShowManager.SHOW_OBJ].terminate()
        if needs_termination is False:
            self.end('killed','killed - no termination of shows required')


# ******************************
# Ending Pi Presents after all the showers and players are closed
# **************************

    # callback from ShowManager when all shows have ended
    def all_shows_ended_callback(self,reason,message):
        self.canvas.config(bg=self.pp_background)
        if reason in ('killed','error') or self.shutdown_required is True or self.exitpipresents_required is True:
            self.end(reason,message)

    def end(self,reason,message):
        self.mon.log(self,"Pi Presents ending with reason: " + reason)
        if self.root is not None:
            self.root.destroy()
        self.tidy_up()
        # gc.collect()
        # print gc.garbage
        if reason == 'killed':
            self.mon.log(self, "Pi Presents Aborted, au revoir")
            # close logging files 
            self.mon.finish()
            sys.exit(101)     
        elif reason == 'error':
            self.mon.log(self, "Pi Presents closing because of error, sorry")
            # close logging files 
            self.mon.finish()
            sys.exit(102)            
        else:
            self.mon.log(self,"Pi Presents  exiting normally, bye")
            # close logging files 
            self.mon.finish()
            if self.shutdown_required is True:
                # print 'SHUTDOWN'
                call(['sudo', 'shutdown', '-h', '-t 5','now'])
                sys.exit(100)
            else:
                sys.exit(100)


    
    # tidy up all the peripheral bits of Pi Presents
    def tidy_up(self):
        self.mon.log(self, "Tidying Up")
        # turn screen blanking back on
        if self.options['noblank'] is True:
            call(["xset","s", "on"])
            call(["xset","s", "+dpms"])
            
        # tidy up animation and gpio
        if self.animate is not None:
            self.animate.terminate()
            
        if self.gpio_enabled==True:
            self.gpiodriver.terminate()

        if self.osc_enabled is True:
            self.oscdriver.terminate()
            
        # tidy up time of day scheduler
        if self.tod_enabled is True:
            self.tod.terminate()
class AntroidGUI(Tk):

    def __init__(self):
        Tk.__init__(self)
        self.protocol("WM_DELETE_WINDOW", self.myquit)
        self.etat = True
        self.readstate = True
        self.title("Antroid Map")
        self.turns = {}
        self.selectTurn = -1
        self.caselength = 10
        self.CaseMarge = 20
        self.var = StringVar()
        self.initGUI()

    def initGUI(self):
        frame = Frame(self, width =630, height = 500)
        self.panel = PanedWindow(frame, orient=HORIZONTAL)

        self.LeftFrame(self.panel)
        self.RightFrame(self.panel)
        self.panel.add(self.LFrame)
        self.panel.add(self.RFrame)
        self.panel.pack()
        frame.pack()

    def LeftFrame(self, parent):
        self.LFrame=Frame(parent, width = 500, height = 500)
        self.maptroid = Canvas(self.LFrame,bg='black',width=500,height=500)
        if self.selectTurn >= 0:
            self.printMap()

        self.maptroid.pack()
        self.LFrame.pack()

    def RightFrame(self, parent):
        self.RFrame = Frame(parent, width = 130, height = 500)
        if self.selectTurn >= 0:
            self.printInfo()
        self.FrameInfo = None
        self.updateT = True
        self.RFrame.pack()

    def setreadstate(self, readstate):
        self.readstate = readstate

    def addTurn(self, turnnumber, turnvalue):
        self.turns[turnnumber] = turnvalue
        self.updateGui(turnnumber)
        return self.etat

    def updateGui(self, turn):
        self.selectTurn = turn
        self.updateMap()
        self.updateInfo()

    def updateMap(self):
        self.maptroid.delete(ALL)
        self.printMap()

    def updateInfo(self):
        if self.FrameInfo:
            if self.updateT:
                self.frameT.destroy()
                self.printTurn()
            self.frameAnts.destroy()
            self.frameAnt.destroy()
            self.printAnts()
            self.updateT = True
        else:
            self.printInfo()

    def updateSpin_turn(self):
        turn = int(self.Spin_T.get())
        self.updateT = False
        self.updateGui(turn)

    def validateTurn(self, event):
        try:
            turn = int(self.Spin_T.get())
        except ValueError:
            turn = self.selectTurn
        if turn in self.turns.keys():
            if turn != self.selectTurn:
                self.updateT = False
                self.updateGui(turn)
        else:
            turn = self.selectTurn


    def choiceAnt(self,event):
        i = self.listbox.curselection()
        id_a = self.listbox.get(i)
        self.frameAnt.destroy()
        self.printInfoAnt(int(id_a))

    def printInfo(self):
        self.FrameInfo=Frame(self.RFrame)
        self.printTurn()
        self.printAnts()
        self.FrameInfo.pack()

    def printTurn(self):
        frameS = PanedWindow(self.FrameInfo, orient=HORIZONTAL)
        turns = Label(frameS, text="Tour :")
        self.var.set(str(self.selectTurn))
        self.Spin_T = Spinbox(frameS, values=self.turns.keys(), command =
                self.updateSpin_turn ,textvariable=self.var)
        self.Spin_T.bind('<Return>', self.validateTurn)
        turns.pack()
        self.Spin_T.pack()
        frameS.add(turns)
        frameS.add(self.Spin_T)
        frameS.pack()
        self.frameT = frameS

    def printAnts(self):
        frameAnts = Frame(self.FrameInfo)
        Text_A = Label(frameAnts, text="Fourmie :")
        s1 = Scrollbar(frameAnts)
        l1 = Listbox(frameAnts)
        id_ants = self.checkAnts()
        for i in id_ants: l1.insert(i, str(i))
        s1.config(command = l1.yview)
        l1.config(yscrollcommand = s1.set)
        l1.bind('<ButtonRelease-1>',self.choiceAnt)
        self.listbox = l1
        Text_A.pack(side = TOP)
        l1.pack(side = LEFT)
        s1.pack(side = RIGHT)
        frameAnts.pack()

        self.printInfoAnt(id_ants[0])
        self.frameAnts = frameAnts


    def printInfoAnt(self, i):
        self.frameAnt = PanedWindow(self.FrameInfo, orient=VERTICAL)
        t_Ant = Label(self.frameAnt, text="Information Ant : %d" %(i))
        (t_brain,t_energie,t_acide) = self.getInfoAnt(i)
        a_b = Label(self.frameAnt, text=t_brain)
        a_e = Label(self.frameAnt, text=t_energie)
        a_a = Label(self.frameAnt, text=t_acide)
        t_Ant.pack(side = TOP)
        self.frameAnt.add(t_Ant)
        self.frameAnt.add(a_b)
        self.frameAnt.add(a_e)
        self.frameAnt.add(a_a)
        self.frameAnt.pack()

    def printMap(self):
        turn = self.turns[self.selectTurn]
        # Information on this turn
        config = turn[0]
        Yants = turn[1]
        EAnts = turn[2]
        InitMap = turn[3]
        Cases = turn[4]

        (MaxX,MaxY,N) = InitMap
        self.MinX = 0
        self.MinY = 0
        MaxX_map = MaxX * self.caselength + (self.CaseMarge *2)
        MaxY_map = MaxY * self.caselength + (self.CaseMarge *2)
        #configure canvas
        self.maptroid.config(scrollregion=(0,0,MaxX_map,MaxY_map))
        x1 = self.CaseMarge
        y1 = self.CaseMarge
        x2 = MaxX * self.caselength + self.CaseMarge
        y2 = MaxY * self.caselength +self.CaseMarge
        self.maptroid.create_rectangle(x1, y1, x2, y2, fill="white")

        # affiche case
        for case in Cases:
            self.printCase(case)
        # affiche your ants
        for ant in Yants:
        # nb A : Your Ant 'ID X Y DX DY E A B'
            (id_a,x,y,dx,dy,e,a,b) = ant
            self.printAnt((x,y,dx,dy,b))
        # affiche enemy ants 
        for ant in EAnts:
            self.printAnt(ant)

        #to move map
        self.maptroid.bind('<ButtonPress-1>',self.grab)
        self.maptroid.bind('<B1-Motion>',self.drag)
        self.maptroid.bind('<MouseWheel>',self.mapZoom)
        self.maptroid.bind("<Button-4>", self.mapZoom)
        self.maptroid.bind("<Button-5>", self.mapZoom)

    def printCase(self, case):
        (x,y,c,s) = case
        (x1, y1, x2, y2) = self.getPoint(x, y)
        color = COLOR[c][s]
        if c%2 == 0:
            self.maptroid.create_rectangle(x1, y1, x2, y2, fill=color)
        else:
            self.maptroid.create_rectangle(x1, y1, x2, y2, fill=COLOR[GRASS][s])
            self.maptroid.create_oval(x1, y1, x2, y2, fill=color)

    def printAnt(self, ant):
        (x,y,dx,dy,brain) = ant
        (x1, y1, x2, y2) = self.getPoint(x, y)
        self.maptroid.create_oval(x1, y1, x2, y2, fill="red4")

    def getPoint(self, x, y):
        x1 = (x - self.MinX) * self.caselength + self.CaseMarge
        y1 = (y - self.MinY) * self.caselength + self.CaseMarge
        x2 = x1 + self.caselength
        y2 = y1 + self.caselength
        return (x1, y1, x2, y2)

    def grab(self,event):
        self._y = event.y
        self._x = event.x

    def drag(self, event):
        self.maptroid.yview('scroll',self._y-event.y,'units')
        self.maptroid.xview('scroll',self._x-event.x,'units')
        self._y = event.y
        self._x = event.x

    def mapZoom(self, event):
        # respond to Linux or Windows wheel event
        if event.num == 5 or event.delta == -120:
            self.caselength -= 5
            self.caselength = max(self.caselength, 10)
        if event.num == 4 or event.delta == 120:
            self.caselength += 5
            self.caselength = min(self.caselength, 40)
        self.CaseMarge = self.caselength
        self.updateMap()

    def getInfoAnt(self,id_ant):
        turn = self.turns[self.selectTurn]
        YAnt = turn[1]
        B_Text = "Brain :"
        E_Text = "Energie :"
        A_Text = "Acide :"
        for ant in YAnt:
            (id_a,x,y,dx,dy,e,a,b) = ant
            if b != 1 :
                b = 0
            if(id_ant == id_a):
                B_Text = "Brain : " + BRAIN[b]
                E_Text = "Energie : %d" % (e)
                A_Text = "Acide : %d" % (a)

        return (B_Text,E_Text,A_Text)

    def checkAnts(self):
        turn = self.turns[self.selectTurn]
        YAnt = turn[1]
        ants_id = []
        for ant in YAnt:
            (id_a,x,y,dx,dy,e,a,b) = ant
            ants_id.append(id_a)
        return ants_id

    def myquit(self):
        self.etat = False
        if not self.readstate:
            self.quit()
Example #29
0
class MapUI:
    def __init__(self, master):
        def center(win):
            win.update_idletasks()
            width = win.winfo_width()
            height = win.winfo_height()
            x = (win.winfo_screenwidth() // 4) - (width // 2) + 40
            y = (win.winfo_screenheight() // 4) - (height // 2) + 40
            win.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        def callback(event):
            event.widget.focus_set()
            print "clicked at", event.x, event.y

            if self.add_tasks_flg.get() == 1:
                # Select number of robots
                # Define elements of pop up window
                self.top = Toplevel()

                self.num_robots = StringVar(self.top)
                self.num_robots.set("1")  # default value
                w = OptionMenu(self.top, self.num_robots, '1', '2', '3',
                               '4').grid(row=0, column=1)
                text1 = Message(self.top, text="Number of robots:",
                                width=150).grid(row=0, column=0)

                self.e = Entry(self.top, width=10)
                self.e.grid(row=1, column=1)
                text2 = Message(self.top, text="Task duration:",
                                width=150).grid(row=1, column=0)
                text3 = Message(self.top, text="(s)", width=60).grid(row=1,
                                                                     column=2)

                newline = Message(self.top, text=" ").grid(row=2)

                button = Button(self.top,
                                text='Enter',
                                command=lambda: self.enter_task(event)).grid(
                                    row=3, column=1)
                button_cancel = Button(self.top,
                                       text='Cancel',
                                       command=self.cancel_task).grid(row=3,
                                                                      column=2)

                center(self.top)

        master.title("Map Interface")
        master.minsize(width=1000, height=750)
        master.maxsize(width=1000, height=750)
        master.config(bg=BKG_COLOUR)
        self.master = master

        # Canvas for overlaying map
        self.map_canvas = Canvas(master,
                                 width=CANVAS_W,
                                 height=CANVAS_H,
                                 bg='gray85',
                                 highlightthickness=0)
        self.map_canvas.pack(side='right', padx=50)
        self.map_canvas.bind("<Button-1>", callback)
        global CANVAS_PTR
        CANVAS_PTR = self.map_canvas
        self.master.update()
        w = self.map_canvas.winfo_width()
        h = self.map_canvas.winfo_height()
        # Overlay a grid
        for i in range(0, w, SQ_SIZE):
            if i != 0:
                self.map_canvas.create_line(i, 0, i, h, dash=1)
        for i in range(0, h, SQ_SIZE):
            if i != 0:
                self.map_canvas.create_line(0, i, w, i, dash=1)

        # Load in flame icon from flame.gif
        self.flame_icon = PhotoImage(file="flame.gif")
        # Load in the drone icon from drone.gif
        global DRONE_ICON
        DRONE_ICON = PhotoImage(file="drone.gif")

        buttons_frame = Canvas(master,
                               width=163,
                               height=230,
                               bg=BUTTONS_BKG_COLOUR,
                               highlightthickness=1,
                               highlightbackground='dim grey')
        buttons_frame.place(x=40, y=200)

        # Define UI buttons
        self.add_tasks_flg = IntVar()
        self.add_tasks_b = Checkbutton(master,
                                       text="Add Tasks",
                                       variable=self.add_tasks_flg,
                                       highlightbackground=BUTTONS_BKG_COLOUR,
                                       background=BUTTONS_BKG_COLOUR)
        self.add_tasks_b.place(x=77, y=240)

        self.clear_wp_b = Button(master,
                                 text='Clear Tasks',
                                 command=self.clear_wp,
                                 highlightbackground=BUTTONS_BKG_COLOUR)
        self.clear_wp_b.config(width=10)
        self.clear_wp_b.place(x=65, y=270)
        '''
        self.gen_wp_file_b = Button(master, text='Generate Waypoints File', command=self.gen_wp_file, highlightbackground=BKG_COLOUR)
        self.gen_wp_file_b.config(width=20)
        self.gen_wp_file_b.place(x=20, y=250)
        '''

        self.land_b = Button(master,
                             text='Land',
                             command=self.land,
                             highlightbackground=BUTTONS_BKG_COLOUR)
        self.land_b.config(width=10)
        self.land_b.place(x=65, y=350)

        # Set up coordinate system conversion and display corners of room:
        file_obj = open('antenna_locations.txt', 'r')
        anchors = []
        for line in file_obj:
            cur_anchors = map(float, line.split())
            anchors.append(cur_anchors)
        file_obj.close()
        anchors = (np.array(anchors)).T

        # Find largest (abs) x and y values to use a reference for conversion ratio
        x_vals = anchors[0]
        largest_x_val = x_vals[np.argmax(abs(x_vals))]
        y_vals = anchors[1]
        largest_y_val = y_vals[np.argmax(abs(y_vals))]

        if largest_x_val > largest_y_val:
            largest_y_val = largest_x_val
        else:
            largest_x_val = largest_y_val

        global m_per_pixel_x
        m_per_pixel_x = float(largest_x_val / (CANVAS_W / 2))
        global m_per_pixel_y
        m_per_pixel_y = float(largest_y_val / (CANVAS_H / 2))

        # Place antenna (anchors) on UI
        anchors = anchors.T
        for cur_anchor in anchors:
            x_pixel_loc = cur_anchor[0] / m_per_pixel_x + CANVAS_W / 2
            y_pixel_loc = -1 * (cur_anchor[1] / m_per_pixel_y) + CANVAS_H / 2

            # Draw antenna @ location
            global ANTENNA_LIST
            antenna_id = self.map_canvas.create_oval(x_pixel_loc - 15,
                                                     y_pixel_loc - 15,
                                                     x_pixel_loc + 15,
                                                     y_pixel_loc + 15,
                                                     fill='red')

        self.master.update()

    global SQ_SIZE
    SQ_SIZE = 20
    global BKG_COLOUR
    BKG_COLOUR = 'gray95'
    global BUTTONS_BKG_COLOUR
    BUTTONS_BKG_COLOUR = 'grey66'
    global CANVAS_W
    CANVAS_W = 700
    global CANVAS_H
    CANVAS_H = 700
    global TASK_LIST
    TASK_LIST = None
    global m_per_pixel_x
    m_per_pixel_x = None
    global m_per_pixel_y
    m_per_pixel_y = None
    global NEW_TASK_FLAG
    NEW_TASK_FLAG = False
    global ANTENNA_LIST
    ANTENNA_LIST = None
    global DRONE_ICON
    DRONE_ICON = None

    flame_icon = None
    ui_wp_list = None
    #task_list = None
    add_wp_flag = False
    task_id = 0
    add_tasks_flg = None

    def add_tasks(self):
        print "adding tasks"
        # function imp here
        self.add_wp_flag = True
        self.map_canvas.config(cursor='pencil')

    def clear_wp(self):
        print "clear tasks"
        global TASK_LIST
        TASK_LIST = None
        for element_id in self.ui_wp_list:
            self.map_canvas.delete(element_id[0])
        self.ui_wp_list = None

    '''
    def gen_wp_file(self):
        print "generate wp file"
        # function imp here
    '''

    def land(self):
        # Send a new task with position (0,0,0) z=0 tells drone to land
        print("land")

    def enter_task(self, event):
        # Determine square (top left corner coords):
        w_start = event.x - event.x % SQ_SIZE
        h_start = event.y - event.y % SQ_SIZE

        #Translate pixel location to physical location
        x_pixel = event.x
        y_pixel = event.y
        # Find out how many pixels from center:
        x_pixel = x_pixel - CANVAS_W / 2
        x_physical = x_pixel * m_per_pixel_x

        #vertical case, note this is flipped
        y_pixel = y_pixel - CANVAS_W / 2
        y_pixel = -1 * y_pixel
        y_physical = y_pixel * m_per_pixel_y

        try:
            # Add to task list
            global TASK_LIST
            if TASK_LIST == None:
                TASK_LIST = [[
                    self.task_id,
                    int(self.num_robots.get()),
                    float(self.e.get()), x_physical, y_physical
                ]]
                global NEW_TASK_FLAG
                NEW_TASK_FLAG = True
            else:
                TASK_LIST.append([
                    self.task_id,
                    int(self.num_robots.get()),
                    float(self.e.get()), x_physical, y_physical
                ])
                global NEW_TASK_FLAG
                NEW_TASK_FLAG = True

            # Indicate task in UI
            element_id = self.map_canvas.create_image(event.x,
                                                      event.y,
                                                      image=self.flame_icon)
            if self.ui_wp_list == None:
                self.ui_wp_list = [[element_id]]
            else:
                self.ui_wp_list.append([element_id])
        except:
            print("Invalid Task Entry")

        self.map_canvas.config(cursor='arrow')
        self.add_wp_flag = False

        print(TASK_LIST)

        self.task_id = self.task_id + 1
        self.top.destroy()

    def cancel_task(self):
        self.top.destroy()
Example #30
0
class PiPresents(object):

    def pipresents_version(self):
        vitems=self.pipresents_issue.split('.')
        if len(vitems)==2:
            # cope with 2 digit version numbers before 1.3.2
            return 1000*int(vitems[0])+100*int(vitems[1])
        else:
            return 1000*int(vitems[0])+100*int(vitems[1])+int(vitems[2])


    def __init__(self):
        gc.set_debug(gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_INSTANCES|gc.DEBUG_OBJECTS|gc.DEBUG_SAVEALL)
        self.pipresents_issue="1.3.2"
        self.pipresents_minorissue = '1.3.2a'
        # position and size of window without -f command line option
        self.nonfull_window_width = 0.45 # proportion of width
        self.nonfull_window_height= 0.7 # proportion of height
        self.nonfull_window_x = 0 # position of top left corner
        self.nonfull_window_y=0   # position of top left corner


        StopWatch.global_enable=False

        # set up the handler for SIGTERM
        signal.signal(signal.SIGTERM,self.handle_sigterm)
        

# ****************************************
# Initialisation
# ***************************************
        # get command line options
        self.options=command_options()

        # get Pi Presents code directory
        pp_dir=sys.path[0]
        self.pp_dir=pp_dir
        
        if not os.path.exists(pp_dir+"/pipresents.py"):
            if self.options['manager']  is False:
                tkMessageBox.showwarning("Pi Presents","Bad Application Directory")
            exit(102)

        
        # Initialise logging and tracing
        Monitor.log_path=pp_dir
        self.mon=Monitor()
        # Init in PiPresents only
        self.mon.init()

        # uncomment to enable control of logging from within a class
        # Monitor.enable_in_code = True # enables control of log level in the code for a class  - self.mon.set_log_level()

        
        # make a shorter list to log/trace only some classes without using enable_in_code.
        Monitor.classes  = ['PiPresents',
                            
                            'HyperlinkShow','RadioButtonShow','ArtLiveShow','ArtMediaShow','MediaShow','LiveShow','MenuShow',
                            'GapShow','Show','ArtShow',
                            'AudioPlayer','BrowserPlayer','ImagePlayer','MenuPlayer','MessagePlayer','VideoPlayer','Player',
                            'MediaList','LiveList','ShowList',
                            'PathManager','ControlsManager','ShowManager','PluginManager',
                            'MplayerDriver','OMXDriver','UZBLDriver',
                            'KbdDriver','GPIODriver','TimeOfDay','ScreenDriver','Animate','OSCDriver',
                            'Network','Mailer'
                            ]
        

        # Monitor.classes=['PiPresents','MediaShow','GapShow','Show','VideoPlayer','Player','OMXDriver']
        
        # get global log level from command line
        Monitor.log_level = int(self.options['debug'])
        Monitor.manager = self.options['manager']
        # print self.options['manager']
        self.mon.newline(3)
        self.mon.sched (self, "Pi Presents is starting, Version:"+self.pipresents_minorissue + ' at '+time.strftime("%Y-%m-%d %H:%M.%S"))
        self.mon.log (self, "Pi Presents is starting, Version:"+self.pipresents_minorissue+ ' at '+time.strftime("%Y-%m-%d %H:%M.%S"))
        # self.mon.log (self," OS and separator:" + os.name +'  ' + os.sep)
        self.mon.log(self,"sys.path[0] -  location of code: "+sys.path[0])

        # log versions of Raspbian and omxplayer, and GPU Memory
        with open("/boot/issue.txt") as file:
            self.mon.log(self,'\nRaspbian: '+file.read())

        self.mon.log(self,'\n'+check_output(["omxplayer", "-v"]))
        self.mon.log(self,'\nGPU Memory: '+check_output(["vcgencmd", "get_mem", "gpu"]))
        
        if "DESKTOP_SESSION" not in os.environ:
            print 'Pi Presents must be run from the Desktop'
            self.mon.log(self,'Pi Presents must be run from the Desktop')
            self.mon.finish()
            sys.exit(102)
        else:
            self.mon.log(self,'Desktop is '+ os.environ['DESKTOP_SESSION'])
        
        # optional other classes used
        self.root=None
        self.ppio=None
        self.tod=None
        self.animate=None
        self.gpiodriver=None
        self.oscdriver=None
        self.osc_enabled=False
        self.gpio_enabled=False
        self.tod_enabled=False
        self.email_enabled=False


        if os.geteuid() == 0:
            self.mon.err(self,'Do not run Pi Presents with sudo')
            self.end('error','Do not run Pi Presents with sudo')

        
        user=os.getenv('USER')

        self.mon.log(self,'User is: '+ user)
        # self.mon.log(self,"os.getenv('HOME') -  user home directory (not used): " + os.getenv('HOME')) # does not work
        # self.mon.log(self,"os.path.expanduser('~') -  user home directory: " + os.path.expanduser('~'))   # does not work



        # check network is available
        self.network_connected=False
        self.network_details=False
        self.interface=''
        self.ip=''
        self.unit=''
        
        # sets self.network_connected and self.network_details
        self.init_network()

        
        # start the mailer and send email when PP starts
        self.email_enabled=False
        if self.network_connected is True:
            self.init_mailer()
            if self.email_enabled is True and self.mailer.email_at_start is True:
                subject= '[Pi Presents] ' + self.unit + ': PP Started on ' + time.strftime("%Y-%m-%d %H:%M")
                message = time.strftime("%Y-%m-%d %H:%M") + '\nUnit: ' + self.unit + '   Profile: '+ self.options['profile']+ '\n ' + self.interface + '\n ' + self.ip 
                self.send_email('start',subject,message) 

         
        # get profile path from -p option
        if self.options['profile'] != '':
            self.pp_profile_path="/pp_profiles/"+self.options['profile']
        else:
            self.mon.err(self,"Profile not specified in command ")
            self.end('error','Profile not specified with the commands -p option')
        
       # get directory containing pp_home from the command,
        if self.options['home']  == "":
            home = os.sep+ 'home' + os.sep + user + os.sep+"pp_home"
        else:
            home = self.options['home'] + os.sep+ "pp_home"         
        self.mon.log(self,"pp_home directory is: " + home)


        # check if pp_home exists.
        # try for 10 seconds to allow usb stick to automount
        found=False
        for i in range (1, 10):
            self.mon.log(self,"Trying pp_home at: " + home +  " (" + str(i)+')')
            if os.path.exists(home):
                found=True
                self.pp_home=home
                break
            time.sleep (1)
        if found is True:
            self.mon.log(self,"Found Requested Home Directory, using pp_home at: " + home)
        else:
            self.mon.err(self,"Failed to find pp_home directory at " + home)
            self.end('error',"Failed to find pp_home directory at " + home)


        # check profile exists
        self.pp_profile=self.pp_home+self.pp_profile_path
        if os.path.exists(self.pp_profile):
            self.mon.sched(self,"Running profile: " + self.pp_profile_path)
            self.mon.log(self,"Found Requested profile - pp_profile directory is: " + self.pp_profile)
        else:
            self.mon.err(self,"Failed to find requested profile: "+ self.pp_profile)
            self.end('error',"Failed to find requested profile: "+ self.pp_profile)

        self.mon.start_stats(self.options['profile'])
        
        if self.options['verify'] is True:
            val =Validator()
            if  val.validate_profile(None,pp_dir,self.pp_home,self.pp_profile,self.pipresents_issue,False) is  False:
                self.mon.err(self,"Validation Failed")
                self.end('error','Validation Failed')

         
        # initialise and read the showlist in the profile
        self.showlist=ShowList()
        self.showlist_file= self.pp_profile+ "/pp_showlist.json"
        if os.path.exists(self.showlist_file):
            self.showlist.open_json(self.showlist_file)
        else:
            self.mon.err(self,"showlist not found at "+self.showlist_file)
            self.end('error',"showlist not found at "+self.showlist_file)

        # check profile and Pi Presents issues are compatible
        if self.showlist.profile_version() != self.pipresents_version():
            self.mon.err(self,"Version of showlist " + self.showlist.profile_version_string + " is not  same as Pi Presents")
            self.end('error',"Version of showlist " + self.showlist.profile_version_string + " is not  same as Pi Presents")


        # get the 'start' show from the showlist
        index = self.showlist.index_of_show('start')
        if index >=0:
            self.showlist.select(index)
            self.starter_show=self.showlist.selected_show()
        else:
            self.mon.err(self,"Show [start] not found in showlist")
            self.end('error',"Show [start] not found in showlist")


# ********************
# SET UP THE GUI
# ********************
        # turn off the screenblanking and saver
        if self.options['noblank'] is True:
            call(["xset","s", "off"])
            call(["xset","s", "-dpms"])

        self.root=Tk()   
       
        self.title='Pi Presents - '+ self.pp_profile
        self.icon_text= 'Pi Presents'
        self.root.title(self.title)
        self.root.iconname(self.icon_text)
        self.root.config(bg=self.starter_show['background-colour'])

        self.mon.log(self, 'monitor screen dimensions are ' + str(self.root.winfo_screenwidth()) + ' x ' + str(self.root.winfo_screenheight()) + ' pixels')
        if self.options['screensize'] =='':        
            self.screen_width = self.root.winfo_screenwidth()
            self.screen_height = self.root.winfo_screenheight()
        else:
            reason,message,self.screen_width,self.screen_height=self.parse_screen(self.options['screensize'])
            if reason =='error':
                self.mon.err(self,message)
                self.end('error',message)

        self.mon.log(self, 'forced screen dimensions (--screensize) are ' + str(self.screen_width) + ' x ' + str(self.screen_height) + ' pixels')
       
        # set window dimensions and decorations
        if self.options['fullscreen'] is False:
            self.window_width=int(self.root.winfo_screenwidth()*self.nonfull_window_width)
            self.window_height=int(self.root.winfo_screenheight()*self.nonfull_window_height)
            self.window_x=self.nonfull_window_x
            self.window_y=self.nonfull_window_y
            self.root.geometry("%dx%d%+d%+d" % (self.window_width,self.window_height,self.window_x,self.window_y))
        else:
            self.window_width=self.screen_width
            self.window_height=self.screen_height
            self.root.attributes('-fullscreen', True)
            os.system('unclutter &')
            self.window_x=0
            self.window_y=0  
            self.root.geometry("%dx%d%+d%+d"  % (self.window_width,self.window_height,self.window_x,self.window_y))
            self.root.attributes('-zoomed','1')

        # canvas cover the whole screen whatever the size of the window. 
        self.canvas_height=self.screen_height
        self.canvas_width=self.screen_width
  
        # make sure focus is set.
        self.root.focus_set()

        # define response to main window closing.
        self.root.protocol ("WM_DELETE_WINDOW", self.handle_user_abort)

        # setup a canvas onto which will be drawn the images or text
        self.canvas = Canvas(self.root, bg=self.starter_show['background-colour'])


        if self.options['fullscreen'] is True:
            self.canvas.config(height=self.canvas_height,
                               width=self.canvas_width,
                               highlightthickness=0)
        else:
            self.canvas.config(height=self.canvas_height,
                    width=self.canvas_width,
                        highlightthickness=1,
                               highlightcolor='yellow')
            
        self.canvas.place(x=0,y=0)
        # self.canvas.config(bg='black')
        self.canvas.focus_set()


                
# ****************************************
# INITIALISE THE INPUT DRIVERS
# ****************************************

        # each driver takes a set of inputs, binds them to symboic names
        # and sets up a callback which returns the symbolic name when an input event occurs/

        # use keyboard driver to bind keys to symbolic names and to set up callback
        kbd=KbdDriver()
        if kbd.read(pp_dir,self.pp_home,self.pp_profile) is False:
            self.end('error','cannot find, or error in keys.cfg')
        kbd.bind_keys(self.root,self.handle_input_event)

        self.sr=ScreenDriver()
        # read the screen click area config file
        reason,message = self.sr.read(pp_dir,self.pp_home,self.pp_profile)
        if reason == 'error':
            self.end('error','cannot find, or error in screen.cfg')


        # create click areas on the canvas, must be polygon as outline rectangles are not filled as far as find_closest goes
        # click areas are made on the Pi Presents canvas not the show canvases.
        reason,message = self.sr.make_click_areas(self.canvas,self.handle_input_event)
        if reason == 'error':
            self.mon.err(self,message)
            self.end('error',message)


# ****************************************
# INITIALISE THE APPLICATION AND START
# ****************************************
        self.shutdown_required=False
        self.terminate_required=False
        self.exitpipresents_required=False

        # delete omxplayer dbus files
        # if os.path.exists("/tmp/omxplayerdbus.{}".format(user)):
            # os.remove("/tmp/omxplayerdbus.{}".format(user))
        # if os.path.exists("/tmp/omxplayerdbus.{}.pid".format(user)):
            # os.remove("/tmp/omxplayerdbus.{}.pid".format(user))
        
        # kick off GPIO if enabled by command line option
        self.gpio_enabled=False
        if os.path.exists(self.pp_profile + os.sep + 'pp_io_config'+os.sep+ 'gpio.cfg'):
            # initialise the GPIO
            self.gpiodriver=GPIODriver()
            reason,message=self.gpiodriver.init(pp_dir,self.pp_home,self.pp_profile,self.canvas,50,self.handle_input_event)
            if reason == 'error':
                self.end('error',message)
            else:
                self.gpio_enabled=True
                # and start polling gpio
                self.gpiodriver.poll()
            
        # kick off animation sequencer
        self.animate = Animate()
        self.animate.init(pp_dir,self.pp_home,self.pp_profile,self.canvas,200,self.handle_output_event)
        self.animate.poll()

        #create a showmanager ready for time of day scheduler and osc server
        show_id=-1
        self.show_manager=ShowManager(show_id,self.showlist,self.starter_show,self.root,self.canvas,self.pp_dir,self.pp_profile,self.pp_home)
        # first time through set callback to terminate Pi Presents if all shows have ended.
        self.show_manager.init(self.canvas,self.all_shows_ended_callback,self.handle_command,self.showlist)
        # Register all the shows in the showlist
        reason,message=self.show_manager.register_shows()
        if reason == 'error':
            self.mon.err(self,message)
            self.end('error',message)


        # Init OSCDriver, read config and start OSC server
        self.osc_enabled=False
        if self.network_connected is True:
            if os.path.exists(self.pp_profile + os.sep + 'pp_io_config'+ os.sep + 'osc.cfg'):
                self.oscdriver=OSCDriver()
                reason,message=self.oscdriver.init(self.pp_profile,self.handle_command,self.handle_input_event,self.e_osc_handle_output_event)
                if reason == 'error':
                    self.mon.err(self,message)
                    self.end('error',message)
                else:
                    self.osc_enabled=True
                    self.root.after(1000,self.oscdriver.start_server())

        
        # enable ToD scheduler if schedule exists      
        if os.path.exists(self.pp_profile + os.sep + 'schedule.json'):                
            self.tod_enabled = True
        else:
            self.tod_enabled=False

        # warn if the network not available when ToD required

        if self.tod_enabled is True and self.network_connected is False:
            self.mon.warn(self,'Network not connected  so Time of Day scheduler may be using the internal clock')

        # warn about start shows and scheduler

        if self.starter_show['start-show']=='' and self.tod_enabled is False:
            self.mon.sched(self,"No Start Shows in Start Show and no shows scheduled") 
            self.mon.warn(self,"No Start Shows in Start Show and no shows scheduled")

        if self.starter_show['start-show'] !='' and self.tod_enabled is True:
            self.mon.sched(self,"Start Shows in Start Show and shows scheduled - conflict?") 
            self.mon.warn(self,"Start Shows in Start Show and shows scheduled - conflict?")

        # run the start shows
        self.run_start_shows()           

        # kick off the time of day scheduler which may run additional shows
        if self.tod_enabled is True:
            self.tod=TimeOfDay()
            self.tod.init(pp_dir,self.pp_home,self.pp_profile,self.root,self.handle_command)
            self.tod.poll()            


        # start Tkinters event loop
        self.root.mainloop( )


    def parse_screen(self,size_text):
        fields=size_text.split('*')
        if len(fields)!=2:
            return 'error','do not understand --screensize comand option',0,0
        elif fields[0].isdigit()  is False or fields[1].isdigit()  is False:
            return 'error','dimensions are not positive integers in --screensize',0,0
        else:
            return 'normal','',int(fields[0]),int(fields[1])
        

# *********************
#  RUN START SHOWS
# ********************   
    def run_start_shows(self):
        self.mon.trace(self,'run start shows')
        # parse the start shows field and start the initial shows       
        show_refs=self.starter_show['start-show'].split()
        for show_ref in show_refs:
            reason,message=self.show_manager.control_a_show(show_ref,'open')
            if reason == 'error':
                self.mon.err(self,message)
                


# *********************
# User inputs
# ********************
    # handles one command provided as a line of text
    
    def handle_command(self,command_text,source='',show=''):
        # print 'PIPRESENTS ',command_text,source,'from',show
        self.mon.log(self,"command received: " + command_text)
        if command_text.strip()=="":
            return

        if command_text[0]=='/': 
            if self.osc_enabled is True:
                self.oscdriver.send_command(command_text)
            return
        
        fields= command_text.split()
        show_command=fields[0]
        if len(fields)>1:
            show_ref=fields[1]
        else:
            show_ref=''

        if show_command in ('open','close'):
            self.mon.sched(self, command_text + ' received from show:'+show)
            if self.shutdown_required is False and self.terminate_required is False:
                reason,message=self.show_manager.control_a_show(show_ref,show_command)
            else:
                return
        elif show_command =='monitor':
            self.handle_monitor_command(show_ref)
            return
        elif show_command == 'event':
            self.handle_input_event(show_ref,'Show Control')
            return
        elif show_command == 'exitpipresents':
            self.exitpipresents_required=True
            if self.show_manager.all_shows_exited() is True:
                # need root.after to get out of st thread
                self.root.after(1,self.e_all_shows_ended_callback)
                return
            else:
                reason,message= self.show_manager.exit_all_shows()

        elif show_command == 'shutdownnow':
            # need root.after to get out of st thread
            self.root.after(1,self.e_shutdown_pressed)
            return
        else:
            reason='error'
            message = 'command not recognised: '+ show_command
            
        if reason=='error':
            self.mon.err(self,message)
        return


    def handle_monitor_command(self,command):
        if command == 'on':
            os.system('vcgencmd display_power 1 >/dev/null')
        elif command == 'off':
            os.system('vcgencmd display_power 0 >/dev/null')           
                      
    

    def e_all_shows_ended_callback(self):
        self.all_shows_ended_callback('normal','no shows running')

    def e_shutdown_pressed(self):
        self.shutdown_pressed('now')


    def e_osc_handle_output_event(self,line):
        #jump  out of server thread
        self.root.after(1, lambda arg=line: self.osc_handle_output_event(arg))

    def  osc_handle_output_event(self,line):
        self.mon.log(self,"output event received: "+ line)
        #osc sends output events as a string
        reason,message,delay,name,param_type,param_values=self.animate.parse_animate_fields(line)
        if reason == 'error':
            self.mon.err(self,message)
            self.end(reason,message)
        self.handle_output_event(name,param_type,param_values,0)

               
    def handle_output_event(self,symbol,param_type,param_values,req_time):
        if self.gpio_enabled is True:
            reason,message=self.gpiodriver.handle_output_event(symbol,param_type,param_values,req_time)
            if reason =='error':
                self.mon.err(self,message)
                self.end(reason,message)
        else:
            self.mon.warn(self,'GPIO not enabled')


    # all input events call this callback with a symbolic name.
    # handle events that affect PP overall, otherwise pass to all active shows
    def handle_input_event(self,symbol,source):
        self.mon.log(self,"event received: "+symbol + ' from '+ source)
        if symbol == 'pp-terminate':
            self.handle_user_abort()
            
        elif symbol == 'pp-shutdown':
            self.shutdown_pressed('delay')
            
        elif symbol == 'pp-shutdownnow':
            # need root.after to grt out of st thread
            self.root.after(1,self.e_shutdown_pressed)
            return
        
        elif symbol == 'pp-exitpipresents':
            self.exitpipresents_required=True
            if self.show_manager.all_shows_exited() is True:
                # need root.after to grt out of st thread
                self.root.after(1,self.e_all_shows_ended_callback)
                return
            reason,message= self.show_manager.exit_all_shows()
        else:
            # events for shows affect the show and could cause it to exit.
            for show in self.show_manager.shows:
                show_obj=show[ShowManager.SHOW_OBJ]
                if show_obj is not None:
                    show_obj.handle_input_event(symbol)



    def shutdown_pressed(self, when):
        if when == 'delay':
            self.root.after(5000,self.on_shutdown_delay)
        else:
            self.shutdown_required=True
            if self.show_manager.all_shows_exited() is True:
               self.all_shows_ended_callback('normal','no shows running')
            else:
                # calls exit method of all shows, results in all_shows_closed_callback
                self.show_manager.exit_all_shows()           


    def on_shutdown_delay(self):
        # 5 second delay is up, if shutdown button still pressed then shutdown
        if self.gpiodriver.shutdown_pressed() is True:
            self.shutdown_required=True
            if self.show_manager.all_shows_exited() is True:
               self.all_shows_ended_callback('normal','no shows running')
            else:
                # calls exit method of all shows, results in all_shows_closed_callback
                self.show_manager.exit_all_shows()


    def handle_sigterm(self,signum,frame):
        self.mon.log(self,'SIGTERM received - '+ str(signum))
        self.terminate()


    def handle_user_abort(self):
        self.mon.log(self,'User abort received')
        self.terminate()

    def terminate(self):
        self.mon.log(self, "terminate received")
        self.terminate_required=True
        needs_termination=False
        for show in self.show_manager.shows:
            # print  show[ShowManager.SHOW_OBJ], show[ShowManager.SHOW_REF]
            if show[ShowManager.SHOW_OBJ] is not None:
                needs_termination=True
                self.mon.log(self,"Sent terminate to show "+ show[ShowManager.SHOW_REF])
                # call shows terminate method
                # eventually the show will exit and after all shows have exited all_shows_callback will be executed.
                show[ShowManager.SHOW_OBJ].terminate()
        if needs_termination is False:
            self.end('killed','killed - no termination of shows required')


# ******************************
# Ending Pi Presents after all the showers and players are closed
# **************************

    # callback from ShowManager when all shows have ended
    def all_shows_ended_callback(self,reason,message):
        self.canvas.config(bg=self.starter_show['background-colour'])
        if reason in ('killed','error') or self.shutdown_required is True or self.exitpipresents_required is True:
            self.end(reason,message)

    def end(self,reason,message):
        self.mon.log(self,"Pi Presents ending with reason: " + reason)
        if self.root is not None:
            self.root.destroy()
        self.tidy_up()
        # gc.collect()
        # print gc.garbage
        if reason == 'killed':
            if self.email_enabled is True and self.mailer.email_on_terminate is True:
                subject= '[Pi Presents] ' + self.unit + ': PP Exited with reason: Terminated'
                message = time.strftime("%Y-%m-%d %H:%M") + '\n ' + self.unit + '\n ' + self.interface + '\n ' + self.ip 
                self.send_email(reason,subject,message)
            self.mon.sched(self, "Pi Presents Terminated, au revoir\n")
            self.mon.log(self, "Pi Presents Terminated, au revoir")
                          
            # close logging files 
            self.mon.finish()
            sys.exit(101)
                          
        elif reason == 'error':
            if self.email_enabled is True and self.mailer.email_on_error is True:
                subject= '[Pi Presents] ' + self.unit + ': PP Exited with reason: Error'
                message_text = 'Error message: '+ message + '\n'+ time.strftime("%Y-%m-%d %H:%M") + '\n ' + self.unit + '\n ' + self.interface + '\n ' + self.ip 
                self.send_email(reason,subject,message_text)   
            self.mon.sched(self, "Pi Presents closing because of error, sorry\n")
            self.mon.log(self, "Pi Presents closing because of error, sorry")
                          
            # close logging files 
            self.mon.finish()
            sys.exit(102)

        else:           
            self.mon.sched(self,"Pi Presents  exiting normally, bye\n")
            self.mon.log(self,"Pi Presents  exiting normally, bye")
            
            # close logging files 
            self.mon.finish()
            if self.shutdown_required is True:
                # print 'SHUTDOWN'
                call (['sudo','shutdown','now','SHUTTING DOWN'])
            sys.exit(100)



    def init_network(self):

        timeout=int(self.options['nonetwork'])
        if timeout== 0:
            self.network_connected=False
            self.unit=''
            self.ip=''
            self.interface=''
            return
        
        self.network=Network()
        self.network_connected=False

        # try to connect to network
        self.mon.log (self, 'Waiting up to '+ str(timeout) + ' seconds for network')
        success=self.network.wait_for_network(timeout)
        if success is False:
            self.mon.warn(self,'Failed to connect to network after ' + str(timeout) + ' seconds')
            # tkMessageBox.showwarning("Pi Presents","Failed to connect to network so using fake-hwclock")
            return

        self.network_connected=True
        self.mon.sched (self, 'Time after network check is '+ time.strftime("%Y-%m-%d %H:%M.%S"))
        self.mon.log (self, 'Time after network check is '+ time.strftime("%Y-%m-%d %H:%M.%S"))

        # Get web configuration
        self.network_details=False
        network_options_file_path=self.pp_dir+os.sep+'pp_config'+os.sep+'pp_web.cfg'
        if not os.path.exists(network_options_file_path):
            self.mon.warn(self,"pp_web.cfg not found at "+network_options_file_path)
            return
        self.mon.log(self, 'Found pp_web.cfg in ' + network_options_file_path)

        self.network.read_config(network_options_file_path)
        self.unit=self.network.unit

        # get interface and IP details of preferred interface
        self.interface,self.ip = self.network.get_preferred_ip()
        if self.interface == '':
            self.network_connected=False
            return
        self.network_details=True
        self.mon.log (self, 'Network details ' + self.unit + ' ' + self.interface + ' ' +self.ip)


    def init_mailer(self):

        self.email_enabled=False
        email_file_path = self.pp_dir+os.sep+'pp_config'+os.sep+'pp_email.cfg'
        if not os.path.exists(email_file_path):
            self.mon.log(self,'pp_email.cfg not found at ' + email_file_path)
            return
        self.mon.log(self,'Found pp_email.cfg at ' + email_file_path)
        self.mailer=Mailer()
        self.mailer.read_config(email_file_path)
        # all Ok so can enable email if config file allows it.
        if self.mailer.email_allowed is True:
            self.email_enabled=True
            self.mon.log (self,'Email Enabled')



    def send_email(self,reason,subject,message):
        if self.try_connect() is False:
            return False
        else:
            success,error = self.mailer.send(subject,message)
            if success is False:
                self.mon.log(self, 'Failed to send email: ' + str(error))
                success,error=self.mailer.disconnect()
                if success is False:
                    self.mon.log(self,'Failed disconnect after send:' + str(error))
                return False
            else:
                self.mon.log(self,'Sent email for ' + reason)
                success,error=self.mailer.disconnect()
                if success is False:
                    self.mon.log(self,'Failed disconnect from email server ' + str(error))
                return True


    def try_connect(self):
        tries=1
        while True:
            success, error = self.mailer.connect()
            if success is True:
                return True
            else:
                self.mon.log(self,'Failed to connect to email SMTP server ' + str(tries) +  '\n ' +str(error))
                tries +=1
                if tries >5:
                    self.mon.log(self,'Failed to connect to email SMTP server after ' + str(tries))
                    return False

                
    
    # tidy up all the peripheral bits of Pi Presents
    def tidy_up(self):
        self.handle_monitor_command('on')
        self.mon.log(self, "Tidying Up")
        # turn screen blanking back on
        if self.options['noblank'] is True:
            call(["xset","s", "on"])
            call(["xset","s", "+dpms"])
            
        # tidy up animation and gpio
        if self.animate is not None:
            self.animate.terminate()
            
        if self.gpio_enabled==True:
            self.gpiodriver.terminate()

        if self.osc_enabled is True:
            self.oscdriver.terminate()
            
        # tidy up time of day scheduler
        if self.tod_enabled is True:
            self.tod.terminate()
Example #31
0
class Example(Frame):

    def __init__(self, parent, w_size, kmeans):
        Frame.__init__(self, parent)
        self.parent = parent
        self.pack(fill=BOTH, expand=1)
        self.title = self.parent.title()
        self.w_size = w_size

        # canvas
        self.canvas = Canvas(self, bg="#000")
        self.parent.title("Not convergence")
        self.canvas.pack(side="top", fill="both", expand="true")

        self.kmeans = kmeans
        self.draw(200)


    def draw(self, delay):
        """
        """
        colors = ["#0f0", "#0ff", "#ff0", "#fff"]

        self.title = self.parent.title()

        width, height = self.w_size, self.w_size
        self.canvas.config(width=width, height=height)
        self.canvas.delete("all")

        min, max = -2, 10
        range_data = max - min
        step = float(self.w_size)/range_data

        # draw centroids
        for k, c in enumerate(self.kmeans.centroids):
            x, y = (max - c[0])*step , (max - c[1])*step
            x, y = self.w_size - x, self.w_size - y

            self.canvas.create_rectangle(
                    x, y, x+15, y+15,
                    fill=colors[k]
                    )

        # draw clusters
        for k in self.kmeans.clusters:
            for i in self.kmeans.clusters[k]:

                row = self.kmeans.dataset[i]
                x, y = (max - row[0])*step , (max - row[1])*step
                x, y = self.w_size - x, self.w_size - y

                self.canvas.create_oval(
                        x, y, x+3, y+3,
                        outline=colors[k], fill=colors[k]
                        )

        self.kmeans.next()

        if not self.kmeans.convergence:
            self.after(delay, lambda: self.draw(delay))
        else:

            text = self.kmeans.purity_function()
            self.parent.title("Convergence reached - Purity value %s" % text)

            self.after(delay)
Example #32
0
class Scraper():

    def __init__(self, img_filename='snap.png'):
        self.canvas = Canvas()
        self.scales = []
        self.canvas.pack()
        self._current_image = None
        self._original_image = None
        
        self.root = self._load_gui()
        self.open_image(img_filename)
        self.repaint()
        self.root.mainloop()

    @property
    def image(self):
        return self._current_image

    @image.setter
    def image(self, value):
        self._current_image = value

    @property
    def original_image(self):
        return self._original_image

    @image.setter
    def image(self, value):
        self._original_image = value

    def open_image(self, filename):
        self.original_image = Image.open(filename).copy()
        self.image = self.original_image

    def repaint(self):
        rgb_min = (self.scale_red_min.get(), self.scale_green_min.get(), self.scale_blue_min.get())
        rgb_max = (self.scale_red_max.get(), self.scale_green_max.get(), self.scale_blue_max.get())
        print "repainting", rgb_min, rgb_max
        self.image = strip_colors(self.original_image, rgb_min, rgb_max)
        self._paint(self.image)

    def _paint(self, image):
        if image is not None:
            # check if we need to resize the canvas, based on the size of the image being painted
            image_width, image_height = image.size
            if self.canvas.winfo_width() != image_width or self.canvas.winfo_height() != image_height:
                self.canvas.config(width=image_width, height=image_height)

            # paint the image to the canvas
            self._img_tk = ImageTk.PhotoImage(image)
            self.canvas.create_image(0, 0, image=self._img_tk, anchor=NW)
        else:
            print 'there is no image to paint'
            return -1
 
    def _load_gui(self):
        root = Tk()
        root.title("Scraper")
        main_frame = Frame(root)
        main_frame.grid(column=0, row=0, sticky=(N, W, E, S))
        main_frame.columnconfigure(0, weight=1)
        main_frame.rowconfigure(0, weight=1)
        main_frame.pack()
        
        self.scale_red_min = Scale(main_frame, from_=0, to=255, orient=HORIZONTAL, command=self._update_red_min)
        self.scale_red_min.grid(column=1, row=1)
       
        self.scale_red_max = Scale(main_frame, from_=0, to=255, orient=HORIZONTAL, command=self._update_red_max)
        self.scale_red_max.grid(column=2, row=1)
        self.scale_red_max.set(255)
        
        self.scale_green_min = Scale(main_frame, from_=0, to=255, orient=HORIZONTAL, command=self._update_green_min)
        self.scale_green_min.grid(column=1, row=2)

        self.scale_green_max = Scale(main_frame, from_=0, to=255, orient=HORIZONTAL, command=self._update_green_max)
        self.scale_green_max.grid(column=2, row=2)
        self.scale_green_max.set(255)

        self.scale_blue_min = Scale(main_frame, from_=0, to=255, orient=HORIZONTAL, command=self._update_blue_min)
        self.scale_blue_min.grid(column=1, row=3)
        
        self.scale_blue_max = Scale(main_frame, from_=0, to=255, orient=HORIZONTAL, command=self._update_blue_max)
        self.scale_blue_max.grid(column=2, row=3)
        self.scale_blue_max.set(255)
        return root

    def _update_red_min(self, value):
        print 'updating red min to %s' % value
        if self.scale_red_min.get() > self.scale_red_max.get():
            self.scale_red_max.set(self.scale_red_min.get())
        self.repaint()

    def _update_red_max(self, value):
        print 'updating red max to %s' % value
        if self.scale_red_max.get() < self.scale_red_min.get():
            self.scale_red_min.set(self.scale_red_max.get())
        self.repaint()

    def _update_green_min(self, value):
        print 'updating green min to %s' % value
        if self.scale_green_min.get() > self.scale_green_max.get():
            self.scale_green_max.set(self.scale_green_min.get())
        self.repaint()

    def _update_green_max(self, value):
        print 'updating green max to  %s' % value
        if self.scale_green_max.get() < self.scale_green_min.get():
            self.scale_green_min.set(self.scale_green_max.get())
        self.repaint()

    def _update_blue_min(self, value):
        print 'updating blue min to %s' % value
        if self.scale_blue_min.get() > self.scale_blue_max.get():
            self.scale_blue_max.set(self.scale_blue_min.get())
        self.repaint()

    def _update_blue_max(self, value):
        print 'updating blue max to %s' % value
        if self.scale_blue_max.get() < self.scale_blue_min.get():
            self.scale_blue_min.set(self.scale_blue_max.get())
        self.repaint()
Example #33
0
def create_widgets():
    global list_box, canvas, label, zoom_label
    #
    root = Tk()
    #
    list_box = Listbox(root, exportselection=False)
    list_box.grid(row=0, column=0, rowspan=2, sticky=NS)
    cardsets_list = list(cardsets_dict)
    cardsets_list.sort()
    for cs in cardsets_list:
        list_box.insert(END, cs)
    list_box.bind('<<ListboxSelect>>', show_cardset)
    #
    sb = Scrollbar(root)
    sb.grid(row=0, column=1, rowspan=2, sticky=NS)
    list_box.config(yscrollcommand=sb.set)
    sb.config(command=list_box.yview)
    #
    canvas = Canvas(root, bg='#5eab6b')
    canvas.grid(row=0, column=2, sticky=NSEW)
    canvas.bind('<4>', lambda e: canvas.yview_scroll(-5, 'unit'))
    canvas.bind('<5>', lambda e: canvas.yview_scroll(5, 'unit'))
    #
    sb = Scrollbar(root)
    sb.grid(row=0, column=3, sticky=NS)
    canvas.config(yscrollcommand=sb.set)
    sb.config(command=canvas.yview)
    #
    if True:
        sb = Scrollbar(root, orient=HORIZONTAL)
        sb.grid(row=1, column=2, sticky=EW)
        canvas.config(xscrollcommand=sb.set)
        sb.config(command=canvas.xview)
    #
    label = Label(root)
    label.grid(row=2, column=0, columnspan=4)
    #
    b_frame = Frame(root)
    b_frame.grid(row=3, column=0, columnspan=4, sticky=EW)
    button = Button(b_frame, text='Quit', command=root.quit, width=8)
    button.pack(side=RIGHT)
    button = Button(b_frame, text='Info', command=show_info, width=8)
    button.pack(side=RIGHT)
    if Image:
        global rotate_var, filter_var
        rotate_var = IntVar(root)
        filter_var = StringVar(root)
        button = Button(b_frame, text='  +  ', command=zoom_in)
        button.pack(side=LEFT)
        button = Button(b_frame, text='  -  ', command=zoom_out)
        button.pack(side=LEFT)
        button = Button(b_frame, text='  =  ', command=zoom_cancel)
        button.pack(side=LEFT)
        button = Checkbutton(b_frame,
                             text='Rotate',
                             indicatoron=0,
                             selectcolor=b_frame['bg'],
                             width=8,
                             variable=rotate_var,
                             command=show_cardset)
        button.pack(side=LEFT, fill='y')
        om = OptionMenu(b_frame,
                        filter_var,
                        'NEAREST',
                        'BILINEAR',
                        'BICUBIC',
                        'ANTIALIAS',
                        command=show_cardset)
        filter_var.set('NEAREST')
        om.pack(side=LEFT, fill='y')

        zoom_label = Label(b_frame)
        zoom_label.pack(side=LEFT)
    #
    root.columnconfigure(2, weight=1)
    root.rowconfigure(0, weight=1)

    root.title('Show Cardsets')

    return root
Example #34
0
class MainNavView(Frame):
    def __init__(self, controller, parent):
        self.controller = controller
        self.parent = parent
        self.app = self.controller.app
        self.enabled = False
        self.has_selected = False
        self.planet_images = []

        self.main_window = controller.parent.view
        self.main_nav = Frame(self.main_window, height=self.main_window.sh, width=self.main_window.sw - 200, background='black')
        # self.main_nav = Frame.__init__(self.main_window, height=self.main_window.sh, width=self.main_window.sw - 200, background='black')

        self.main_nav.place(x=200, y=0)
        self.main_canvas = Canvas(self.parent)
        self.main_canvas_has_been_created = True

    def build(self):  # formerly build_main_nav

        self.app.debug("Building Main Nav View")

        if self.enabled:
            self.main_canvas.destroy()
            self.build_planet_view()
        else:
            self.build_planet_view()
            self.enabled = True

    def build_planet_view(self):

        app = self.app
        main_window = app.main_controller.view
        player = app.game.player

        # global main_canvas_has_been_created, main_nav, main_canvas

        self.app.debug(("Displayed: main_nav,", main_window.sw - 200, ",", main_window.sh))

        # draw corner lines
        if self.app.conf.debug_lines == 1:
            self.main_canvas.create_line(0, 0, main_window.sw - 200, main_window.sh, fill='red')
            self.main_canvas.create_line(main_window.sw - 200, 0, 0, main_window.sh, fill='red')

        if self.app.conf.debug == 1:
            print "CreatedLine:", 0, " ", 0, " ", main_window.sw - 200, " ", main_window.sh
            print "CreatedLine:", main_window.sw - 200, " ", 0, " ", 0, " ", main_window.sh
            print "CurrWin0:", self.convert_coordinates_x(0), self.convert_coordinates_y(0)

        self.main_canvas.config(width=main_window.sw - 200, height=main_window.sh)
        self.main_canvas.config(background='black')
        self.main_canvas.config(highlightbackground=self.app.conf.main_background)
        self.main_canvas.config(highlightthickness=0)

        if self.app.conf.debug == 1:
            print "*********************"
            print "***Drawing Planets***"
            print "*********************"

        # draw planets
        for planet in player.planets:
            if self.app.conf.debug == 1:
                print "init:", planet.loc.x, ",", planet.loc.y
            if planet == player.selected_planet:
                self.draw_planet_highlighted(planet)
            else:
                self.draw_planet(planet)

        self.finish_drawing_planets()

    def redraw_planet_view(self):

        app = self.app
        main_window = app.main_controller.view

        if self.main_canvas_has_been_created:
            self.main_canvas.config(width=main_window.sw - 200, height=main_window.sh)
            self.main_canvas.delete('all')
            self.finish_drawing_planets()
            self.app.debug("Redraw:AlreadyCreated")
        else:
            self.build_planet_view()
            self.app.debug("Redraw:New")

    def finish_drawing_planets(self):

        self.main_canvas.pack(fill='both')
        main_window = self.controller.parent.view
        self.app.debug(("WindowSize:", main_window.sw, ":", main_window.sh))

    def draw_planet(self, planet):

        # global main_nav, main_canvas, label, planet_images, main_window

        new_x = self.convert_coordinates_x(planet.loc.x)
        new_y = self.convert_coordinates_y(planet.loc.y)
        name_y = self.convert_coordinates_name(planet.loc.y, planet.loc.size)
        color = self.get_terrain_color(planet.terrain)

        size = planet.loc.size, planet.loc.size
        planet_image = Image.open(self.get_terrain_image(planet.terrain))
        planet_image.thumbnail(size, Image.ANTIALIAS)
        planet_image_res = ImageTk.PhotoImage(planet_image)
        new_planet_image = planet_image_res
        self.planet_images.append(new_planet_image)
        label = Label(self.main_canvas)
        label.config(image=planet_image_res)
        label.config(background='black')
        label.grid()
        label.planet_image_res = planet_image_res  # keep a reference!
        label.place(anchor=CENTER, x=new_x, y=new_y)
        label.bind("<Button-1>", lambda event, arg=planet: self.controller.select_planet(event, arg))

        label_name = Label(self.main_canvas, text=planet.name, fg=self.app.conf.main_text_color, bg='black'
                           , borderwidth=1
                           , highlightthickness=0)
        label_name.place(anchor=CENTER, x=new_x, y=name_y)

        if self.app.conf.debug == 1:
            print "Drawing planet: [", planet.name, ",", new_x, ",", new_y, ",", planet.loc.size, ",", color, "]"

    def draw_planet_highlighted(self, planet):

        # global main_nav, main_canvas, label, planet_images, main_window

        new_x = self.convert_coordinates_x(planet.loc.x)
        new_y = self.convert_coordinates_y(planet.loc.y)
        name_y = self.convert_coordinates_name(planet.loc.y, planet.loc.size)
        color = self.get_terrain_color(planet.terrain)

        size = planet.loc.size, planet.loc.size
        planet_image = Image.open(self.get_terrain_image(planet.terrain))
        planet_image.thumbnail(size, Image.ANTIALIAS)
        planet_image_res = ImageTk.PhotoImage(planet_image)
        new_planet_image = planet_image_res
        self.planet_images.append(new_planet_image)
        label_planet = Label(self.main_canvas)
        label_planet.config(image=planet_image_res)
        label_planet.config(background='black')
        label_planet.planet_image_res = planet_image_res  # keep a reference!
        label_planet.place(anchor=CENTER, x=new_x, y=new_y)
        label_planet.bind("<Button-1>", lambda event, arg=planet: self.controller.select_planet(event, arg))
        label_name = Label(self.main_canvas, text=planet.name, fg='red', bg='black', borderwidth=1
                           , highlightthickness=0)
        label_name.place(anchor=CENTER, x=new_x, y=name_y)

        if self.app.conf.debug == 1:
            print "Drawing planet: [", planet.name, ",", new_x, ",", new_y, ",", planet.loc.size, ",", color, "]"

        # get nearest planet and draw a line
        if self.has_selected:
            nearest_planet = self.get_nearest_planet(planet)
            l = self.get_line_points((planet.loc.x, planet.loc.y)
                                     , (nearest_planet.loc.x, nearest_planet.loc.y)
                                     , planet.loc.size
                                     , nearest_planet.loc.size)
            self.main_canvas.create_line(l.x1, l.y1, l.x2, l.y2, fill='blue', dash=(4, 4))
            self.main_canvas.pack()
            self.app.debug(("Drawing line:", l.x1, ',', l.y1, ',', l.x2, ',', l.y2))
        else:
            self.app.debug("Line next time")
            self.has_selected = True

    def draw_planet_h(self, planet):

        # global main_nav, main_canvas, label, planet_images, main_window

        new_x = self.convert_coordinates_x(planet.loc.x)
        new_y = self.convert_coordinates_y(planet.loc.y)
        name_y = self.convert_coordinates_name(planet.loc.y, planet.loc.size)
        color = self.get_terrain_color(planet.terrain)

        size = planet.loc.size, planet.loc.size
        planet_image = Image.open(self.get_terrain_image(planet.terrain))
        planet_image.thumbnail(size, Image.ANTIALIAS)
        planet_image_res = ImageTk.PhotoImage(planet_image)
        new_planet_image = planet_image_res
        self.planet_images.append(new_planet_image)
        label_planet = Label(self.main_canvas)
        label_planet.config(image=planet_image_res)
        label_planet.config(background='black')
        label_planet.planet_image_res = planet_image_res  # keep a reference!
        label_planet.place(anchor=CENTER, x=new_x, y=new_y)
        label_planet.bind("<Button-1>", lambda event, arg=planet: self.controller.select_planet(event, arg))
        label_name = Label(self.main_canvas, text=planet.name, fg='red', bg='black', borderwidth=1
                           , highlightthickness=0)
        label_name.place(anchor=CENTER, x=new_x, y=name_y)

        if self.app.conf.debug == 1:
            print "Drawing planet: [", planet.name, ",", new_x, ",", new_y, ",", planet.loc.size, ",", color, "]"

    def get_nearest_planet(self, planet):
        planets = self.app.game.player.planets
        distances = {}
        for i in range(len(planets)):
            if planets[i].name != planet.name:
                print i
                tmp = self.get_distance(planet, planets[i])
                distances[i] = tmp
        self.app.debug(("Found nearest planet:", planets[min(distances)].name, "and", planet.name))
        self.draw_planet_h(planets[min(distances)])
        return planets[min(distances)]

    @staticmethod
    def get_distance(planet1, planet2):
        return hypot(planet2.loc.x - planet1.loc.x, planet2.loc.y - planet1.loc.y)

    def redraw_planet(self, planet):

        self.draw_planet(self.app.game.player.last_selected_planet)
        self.draw_planet_highlighted(planet)

    @staticmethod
    def get_terrain_color(terrain):

        """

        :param terrain:
        :return:

        # Planet Terrains
        # 1 Ice
        # 2 Rock
        # 3 Green
        # 4 Water
        # 5 Alien

        """

        if terrain == 1:
            return 'ice'
        elif terrain == 2:
            return 'rock'
        elif terrain == 3:
            return 'green'
        elif terrain == 4:
            return 'water'
        elif terrain == 5:
            return 'alien'
        else:
            return 'black'

    def get_terrain_image(self, terrain):

        # Planet Terrains
        # 1 Ice
        # 2 Rock
        # 3 Green
        # 4 Water
        # 5 Alien

        if terrain == 1:
            return self.app.conf.ice_planet_image_path
        elif terrain == 2:
            return self.app.conf.rock_planet_image_path
        elif terrain == 3:
            return self.app.conf.green_planet_image_path
        elif terrain == 4:
            return self.app.conf.water_planet_image_path
        elif terrain == 5:
            return self.app.conf.alien_planet_image_path
        else:
            return self.app.conf.alien_planet_image_path

    def convert_coordinates_x(self, x):
        main_window = self.app.main_controller.view
        return ((main_window.sw - 200) / 2) + x

    def convert_coordinates_y(self, y):
        main_window = self.app.main_controller.view
        return (main_window.sh / 2) + y

    def convert_coordinates_name(self, y, size):
        main_window = self.app.main_controller.view
        return (main_window.sh / 2) + y - (size / 2) - self.app.conf.planet_name_height

    @staticmethod
    def angle(pt1, pt2):
        x1, y1 = pt1
        x2, y2 = pt2

        deltax = x2 - x1
        deltay = y2 - y1

        angle_rad = atan2(deltay, deltax)
        angle_deg = angle_rad * 180.0 / pi

        # return angle_rad
        return angle_deg

    def get_line_points(self, p1, p2, p1width, p2width):

        # initialize vars

        x1, y1 = p1
        x2, y2 = p2

        self.app.debug(("x1", x1))
        self.app.debug(("y1", y1))
        self.app.debug(("x2", x2))
        self.app.debug(("y2", y2))

        # x3 = 0
        # y3 = 0
        # x4 = 0
        # y4 = 0

        # get angle1

        a1 = self.angle(p1, p2)

        # determine line start distance from planet centers

        o1 = 2 * p1width
        o2 = 2 * p2width

        # get first point of the line

        x3 = x1 + (cos(a1) * o1)
        y3 = y1 + (sin(a1) * o1)

        # get angle 2

        a2 = (90 + a1) - 180

        # establish 2nd point of the line

        x4 = x2 + (cos(a2) * o2)
        y4 = y2 + (sin(a2) * o2)

        # convert coordinates for window size

        x3 = self.convert_coordinates_x(x3)
        y3 = self.convert_coordinates_y(y3)
        x4 = self.convert_coordinates_x(x4)
        y4 = self.convert_coordinates_y(y4)

        # create object to return

        line_points = LinePoints(x3, y3, x4, y4)

        return line_points

    def get_line_points_(self, p1, p2, p1width, p2width):

        # initialize vars

        x1, y1 = p1
        x2, y2 = p2

        # x3 = 0
        # y3 = 0
        # x4 = 0
        # y4 = 0

        # get angle1

        a1 = self.angle(p1, p2)

        # determine line start distance from planet centers

        o1 = 2 * p1width
        o2 = 2 * p2width

        # get first point of the line

        x3 = x1 + (cos(a1) * o1)
        y3 = y1 + (sin(a1) * o1)

        # get angle 2

        a2 = (90 + a1) - 180

        # establish 2nd point of the line

        x4 = x2 + (cos(a2) * o2)
        y4 = y2 + (sin(a2) * o2)

        # create object to return

        line_points = LinePoints(x3, y3, x4, y4)

        return line_points
class AppAnalysis:


    def __init__(self, root):

        self.canvas = Canvas(root, width = 400, height = 350)
        self.canvas.configure(cursor="crosshair")
        self.canvas.pack(expand=YES, fill=BOTH, side='right')

        self.canvas.bind("<Key>", self.handle_key)
        self.canvas.bind("<Double-Button-1>", self.set_focus)
        self.canvas.bind("<Button-1>", self.set_cursor)
        self.canvas.bind("<Return>", self.remove_highlight)

        self.image, self.ponto1, self.ponto2 = (None, None, None)

        self.menubar = Menu(root)

        filemenu = Menu(self.menubar, tearoff=0)
        filemenu.add_command(label="Open Image", command=self.openImage)
        filemenu.add_command(label="Save", command=self.hello)
        filemenu.add_separator()
        filemenu.add_command(label="Exit", command=root.quit)
        self.menubar.add_cascade(label="File", menu=filemenu)

        editmenu = Menu(self.menubar, tearoff=0)
        for e in ("Cut","Copy","Paste"):
            editmenu.add_command(label=e, command=self.hello)

        self.menubar.add_cascade(label="Edit", menu=editmenu)

        filtermenu = Menu(self.menubar, tearoff=0)
        filtermenu.add_command(label="Threshold", command=self.thresholdFilter)
        self.menubar.add_cascade(label="Filter", menu=filtermenu)

        reportmenu = Menu(self.menubar, tearoff=0)
        reportmenu.add_command(label="Relatorio.txt",
        command=self.generateReport)
        reportmenu.add_command(label="Relatorio.pdf")
        reportmenu.add_command(label="Email")
        self.menubar.add_cascade(label="Report", menu=reportmenu)

        helpmenu = Menu(self.menubar, tearoff=0)
        helpmenu.add_command(label="About", command=self.hello)
        self.menubar.add_cascade(label="Help", menu=helpmenu)

        root.config(menu=self.menubar)

        self.toolbar = Frame(root)
        self.toolbar.pack(side='left', fill='both')
        clean = Label(self.toolbar, text='Clean')
        clean.bind("<Button-1>", self.clean)
        b = Label(self.toolbar, text='B')
        c = Label(self.toolbar, text='C')
        d = Label(self.toolbar, text='D')

        for w in (clean,b,c,d):
            w.configure(relief="groove", font="Times 12 bold")
            w.pack(fill='both')

    def openImage(self):
        arquivo = tkFileDialog.askopenfile(parent=self.canvas,mode='rb',
        title='Imagem')
        e = ['GIF','JPEG','JPG','BMP','PNG','TIF']
        if(e.__contains__(arquivo.name.split(".")[-1].upper())):
            self.ponto1, self.ponto2 = (None,None)
            img_tmp = Image.open(arquivo)
            #self.img_name = path.dirname(path.abspath(arquivo.name))
            self.img_name = arquivo.name
            print self.img_name
            self.new_img_name = arquivo.name.split('/')[-1] + "_tmp.gif"
            pathtemp = mydir +"/temp/"+ self.new_img_name
            img_tmp.save(pathtemp)
            self.image = PhotoImage(file=pathtemp)
            self.setImage()
            self.canvas.bind("<Button-1>", self.click)
            self.proporcao = ""

    def clean(self, event):
        self.ponto1, self.ponto2 = (None,None)
        self.setImage()
        self.proporcao = ""

    def setImage(self):
        self.canvas.delete(ALL)
        if self.image.width() > 200 and self.image.height > 200:
            self.canvas.config(width = self.image.width())
            self.canvas.config(height = self.image.height())
        self.canvas.create_image(0, 0, image=self.image, anchor=NW)

    def generateReport(self):
        report = GeradorRelatorio(self.img_name)
        report.start()

    def hello(self):
        print "hello!"

    def thresholdFilter(self):
        img = Image.open(self.img_name)
        new_img = img.filter(ImageFilter.BLUR)
        aux = mydir +"/temp/"+ self.new_img_name
        new_img.save(aux)
        self.image = PhotoImage(file=aux)
        self.setImage()

    def click(self, event):
        if not self.ponto1:
            self.canvas.create_oval(event.x, event.y, event.x+5, event.y+5,
            fill="red")
            self.ponto1 = (event.x,event.y)
        else:
            if not self.ponto2:
                self.canvas.create_oval(event.x, self.ponto1[1],
                event.x+5, self.ponto1[1]+5, fill="red")

                self.ponto2 = (event.x,self.ponto1[1])

                pontos = [self.ponto1[0]+1,self.ponto1[1]+2,
                self.ponto2[0]+1,self.ponto2[1]+2]

                self.canvas.create_line(pontos, tags="theline", fill='red')
                x = (self.ponto2[0] + self.ponto1[0]) / 2
                self.canvas.create_text(x, self.ponto1[1]+8, text="1 umm")

    def remove_highlight(self,event):
        self.canvas.delete("highlight")

    def highlight(self, item):
        bbox = self.canvas.bbox(item)
        self.canvas.delete("highlight")
        if bbox:
            i = self.canvas.create_rectangle(
            bbox, fill="white",
            tag="highlight"
            )
            self.canvas.lower(i, item)

    def has_focus(self):
        return self.canvas.focus()

    def has_selection(self):
        return self.canvas.tk.call(self.canvas._w, 'select', 'item')

    def set_focus(self, event):
        if self.canvas.type(CURRENT) != "text":
            return

        self.highlight(CURRENT)

        self.canvas.focus_set()
        self.canvas.focus(CURRENT)
        self.canvas.select_from(CURRENT, 0)
        self.canvas.select_to(CURRENT, END)

    def set_cursor(self, event):
        item = self.has_focus()
        if not item:
            return

        x = self.canvas.canvasx(event.x)
        y = self.canvas.canvasy(event.y)

        self.canvas.icursor(item, "@%d,%d" % (x, y))
        self.canvas.select_clear()

    def handle_key(self, event):
        item = self.has_focus()
        if not item:
            return

        insert = self.canvas.index(item, INSERT)

        if event.char >= " ":
            if self.has_selection():
                self.canvas.dchars(item, SEL_FIRST, SEL_LAST)
                self.canvas.select_clear()
            self.canvas.insert(item, "insert", event.char)
            self.highlight(item)

        elif event.keysym == "BackSpace":
            if self.has_selection():
                self.canvas.dchars(item, SEL_FIRST, SEL_LAST)
                self.canvas.select_clear()
            else:
                if insert > 0:
                    self.canvas.dchars(item, insert-1, insert)
            self.highlight(item)

        elif event.keysym == "Home":
            self.canvas.icursor(item, 0)
            self.canvas.select_clear()
        elif event.keysym == "End":
            self.canvas.icursor(item, END)
            self.canvas.select_clear()
        elif event.keysym == "Right":
            self.canvas.icursor(item, insert+1)
            self.canvas.select_clear()
        elif event.keysym == "Left":
            self.canvas.icursor(item, insert-1)
            self.canvas.select_clear()
        else:
            pass
    def on_show_frame(self):
        self.canvas_wrappers = []
        self.canvases = []
        self.page_num = 0

        if len(self.controller.sr_results) == 0:
            self.controller.show_frame(SrNoFramesFoundScreen)
        else:
            pages = int(ceil(len(self.controller.sr_results) / 10.0))
            for page in range(0, pages):
                canvas_wrapper = Frame(self.content_wrapper,
                                       borderwidth="1",
                                       relief="solid")
                canvas = Canvas(canvas_wrapper,
                                width=int(WINDOW_WIDTH * 7 / 8),
                                height=(WINDOW_HEIGHT * 2 / 3))
                scroll_bar = Scrollbar(canvas_wrapper,
                                       orient=VERTICAL,
                                       command=canvas.yview)
                results_list_frame = Frame(canvas)

                canvas.configure(yscrollcommand=scroll_bar.set)
                canvas.create_window(0, 0, window=results_list_frame)
                canvas.bind_all("<Up>", self.on_up_key)
                canvas.bind_all("<Down>", self.on_down_key)
                canvas.bind_all("<Left>", self.on_left_key)
                canvas.bind_all("<Right>", self.on_right_key)

                canvas.grid(row=0, column=0, sticky="nsew")
                scroll_bar.grid(row=0, column=1, sticky="ns")
                canvas_wrapper.grid(row=2,
                                    column=0,
                                    columnspan=3,
                                    sticky="nsew")

                select_buttons_on_page = []

                for row in range(0, RESULTS_PER_PAGE):
                    result_num = page * RESULTS_PER_PAGE + row
                    if result_num < len(self.controller.sr_results):
                        frame_num = self.controller.sr_results[result_num][
                            FRAME_NUM_LABEL]

                        result_entry = Frame(results_list_frame,
                                             borderwidth="1",
                                             relief="solid")
                        description = PLabel(
                            result_entry,
                            text="Frame #" + str(int(frame_num)) + ", Time: " +
                            str(datetime.timedelta(seconds=frame_num / 30)))
                        preview_wrapper = Frame(result_entry)
                        left_video_preview = Label(
                            preview_wrapper,
                            image=self.controller.sr_results[result_num][LEFT])
                        right_video_preview = Label(
                            preview_wrapper,
                            image=self.controller.sr_results[result_num]
                            [RIGHT])
                        select_button = SrSelectButton(
                            preview_wrapper,
                            self.controller,
                            self.controller.sr_results[result_num]
                            [SR_MAP_LABEL],
                            text="Select")

                        select_buttons_on_page.append(select_button)

                        description.pack()
                        left_video_preview.grid(row=row, column=0)
                        right_video_preview.grid(row=row, column=1)
                        select_button.grid(row=row, column=2)
                        preview_wrapper.pack()
                        result_entry.pack()

                for i in range(0, len(select_buttons_on_page)):
                    select_buttons_on_page[i].configure(
                        command=select_buttons_on_page[i].use_sr_map)

                self.master.update_idletasks()
                canvas.config(scrollregion=canvas.bbox("all"))
                canvas.yview_moveto(0)
                self.canvas_wrappers.append(canvas_wrapper)
                self.canvases.append(canvas)

            self.prev_result_page = Button(
                self.content_wrapper,
                text="<",
                command=lambda: self.prev_page_command())
            self.page_info_label = PLabel(
                self.content_wrapper,
                text=get_page_info_label_message(self.page_num,
                                                 len(self.canvases),
                                                 RESULTS_PER_PAGE))
            self.next_result_page = Button(
                self.content_wrapper,
                text=">",
                command=lambda: self.next_page_command())

            self.prev_result_page.grid(row=3, column=0)
            self.page_info_label.grid(row=3, column=1)
            self.next_result_page.grid(row=3, column=2)
            self.canvas_wrappers[self.page_num].tkraise()
Example #37
0
class GcFrame(LabelFrame):
	def __init__(self, root, filename, contents, settings, logger, *arg):
		LabelFrame.__init__(self, root, *arg, text="gcode Viewer")

		self.label = Label(self)
		self.canvas = Canvas(self, width=settings.buildarea[0]*SCALE, height=settings.buildarea[1]*SCALE, bd=2, relief=RIDGE, bg="black")
		self.canvas.config(takefocus="1")
		self.root = root
		self.settings = settings
		self.buildarea = settings.buildarea
		self.log = logger
		self.zoom = 1
		self.offsetx = 0
		self.offsety = 0
		self.movestartx = 0
		self.movestarty = 0
		
		
		self.sb = Scrollbar(self)
		self.sb.config(command=self.scroll)
		self.sb.set(0.0, 1.0)
		self.sbslidersize = 1.0
		self.syncwithprint = IntVar()
		self.syncwithprint.set(1)
		self.bZoomOut = Button(self, text="-", width=3, command=self.doZoomOut)
		self.bZoomIn = Button(self, text="+", width=3, command=self.doZoomIn)
		self.cb = Checkbutton(self, text="Sync view with print", variable=self.syncwithprint,
			command=self.syncClick)
		self.bReset = Button(self, text="Reset View", command=self.pressReset)

		self.canvas.bind("<Button-1>", self.startMove);
		self.canvas.bind("<B1-Motion>", self.continueMove);
		self.canvas.bind("<MouseWheel>", self.mouseWheel);
		self.canvas.bind("<Button-4>", self.mouseWheel);
		self.canvas.bind("<Button-5>", self.mouseWheel);
		self.canvas.bind("<Shift-MouseWheel>", self.mouseWheelZoom);
		self.canvas.bind("<Shift-Button-4>", self.mouseWheelZoom);
		self.canvas.bind("<Shift-Button-5>", self.mouseWheelZoom);

		self.label.grid(row=1, column=1, columnspan=5)
		self.canvas.grid(row=2,column=1,columnspan=5)
		self.sb.grid(row=2, column=6, sticky=N+S)	
		self.bZoomOut.grid(row=3, column=1, sticky=E)
		self.bZoomIn.grid(row=3, column=2, sticky=W)
		self.cb.grid(row=3, column=3, columnspan=2)
		self.bReset.grid(row=3, column=5, columnspan=2)

		self.currentlayer = None
		self.currentdrawn = None
		self.currentlx = None
		self.layercount = 0
		self.filename = None
		self.printprogress = 0
		self.minline = 0
		self.maxline = 0
		
		self.drawGrid()

		self.model = Model()
		
		if filename != None:
			self.loadFile(filename, contents)
		
		#self.drawLayer(self.currentlayer)

	def getPrintStartLine(self):
		return self.model.getPrintStartLine()

	def pressReset(self):
		self.resetView()

	def startMove(self, e):
		self.canvas.focus_set()
		self.movestartx = e.x
		self.movestarty = e.y
		self.moveoffsetx = self.offsetx
		self.moveoffsety = self.offsety

	def continueMove(self, e):
		dx = e.x - self.movestartx
		dy = e.y - self.movestarty
		self.offsetx = self.moveoffsetx - dx/(2*self.zoom)
		self.offsety = self.moveoffsety - dy/(2*self.zoom)
		self.drawCanvas()
	
	def updatePrintProgress(self, n, restart=False):
		if n == 0:
			self.printprogress = 0
			if self.syncwithprint.get() == 1:
				if restart:
					self.currentLayer = self.model.bottomLayer()
					self.currentdrawn = None
					self.currentlx = 0
					self.setSliderPos()
				self.drawLayer(self.currentlayer)
			return
		
		if n <= self.printprogress:
			return

		ll = self.model.findLayersbyLineNo(self.printprogress, n)
		if len(ll) == 0: return

		self.printprogress = n		
		if self.syncwithprint.get() == 1:
			if self.currentlayer != ll[-1]:
				self.currentlayer = ll[-1]
				self.currentlx = self.model.getLayerNumber(self.currentlayer)
				self.drawLayer(self.currentlayer)
				self.setSliderPos()
			else:
				self.drawOneLayer(self.currentlayer, updateonly=True)
			
		else:
			if self.currentlayer in ll:
				self.drawOneLayer(self.currentlayer, updateonly=True)
		
	def scroll(self, *a):
		if self.currentlx == None:
			self.currentlx = 0
		
		if a[0] == "scroll":
			nlx = self.currentlx - int(a[1])
			if nlx < 0:
				nlx = 0
			elif nlx >= self.model.countLayers():
				nlx = self.model.countLayers()-1
				
		elif a[0] == "moveto":
			pos = 1.0 - float(a[1])
			nlx = int(pos / self.sbslidersize) - 1
			if nlx < 0:
				nlx = 0
			elif nlx >= self.model.countLayers():
				nlx = self.model.countLayers()-1
				
		else:
			return
	
		self.currentlx = nlx
		self.currentlayer = self.model.getLayerName(nlx)
		self.drawLayer(self.currentlayer)
		self.setSliderPos()
	
	def setSliderPos(self):
		if self.currentlx == None:
			self.currentlx = 0
		sbpos = 1.0 - (self.currentlx * self.sbslidersize) - self.sbslidersize
		if sbpos < 0.0:
			sbpos = 0.0
		self.sb.set(sbpos, sbpos+self.sbslidersize)

	def syncClick(self):
		if self.syncwithprint.get() == 1:
			self.updatePrintProgress(self.printprogress)
		
	def mouseWheel(self, e):
		if e.num == 5 or e.keycode == -120: #scroll down
			self.scroll("scroll", 1)
		elif e.num == 4 or e.keycode == 120: #scroll up
			self.scroll("scroll", -1)

	def mouseWheelZoom(self, e):
		if e.num == 5 or e.keycode == -120: #zoom in
			self.doZoomIn()

		elif e.num == 4 or e.keycode == 120: #zoom out
			if self.zoom > 1:
				self.doZoomOut()
				
	def doZoomIn(self):
		cw = self.buildarea[0]/self.zoom
		ch = self.buildarea[1]/self.zoom
		self.zoom += 1

		nw = self.buildarea[0]/self.zoom
		nh = self.buildarea[1]/self.zoom

		self.offsetx += (cw-nw)/2
		self.offsety += (ch-nh)/2
		self.drawCanvas()
	
	def doZoomOut(self):
		if self.zoom > 1:
			cw = self.buildarea[0]/self.zoom
			ch = self.buildarea[1]/self.zoom
			self.zoom -= 1
			if self.zoom < 1: self.zoom = 1

			nw = self.buildarea[0]/self.zoom
			nh = self.buildarea[1]/self.zoom

			self.offsetx -= (nw-cw)/2
			self.offsety -= (nh-ch)/2
			self.drawCanvas()

	def loadFile(self, filename, contents):
		self.filename = filename	
		self.model.addFile(contents)
		self.currentlayer = self.model.bottomLayer()
		self.currentlx = 0
		self.currentdrawn = None
		self.printprogress = 0
		self.layercount = self.model.countLayers()
			
		self.drawLayer(self.currentlayer)
	
		if self.layercount > 0:	
			self.sbslidersize = 1.0 / self.layercount
			self.setSliderPos()
			
	def getLayerNumberByHeight(self, z):
		return self.model.getLayerNumberByHeight(z)

	def resetView(self):
		self.zoom = 1
		self.offsety = 0
		self.offsetx = 0
		self.drawCanvas()

	def drawCanvas(self):
		self.currentdrawn = None
		self.drawGrid()
		self.drawLayer(self.currentlayer)
		self.setSliderPos()
			
	def drawGrid(self):
		self.canvas.delete("GRID")
		ltGrey = "#424242"
		dkGrey = "#404040"

		yleft = (0 - self.offsety)*self.zoom*SCALE
		if yleft < 0: yleft = 0

		yright = (self.buildarea[1] - self.offsety)*self.zoom*SCALE
		if yright > self.buildarea[1]*SCALE: yright = self.buildarea[1]*SCALE

		for x in range(0, self.buildarea[0], 10):
			if x%50 == 0:
				c = ltGrey
			else:
				c = dkGrey
			x = (x - self.offsetx)*self.zoom*SCALE
			if x >= 0 and x <= self.buildarea[0]*SCALE:
				self.canvas.create_line(x, yleft, x, yright, fill=c, tags="GRID")
			
		xtop = (0 - self.offsetx)*self.zoom*SCALE
		if xtop <0: xtop = 0

		xbottom = (self.buildarea[0] - self.offsetx)*self.zoom*SCALE
		if xbottom > self.buildarea[0]*SCALE: xbottom = self.buildarea[0]*SCALE

		for y in range(0, self.buildarea[1], 10):
			if y%50 == 0:
				c = dkGrey
			else:
				c = ltGrey
			y = (y - self.offsety)*self.zoom*SCALE
			if y >= 0 and y <= self.buildarea[1]*SCALE:
				self.canvas.create_line(xtop, y, xbottom, y, fill=c, tags="GRID")
			
	def drawLayer(self, layername):
		if layername == self.currentdrawn:
			#print "deleting object"
			#self.canvas.delete("OBJECT")
			self.drawOneLayer(layername, updateonly=True)
		else:
			self.canvas.delete("OBJECT")
			self.canvas.delete("SHADOW")
		
			pl = self.model.prevLayer(layername)
			if pl and self.settings.showprevious:
				self.drawOneLayer(pl, background=True)
			
			self.drawOneLayer(layername)
			self.currentdrawn = layername
		
	def drawOneLayer(self, layername, background=False, updateonly=False):
		if not self.model.setLayer(layername):
			return
		
		lx = self.model.getLayerNumber(layername)
		
		prev = [None, None]
		segmentextrusion = 0.0
		cx = 0
		segments = 0
		
		if background:
			tag = "SHADOW"
		else:
			tag = "OBJECT"

		if not background and not updateonly:
				self.label.config(text="file: %.30s    z = %.3f (%d/%d)" %
								(os.path.basename(self.filename), self.model.getLayerHeight(layername), lx+1, self.model.countLayers()))		
		for p in self.model:
			if prev == [None, None]:
				prev = [p[0], p[1]]
				if segments != 0:
					segments = 0
					cx = (cx + 1) % len(colors)
			else:
				if p[3] <= segmentextrusion or p[3] == -1:
					if p[3] == -1:
						segmentextrusion = 0.0

					if not updateonly:
						if not background and self.settings.showmoves:
							c = "white"	
							if prev != [p[0], p[1]]:
								(x1, y1) = self.transform(prev[0], self.buildarea[1]-prev[1])
								(x2, y2) = self.transform(p[0], self.buildarea[1]-p[1])
								self.canvas.create_line(x1, y1, x2, y2, fill=c, tags=tag)
						if segments != 0:
							segments = 0
							cx = (cx + 1) % len(colors)
				else:
					if prev != [p[0], p[1]]:
						segments += 1
						segmentextrusion = p[3]
						if background:
							c = grey
							f = not updateonly
						elif self.printprogress >= p[5]:
							c = "red"
							f = True
						else:
							c = colors[cx]
							f = not updateonly
						if f:
							(x1, y1) = self.transform(prev[0], self.buildarea[1]-prev[1])
							(x2, y2) = self.transform(p[0], self.buildarea[1]-p[1])
							self.canvas.create_line(x1, y1, x2, y2, fill=c, tags=tag)
				prev = [p[0], p[1]]

	def transform(self, ptx, pty):
		x = (ptx - self.offsetx)*self.zoom*SCALE
		y = (pty - self.offsety)*self.zoom*SCALE
		return (x, y)
class AntroidGUI(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.protocol("WM_DELETE_WINDOW", self.myquit)
        self.etat = True
        self.readstate = True
        self.title("Antroid Map")
        self.turns = {}
        self.selectTurn = -1
        self.caselength = 10
        self.CaseMarge = 20
        self.var = StringVar()
        self.initGUI()

    def initGUI(self):
        frame = Frame(self, width=630, height=500)
        self.panel = PanedWindow(frame, orient=HORIZONTAL)

        self.LeftFrame(self.panel)
        self.RightFrame(self.panel)
        self.panel.add(self.LFrame)
        self.panel.add(self.RFrame)
        self.panel.pack()
        frame.pack()

    def LeftFrame(self, parent):
        self.LFrame = Frame(parent, width=500, height=500)
        self.maptroid = Canvas(self.LFrame, bg='black', width=500, height=500)
        if self.selectTurn >= 0:
            self.printMap()

        self.maptroid.pack()
        self.LFrame.pack()

    def RightFrame(self, parent):
        self.RFrame = Frame(parent, width=130, height=500)
        if self.selectTurn >= 0:
            self.printInfo()
        self.FrameInfo = None
        self.updateT = True
        self.RFrame.pack()

    def setreadstate(self, readstate):
        self.readstate = readstate

    def addTurn(self, turnnumber, turnvalue):
        self.turns[turnnumber] = turnvalue
        self.updateGui(turnnumber)
        return self.etat

    def updateGui(self, turn):
        self.selectTurn = turn
        self.updateMap()
        self.updateInfo()

    def updateMap(self):
        self.maptroid.delete(ALL)
        self.printMap()

    def updateInfo(self):
        if self.FrameInfo:
            if self.updateT:
                self.frameT.destroy()
                self.printTurn()
            self.frameAnts.destroy()
            self.frameAnt.destroy()
            self.printAnts()
            self.updateT = True
        else:
            self.printInfo()

    def updateSpin_turn(self):
        turn = int(self.Spin_T.get())
        self.updateT = False
        self.updateGui(turn)

    def validateTurn(self, event):
        try:
            turn = int(self.Spin_T.get())
        except ValueError:
            turn = self.selectTurn
        if turn in self.turns.keys():
            if turn != self.selectTurn:
                self.updateT = False
                self.updateGui(turn)
        else:
            turn = self.selectTurn

    def choiceAnt(self, event):
        i = self.listbox.curselection()
        id_a = self.listbox.get(i)
        self.frameAnt.destroy()
        self.printInfoAnt(int(id_a))

    def printInfo(self):
        self.FrameInfo = Frame(self.RFrame)
        self.printTurn()
        self.printAnts()
        self.FrameInfo.pack()

    def printTurn(self):
        frameS = PanedWindow(self.FrameInfo, orient=HORIZONTAL)
        turns = Label(frameS, text="Tour :")
        self.var.set(str(self.selectTurn))
        self.Spin_T = Spinbox(frameS,
                              values=self.turns.keys(),
                              command=self.updateSpin_turn,
                              textvariable=self.var)
        self.Spin_T.bind('<Return>', self.validateTurn)
        turns.pack()
        self.Spin_T.pack()
        frameS.add(turns)
        frameS.add(self.Spin_T)
        frameS.pack()
        self.frameT = frameS

    def printAnts(self):
        frameAnts = Frame(self.FrameInfo)
        Text_A = Label(frameAnts, text="Fourmie :")
        s1 = Scrollbar(frameAnts)
        l1 = Listbox(frameAnts)
        id_ants = self.checkAnts()
        for i in id_ants:
            l1.insert(i, str(i))
        s1.config(command=l1.yview)
        l1.config(yscrollcommand=s1.set)
        l1.bind('<ButtonRelease-1>', self.choiceAnt)
        self.listbox = l1
        Text_A.pack(side=TOP)
        l1.pack(side=LEFT)
        s1.pack(side=RIGHT)
        frameAnts.pack()

        self.printInfoAnt(id_ants[0])
        self.frameAnts = frameAnts

    def printInfoAnt(self, i):
        self.frameAnt = PanedWindow(self.FrameInfo, orient=VERTICAL)
        t_Ant = Label(self.frameAnt, text="Information Ant : %d" % (i))
        (t_brain, t_energie, t_acide) = self.getInfoAnt(i)
        a_b = Label(self.frameAnt, text=t_brain)
        a_e = Label(self.frameAnt, text=t_energie)
        a_a = Label(self.frameAnt, text=t_acide)
        t_Ant.pack(side=TOP)
        self.frameAnt.add(t_Ant)
        self.frameAnt.add(a_b)
        self.frameAnt.add(a_e)
        self.frameAnt.add(a_a)
        self.frameAnt.pack()

    def printMap(self):
        turn = self.turns[self.selectTurn]
        # Information on this turn
        config = turn[0]
        Yants = turn[1]
        EAnts = turn[2]
        InitMap = turn[3]
        Cases = turn[4]

        (MaxX, MaxY, N) = InitMap
        self.MinX = 0
        self.MinY = 0
        MaxX_map = MaxX * self.caselength + (self.CaseMarge * 2)
        MaxY_map = MaxY * self.caselength + (self.CaseMarge * 2)
        #configure canvas
        self.maptroid.config(scrollregion=(0, 0, MaxX_map, MaxY_map))
        x1 = self.CaseMarge
        y1 = self.CaseMarge
        x2 = MaxX * self.caselength + self.CaseMarge
        y2 = MaxY * self.caselength + self.CaseMarge
        self.maptroid.create_rectangle(x1, y1, x2, y2, fill="white")

        # affiche case
        for case in Cases:
            self.printCase(case)
        # affiche your ants
        for ant in Yants:
            # nb A : Your Ant 'ID X Y DX DY E A B'
            (id_a, x, y, dx, dy, e, a, b) = ant
            self.printAnt((x, y, dx, dy, b))
        # affiche enemy ants
        for ant in EAnts:
            self.printAnt(ant)

        #to move map
        self.maptroid.bind('<ButtonPress-1>', self.grab)
        self.maptroid.bind('<B1-Motion>', self.drag)
        self.maptroid.bind('<MouseWheel>', self.mapZoom)
        self.maptroid.bind("<Button-4>", self.mapZoom)
        self.maptroid.bind("<Button-5>", self.mapZoom)

    def printCase(self, case):
        (x, y, c, s) = case
        (x1, y1, x2, y2) = self.getPoint(x, y)
        color = COLOR[c][s]
        if c % 2 == 0:
            self.maptroid.create_rectangle(x1, y1, x2, y2, fill=color)
        else:
            self.maptroid.create_rectangle(x1,
                                           y1,
                                           x2,
                                           y2,
                                           fill=COLOR[GRASS][s])
            self.maptroid.create_oval(x1, y1, x2, y2, fill=color)

    def printAnt(self, ant):
        (x, y, dx, dy, brain) = ant
        (x1, y1, x2, y2) = self.getPoint(x, y)
        self.maptroid.create_oval(x1, y1, x2, y2, fill="red4")

    def getPoint(self, x, y):
        x1 = (x - self.MinX) * self.caselength + self.CaseMarge
        y1 = (y - self.MinY) * self.caselength + self.CaseMarge
        x2 = x1 + self.caselength
        y2 = y1 + self.caselength
        return (x1, y1, x2, y2)

    def grab(self, event):
        self._y = event.y
        self._x = event.x

    def drag(self, event):
        self.maptroid.yview('scroll', self._y - event.y, 'units')
        self.maptroid.xview('scroll', self._x - event.x, 'units')
        self._y = event.y
        self._x = event.x

    def mapZoom(self, event):
        # respond to Linux or Windows wheel event
        if event.num == 5 or event.delta == -120:
            self.caselength -= 5
            self.caselength = max(self.caselength, 10)
        if event.num == 4 or event.delta == 120:
            self.caselength += 5
            self.caselength = min(self.caselength, 40)
        self.CaseMarge = self.caselength
        self.updateMap()

    def getInfoAnt(self, id_ant):
        turn = self.turns[self.selectTurn]
        YAnt = turn[1]
        B_Text = "Brain :"
        E_Text = "Energie :"
        A_Text = "Acide :"
        for ant in YAnt:
            (id_a, x, y, dx, dy, e, a, b) = ant
            if b != 1:
                b = 0
            if (id_ant == id_a):
                B_Text = "Brain : " + BRAIN[b]
                E_Text = "Energie : %d" % (e)
                A_Text = "Acide : %d" % (a)

        return (B_Text, E_Text, A_Text)

    def checkAnts(self):
        turn = self.turns[self.selectTurn]
        YAnt = turn[1]
        ants_id = []
        for ant in YAnt:
            (id_a, x, y, dx, dy, e, a, b) = ant
            ants_id.append(id_a)
        return ants_id

    def myquit(self):
        self.etat = False
        if not self.readstate:
            self.quit()
Example #39
0
class IntroView(Frame):
    def __init__(self, controller, parent):     # formerly init_intro_nav():

        '''     using class objects for all these vars now
        global intro_nav, background_frame, can, button_load_game\
            , button_new_game, button_quit, intro_fill_bottom\
            , label_version, title_image_res\
            , intro_top_padding, intro_btm_padding
        '''

        self.controller = controller
        self.parent = parent
        self.app = self.controller.app

        # declare vars

        self.background_frame = 0
        self.intro_nav = 0
        self.intro_top_padding = 0

    def build(self):        # prev: build_intro_nav

        # frame setup
        conf = self.app.conf

        self.background_frame = Frame(self.parent, height=self.parent.sh, width=self.parent.sw
                                      , background=conf.window_background)
        self.intro_nav = Frame(self.background_frame, height=500, width=500
                               , background=conf.intro_background)

        # elements

        self.intro_top_padding = Canvas(self.intro_nav)
        self.intro_top_padding.configure(height=conf.intro_padding_height
                                         , background=conf.intro_background
                                         , highlightbackground=conf.intro_background)

        self.title_image_resource = Image.open(conf.title_image_path)
        self.title_image_res = ImageTk.PhotoImage(self.title_image_resource)
        self.can = Canvas(self.intro_nav, background=conf.intro_background
                          , highlightbackground=conf.intro_background)
        self.can.title_image_res = self.title_image_res
        self.can.config(width=self.title_image_res.width(), height=self.title_image_res.height())

        self.button_new_game = Button(self.intro_nav, text="New Game"
                                      , command=self.controller.event_button_new_game
                                      , bg=conf.intro_background)
        self.button_new_game.config(highlightbackground=conf.intro_background)

        self.button_load_game = Button(self.intro_nav, text="Load Game"
                                       , command=self.controller.event_button_load_game
                                       , bg=conf.intro_background)
        self.button_load_game.config(highlightbackground=conf.intro_background)
        self.button_load_game.config(state='disabled')

        self.button_quit = Button(self.intro_nav, text="Quit"
                                  , command=self.controller.event_button_quit
                                  , bg=conf.intro_background)
        self.button_quit.config(highlightbackground=conf.intro_background)

        self.label_version = Label(self.intro_nav, bg=conf.intro_background, text=conf.version)

        self.intro_btm_padding = Canvas(self.intro_nav)
        self.intro_btm_padding.configure(height=conf.intro_padding_height
                                         , background=conf.intro_background
                                         , highlightbackground=conf.intro_background)

    def hide(self):     # formerly hide_intro_nav
        self.intro_nav.destroy()
        self.background_frame.destroy()
        self.can.destroy()
        self.button_load_game.destroy()
        self.button_new_game.destroy()
        self.button_quit.destroy()
        self.label_version.destroy()
        self.title_image_res.__del__()
        self.intro_top_padding.destroy()
        self.intro_btm_padding.destroy()


    def draw(self):       # formerly draw_intro_nav()

        # frame setup

        self.intro_top_padding.pack()

        self.background_frame.pack(fill='both')
        self.intro_nav.pack(fill='both', padx=(self.parent.sw/2)-250, pady=(self.parent.sh/2)-250)

        self.app.debug(("Drew Intro, padding: (", (self.parent.sw/2)-250, ",", (self.parent.sh/2)-250, ")"))

        # elements

        self.can.pack(fill='both', side='top', padx=50, pady=50)
        self.can.create_image(2, 2, image=self.title_image_res, anchor='nw')

        self.button_new_game.pack(fill="x", padx=50)
        self.button_load_game.pack(fill="x", padx=50)
        self.button_quit.pack(fill="x", padx=50)
        self.label_version.pack(fill='y', padx=10, pady=10)

        self.intro_btm_padding.pack()

        '''
class PiPresents(object):
    def __init__(self):
        gc.set_debug(gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_INSTANCES
                     | gc.DEBUG_OBJECTS | gc.DEBUG_SAVEALL)
        self.pipresents_issue = "1.3"
        self.pipresents_minorissue = '1.3.1g'
        # position and size of window without -f command line option
        self.nonfull_window_width = 0.45  # proportion of width
        self.nonfull_window_height = 0.7  # proportion of height
        self.nonfull_window_x = 0  # position of top left corner
        self.nonfull_window_y = 0  # position of top left corner
        self.pp_background = 'black'

        StopWatch.global_enable = False

        # set up the handler for SIGTERM
        signal.signal(signal.SIGTERM, self.handle_sigterm)

        # ****************************************
        # Initialisation
        # ***************************************
        # get command line options
        self.options = command_options()

        # get Pi Presents code directory
        pp_dir = sys.path[0]
        self.pp_dir = pp_dir

        if not os.path.exists(pp_dir + "/pipresents.py"):
            if self.options['manager'] is False:
                tkMessageBox.showwarning(
                    "Pi Presents",
                    "Bad Application Directory:\n{0}".format(pp_dir))
            exit(103)

        # Initialise logging and tracing
        Monitor.log_path = pp_dir
        self.mon = Monitor()
        # Init in PiPresents only
        self.mon.init()

        # uncomment to enable control of logging from within a class
        # Monitor.enable_in_code = True # enables control of log level in the code for a class  - self.mon.set_log_level()

        # make a shorter list to log/trace only some classes without using enable_in_code.
        Monitor.classes = [
            'PiPresents', 'pp_paths', 'HyperlinkShow', 'RadioButtonShow',
            'ArtLiveShow', 'ArtMediaShow', 'MediaShow', 'LiveShow', 'MenuShow',
            'PathManager', 'ControlsManager', 'ShowManager', 'PluginManager',
            'MplayerDriver', 'OMXDriver', 'UZBLDriver', 'KbdDriver',
            'GPIODriver', 'TimeOfDay', 'ScreenDriver', 'Animate', 'OSCDriver'
        ]

        # Monitor.classes=['PiPresents','ArtMediaShow','VideoPlayer','OMXDriver']

        # get global log level from command line
        Monitor.log_level = int(self.options['debug'])
        Monitor.manager = self.options['manager']
        # print self.options['manager']
        self.mon.newline(3)
        self.mon.log(
            self,
            "Pi Presents is starting, Version:" + self.pipresents_minorissue)
        # self.mon.log (self," OS and separator:" + os.name +'  ' + os.sep)
        self.mon.log(self, "sys.path[0] -  location of code: " + sys.path[0])
        if os.geteuid() != 0:
            user = os.getenv('USER')
        else:
            user = os.getenv('SUDO_USER')
        self.mon.log(self, 'User is: ' + user)
        # self.mon.log(self,"os.getenv('HOME') -  user home directory (not used): " + os.getenv('HOME')) # does not work
        # self.mon.log(self,"os.path.expanduser('~') -  user home directory: " + os.path.expanduser('~'))   # does not work

        # optional other classes used
        self.root = None
        self.ppio = None
        self.tod = None
        self.animate = None
        self.gpiodriver = None
        self.oscdriver = None
        self.osc_enabled = False
        self.gpio_enabled = False
        self.tod_enabled = False

        # get home path from -o option
        self.pp_home = pp_paths.get_home(self.options['home'])
        if self.pp_home is None:
            self.end('error', 'Failed to find pp_home')

        # get profile path from -p option
        # pp_profile is the full path to the directory that contains
        # pp_showlist.json and other files for the profile
        self.pp_profile = pp_paths.get_profile_dir(self.pp_home,
                                                   self.options['profile'])
        if self.pp_profile is None:
            self.end('error', 'Failed to find profile')

        # check profile exists
        if os.path.exists(self.pp_profile):
            self.mon.log(
                self, "Found Requested profile - pp_profile directory is: " +
                self.pp_profile)
        else:
            self.mon.err(
                self, "Failed to find requested profile: " + self.pp_profile)
            self.end('error', 'Failed to find profile')

        self.mon.start_stats(self.options['profile'])

        # check 'verify' option
        if self.options['verify'] is True:
            val = Validator()
            if val.validate_profile(None, pp_dir, self.pp_home,
                                    self.pp_profile, self.pipresents_issue,
                                    False) is False:
                self.mon.err(self, "Validation Failed")
                self.end('error', 'Validation Failed')

        # initialise and read the showlist in the profile
        self.showlist = ShowList()
        self.showlist_file = self.pp_profile + "/pp_showlist.json"
        if os.path.exists(self.showlist_file):
            self.showlist.open_json(self.showlist_file)
        else:
            self.mon.err(self, "showlist not found at " + self.showlist_file)
            self.end('error', 'showlist not found')

        # check profile and Pi Presents issues are compatible
        if float(self.showlist.sissue()) != float(self.pipresents_issue):
            self.mon.err(
                self, "Version of profile " + self.showlist.sissue() +
                " is not  same as Pi Presents, must exit")
            self.end('error', 'wrong version of profile')

        # get the 'start' show from the showlist
        index = self.showlist.index_of_show('start')
        if index >= 0:
            self.showlist.select(index)
            self.starter_show = self.showlist.selected_show()
        else:
            self.mon.err(self, "Show [start] not found in showlist")
            self.end('error', 'start show not found')

        if self.starter_show['start-show'] == '':
            self.mon.warn(self, "No Start Shows in Start Show")

# ********************
# SET UP THE GUI
# ********************
# turn off the screenblanking and saver
        if self.options['noblank'] is True:
            call(["xset", "s", "off"])
            call(["xset", "s", "-dpms"])

        self.root = Tk()

        self.title = 'Pi Presents - ' + self.pp_profile
        self.icon_text = 'Pi Presents'
        self.root.title(self.title)
        self.root.iconname(self.icon_text)
        self.root.config(bg=self.pp_background)

        self.mon.log(
            self, 'native screen dimensions are ' +
            str(self.root.winfo_screenwidth()) + ' x ' +
            str(self.root.winfo_screenheight()) + ' pixcels')
        if self.options['screensize'] == '':
            self.screen_width = self.root.winfo_screenwidth()
            self.screen_height = self.root.winfo_screenheight()
        else:
            reason, message, self.screen_width, self.screen_height = self.parse_screen(
                self.options['screensize'])
            if reason == 'error':
                self.mon.err(self, message)
                self.end('error', message)

        self.mon.log(
            self, 'commanded screen dimensions are ' + str(self.screen_width) +
            ' x ' + str(self.screen_height) + ' pixcels')

        # set window dimensions and decorations
        if self.options['fullscreen'] is False:
            self.window_width = int(self.root.winfo_screenwidth() *
                                    self.nonfull_window_width)
            self.window_height = int(self.root.winfo_screenheight() *
                                     self.nonfull_window_height)
            self.window_x = self.nonfull_window_x
            self.window_y = self.nonfull_window_y
            self.root.geometry("%dx%d%+d%+d" %
                               (self.window_width, self.window_height,
                                self.window_x, self.window_y))
        else:
            self.window_width = self.screen_width
            self.window_height = self.screen_height
            self.root.attributes('-fullscreen', True)
            os.system(
                'unclutter 1>&- 2>&- &'
            )  # Suppress 'someone created a subwindow' complaints from unclutter
            self.window_x = 0
            self.window_y = 0
            self.root.geometry("%dx%d%+d%+d" %
                               (self.window_width, self.window_height,
                                self.window_x, self.window_y))
            self.root.attributes('-zoomed', '1')

        # canvs cover the whole screen whatever the size of the window.
        self.canvas_height = self.screen_height
        self.canvas_width = self.screen_width

        # make sure focus is set.
        self.root.focus_set()

        # define response to main window closing.
        self.root.protocol("WM_DELETE_WINDOW", self.handle_user_abort)

        # setup a canvas onto which will be drawn the images or text
        self.canvas = Canvas(self.root, bg=self.pp_background)

        if self.options['fullscreen'] is True:
            self.canvas.config(height=self.canvas_height,
                               width=self.canvas_width,
                               highlightthickness=0)
        else:
            self.canvas.config(height=self.canvas_height,
                               width=self.canvas_width,
                               highlightthickness=1,
                               highlightcolor='yellow')

        self.canvas.place(x=0, y=0)
        # self.canvas.config(bg='black')
        self.canvas.focus_set()

        # ****************************************
        # INITIALISE THE INPUT DRIVERS
        # ****************************************

        # each driver takes a set of inputs, binds them to symboic names
        # and sets up a callback which returns the symbolic name when an input event occurs/

        # use keyboard driver to bind keys to symbolic names and to set up callback
        kbd = KbdDriver()
        if kbd.read(pp_dir, self.pp_home, self.pp_profile) is False:
            self.end('error', 'cannot find or error in keys.cfg')
        kbd.bind_keys(self.root, self.handle_input_event)

        self.sr = ScreenDriver()
        # read the screen click area config file
        reason, message = self.sr.read(pp_dir, self.pp_home, self.pp_profile)
        if reason == 'error':
            self.end('error', 'cannot find screen.cfg')

        # create click areas on the canvas, must be polygon as outline rectangles are not filled as far as find_closest goes
        # click areas are made on the Pi Presents canvas not the show canvases.
        reason, message = self.sr.make_click_areas(self.canvas,
                                                   self.handle_input_event)
        if reason == 'error':
            self.mon.err(self, message)
            self.end('error', message)

# ****************************************
# INITIALISE THE APPLICATION AND START
# ****************************************
        self.shutdown_required = False
        self.exitpipresents_required = False

        # kick off GPIO if enabled by command line option
        self.gpio_enabled = False
        if os.path.exists(self.pp_profile + os.sep + 'pp_io_config' + os.sep +
                          'gpio.cfg'):
            # initialise the GPIO
            self.gpiodriver = GPIODriver()
            reason, message = self.gpiodriver.init(pp_dir, self.pp_home,
                                                   self.pp_profile,
                                                   self.canvas, 50,
                                                   self.handle_input_event)
            if reason == 'error':
                self.end('error', message)
            else:
                self.gpio_enabled = True
                # and start polling gpio
                self.gpiodriver.poll()

        # kick off animation sequencer
        self.animate = Animate()
        self.animate.init(pp_dir, self.pp_home, self.pp_profile, self.canvas,
                          200, self.handle_output_event)
        self.animate.poll()

        #create a showmanager ready for time of day scheduler and osc server
        show_id = -1
        self.show_manager = ShowManager(show_id, self.showlist,
                                        self.starter_show, self.root,
                                        self.canvas, self.pp_dir,
                                        self.pp_profile, self.pp_home)
        # first time through set callback to terminate Pi Presents if all shows have ended.
        self.show_manager.init(self.canvas, self.all_shows_ended_callback,
                               self.handle_command, self.showlist)
        # Register all the shows in the showlist
        reason, message = self.show_manager.register_shows()
        if reason == 'error':
            self.mon.err(self, message)
            self.end('error', message)

        # Init OSCDriver, read config and start OSC server
        self.osc_enabled = False
        if os.path.exists(self.pp_profile + os.sep + 'pp_io_config' + os.sep +
                          'osc.cfg'):
            self.oscdriver = OSCDriver()
            reason, message = self.oscdriver.init(
                self.pp_profile, self.handle_command, self.handle_input_event,
                self.e_osc_handle_output_event)
            if reason == 'error':
                self.end('error', message)
            else:
                self.osc_enabled = True
                self.root.after(1000, self.oscdriver.start_server())

        # and run the start shows
        self.run_start_shows()

        # set up the time of day scheduler including catchup
        self.tod_enabled = False
        if os.path.exists(self.pp_profile + os.sep + 'schedule.json'):
            # kick off the time of day scheduler which may run additional shows
            self.tod = TimeOfDay()
            self.tod.init(pp_dir, self.pp_home, self.pp_profile, self.root,
                          self.handle_command)
            self.tod_enabled = True

        # then start the time of day scheduler
        if self.tod_enabled is True:
            self.tod.poll()

        # start Tkinters event loop
        self.root.mainloop()

    def parse_screen(self, size_text):
        fields = size_text.split('*')
        if len(fields) != 2:
            return 'error', 'do not understand --fullscreen comand option', 0, 0
        elif fields[0].isdigit() is False or fields[1].isdigit() is False:
            return 'error', 'dimensions are not positive integers in ---fullscreen', 0, 0
        else:
            return 'normal', '', int(fields[0]), int(fields[1])

# *********************
#  RUN START SHOWS
# ********************

    def run_start_shows(self):
        self.mon.trace(self, 'run start shows')
        # parse the start shows field and start the initial shows
        show_refs = self.starter_show['start-show'].split()
        for show_ref in show_refs:
            reason, message = self.show_manager.control_a_show(
                show_ref, 'open')
            if reason == 'error':
                self.mon.err(self, message)

# *********************
# User inputs
# ********************
# handles one command provided as a line of text

    def handle_command(self, command_text):
        self.mon.log(self, "command received: " + command_text)
        if command_text.strip() == "":
            return

        if command_text[0] == '/':
            if self.osc_enabled is True:
                self.oscdriver.send_command(command_text)
            return

        fields = command_text.split()
        show_command = fields[0]
        if len(fields) > 1:
            show_ref = fields[1]
        else:
            show_ref = ''

        if show_command in ('open', 'close'):
            if self.shutdown_required is False:
                reason, message = self.show_manager.control_a_show(
                    show_ref, show_command)
            else:
                return
        elif show_command == 'exitpipresents':
            self.exitpipresents_required = True
            if self.show_manager.all_shows_exited() is True:
                # need root.after to get out of st thread
                self.root.after(1, self.e_all_shows_ended_callback)
                return
            else:
                reason, message = self.show_manager.exit_all_shows()

        elif show_command == 'shutdownnow':
            # need root.after to get out of st thread
            self.root.after(1, self.e_shutdown_pressed)
            return
        else:
            reason = 'error'
            message = 'command not recognised: ' + show_command

        if reason == 'error':
            self.mon.err(self, message)
        return

    def e_all_shows_ended_callback(self):
        self.all_shows_ended_callback('normal', 'no shows running')

    def e_shutdown_pressed(self):
        self.shutdown_pressed('now')

    def e_osc_handle_output_event(self, line):
        #jump  out of server thread
        self.root.after(1, lambda arg=line: self.osc_handle_output_event(arg))

    def osc_handle_output_event(self, line):
        self.mon.log(self, "output event received: " + line)
        #osc sends output events as a string
        reason, message, delay, name, param_type, param_values = self.animate.parse_animate_fields(
            line)
        if reason == 'error':
            self.mon.err(self, message)
            self.end(reason, message)
        self.handle_output_event(name, param_type, param_values, 0)

    def handle_output_event(self, symbol, param_type, param_values, req_time):
        if self.gpio_enabled is True:
            reason, message = self.gpiodriver.handle_output_event(
                symbol, param_type, param_values, req_time)
            if reason == 'error':
                self.mon.err(self, message)
                self.end(reason, message)
        else:
            self.mon.warn(self, 'GPIO not enabled')

    # all input events call this callback with a symbolic name.
    # handle events that affect PP overall, otherwise pass to all active shows
    def handle_input_event(self, symbol, source):
        self.mon.log(self, "event received: " + symbol + ' from ' + source)
        if symbol == 'pp-terminate':
            self.handle_user_abort()

        elif symbol == 'pp-shutdown':
            self.shutdown_pressed('delay')

        elif symbol == 'pp-shutdownnow':
            # need root.after to grt out of st thread
            self.root.after(1, self.e_shutdown_pressed)
            return

        elif symbol == 'pp-exitpipresents':
            self.exitpipresents_required = True
            if self.show_manager.all_shows_exited() is True:
                # need root.after to grt out of st thread
                self.root.after(1, self.e_all_shows_ended_callback)
                return
            reason, message = self.show_manager.exit_all_shows()
        else:
            # events for shows affect the show and could cause it to exit.
            for show in self.show_manager.shows:
                show_obj = show[ShowManager.SHOW_OBJ]
                if show_obj is not None:
                    show_obj.handle_input_event(symbol)

    def shutdown_pressed(self, when):
        if when == 'delay':
            self.root.after(5000, self.on_shutdown_delay)
        else:
            self.shutdown_required = True
            if self.show_manager.all_shows_exited() is True:
                self.all_shows_ended_callback('normal', 'no shows running')
            else:
                # calls exit method of all shows, results in all_shows_closed_callback
                self.show_manager.exit_all_shows()

    def on_shutdown_delay(self):
        # 5 second delay is up, if shutdown button still pressed then shutdown
        if self.gpiodriver.shutdown_pressed() is True:
            self.shutdown_required = True
            if self.show_manager.all_shows_exited() is True:
                self.all_shows_ended_callback('normal', 'no shows running')
            else:
                # calls exit method of all shows, results in all_shows_closed_callback
                self.show_manager.exit_all_shows()

    def handle_sigterm(self, signum, frame):
        self.mon.log(self, 'SIGTERM received - ' + str(signum))
        self.terminate()

    def handle_user_abort(self):
        self.mon.log(self, 'User abort received')
        self.terminate()

    def terminate(self):
        self.mon.log(self, "terminate received")
        needs_termination = False
        for show in self.show_manager.shows:
            # print  show[ShowManager.SHOW_OBJ], show[ShowManager.SHOW_REF]
            if show[ShowManager.SHOW_OBJ] is not None:
                needs_termination = True
                self.mon.log(
                    self,
                    "Sent terminate to show " + show[ShowManager.SHOW_REF])
                # call shows terminate method
                # eventually the show will exit and after all shows have exited all_shows_callback will be executed.
                show[ShowManager.SHOW_OBJ].terminate()
        if needs_termination is False:
            self.end('killed', 'killed - no termination of shows required')


# ******************************
# Ending Pi Presents after all the showers and players are closed
# **************************

# callback from ShowManager when all shows have ended

    def all_shows_ended_callback(self, reason, message):
        self.canvas.config(bg=self.pp_background)
        if reason in (
                'killed', 'error'
        ) or self.shutdown_required is True or self.exitpipresents_required is True:
            self.end(reason, message)

    def end(self, reason, message):
        self.mon.log(self, "Pi Presents ending with reason: " + reason)
        if self.root is not None:
            self.root.destroy()
        self.tidy_up()
        # gc.collect()
        # print gc.garbage
        if reason == 'killed':
            self.mon.log(self, "Pi Presents Aborted, au revoir")
            # close logging files
            self.mon.finish()
            sys.exit(101)
        elif reason == 'error':
            self.mon.log(self, "Pi Presents closing because of error, sorry")
            # close logging files
            self.mon.finish()
            sys.exit(102)
        else:
            self.mon.log(self, "Pi Presents  exiting normally, bye")
            # close logging files
            self.mon.finish()
            if self.shutdown_required is True:
                # print 'SHUTDOWN'
                call(['sudo', 'shutdown', '-h', '-t 5', 'now'])
                sys.exit(100)
            else:
                sys.exit(100)

    # tidy up all the peripheral bits of Pi Presents
    def tidy_up(self):
        self.mon.log(self, "Tidying Up")
        # turn screen blanking back on
        if self.options['noblank'] is True:
            call(["xset", "s", "on"])
            call(["xset", "s", "+dpms"])

        # tidy up animation and gpio
        if self.animate is not None:
            self.animate.terminate()

        if self.gpio_enabled == True:
            self.gpiodriver.terminate()

        if self.osc_enabled is True:
            self.oscdriver.terminate()

        # tidy up time of day scheduler
        if self.tod_enabled is True:
            self.tod.terminate()
Example #41
0
class TutorWindow( Toplevel ):
    """
    Window for displaying a basic help
    """
    labels      = {}            # Dictionary for keeping clickable labels
    size_x      = 600           # horizontal size of canvas
    size_y      = 800           # vertical size of canvas
    last_images = []            # handle on images currently on the canvas
    images      = []            # new images to go on the canvas
    curr_key    = None          # Current key that is looked at
    
    # Names of label links and list of pictures to load. These pictures are generated from a pdf by save as, type .png
    help_dict = { "Get Pictures"    : [ "Get_Pictures_Page_1.png" , "Get_Pictures_Page_2.png" , "Get_Pictures_Page_3.png"  ],
                  "Save Pictures"   : [ "Save_Pictures_Page_1.png", "Save_Pictures_Page_2.png", "Save_Pictures_Page_3.png" ],
                  "Pictures Effects": [ "Pic_Effects_Page_1.png"  , "Pic_Effects_Page_2.png"                               ],
                  "Options"         : [ "Options.png"                                                                      ],
                }

    def __init__( self ):
        """
        Initialize window settings
        """
        
        Toplevel.__init__( self )
        self.title( "Tutorial" )
        self.iconbitmap( ICON_FILENAME )
        self.geometry( "+100+50" )
        
        # init frames for window. This window contains complicated frames. i.e. frames with frames inside them.
        fr11 = Frame( self )
        fr1  = Frame( fr11 )
        fr2  = Frame( fr11 )
        fr3  = Frame( self )
        
        # create labels links for displaying different help information
        for name in self.help_dict:
            self.labels[ name ] = Label( fr1, text=name, fg="blue" ) 
            self.labels[ name ].bind( "<ButtonPress-1>", lambda e, arg=name: self.HandleLB( e, arg ) )
            self.labels[ name ].pack( fill=X )
        fr1.pack( side=LEFT )
        
        # create/configure canvas and scrollbar for displaying help pictures
        self.canv = Canvas( fr2, width=self.size_x, height=self.size_y, scrollregion=( 0, 0, 300, 0 ) )
        self.sbar = Scrollbar( fr2 )
        self.sbar.config( command=self.canv.yview )
        self.canv.config( yscrollcommand=self.sbar.set )
        self.canv.focus_set()
        self.sbar.pack( side=RIGHT, fill=Y )
        self.canv.pack( side=LEFT, fill=Y )

        fr2.pack( side=LEFT )
        fr11.pack()
    
        # create ok button for closing the window
        btn = Button( fr3, text="Ok", width=10, command=self.quit )
        btn.pack( side=LEFT )
        fr3.pack()
        
        self.mainloop()
        self.destroy()
        
    def HandleLB( self, event, key ):
        """
        handle clicking a label link
        """
        
        if( key != self.curr_key ):
        
        
            # reset the position of the scrollbar to the top
            self.canv.yview_moveto( 0.0 )

            # load new images
            print "Key: ", key
            self.LoadImages( key )
            
            # change formatting on labels, color red for current one clicked
            self.FormatLabels( key )
            
            # remove old pictures from the canvas before adding new ones
            if( len( self.last_images ) != 0 ):
                for image in self.last_images:
                    self.canv.delete( image )
            self.last_images = []
    
            # There's an offset required in order to show everything correctly, don't know why...
            image_y = 390
    
            # change scrollable area for the canvas to be exact size of all pictures
            self.canv.config( scrollregion=( 0, 0, 300, 776*len( self.images ) ) )
            
            # add new pictures to canvas stacking them on top of each other and making them seamless
            for i in range( len( self.images ) ):
                self.last_images.append( self.canv.create_image( ( self.size_x/2, image_y ), image=self.images[ i ] ) )
                image_y += self.images[ i ].height()
                
            self.curr_key = key
            
    def LoadImages( self, key ):
        """
        load new inmages into class storage
        """
        self.images = []
        print "help_dict: ", self.help_dict        
        # get images from hardcoded array
        for image in self.help_dict[ key ]:
            
            # open PIL image
            print "image: ", path.join( HELP_DIR, image )

            image1 = PILopen( path.join( HELP_DIR, image ) )
    
            # resize to fit canvas area
            image1 = image1.resize( ( self.size_x , self.size_y ), ANTIALIAS )
            
            # make into a tkimage
            im = PhotoImage( image1 )
             
            # add to list of images to display 
            self.images.append( im )
    
    def FormatLabels( self, key ):
        for name in self.labels:
            self.labels[ name ].config( fg="blue" )
            
        self.labels[ key ].config( fg="red" )
Example #42
0
class DrawDigit(object):

	def __init__(self, digitsData):
		self.digitsData = digitsData
		self.checkingDigit = False

		self.master = Tk()
		self.master.title("Draw Digit")
		self.master.config(bg='grey',width=canvasWidth*2, height=625,padx=50,pady=50)

		self.isClicking = False
		self.currentX = -1
		self.currentY = -1

		self.canvas = Canvas(self.master, width=canvasWidth, height=canvasHeight)
		self.canvas.config(bg='white')
		self.canvas.pack()

		self.recognizeButton = Button(self.master, text="Recognize", command=self.recognize)
		self.recognizeButton.pack()

		self.clearButton = Button(self.master, text="Clear", command=self.clearCanvas)
		self.clearButton.pack()

		self.rightButton = Button(self.master, text="Right!", command=self.digitRecognized)
		self.rightButton.pack_forget()

		self.wrongButton = Button(self.master, text="Wrong!", command=self.digitNotRecognized)
		self.wrongButton.pack_forget()

		self.retryButton = Button(self.master, text="Retry!", command=self.resetGUI)
		self.retryButton.pack_forget()

		self.master.bind('<Button-1>', self.mousePress)
		self.master.bind('<B1-Motion>', self.mouseMove)
		self.master.bind('<ButtonRelease-1>', self.mouseRelease) 

		self.image = Image.new("L",(canvasWidth,canvasHeight))
		self.draw = ImageDraw.Draw(self.image)

		return


	def mousePress(self, event):
		if not self.isClicking and not self.checkingDigit:
			self.currentX = event.x
			self.currentY = event.y
			self.isClicking = True
		return

	def mouseMove(self, event):
		if self.isClicking and not self.checkingDigit:
			self.draw.line([(self.currentX,self.currentY),(event.x,event.y)],(0,0,0),width=5)
			self.canvas.create_line(self.currentX, self.currentY, event.x, event.y, width=5.0)
			self.currentX = event.x
			self.currentY = event.y
		return

	def mouseRelease(self, event):
		self.isClicking = False
		return

	def clearCanvas(self):
		self.canvas.delete('all')
		self.image = Image.new("L",(canvasWidth,canvasHeight))
		self.draw = ImageDraw.Draw(self.image)
		return

	def recognize(self):
		if len(self.canvas.find_all()) != 0:
			self.checkingDigit = True

			self.originalImage = ImageOps.invert(self.image)
			print "***************************************************"
			print 'Recognizing the digit...'

			featureVector = ocr_machine_learning.getVector(self.originalImage, self.digitsData)
			print 'The feature vector for the image is: {0}'.format(featureVector)

			finalDigit = ocr_machine_learning.recognizeDigit(featureVector)
			print 'The digit in the image is:'
			print digitASCII.digits[finalDigit]

			self.checkCorrectDigitGUI(finalDigit)

		return

	def startGUI(self):
		print 'Please draw the digit in the white square of the GUI window...'
		self.master.mainloop()
		return

	def checkCorrectDigitGUI(self, finalDigit):

		self.finalDigit = finalDigit

		self.recognizeButton.pack_forget()
		self.clearButton.pack_forget()
		self.rightButton.pack()
		self.wrongButton.pack()
		self.retryButton.pack()
		
		self.master.update()

		return

	def digitRecognized(self):
		ocr_utils.saveImageToCorrectDigitFolder(self.originalImage, self.finalDigit)
		self.resetGUI()
		return

	def digitNotRecognized(self):
		ocr_utils.guessedWrong(self.originalImage)
		self.resetGUI()
		return

	def resetGUI(self):
		self.clearCanvas()

		self.rightButton.pack_forget()
		self.wrongButton.pack_forget()
		self.retryButton.pack_forget()
		self.canvas.pack()
		self.recognizeButton.pack()
		self.clearButton.pack()

		self.checkingDigit = False
		print "***************************************************"
		print "Please draw another digit..."

		self.master.update()
		return
Example #43
0
                        </Persistence>
                    </ServiceProfile>
                    <ServiceProfile>
                        <IsEnabled>false</IsEnabled>
                        <Protocol>TCP</Protocol>
                        <Port/>
                        <Persistence>
                            <Method/>
                        </Persistence>
                    </ServiceProfile>
                    <Logging>true</Logging>
                    <Pool>DCTM-UKHTTPD</Pool>
                </VirtualServer>
            </LoadBalancerService>
        </EdgeGatewayServiceConfiguration>
        <HaEnabled>true</HaEnabled>
        <UseDefaultRouteForDnsRelay>false</UseDefaultRouteForDnsRelay>
    </Configuration>
</EdgeGateway>
    '''
    root = Tk()
    canvas = Canvas(root)
    canvas.config(bg='white')
    canvas.pack()
    dom = parseString(example_data)
    item = DomTreeItem(dom.documentElement)
    node = TreeNode(canvas, None, item)
    node.update()
    node.expand()
    root.mainloop()
    def IsExpandable(self):
        node = self.node
        return node.hasChildNodes()

    def GetSubList(self):
        parent = self.node
        children = parent.childNodes
        prelist = [DomTreeItem(node) for node in children]
        itemlist = [item for item in prelist if item.GetText().strip()]
        return itemlist


data = '''
<Computer>
  <Local_Devices>
  </Local_Devices>
</Computer>
'''

root = Tk()
canvas = Canvas(root)
canvas.config(bg='white')
canvas.pack()
dom = parseString(data)
item = DomTreeItem(dom.documentElement)
node = TreeNode(canvas, None, item)
node.update()
node.expand()
root.mainloop()
Example #45
0
class PhraseEditor(HasTraits):
    """A graphical editor for musical phrases."""

    phrase = Instance(Phrase)
    """The phrase which is edited."""

    selected_point = Instance(Point)
    """The point that is currently moved around."""

    use_grid = Bool
    """Whether added points shall be snapped to a grid."""

    grid_resolution = Range(2,64, 16)
    """The resolution of the grid."""

    point_handle_size = Int(4)
    """The size of the handles used to move points around."""

    def __init__(self, toplevel, phrase, **kwargs):
        """
        Initializes a PhraseEditor.

        @param toplevel: the Tk Toplevel window
        @param phrase: the phrase to be edited
        """

        # The Tk Toplevel object to which the editor will be attached 
        self.toplevel = toplevel

        control_frame = Frame(self.toplevel)
        control_frame.pack(side=TOP)

        title_frame = Frame(control_frame, padx=8)
        title_frame.pack(side=LEFT)

        Label(title_frame, text="Title").pack(side=LEFT)

        self.title_entry_manager = EntryManager(
            title_frame, self, 'phrase.name'
        )
        self.title_entry_manager.entry.pack(side=LEFT)

        grid_frame = Frame(control_frame, padx=8)
        grid_frame.pack(side=LEFT)

        self.grid_checkbutton_manager = CheckbuttonManager(
            grid_frame, self, 'use_grid', text="Grid"
        )
        self.grid_checkbutton_manager.checkbutton.pack(side=LEFT)

        Label(grid_frame, text="Resolution").pack(side=LEFT)

        self.grid_resolution_spinbox_manager = SpinboxManager(
            grid_frame, self, 'grid_resolution',
        )
        self.grid_resolution_spinbox_manager.spinbox.pack(side=LEFT)

        steps_frame = Frame(control_frame, padx=8)
        steps_frame.pack(side=LEFT)

        Label(steps_frame, text="Steps").pack(side=LEFT)

        self.steps_spinbox_manager = SpinboxManager(
            steps_frame, self, 'phrase.steps',
        )
        self.steps_spinbox_manager.spinbox.pack(side=LEFT)

        transpose_frame = Frame(control_frame, padx=8)
        transpose_frame.pack(side=LEFT)

        Label(transpose_frame, text="Transpose").pack(side=LEFT)

        self.transpose_spinbox_manager = SpinboxManager(
            transpose_frame, self, 'phrase.transpose',
        )
        self.transpose_spinbox_manager.spinbox.pack(side=LEFT)

        self.v_point_type = StringVar()
        self.v_point_type.set('Note')

        OptionMenu(
            control_frame, self.v_point_type, 'Note', 'Rest',
        ).pack(side=LEFT)

        self.canvas = Canvas(self.toplevel, width=600, height=400)
        self.canvas.pack(side=BOTTOM)

        # Maps a Point to the ID of its handle, which is a rectangle on the
        # canvas. 
        self._point_handles = {}

        # Maps a tuple of two Points to the ID of the line connecting them on
        # the canvas.
        self._point_lines = {}

        # Maps a Point to the line to its next Point that is currently played.
        self._playing_lines = {}

        # A set of dotted lines marking the grid on the canvas.
        self._grid_lines = set()

        super(PhraseEditor, self).__init__(
            phrase=phrase, use_grid=True, **kwargs
        )

        def find_point(x,y):
            """
            @return: the point at the specified position on the canvas.
            """
            s = self.point_handle_size
            for point in self.phrase.points:
                px,py = point.pos
                if px-s <= x <= px+s and py-s <= y <= py+s:
                    return point
            return None

        def snap_to_grid(x,y):
            """
            Rounds the given coordinates to the grid defined by
            L{PhraseEditor.grid_resolution}.
            """
            res = self.grid_resolution
            return round(x/float(res))*res, round(y/float(res))*res

        def button_pressed(event):
            """
            When the left mouse button is pressed over a point, it becomes the
            L{PhraseEditor.selected_point}, which can be moved around by
            L{button_motion()}.

            If there is no point under the mouse pointer, a new point is
            appended to the L{Phrase}.
            """
            x = self.canvas.canvasx(event.x)
            y = self.canvas.canvasy(event.y)
            point = find_point(x,y)
            if point is None:
                if self.use_grid:
                    x,y = snap_to_grid(x,y)
                point = Point(
                    pos=(int(x),int(y)),
                    type=self.v_point_type.get(),
                )
                self.phrase.points.append(point)
            self.selected_point = point
        self.canvas.bind('<Button-1>', button_pressed)

        def button_motion(event):
            """
            If the mouse is moved while the left or miffle mouse button is held
            down and a point is selected, this point is moved to the current
            mouse pointer position.
            """
            if self.selected_point is None:
                return
            x = self.canvas.canvasx(event.x)
            y = self.canvas.canvasy(event.y)
            if self.use_grid:
                x,y = snap_to_grid(x,y)
            canvas_config = self.canvas.config()
            canvas_width = int(canvas_config['width'][-1])
            canvas_height = int(canvas_config['height'][-1])
            self.selected_point.pos = (
                min(canvas_width, max(0, int(x))),
                min(canvas_height, max(0, int(y)))
            )
        self.canvas.bind('<B1-Motion>', button_motion)
        self.canvas.bind('<B2-Motion>', button_motion)

        def button_released(event):
            """
            When releasing the left or middle mouse button, the currently
            selected point is deselected.
            """
            self.selected_point = None
        self.canvas.bind('<ButtonRelease-1>', button_released)
        self.canvas.bind('<ButtonRelease-2>', button_released)

        def right_button_pressed(event):
            """
            Pressing the right mouse button over a point removes it from the
            L{Phrase}.
            """
            x = self.canvas.canvasx(event.x)
            y = self.canvas.canvasy(event.y)
            point = find_point(x,y)
            if point is not None:
                self.phrase.points.remove(point)
        self.canvas.bind('<Button-3>', right_button_pressed)

        def middle_button_pressed(event):
            if self.selected_point is not None:
                return
            x = self.canvas.canvasx(event.x)
            y = self.canvas.canvasy(event.y)
            point = find_point(x,y)
            if point is None:
                return
            new_point = Point(pos=point.pos, type=self.v_point_type.get())
            self.phrase.points.insert(
                self.phrase.points.index(point)+1,
                new_point
            )
            self.selected_point = new_point
        self.canvas.bind('<Button-2>', middle_button_pressed)

    def close(self):
        """
        Closes the editor, destroying its Toplevel window.
        """
        #del self.phrase
        #del self.selected_point
        #del self._point_handles
        #del self._point_lines
        #del self._playing_lines
        self.toplevel.destroy()

    def _add_point_handle(self, point):
        """
        Adds a point handle for the given point to the canvas.
        """
        s = self.point_handle_size
        px, py = point.pos
        self._point_handles[point] = self.canvas.create_rectangle(
            px-s,py-s, px+s,py+s,
        )

    def _remove_point_handle(self, point):
        """
        Removes the point handle for the given point.
        """
        self.canvas.delete(self._point_handles[point])
        del self._point_handles[point]

    def _add_point_line(self, point1, point2):
        """
        Adds a line between two points on the canvas.
        """
        px1, py1 = point1.pos
        px2, py2 = point2.pos
        self._point_lines[
            (point1, point2)
        ] = self.canvas.create_line(
            px1,py1, px2,py2,
            dash=[2,2] if point2.type == 'Rest' else None
        )

    def _remove_point_line(self, point1, point2):
        """
        Removes the line between two given points.
        """
        px1, py1 = point1.pos
        px2, py2 = point2.pos
        self.canvas.delete(self._point_lines[(point1, point2)])
        del self._point_lines[(point1, point2)]

    def _remove_point_lines(self):
        for points, line in self._point_lines.iteritems():
            self.canvas.delete(line)
        self._point_lines = {}

    def _remove_point_handles(self):
        for point, handle in self._point_handles.iteritems():
            self.canvas.delete(handle)
        self._point_handles = {}

    @on_trait_change('phrase, phrase:points')
    def _points_changed(self, obj, name, old, new):
        if self.phrase is None:
            return
        self._remove_point_handles()
        self._remove_point_lines()
        points = self.phrase.points
        for i, point in enumerate(points):
            self._add_point_handle(point)
            if i > 0:
                self._add_point_line(points[i-1], point)

    @on_trait_change('phrase:points:pos')
    def _point_pos_changed(self, point, name, old, new):
        """
        When a point's position changes, its handle and lines to its
        surrounding points are redefined.
        """
        self._remove_point_handle(point)
        self._add_point_handle(point)
        points = self.phrase.points
        assert point in points
        i = points.index(point)
        if i > 0:
            source_point = points[i-1]
            self._remove_point_line(source_point, point)
            self._add_point_line(source_point, point)
        if i < len(points)-1:
            target_point = points[i+1]
            self._remove_point_line(point, target_point)
            self._add_point_line(point, target_point)

    @on_trait_change('phrase.name')
    def _phrase_name_changed(self):
        """
        When the name of the phrase changes, the window title is update.
        """
        if self.phrase is None:
            return
        self.toplevel.title("Phrase: %s" % self.phrase.name)

    def add_playing_point(self, point, color):
        if point in self._playing_lines:
            self.remove_playing_point(point, color)
        if point not in self.phrase.points:
            return
        px,py, px2,py2 = self.phrase.get_line(point)
        self._playing_lines[point] = self.canvas.create_line(
            px,py, px2,py2, fill=color, width=2.0,
            dash=[2,2] if point.type == 'Rest' else None
        )

    def remove_playing_point(self, point, color):
        if point not in self._playing_lines:
            return
        self.canvas.delete(self._playing_lines[point])
        del self._playing_lines[point]

    @on_trait_change('use_grid, grid_resolution')
    def _grid_changed(self):
        """
        Draws a grid if L{PhraseEditor.use_grid} is True, otherwise removes it.
        """
        for rect in self._grid_lines:
            self.canvas.delete(rect)
        self._grid_lines.clear()
        if self.use_grid:
            config = self.canvas.config()
            w = int(config['width'][-1])
            h = int(config['height'][-1])
            res = self.grid_resolution
            for y in range(0, h, res):
                self._grid_lines.add(self.canvas.create_line(
                    0,y, w,y, dash=[1,res-1], fill="#666666"
                ))
Example #46
-1
class PiPresents(object):

    def pipresents_version(self):
        vitems=self.pipresents_issue.split('.')
        if len(vitems)==2:
            # cope with 2 digit version numbers before 1.3.2
            return 1000*int(vitems[0])+100*int(vitems[1])
        else:
            return 1000*int(vitems[0])+100*int(vitems[1])+int(vitems[2])


    def __init__(self):
        # gc.set_debug(gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_INSTANCES|gc.DEBUG_OBJECTS|gc.DEBUG_SAVEALL)
        gc.set_debug(gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_SAVEALL)
        self.pipresents_issue="1.3.5"
        self.pipresents_minorissue = '1.3.5d'
        # position and size of window without -f command line option
        self.nonfull_window_width = 0.45 # proportion of width
        self.nonfull_window_height= 0.7 # proportion of height
        self.nonfull_window_x = 0 # position of top left corner
        self.nonfull_window_y=0   # position of top left corner


        StopWatch.global_enable=False

        # set up the handler for SIGTERM
        signal.signal(signal.SIGTERM,self.handle_sigterm)
        

# ****************************************
# Initialisation
# ***************************************
        # get command line options
        self.options=command_options()

        # get Pi Presents code directory
        pp_dir=sys.path[0]
        self.pp_dir=pp_dir
        
        if not os.path.exists(pp_dir+"/pipresents.py"):
            if self.options['manager']  is False:
                tkMessageBox.showwarning("Pi Presents","Bad Application Directory")
            exit(102)

        
        # Initialise logging and tracing
        Monitor.log_path=pp_dir
        self.mon=Monitor()
        # Init in PiPresents only
        self.mon.init()

        # uncomment to enable control of logging from within a class
        # Monitor.enable_in_code = True # enables control of log level in the code for a class  - self.mon.set_log_level()

        
        # make a shorter list to log/trace only some classes without using enable_in_code.
        Monitor.classes  = ['PiPresents',
                            
                            'HyperlinkShow','RadioButtonShow','ArtLiveShow','ArtMediaShow','MediaShow','LiveShow','MenuShow',
                            'GapShow','Show','ArtShow',
                            'AudioPlayer','BrowserPlayer','ImagePlayer','MenuPlayer','MessagePlayer','VideoPlayer','Player',
                            'MediaList','LiveList','ShowList',
                            'PathManager','ControlsManager','ShowManager','PluginManager','IOPluginManager',
                            'MplayerDriver','OMXDriver','UZBLDriver',
                            'TimeOfDay','ScreenDriver','Animate','OSCDriver','CounterManager',
                            'Network','Mailer'
                            ]
        

        # Monitor.classes=['PiPresents','MediaShow','GapShow','Show','VideoPlayer','Player','OMXDriver']
        # Monitor.classes=['OSCDriver']
        
        # get global log level from command line
        Monitor.log_level = int(self.options['debug'])
        Monitor.manager = self.options['manager']
        # print self.options['manager']
        self.mon.newline(3)
        self.mon.sched (self,None, "Pi Presents is starting, Version:"+self.pipresents_minorissue + ' at '+time.strftime("%Y-%m-%d %H:%M.%S"))
        self.mon.log (self, "Pi Presents is starting, Version:"+self.pipresents_minorissue+ ' at '+time.strftime("%Y-%m-%d %H:%M.%S"))
        # self.mon.log (self," OS and separator:" + os.name +'  ' + os.sep)
        self.mon.log(self,"sys.path[0] -  location of code: "+sys.path[0])

        # log versions of Raspbian and omxplayer, and GPU Memory
        with open("/boot/issue.txt") as ifile:
            self.mon.log(self,'\nRaspbian: '+ifile.read())

        self.mon.log(self,'\n'+check_output(["omxplayer", "-v"]))
        self.mon.log(self,'\nGPU Memory: '+check_output(["vcgencmd", "get_mem", "gpu"]))

        if os.geteuid() == 0:
            print 'Do not run Pi Presents with sudo'
            self.mon.log(self,'Do not run Pi Presents with sudo')
            self.mon.finish()
            sys.exit(102)

        
        if "DESKTOP_SESSION" not in os.environ:
            print 'Pi Presents must be run from the Desktop'
            self.mon.log(self,'Pi Presents must be run from the Desktop')
            self.mon.finish()
            sys.exit(102)
        else:
            self.mon.log(self,'Desktop is '+ os.environ['DESKTOP_SESSION'])
        
        # optional other classes used
        self.root=None
        self.ppio=None
        self.tod=None
        self.animate=None
        self.ioplugin_manager=None
        self.oscdriver=None
        self.osc_enabled=False
        self.tod_enabled=False
        self.email_enabled=False
        
        user=os.getenv('USER')

        if user is None:
            tkMessageBox.showwarning("You must be logged in to run Pi Presents")
            exit(102)

        if user !='pi':
            self.mon.warn(self,"You must be logged as pi to use GPIO")

        self.mon.log(self,'User is: '+ user)
        # self.mon.log(self,"os.getenv('HOME') -  user home directory (not used): " + os.getenv('HOME')) # does not work
        # self.mon.log(self,"os.path.expanduser('~') -  user home directory: " + os.path.expanduser('~'))   # does not work



        # check network is available
        self.network_connected=False
        self.network_details=False
        self.interface=''
        self.ip=''
        self.unit=''
        
        # sets self.network_connected and self.network_details
        self.init_network()

        
        # start the mailer and send email when PP starts
        self.email_enabled=False
        if self.network_connected is True:
            self.init_mailer()
            if self.email_enabled is True and self.mailer.email_at_start is True:
                subject= '[Pi Presents] ' + self.unit + ': PP Started on ' + time.strftime("%Y-%m-%d %H:%M")
                message = time.strftime("%Y-%m-%d %H:%M") + '\nUnit: ' + self.unit + '   Profile: '+ self.options['profile']+ '\n ' + self.interface + '\n ' + self.ip 
                self.send_email('start',subject,message) 

         
        # get profile path from -p option
        if self.options['profile'] != '':
            self.pp_profile_path="/pp_profiles/"+self.options['profile']
        else:
            self.mon.err(self,"Profile not specified in command ")
            self.end('error','Profile not specified with the commands -p option')
        
       # get directory containing pp_home from the command,
        if self.options['home']  == "":
            home = os.sep+ 'home' + os.sep + user + os.sep+"pp_home"
        else:
            home = self.options['home'] + os.sep+ "pp_home"         
        self.mon.log(self,"pp_home directory is: " + home)


        # check if pp_home exists.
        # try for 10 seconds to allow usb stick to automount
        found=False
        for i in range (1, 10):
            self.mon.log(self,"Trying pp_home at: " + home +  " (" + str(i)+')')
            if os.path.exists(home):
                found=True
                self.pp_home=home
                break
            time.sleep (1)
        if found is True:
            self.mon.log(self,"Found Requested Home Directory, using pp_home at: " + home)
        else:
            self.mon.err(self,"Failed to find pp_home directory at " + home)
            self.end('error',"Failed to find pp_home directory at " + home)


        # check profile exists
        self.pp_profile=self.pp_home+self.pp_profile_path
        if os.path.exists(self.pp_profile):
            self.mon.sched(self,None,"Running profile: " + self.pp_profile_path)
            self.mon.log(self,"Found Requested profile - pp_profile directory is: " + self.pp_profile)
        else:
            self.mon.err(self,"Failed to find requested profile: "+ self.pp_profile)
            self.end('error',"Failed to find requested profile: "+ self.pp_profile)

        self.mon.start_stats(self.options['profile'])
        
        if self.options['verify'] is True:
            self.mon.err(self,"Validation option not supported - use the editor")
            self.end('error','Validation option not supported - use the editor')

         
        # initialise and read the showlist in the profile
        self.showlist=ShowList()
        self.showlist_file= self.pp_profile+ "/pp_showlist.json"
        if os.path.exists(self.showlist_file):
            self.showlist.open_json(self.showlist_file)
        else:
            self.mon.err(self,"showlist not found at "+self.showlist_file)
            self.end('error',"showlist not found at "+self.showlist_file)

        # check profile and Pi Presents issues are compatible
        if self.showlist.profile_version() != self.pipresents_version():
            self.mon.err(self,"Version of showlist " + self.showlist.profile_version_string + " is not  same as Pi Presents")
            self.end('error',"Version of showlist " + self.showlist.profile_version_string + " is not  same as Pi Presents")


        # get the 'start' show from the showlist
        index = self.showlist.index_of_start_show()
        if index >=0:
            self.showlist.select(index)
            self.starter_show=self.showlist.selected_show()
        else:
            self.mon.err(self,"Show [start] not found in showlist")
            self.end('error',"Show [start] not found in showlist")


# ********************
# SET UP THE GUI
# ********************
        # turn off the screenblanking and saver
        if self.options['noblank'] is True:
            call(["xset","s", "off"])
            call(["xset","s", "-dpms"])

        self.root=Tk()   
       
        self.title='Pi Presents - '+ self.pp_profile
        self.icon_text= 'Pi Presents'
        self.root.title(self.title)
        self.root.iconname(self.icon_text)
        self.root.config(bg=self.starter_show['background-colour'])

        self.mon.log(self, 'monitor screen dimensions are ' + str(self.root.winfo_screenwidth()) + ' x ' + str(self.root.winfo_screenheight()) + ' pixels')
        if self.options['screensize'] =='':        
            self.screen_width = self.root.winfo_screenwidth()
            self.screen_height = self.root.winfo_screenheight()
        else:
            reason,message,self.screen_width,self.screen_height=self.parse_screen(self.options['screensize'])
            if reason =='error':
                self.mon.err(self,message)
                self.end('error',message)

        self.mon.log(self, 'forced screen dimensions (--screensize) are ' + str(self.screen_width) + ' x ' + str(self.screen_height) + ' pixels')
       
        # set window dimensions and decorations
        if self.options['fullscreen'] is False:
            self.window_width=int(self.root.winfo_screenwidth()*self.nonfull_window_width)
            self.window_height=int(self.root.winfo_screenheight()*self.nonfull_window_height)
            self.window_x=self.nonfull_window_x
            self.window_y=self.nonfull_window_y
            self.root.geometry("%dx%d%+d%+d" % (self.window_width,self.window_height,self.window_x,self.window_y))
        else:
            self.window_width=self.screen_width
            self.window_height=self.screen_height
            self.root.attributes('-fullscreen', True)
            os.system('unclutter &')
            self.window_x=0
            self.window_y=0  
            self.root.geometry("%dx%d%+d%+d"  % (self.window_width,self.window_height,self.window_x,self.window_y))
            self.root.attributes('-zoomed','1')

        # canvas cover the whole screen whatever the size of the window. 
        self.canvas_height=self.screen_height
        self.canvas_width=self.screen_width
  
        # make sure focus is set.
        self.root.focus_set()

        # define response to main window closing.
        self.root.protocol ("WM_DELETE_WINDOW", self.handle_user_abort)

        # setup a canvas onto which will be drawn the images or text
        self.canvas = Canvas(self.root, bg=self.starter_show['background-colour'])


        if self.options['fullscreen'] is True:
            self.canvas.config(height=self.canvas_height,
                               width=self.canvas_width,
                               highlightthickness=0)
        else:
            self.canvas.config(height=self.canvas_height,
                    width=self.canvas_width,
                        highlightthickness=1,
                               highlightcolor='yellow')
            
        self.canvas.place(x=0,y=0)
        # self.canvas.config(bg='black')
        self.canvas.focus_set()


                
# ****************************************
# INITIALISE THE TOUCHSCREEN DRIVER
# ****************************************

        # each driver takes a set of inputs, binds them to symboic names
        # and sets up a callback which returns the symbolic name when an input event occurs

        self.sr=ScreenDriver()
        # read the screen click area config file
        reason,message = self.sr.read(pp_dir,self.pp_home,self.pp_profile)
        if reason == 'error':
            self.end('error','cannot find, or error in screen.cfg')


        # create click areas on the canvas, must be polygon as outline rectangles are not filled as far as find_closest goes
        # click areas are made on the Pi Presents canvas not the show canvases.
        reason,message = self.sr.make_click_areas(self.canvas,self.handle_input_event)
        if reason == 'error':
            self.mon.err(self,message)
            self.end('error',message)


# ****************************************
# INITIALISE THE APPLICATION AND START
# ****************************************
        self.shutdown_required=False
        self.reboot_required=False
        self.terminate_required=False
        self.exitpipresents_required=False

        # initialise the I/O plugins by importing their drivers
        self.ioplugin_manager=IOPluginManager()
        reason,message=self.ioplugin_manager.init(self.pp_dir,self.pp_profile,self.root,self.handle_input_event)
        if reason == 'error':
            # self.mon.err(self,message)
            self.end('error',message)

        
        # kick off animation sequencer
        self.animate = Animate()
        self.animate.init(pp_dir,self.pp_home,self.pp_profile,self.canvas,200,self.handle_output_event)
        self.animate.poll()

        #create a showmanager ready for time of day scheduler and osc server
        show_id=-1
        self.show_manager=ShowManager(show_id,self.showlist,self.starter_show,self.root,self.canvas,self.pp_dir,self.pp_profile,self.pp_home)
        # first time through set callback to terminate Pi Presents if all shows have ended.
        self.show_manager.init(self.canvas,self.all_shows_ended_callback,self.handle_command,self.showlist)
        # Register all the shows in the showlist
        reason,message=self.show_manager.register_shows()
        if reason == 'error':
            self.mon.err(self,message)
            self.end('error',message)


        # Init OSCDriver, read config and start OSC server
        self.osc_enabled=False
        if self.network_connected is True:
            if os.path.exists(self.pp_profile + os.sep + 'pp_io_config'+ os.sep + 'osc.cfg'):
                self.oscdriver=OSCDriver()
                reason,message=self.oscdriver.init(self.pp_profile,
                                                   self.unit,self.interface,self.ip,
                                                   self.handle_command,self.handle_input_event,self.e_osc_handle_animate)
                if reason == 'error':
                    self.mon.err(self,message)
                    self.end('error',message)
                else:
                    self.osc_enabled=True
                    self.root.after(1000,self.oscdriver.start_server())

        
        # initialise ToD scheduler calculating schedule for today
        self.tod=TimeOfDay()
        reason,message,self.tod_enabled = self.tod.init(pp_dir,self.pp_home,self.pp_profile,self.showlist,self.root,self.handle_command)
        if reason == 'error':
            self.mon.err(self,message)
            self.end('error',message)
            
        # warn if the network not available when ToD required
        if self.tod_enabled is True and self.network_connected is False:
            self.mon.warn(self,'Network not connected  so Time of Day scheduler may be using the internal clock')

        # init the counter manager
        self.counter_manager=CounterManager()
        self.counter_manager.init()


        # warn about start shows and scheduler

        if self.starter_show['start-show']=='' and self.tod_enabled is False:
            self.mon.sched(self,None,"No Start Shows in Start Show and no shows scheduled") 
            self.mon.warn(self,"No Start Shows in Start Show and no shows scheduled")

        if self.starter_show['start-show'] !='' and self.tod_enabled is True:
            self.mon.sched(self,None,"Start Shows in Start Show and shows scheduled - conflict?") 
            self.mon.warn(self,"Start Shows in Start Show and shows scheduled - conflict?")

        # run the start shows
        self.run_start_shows()           

        # kick off the time of day scheduler which may run additional shows
        if self.tod_enabled is True:
            self.tod.poll()

        # start the I/O plugins input event generation
        self.ioplugin_manager.start()


        # start Tkinters event loop
        self.root.mainloop( )


    def parse_screen(self,size_text):
        fields=size_text.split('*')
        if len(fields)!=2:
            return 'error','do not understand --screensize comand option',0,0
        elif fields[0].isdigit()  is False or fields[1].isdigit()  is False:
            return 'error','dimensions are not positive integers in --screensize',0,0
        else:
            return 'normal','',int(fields[0]),int(fields[1])
        

# *********************
#  RUN START SHOWS
# ********************   
    def run_start_shows(self):
        self.mon.trace(self,'run start shows')
        # parse the start shows field and start the initial shows       
        show_refs=self.starter_show['start-show'].split()
        for show_ref in show_refs:
            reason,message=self.show_manager.control_a_show(show_ref,'open')
            if reason == 'error':
                self.mon.err(self,message)
                


# *********************
# User inputs
# ********************

    def e_osc_handle_animate(self,line):
        #jump  out of server thread
        self.root.after(1, lambda arg=line: self.osc_handle_animate(arg))

    def osc_handle_animate(self,line):
        self.mon.log(self,"animate command received: "+ line)
        #osc sends output events as a string
        reason,message,delay,name,param_type,param_values=self.animate.parse_animate_fields(line)
        if reason == 'error':
            self.mon.err(self,message)
            self.end(reason,message)
        self.handle_output_event(name,param_type,param_values,0)

    # output events are animate commands       
    def handle_output_event(self,symbol,param_type,param_values,req_time):
            reason,message=self.ioplugin_manager.handle_output_event(symbol,param_type,param_values,req_time)
            if reason =='error':
                self.mon.err(self,message)
                self.end(reason,message)



    # all input events call this callback providing a symbolic name.
    # handle events that affect PP overall, otherwise pass to all active shows
    def handle_input_event(self,symbol,source):
        self.mon.log(self,"event received: "+symbol + ' from '+ source)
        if symbol == 'pp-terminate':
            self.handle_user_abort()
            
        elif symbol == 'pp-shutdown':
            self.mon.err(self,'pp-shutdown removed in version 1.3.3a, see Release Notes')
            self.end('error','pp-shutdown removed in version 1.3.3a, see Release Notes')

            
        elif symbol == 'pp-shutdownnow':
            # need root.after to grt out of st thread
            self.root.after(1,self.shutdownnow_pressed)
            return
        
        elif symbol == 'pp-exitpipresents':
            self.exitpipresents_required=True
            if self.show_manager.all_shows_exited() is True:
                # need root.after to grt out of st thread
                self.root.after(1,self.e_all_shows_ended_callback)
                return
            reason,message= self.show_manager.exit_all_shows()
        else:
            # pass the input event to all registered shows
            for show in self.show_manager.shows:
                show_obj=show[ShowManager.SHOW_OBJ]
                if show_obj is not None:
                    show_obj.handle_input_event(symbol)



    # commands are generaed by tracks and shows
    # they can open or close shows, generate input events and do special tasks
    # commands also generate osc outputs to other computers
    # handles one command provided as a line of text
    
    def handle_command(self,command_text,source='',show=''):
        # print 'PIPRESENTS ',command_text,'\n   Source',source,'from',show
        self.mon.log(self,"command received: " + command_text)
        if command_text.strip()=="":
            return

        fields= command_text.split()

        if fields[0] in ('osc','OSC'): 
            if self.osc_enabled is True:
                status,message=self.oscdriver.parse_osc_command(fields[1:])
                if status=='warn':
                    self.mon.warn(self,message)
                if status=='error':
                    self.mon.err(self,message)
                    self.end('error',message)
                return
        

        if fields[0] =='counter':
            status,message=self.counter_manager.parse_counter_command(fields[1:])
            if status=='error':
                self.mon.err(self,message)
                self.end('error',message)
            return

                           
        show_command=fields[0]
        if len(fields)>1:
            show_ref=fields[1]
        else:
            show_ref=''
        if show_command in ('open','close','closeall','openexclusive'):
            self.mon.sched(self, TimeOfDay.now,command_text + ' received from show:'+show)
            if self.shutdown_required is False and self.terminate_required is False:
                reason,message=self.show_manager.control_a_show(show_ref,show_command)
            else:
                return
            
        elif show_command =='monitor':
            self.handle_monitor_command(show_ref)
            return

        elif show_command =='cec':
            self.handle_cec_command(show_ref)
            return
        
        elif show_command == 'event':
            self.handle_input_event(show_ref,'Show Control')
            return
        
        elif show_command == 'exitpipresents':
            self.exitpipresents_required=True
            if self.show_manager.all_shows_exited() is True:
                # need root.after to get out of st thread
                self.root.after(1,self.e_all_shows_ended_callback)
                return
            else:
                reason,message= self.show_manager.exit_all_shows()

        elif show_command == 'shutdownnow':
            # need root.after to get out of st thread
            self.root.after(1,self.shutdownnow_pressed)
            return

        elif show_command == 'reboot':
            # need root.after to get out of st thread
            self.root.after(1,self.reboot_pressed)
            return
        
        else:
            reason='error'
            message = 'command not recognised: '+ show_command
            
        if reason=='error':
            self.mon.err(self,message)
        return


    def handle_monitor_command(self,command):
        if command == 'on':
            os.system('vcgencmd display_power 1 >/dev/null')
        elif command == 'off':
            os.system('vcgencmd display_power 0 >/dev/null')

    def handle_cec_command(self,command):
        if command == 'on':
            os.system('echo "on 0" | cec-client -s')
        elif command == 'standby':
            os.system('echo "standby 0" | cec-client -s')

        elif command == 'scan':
            os.system('echo scan | cec-client -s -d 1')
                      
    # deal with differnt commands/input events

    def shutdownnow_pressed(self):
        self.shutdown_required=True
        if self.show_manager.all_shows_exited() is True:
           self.all_shows_ended_callback('normal','no shows running')
        else:
            # calls exit method of all shows, results in all_shows_closed_callback
            self.show_manager.exit_all_shows()

    def reboot_pressed(self):
        self.reboot_required=True
        if self.show_manager.all_shows_exited() is True:
           self.all_shows_ended_callback('normal','no shows running')
        else:
            # calls exit method of all shows, results in all_shows_closed_callback
            self.show_manager.exit_all_shows() 


    def handle_sigterm(self,signum,fframe):
        self.mon.log(self,'SIGTERM received - '+ str(signum))
        self.terminate()


    def handle_user_abort(self):
        self.mon.log(self,'User abort received')
        self.terminate()

    def terminate(self):
        self.mon.log(self, "terminate received")
        self.terminate_required=True
        needs_termination=False
        for show in self.show_manager.shows:
            # print  show[ShowManager.SHOW_OBJ], show[ShowManager.SHOW_REF]
            if show[ShowManager.SHOW_OBJ] is not None:
                needs_termination=True
                self.mon.log(self,"Sent terminate to show "+ show[ShowManager.SHOW_REF])
                # call shows terminate method
                # eventually the show will exit and after all shows have exited all_shows_callback will be executed.
                show[ShowManager.SHOW_OBJ].terminate()
        if needs_termination is False:
            self.end('killed','killed - no termination of shows required')



# ******************************
# Ending Pi Presents after all the showers and players are closed
# **************************

    def e_all_shows_ended_callback(self):
        self.all_shows_ended_callback('normal','no shows running')

    # callback from ShowManager when all shows have ended
    def all_shows_ended_callback(self,reason,message):
        self.canvas.config(bg=self.starter_show['background-colour'])
        if reason in ('killed','error') or self.shutdown_required is True or self.exitpipresents_required is True or self.reboot_required is True:
            self.end(reason,message)

    def end(self,reason,message):
        self.mon.log(self,"Pi Presents ending with reason: " + reason)
        if self.root is not None:
            self.root.destroy()
        self.tidy_up()
        if reason == 'killed':
            if self.email_enabled is True and self.mailer.email_on_terminate is True:
                subject= '[Pi Presents] ' + self.unit + ': PP Exited with reason: Terminated'
                message = time.strftime("%Y-%m-%d %H:%M") + '\n ' + self.unit + '\n ' + self.interface + '\n ' + self.ip 
                self.send_email(reason,subject,message)
            self.mon.sched(self, None,"Pi Presents Terminated, au revoir\n")
            self.mon.log(self, "Pi Presents Terminated, au revoir")
                          
            # close logging files
            self.mon.finish()
            print 'Uncollectable Garbage',gc.collect()
            # objgraph.show_backrefs(objgraph.by_type('Monitor'))
            sys.exit(101)
                          
        elif reason == 'error':
            if self.email_enabled is True and self.mailer.email_on_error is True:
                subject= '[Pi Presents] ' + self.unit + ': PP Exited with reason: Error'
                message_text = 'Error message: '+ message + '\n'+ time.strftime("%Y-%m-%d %H:%M") + '\n ' + self.unit + '\n ' + self.interface + '\n ' + self.ip 
                self.send_email(reason,subject,message_text)   
            self.mon.sched(self,None, "Pi Presents closing because of error, sorry\n")
            self.mon.log(self, "Pi Presents closing because of error, sorry")
                          
            # close logging files 
            self.mon.finish()
            print 'uncollectable garbage',gc.collect()
            sys.exit(102)

        else:           
            self.mon.sched(self,None,"Pi Presents  exiting normally, bye\n")
            self.mon.log(self,"Pi Presents  exiting normally, bye")
            
            # close logging files 
            self.mon.finish()
            if self.reboot_required is True:
                # print 'REBOOT'
                call (['sudo','reboot'])
            if self.shutdown_required is True:
                # print 'SHUTDOWN'
                call (['sudo','shutdown','now','SHUTTING DOWN'])
            print 'uncollectable garbage',gc.collect()
            sys.exit(100)


    # tidy up all the peripheral bits of Pi Presents
    def tidy_up(self):
        self.handle_monitor_command('on')
        self.mon.log(self, "Tidying Up")
        # turn screen blanking back on
        if self.options['noblank'] is True:
            call(["xset","s", "on"])
            call(["xset","s", "+dpms"])
            
        # tidy up animation
        if self.animate is not None:
            self.animate.terminate()

        # tidy up i/o plugins
        if self.ioplugin_manager != None:
            self.ioplugin_manager.terminate()

        if self.osc_enabled is True:
            self.oscdriver.terminate()
            
        # tidy up time of day scheduler
        if self.tod_enabled is True:
            self.tod.terminate()



# *******************************
# Connecting to network and email
# *******************************

    def init_network(self):

        timeout=int(self.options['nonetwork'])
        if timeout== 0:
            self.network_connected=False
            self.unit=''
            self.ip=''
            self.interface=''
            return
        
        self.network=Network()
        self.network_connected=False

        # try to connect to network
        self.mon.log (self, 'Waiting up to '+ str(timeout) + ' seconds for network')
        success=self.network.wait_for_network(timeout)
        if success is False:
            self.mon.warn(self,'Failed to connect to network after ' + str(timeout) + ' seconds')
            # tkMessageBox.showwarning("Pi Presents","Failed to connect to network so using fake-hwclock")
            return

        self.network_connected=True
        self.mon.sched (self, None,'Time after network check is '+ time.strftime("%Y-%m-%d %H:%M.%S"))
        self.mon.log (self, 'Time after network check is '+ time.strftime("%Y-%m-%d %H:%M.%S"))

        # Get web configuration
        self.network_details=False
        network_options_file_path=self.pp_dir+os.sep+'pp_config'+os.sep+'pp_web.cfg'
        if not os.path.exists(network_options_file_path):
            self.mon.warn(self,"pp_web.cfg not found at "+network_options_file_path)
            return
        self.mon.log(self, 'Found pp_web.cfg in ' + network_options_file_path)

        self.network.read_config(network_options_file_path)
        self.unit=self.network.unit

        # get interface and IP details of preferred interface
        self.interface,self.ip = self.network.get_preferred_ip()
        if self.interface == '':
            self.network_connected=False
            return
        self.network_details=True
        self.mon.log (self, 'Network details ' + self.unit + ' ' + self.interface + ' ' +self.ip)


    def init_mailer(self):

        self.email_enabled=False
        email_file_path = self.pp_dir+os.sep+'pp_config'+os.sep+'pp_email.cfg'
        if not os.path.exists(email_file_path):
            self.mon.log(self,'pp_email.cfg not found at ' + email_file_path)
            return
        self.mon.log(self,'Found pp_email.cfg at ' + email_file_path)
        self.mailer=Mailer()
        self.mailer.read_config(email_file_path)
        # all Ok so can enable email if config file allows it.
        if self.mailer.email_allowed is True:
            self.email_enabled=True
            self.mon.log (self,'Email Enabled')


    def try_connect(self):
        tries=1
        while True:
            success, error = self.mailer.connect()
            if success is True:
                return True
            else:
                self.mon.log(self,'Failed to connect to email SMTP server ' + str(tries) +  '\n ' +str(error))
                tries +=1
                if tries >5:
                    self.mon.log(self,'Failed to connect to email SMTP server after ' + str(tries))
                    return False


    def send_email(self,reason,subject,message):
        if self.try_connect() is False:
            return False
        else:
            success,error = self.mailer.send(subject,message)
            if success is False:
                self.mon.log(self, 'Failed to send email: ' + str(error))
                success,error=self.mailer.disconnect()
                if success is False:
                    self.mon.log(self,'Failed disconnect after send:' + str(error))
                return False
            else:
                self.mon.log(self,'Sent email for ' + reason)
                success,error=self.mailer.disconnect()
                if success is False:
                    self.mon.log(self,'Failed disconnect from email server ' + str(error))
                return True