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)
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
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
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)
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)
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()
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()
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()
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()
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)
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()
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()
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)
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()
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")
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)
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)
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')
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
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")
class TrailUI: def __init__(self, parent, trail=None): self.parent = parent self.trail = trail self.alpha_reflection = trail.alpha_reflection self.states = [] self.probabilitylabels = {} ## scrollbar # create a canvas object and a vertical scrollbar for scrolling it self.scrollframe = Frame(parent) self.hsb = Scrollbar(self.scrollframe, orient=Tkinter.HORIZONTAL) self.hsb.pack(fill=Tkinter.X, side=BOTTOM, expand=Tkinter.FALSE) self.scrollcanvas = Canvas(self.scrollframe, bd=0, highlightthickness=0, xscrollcommand=self.hsb.set) self.scrollcanvas.pack(side=LEFT, fill=BOTH, expand=Tkinter.TRUE) self.hsb.config(command=self.scrollcanvas.xview) # reset the view self.scrollcanvas.xview_moveto(0) self.scrollcanvas.yview_moveto(0) # put trailframe into scrollframe and assign configs self.trailframe = interior = Frame(self.scrollcanvas) self.interior_id = self.scrollcanvas.create_window(10, 0, window=interior, anchor=Tkinter.NW) interior.bind('<Configure>', self._configure_interior) self.scrollcanvas.bind('<Configure>', self._configure_canvas) self.scrollframe.pack(fill=Tkinter.X, expand=1) self.infoframe = Frame(parent) self.infoframe.pack(fill=Tkinter.X, expand=1, side=BOTTOM) self.canvas = Canvas(self.infoframe, width=1000, height=200) self.canvas.pack() self.b = Button(self.infoframe, text='Disable Propagation', command=self.__toggle_prop) self.b.pack() self.b2 = Button(self.infoframe, text='Make active only', command=self.__activeonly) self.b2.pack() self.parent.title("ClusterF**k") self.enable_propagation = True self.trail.updateColorList() self.maxgridcol = -1 self.trail.initUI(self) # Multi Cell Selection self.multiselection_pressed = False self.dynamicselection_pressed = False self.selectedcells = [] self.parent.bind("<Control_L>", self.__selection_start) self.parent.bind("<KeyRelease-Control_L>", self.__selection_end) self.parent.bind("<Shift_L>", self.__dynamic_selection_start) self.parent.bind("<KeyRelease-Shift_L>", self.__dynamic_selection_end) self.parent.bind("<Escape>", lambda event: self._clear_selection()) self.parent.bind("<Return>", lambda event: self.open_cell_dialogue()) # track changes to the canvas and frame width and sync them, # also updating the scrollbar # taken from https://gist.github.com/EugeneBakin/76c8f9bcec5b390e45df def _configure_interior(self, event): # update the scrollbars to match the size of the inner frame size = (self.trailframe.winfo_reqwidth(), self.trailframe.winfo_reqheight()) self.scrollcanvas.config(scrollregion="0 0 %s %s" % size) if self.trailframe.winfo_reqwidth() != self.scrollcanvas.winfo_width(): # update the canvas's width to fit the inner frame self.scrollcanvas.config(width=self.trailframe.winfo_reqwidth()) def _configure_canvas(self, event): if self.trailframe.winfo_reqwidth() != self.scrollcanvas.winfo_width(): # update the inner frame's width to fill the canvas self.scrollcanvas.itemconfigure( self.trailframe, width=self.scrollcanvas.winfo_width()) def __selection_start(self, event): print "Selection start/continue" self.multiselection_pressed = True def __dynamic_selection_start(self, event): print "Dynamic selection start" self.dynamicselection_pressed = True def __selection_end(self, event): print "Selection end" self.multiselection_pressed = False def __dynamic_selection_end(self, event): print "Dynamic selection end" self.dynamicselection_pressed = False def open_cell_dialogue(self): if len(self.selectedcells) is 0: return # oldstate = self.__clickedcells[0]["oldstate"] # oldstatestr = ",".join(["{:x}".format(x) for x in oldstate]) oldstatestr = "" dialog = StatePopup( self, oldstatestr, self.selectedcells[0]["state_probs"]) # TODO add probs self.trailframe.wait_window(dialog.top) newstate = dialog.value # set each cell of the selection to the new state if newstate is not None: for i, cell in enumerate(self.selectedcells): cell["stateUI"].state.set(cell["row"], cell["col"], set(newstate)) # self._clear_selection() self.redraw_all() self.redraw_selection() def _clear_selection(self): for cell in self.selectedcells: cell["stateUI"].undraw_selection(cell) self.selectedcells = [] def __toggle_prop(self): self.enable_propagation = not self.enable_propagation if self.enable_propagation: self.b.config(text="Disable Propagation") self.redraw_all() else: self.b.config(text="Enable Propagation") def __activeonly(self): self.trail.makeActiveOnly() self.redraw_all() def get_stateui_at(self, row, col): # retrieve state from specific grid position for state in self.states: if state._row is row and state._col is col: return state return self.get_stateui_at(row, col - 1) def redraw_selection(self): for cell in self.selectedcells: cell["stateUI"].draw_selection(cell) def redraw_all(self): if self.enable_propagation: self.trail.propagate() self.trail.getProbability(verbose=True) self.redrawColorList() self.redraw_states() self.redraw_selection() if self.enable_propagation: self.redraw_probablities() def redraw_states(self): for state in self.states: state.redraw_state() if PRINT_PROPS is True: for state in self.states: state.redraw_propagation() def redraw_probablities(self): if self.alpha_reflection is True: for i, prob in enumerate(self.trail.probabilities): overallprob, sboxprob, mixcolprob = prob.getProbability() if i < self.trail.rounds: self.probabilitylabels["S" + str(i)].textvar.set( "2^{0:.2f}".format(math.log(sboxprob, 2))) self.probabilitylabels["M" + str(i + 1)].textvar.set( "2^{0:.2f}".format(math.log(mixcolprob, 2))) elif i >= self.trail.rounds + 1: self.probabilitylabels["S" + str(i + 2)].textvar.set( "2^{0:.2f}".format(math.log(sboxprob, 2))) self.probabilitylabels["M" + str(i + 1)].textvar.set( "2^{0:.2f}".format(math.log(mixcolprob, 2))) else: # inner round self.probabilitylabels["I"].textvar.set("2^{0:.2f}".format( math.log(overallprob, 2))) else: for i, prob in enumerate(self.trail.probabilities): overallprob, sboxprob, mixcolprob = prob.getProbability() self.probabilitylabels["S" + str(i + 1)].textvar.set( "2^{0:.2f}".format(math.log(sboxprob, 2))) self.probabilitylabels["M" + str(i + 1)].textvar.set( "2^{0:.2f}".format(math.log(mixcolprob, 2))) def redrawColorList(self): self.canvas.delete("colorlist") self.trail.updateColorList() for i, (state, color) in enumerate(self.trail.colorlist.items()): statestr = ",".join(["{:x}".format(x) for x in state]) x = 15 + int(i / 5) * 250 y = 15 + (i % 5) * 40 self.canvas.create_rectangle(x, y, x + 25, y + 25, fill=color, tags="colorlist") textx = x + 40 texty = y + 12 self.canvas.create_text(textx, texty, text=statestr, tags="colorlist", fill="black", anchor="w") def cleanup(self): self.infoframe.destroy() self.trailframe.destroy()
class 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
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()
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()
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()
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()
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)
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()
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
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()
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()
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()
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" )
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
</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()
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" ))
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