class ContinuousTMPViewer(object): def __init__(self, suction_height, regions, tl_x=0, tl_y=0, width=500, height=150, title='Grid', background='tan'): self.tk = Tk() # tk.geometry('%dx%d+%d+%d'%(width, height, 100, 0)) self.tk.withdraw() self.top = Toplevel(self.tk) self.top.wm_title(title) self.top.protocol('WM_DELETE_WINDOW', self.top.destroy) self.suction_height = suction_height self.regions = regions self.tl_x = tl_x self.tl_y = tl_y self.width = width self.height = height self.canvas = Canvas(self.top, width=self.width, height=self.height, background=background) self.canvas.pack() # self.center() self.move_frame(self.tl_x, self.tl_y) max_width = max( map(get_width, regions.values())) # Really should take width of max minus min self.dist_to_pixel = (self.width - 2 * PIXEL_BUFFER ) / max_width # Maintains aspect ratio self.dist_width = self.width / self.dist_to_pixel self.dist_height = self.height / self.dist_to_pixel self.ground_height = self.height - self.dist_to_pixel * ENV_HEIGHT self.robot_dist = self.dist_height / 2. self.robot = [] self.blocks = [] self.holding = None self.environment = [] self.draw_environment() def center(self): self.top.update_idletasks() w = self.top.winfo_screenwidth() h = self.top.winfo_screenheight() size = tuple( int(_) for _ in self.top.geometry().split('+')[0].split('x')) x = w / 2 - size[0] / 2 y = h / 2 - size[1] / 2 self.top.geometry("%dx%d+%d+%d" % (size + (x, y))) def move_frame(self, x, y): self.top.update_idletasks() size = tuple( int(_) for _ in self.top.geometry().split('+')[0].split('x')) self.top.geometry("%dx%d+%d+%d" % (size + (x, y))) def scale_x(self, x): # x \in [-self.dist_width/2, self.dist_width/2] return self.dist_to_pixel * (x + self.dist_width / 2.) def scale_y(self, y): # y \in [0, self.dist_height] return self.ground_height - self.dist_to_pixel * y def draw_block(self, x, y, width, height, name='', color='blue'): self.blocks.extend([ self.canvas.create_rectangle(self.scale_x(x - width / 2.), self.scale_y(y), self.scale_x(x + width / 2.), self.scale_y(y + height), fill=color, outline='black', width=2), self.canvas.create_text(self.scale_x(x), self.scale_y(y + height / 2), text=name), ]) # def draw_holding(self, x, width, height, color='blue'): # self.holding = self.canvas.create_rectangle(self.scale_x(x - width / 2.), # self.scale_y(self.robot_dist - SUCTION_HEIGHT / 2 - height), # self.scale_x(x + width / 2.), # self.scale_y(self.robot_dist - SUCTION_HEIGHT / 2), # fill=color, outline='black', width=2) def draw_region(self, region, name='', color='red'): x1, x2 = map(self.scale_x, region) y1, y2 = self.ground_height, self.height self.environment.extend([ self.canvas.create_rectangle(x1, y1, x2, y2, fill=color, outline='black', width=2), self.canvas.create_text((x1 + x2) / 2, (y1 + y2) / 2, text=name), ]) def draw_environment(self): # TODO: automatically draw in order self.environment = [] for name, region in sorted(self.regions.items(), key=lambda pair: get_width(pair[1]), reverse=True): self.draw_region(region, name=name, color=name) def draw_robot( self, x, y, color='yellow' ): # TODO - could also visualize as top grasps instead of side grasps #y = self.robot_dist self.robot = [ self.canvas.create_rectangle( self.scale_x(x - SUCTION_WIDTH / 2.), self.scale_y(y - self.suction_height / 2.), self.scale_x(x + SUCTION_WIDTH / 2.), self.scale_y(y + self.suction_height / 2.), fill=color, outline='black', width=2), self.canvas.create_rectangle( self.scale_x(x - STEM_WIDTH / 2.), self.scale_y(y + self.suction_height / 2.), self.scale_x(x + STEM_WIDTH / 2.), self.scale_y(y + self.suction_height / 2. + STEM_HEIGHT), fill=color, outline='black', width=2), ] def clear_state(self): for block in self.blocks: self.canvas.delete(block) for part in self.robot: self.canvas.delete(part) if self.holding is not None: self.canvas.delete(self.holding) def clear_all(self): self.canvas.delete('all') def save(self, filename): # TODO: screen recording based on location like I did before # TODO: only works on windows # self.canvas.postscript(file='%s.ps'%filename, colormode='color') #from PIL import ImageGrab try: import pyscreenshot as ImageGrab except ImportError: return None x, y = self.top.winfo_x(), 2 * self.top.winfo_y() width, height = self.top.winfo_width(), self.top.winfo_height( ) # winfo_width, winfo_reqheight path = filename + '.png' ImageGrab.grab((x, y, x + width, y + height)).save(path) return path
def hiya(self): if not self.nand_mode: showinfo( 'Info', 'Now you will be asked to choose the SD card path that will be used ' 'for installing the custom firmware (or an output folder).\n\nIn order to avoid ' 'boot errors please assure it is empty before continuing.') self.sd_path = askdirectory() # Exit if no path was selected if self.sd_path == '': return # If adding a No$GBA footer, check if CID and ConsoleID values are OK elif self.nand_operation.get() == 2: cid = self.cid.get() console_id = self.console_id.get() # Check lengths if len(cid) != 32: showerror('Error', 'Bad eMMC CID') return elif len(console_id) != 16: showerror('Error', 'Bad Console ID') return # Parse strings to hex try: cid = cid.decode('hex') except TypeError: showerror('Error', 'Bad eMMC CID') return try: console_id = bytearray(reversed(console_id.decode('hex'))) except TypeError: showerror('Error', 'Bad Console ID') return dialog = Toplevel(self) # Open as dialog (parent disabled) dialog.grab_set() dialog.title('Status') # Disable maximizing dialog.resizable(0, 0) frame = Frame(dialog, bd=2, relief=SUNKEN) scrollbar = Scrollbar(frame) scrollbar.pack(side=RIGHT, fill=Y) self.log = ThreadSafeText(frame, bd=0, width=52, height=20, yscrollcommand=scrollbar.set) self.log.pack() scrollbar.config(command=self.log.yview) frame.pack() Button(dialog, text='Close', command=dialog.destroy, width=16).pack(pady=10) # Center in window dialog.update_idletasks() width = dialog.winfo_width() height = dialog.winfo_height() dialog.geometry( '%dx%d+%d+%d' % (width, height, root.winfo_x() + (root.winfo_width() / 2) - (width / 2), root.winfo_y() + (root.winfo_height() / 2) - (height / 2))) # Check if we'll be adding a No$GBA footer if self.nand_mode and self.nand_operation.get() == 2: Thread(target=self.add_footer, args=(cid, console_id)).start() else: Thread(target=self.check_nand).start()