class Screen(Observer): def __init__(self,parent,bg="white"): self.canvas=Canvas(parent,bg=bg) print("parent",parent.cget("width"),parent.cget("height")) parent.bind("<Configure>", self.resize) self.parent=parent self.width=int(self.canvas.cget("width")) self.height=int(self.canvas.cget("height")) self.models=[] def update(self,model): if model not in self.models: self.models.append(model) print("View update") signal=model.get_signal() self.plot_signal(signal,model.get_color(),model.get_name()) def plot_signal(self,signal,color,name): w,h=self.canvas.winfo_width(),self.canvas.winfo_height() width,height=int(w),int(h) print(self.canvas.find_withtag("signal"+name)) if self.canvas.find_withtag("signal"+name) : self.canvas.delete("signal"+name) if signal and len(signal) > 1: if name=="X-Y" : plot = [((x+2)*width/4, (2*y/self.m+1)*height/2) for (x, y) in signal] else : plot = [(x*width, y*height/self.m + height/2) for (x, y) in signal] signal_id = self.canvas.create_line(plot, fill=color, smooth=1, width=3,tags="signal"+name) return def packing(self) : self.canvas.pack(fill="both", expand=1) def grid(self,n,m): self.n=n self.m=m w,h=self.canvas.winfo_width(),self.canvas.winfo_height() self.width,self.height=int(w),int(h) self.canvas.create_line(0,self.height/2.0,self.width-4,self.height/2,arrow="last",tags="line",fill="blue") self.canvas.create_line(self.width/2,self.height,self.width/2,5,arrow="last",tags="line",fill="blue") step1=self.width/n for t in range(1,n): x =t*step1 self.canvas.create_line(x,0,x,self.height,tags="line") step=self.height/m for t in range(1,m): y =t*step self.canvas.create_line(0,y,self.width,y,tags="line") def resize(self,event): self.canvas.delete("line") self.grid(self.n,self.m) for model in self.models : self.plot_signal(model.get_signal(), model.get_color(), model.get_name())
class canvasInterface(interfaceScreen): def __init__(self,master,width,height): interfaceScreen.__init__(self) self.canvas = Canvas(master, width=width, height=height,bg='white') self.canvas.grid(row=0,column=1) """ ---------------Interfaz con objeto dibujante--------------------- """ def deleteFromCanvas(self,id): self.canvas.delete(id) pass def create_rectangle(self,x1, y1, x2, y2,*arg,**kargs): return self.canvas.create_rectangle(x1, y1, x2, y2,*arg,**kargs) pass def create_line(self,x1, y1, x2, y2, *args,**kwargs): return self.canvas.create_line(x1, y1, x2, y2, *args,**kwargs) def create_text(self,x1, y1,*args,**kargs): return self.canvas.create_text(x1, y1,*args,**kargs) def scan_mark(self,x,y): self.canvas.scan_mark(x, y) def scan_dragto(self,x, y, *args,**kwargs): self.canvas.scan_dragto(x, y, *args,**kwargs) def winfo_height(self): return self.canvas.winfo_height() def winfo_width(self): return self.canvas.winfo_width()
class MainWindow(Tk): def __init__(self, width=100, height=100, bg="red"): Tk.__init__(self) self.title("Editeur Graphique") self.geometry("400x300+1200+300") self.canvas = Canvas(self, width=width - 20, height=height - 20, bg=bg) self.libelle = Label(text="Serious Game", font="Helvetica 14 bold") self.canvas.pack() self.libelle.pack() print(self.canvas.cget("height")) print(self.canvas.cget("width")) print(self.canvas.winfo_height()) print(self.canvas.winfo_width())
class MainWindow(Frame): def __init__(self, parent=None, width=100,height=100,bg="red"): Frame.__init__(self,parent, relief="sunken", bd=5) self.canvas =Canvas(self,width=width-20,height=height-20, bg=bg) self.libelle =Label(text ="Serious Game", font="Helvetica 14 bold") print(self.canvas.cget("height")) print(self.canvas.cget("width")) print(self.canvas.winfo_height()) print(self.canvas.winfo_width()) def packing(self) : self.pack() self.canvas.pack(fill="both",expand=True) self.libelle.pack()
class MainWindow(Frame): def __init__(self, parent=None, bg="red"): Frame.__init__(self, parent, relief="sunken", bd=5) self.parent = parent self.menubar = MenuBar(self) self.canvas = Canvas(self, bg=bg) self.libelle = Label(text="Serious Game", font="Helvetica 14 bold") print(self.canvas.cget("height")) print(self.canvas.cget("width")) print(self.canvas.winfo_height()) print(self.canvas.winfo_width()) def packing(self): self.menubar.pack(fill="x") self.canvas.pack(fill="both", expand=True) self.libelle.pack() self.pack() def file_save(self): formats = [('Texte', '*.py'), ('Portable Network Graphics', '*.png')] if sys.version_info[0] < 3: filename = tkFileDialog.asksaveasfilename(parent=self.parent, filetypes=formats, title="Save...") else: filename = filedialog.asksaveasfilename(parent=self.parent, filetypes=formats, title="Save...") if len(nfilename) > 0: print("Sauvegarde en cours dans %s" % filename) def file_quit(self): exit(0) def create_circle(self): pass def delete_circle(self): pass def help_us(self): pass def help_tkinter(self): pass
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 SkyglowEstimationToolbox: """Main class that establishes GUI.""" def __init__(self, root): self.root = root # Radio action buttons self.action = None self.sgmap_single_btn, self.krn_lib_btn, self.multi_map_btn = None, None, None self.file_log_var = StringVar() self.csv_file_var = StringVar() self.krn_folder_var = StringVar() self.output_folder_var = StringVar() self.sgmap_folder_var = StringVar() self.krn_ent_var = StringVar() self.krn_var, self.hem_var = IntVar(), IntVar() self.img, self.cdiag = None, None self.lat_lbl, self.lat_entry = None, None self.k_lbl, self.k_entry = None, None self.zen_lbl, self.zen_entry = None, None self.azi_lbl, self.azi_entry = None, None self.krn_lvl, self.krn_entry, self.krn_btn = None, None, None self.txt_redir, self.prg_log = None, None self.map_btn, self.gen_krn_btn = None, None # Sets window title, size, and icon on screen. self.root.title("Skyglow Estimation Toolbox (SET)") self.root.geometry('%dx%d+%d+%d' % (constants.SW * 0.75, constants.SH * 0.75, 25, 25)) self.root.iconbitmap(os.path.join(os.getcwd(), constants.ICO)) self.root.resizable(False, False) self.root.update_idletasks() # Creates three paned windows for the main screen. base = PanedWindow() base.pack(fill=BOTH, expand=1) sub1 = PanedWindow(base, orient=VERTICAL, height=self.root.winfo_height() * 3 / 4) base.add(sub1) sub2 = PanedWindow(sub1, orient=HORIZONTAL, height=self.root.winfo_height() / 5) sub1.add(sub2) # Creates frame for holding inputs. self.input_frame = Frame(sub2) sub2.add(self.input_frame) # Creates frame for bottom half of main screen. self.img_frame = Frame(sub1, bd=2, bg='white', relief="sunken") sub1.add(self.img_frame) # Creates canvas for displaying images. self.img_canvas = Canvas(self.img_frame, bd=2, relief="groove", width=constants.SW * 0.6, height=self.root.winfo_height() * 3 / 4 * 0.9) self.img_canvas.place(relx=.5, rely=.5, anchor=CENTER) # Creates help button for link to documentation, instructions, and about. self.help_btn = Menubutton(self.input_frame, text="Help", relief="raised", bd=2, width=8, pady=1) #self.help_btn.place(relx=1, rely=0, anchor=NE) self.help_btn.grid(column=4, columnspan=1, row=0) self.help_btn_menu = Menu(self.help_btn, tearoff=0) doc = 'https://github.com/NASA-DEVELOP' self.help_btn_menu.add_command(label="Documentation", command=lambda: self.open_url(doc)) self.help_btn_menu.add_command(label="Instructions", command=self.instructions) self.help_btn_menu.add_separator() self.help_btn_menu.add_command(label="About", command=self.about) self.help_btn["menu"] = self.help_btn_menu def main_screen(self): """Set up input GUI and image display screen.""" self.action = IntVar() btn_width = int(constants.SW / 60) file_width = int(constants.SW / 18) lbl_width = int(constants.SW / 60) gen_width = int(constants.SW / 42) radio_font = Font(family='TkDefaultFont', size=12) self.sgmap_single_btn = Radiobutton( self.input_frame, text="Generate Artificial Skyglow Map", font=radio_font, width=btn_width, variable=self.action, value='sng', command=self.sng_popup) self.krn_lib_btn = Radiobutton(self.input_frame, text="Generate Kernel Library", font=radio_font, width=btn_width, variable=self.action, value='krn', command=self.krn_popup) self.multi_map_btn = Radiobutton( self.input_frame, text="Generate Maps from Multiple Kernels", font=radio_font, width=btn_width, variable=self.action, value='mul', command=self.mul_popup) self.hem_map_btn = Radiobutton( self.input_frame, text="Generate Hemispherical Visualization", font=radio_font, width=btn_width, variable=self.action, value='hem', command=self.hem_popup) #Place widget self.sgmap_single_btn.grid(column=0, columnspan=1, row=0) self.krn_lib_btn.grid(column=1, columnspan=1, row=0) self.multi_map_btn.grid(column=2, columnspan=1, row=0) self.hem_map_btn.grid(column=3, columnspan=1, row=0) # VIIRS Image Reference File self.file_lbl = Label(self.input_frame, text="Image File:", width=lbl_width, anchor=E) self.file_log = Entry(self.input_frame, width=file_width, bd=2, relief="sunken", textvariable=self.file_log_var) self.browse_btn = Button(self.input_frame, text="Browse", command=self.import_viirs) # Angles CSV File self.csv_file_lbl = Label(self.input_frame, text="Angles CSV File:", width=lbl_width, anchor=E) self.csv_file_log = Entry(self.input_frame, width=file_width, bd=2, relief="sunken", textvariable=self.csv_file_var) self.csv_browse_btn = Button(self.input_frame, text="Browse", command=self.import_csv) # Multiple Maps form Kernel library self.mul_file_lbl = Label(self.input_frame, text="Kernel Folder:", width=lbl_width, anchor=E) self.mul_file_log = Entry(self.input_frame, width=file_width, bd=2, relief="sunken", textvariable=self.krn_folder_var) self.mul_browse_btn = Button(self.input_frame, text="Browse", command=self.import_krn_folder) # MultiKrn Map Output Location self.output_lbl = Label(self.input_frame, text="Output Location:", width=lbl_width, anchor=E) self.output_log = Entry(self.input_frame, width=file_width, bd=2, relief="sunken", textvariable=self.output_folder_var) self.output_btn = Button(self.input_frame, text="Browse", command=self.import_out_folder) # Hemisphere Output Location self.sgmap_folder_lbl = Label(self.input_frame, text="Skyglow Map Location:", width=lbl_width, anchor=E) self.sgmap_folder_log = Entry(self.input_frame, width=file_width, bd=2, relief="sunken", textvariable=self.sgmap_folder_var) self.sgmap_folder_btn = Button(self.input_frame, text="Browse", command=self.import_sgmap_folder) # Import Kernel Checkbutton self.check_lbl = Label(self.input_frame, text="Import Kernel:", width=lbl_width, anchor=E) self.krn_chk = Checkbutton(self.input_frame, anchor=W, variable=self.krn_var, command=self.checkbtn_val) self.hem_chk_lbl = Label(self.input_frame, text="Generate kernels for hemisphere:", width=lbl_width, anchor=E) self.hem_chk = Checkbutton(self.input_frame, anchor=W, variable=self.hem_var) # Region Latitude (deg), Grand Teton National park = 43.7904 degrees N self.lat_lbl = Label(self.input_frame, text="Latitude (deg):", width=lbl_width, anchor=E) self.lat_entry = Entry(self.input_frame, width=btn_width, bd=2, relief="sunken") self.lon_lbl = Label(self.input_frame, text="Longitude (deg):", width=lbl_width, anchor=E) self.lon_entry = Entry(self.input_frame, width=btn_width, bd=2, relief="sunken") # Atmospheric Clarity Parameter, REF 2, Eq. 12, p. 645 self.k_lbl = Label(self.input_frame, text="Atmospheric Clarity Parameter:", width=btn_width, anchor=E) self.k_entry = Entry(self.input_frame, width=btn_width, bd=2, relief="sunken") # Zenith angle (deg), z, REF 2, Fig. 6, p.648 self.zen_lbl = Label(self.input_frame, text="Zenith Angle (deg):", width=lbl_width, anchor=E) self.zen_entry = Entry(self.input_frame, width=btn_width, bd=2, relief="sunken") # Azimuth angle (deg) self.azi_lbl = Label(self.input_frame, text="Azimuth Angle (deg):", width=lbl_width, anchor=E) self.azi_entry = Entry(self.input_frame, width=btn_width, bd=2, relief="sunken") self.krn_lbl = Label(self.input_frame, text="Kernel File:", width=lbl_width, anchor=E) self.krn_ent = Entry(self.input_frame, width=file_width, bd=2, relief="sunken", textvariable=self.krn_ent_var) self.krn_btn = Button(self.input_frame, text="Browse", command=self.import_krn) # Generate Artificial Skyglow Map Button self.map_btn = Button(self.input_frame, text="Generate Artificial Skyglow Map", width=gen_width, command=self.generate_map) # Generate Kernal library button for SET self.gen_krn_btn = Button(self.input_frame, text="Generate Kernel Library", width=gen_width, command=self.generate_krn) # Generate Map of Multiple Kernals(word better later on) self.mul_map_btn = Button(self.input_frame, text="Generate Maps from Multiple Kernels", width=gen_width, command=self.generate_mmap) # Generate Hemispherical Visualization Display of Skyglow self.hem_gen_btn = Button(self.input_frame, text="Generate Hemisphere", width=gen_width, command=self.generate_hem) def import_viirs(self): """Import a VIIRS DNB file.""" # Allows user to search through his directory for VIIRS Image file. file_types = [('TIFF Files', '*.tif'), ('All files', '*')] file_name = filedialog.askopenfilename(initialdir='/', title="Select file", filetypes=file_types) self.file_log_var.set(file_name) # Checks to see if file is empty. If not, displays image on canvas. if file_name != '': pilimg = Image.open(file_name) pilimg_width, pilimg_height = pilimg.size pilimg.tile = [ t for t in pilimg.tile if t[1][2] < pilimg_width and t[1][3] < pilimg_height ] canvas_size = (self.img_canvas.winfo_width(), self.img_canvas.winfo_height()) pilimg_r = pilimg.resize(canvas_size, Image.ANTIALIAS) pilimg_col = ImageOps.colorize(ImageOps.grayscale(pilimg_r), (0, 0, 0), (255, 255, 255)) pilimg_cont = ImageOps.autocontrast(pilimg_col, cutoff=.4, ignore=None) self.img = ImageTk.PhotoImage(pilimg_cont) self.img_canvas.create_image(canvas_size[0] / 2, canvas_size[1] / 2, image=self.img) else: print('File is empty.') def import_csv(self): """Import CSV file.""" file_types = [('CSV Files', '*.csv'), ('All files', '*')] file_name = filedialog.askopenfilename(initialdir='/', title="Select file", filetypes=file_types) self.csv_file_var.set(file_name) if file_name is '': print('File is empty.') def import_krn_folder(self): """Import kernel folder.""" krn_dir = filedialog.askdirectory(initialdir='/', title="Select kernel folder") self.krn_folder_var.set(krn_dir) if krn_dir is '': print('Directory is empty.') def import_out_folder(self): """Import skyglow output folder.""" output_dir = filedialog.askdirectory(initialdir='/', title="Select output folder") self.output_folder_var.set(output_dir) if output_dir is '': print('Directory is empty.') def import_krn(self): """Import existing kernel tif.""" file_types = [('TIFF Files', '*.tif'), ('All files', '*')] file_name = filedialog.askopenfilename(initialdir='/', title="Select file", filetypes=file_types) self.krn_ent_var.set(file_name) def import_sgmap_folder(self): """Import skyglow map folder for hemisphere building.""" sgmap_dir = filedialog.askdirectory(initialdir='/', title="Select skyglow map folder") self.sgmap_folder_var.set(sgmap_dir) if sgmap_dir is '': print('Directory is empty.') def sng_popup(self): """Single map tab.""" self.remove_all() self.check_lbl.grid(column=0, row=2) self.krn_chk.place(relx=.22, rely=.41, anchor=CENTER) self.file_lbl.grid(column=0, row=1) self.file_log.grid(column=1, columnspan=3, row=1) self.browse_btn.grid(column=4, row=1, sticky=W, padx=3) self.lat_lbl.grid(column=0, row=3) self.lat_entry.grid(column=1, row=3) self.k_lbl.grid(column=2, row=3) self.k_entry.grid(column=3, row=3) self.zen_lbl.grid(column=0, row=4) self.zen_entry.grid(column=1, row=4) self.azi_lbl.grid(column=2, row=4) self.azi_entry.grid(column=3, row=4) self.map_btn.grid(column=1, columnspan=3, row=5, sticky=N + S + E + W) def krn_popup(self): """Kernel lib tab.""" self.remove_all() # latitude self.lat_lbl.grid(column=0, row=3) self.lat_entry.grid(column=1, row=3) # atmospheric clarity self.k_lbl.grid(column=2, row=3) self.k_entry.grid(column=3, row=3) # angles file self.csv_file_lbl.grid(column=0, row=1) self.csv_file_log.grid(column=1, columnspan=3, row=1) self.csv_browse_btn.grid(column=4, row=1, sticky=W, padx=3) # input VIIRS image self.file_lbl.grid(column=0, row=2) self.file_log.grid(column=1, columnspan=3, row=2) self.browse_btn.grid(column=4, row=2, sticky=W, padx=3) self.hem_chk_lbl.grid(column=0, row=4) self.hem_chk.place(relx=.21, rely=.69) self.gen_krn_btn.grid(column=1, columnspan=3, row=5, sticky=N + S + E + W) def mul_popup(self): """Multiple maps tab.""" self.remove_all() # Kernel folder location self.mul_file_lbl.grid(column=0, row=1) self.mul_file_log.grid(column=1, columnspan=3, row=1) self.mul_browse_btn.grid(column=4, row=1, sticky=W, padx=3) # input VIIRS image self.file_lbl.grid(column=0, row=2) self.file_log.grid(column=1, columnspan=3, row=2) self.browse_btn.grid(column=4, row=2, sticky=W, padx=3) # Choose output location self.output_lbl.grid(column=0, row=3) self.output_log.grid(column=1, columnspan=3, row=3) self.output_btn.grid(column=4, row=3, sticky=W, padx=3) # Generate map from kernel folder self.mul_map_btn.grid(column=1, columnspan=3, row=4, sticky=N + S + E + W) def hem_popup(self): """Hemisphere tab.""" self.remove_all() # Skyglow Map Folder self.sgmap_folder_lbl.grid(column=0, row=1) self.sgmap_folder_log.grid(column=1, columnspan=3, row=1) self.sgmap_folder_btn.grid(column=4, row=1, sticky=W, padx=3) # Latitude entry self.lat_lbl.grid(column=0, row=3) self.lat_entry.grid(column=1, row=3) # Longitude entry self.lon_lbl.grid(column=2, row=3) self.lon_entry.grid(column=3, row=3) # Generate Hemispherical Visualization button self.hem_gen_btn.grid(column=1, columnspan=3, row=4, sticky=N + S + E + W) def remove_all(self): """Remove all existing GUI elements before opening new tab.""" self.check_lbl.grid_remove() self.krn_chk.place_forget() self.hem_chk.place_forget() self.hem_chk_lbl.grid_remove() self.file_lbl.grid_remove() self.file_log.grid_remove() self.browse_btn.grid_remove() self.krn_lbl.grid_remove() self.krn_ent.grid_remove() self.krn_btn.grid_remove() self.lat_lbl.grid_remove() self.lat_entry.grid_remove() self.k_lbl.grid_remove() self.k_entry.grid_remove() self.zen_lbl.grid_remove() self.zen_entry.grid_remove() self.azi_lbl.grid_remove() self.azi_entry.grid_remove() self.map_btn.grid_remove() self.gen_krn_btn.grid_remove() self.mul_map_btn.grid_remove() self.csv_file_lbl.grid_remove() self.csv_file_log.grid_remove() self.csv_browse_btn.grid_remove() self.mul_file_lbl.grid_remove() self.mul_file_log.grid_remove() self.mul_browse_btn.grid_remove() self.output_lbl.grid_remove() self.output_log.grid_remove() self.output_btn.grid_remove() self.hem_gen_btn.grid_remove() self.lat_lbl.grid_remove() self.lat_entry.grid_remove() self.lon_lbl.grid_remove() self.lon_entry.grid_remove() self.sgmap_folder_lbl.grid_remove() self.sgmap_folder_log.grid_remove() self.sgmap_folder_btn.grid_remove() def checkbtn_val(self): """Change interface based on if Import Kernel button is checked.""" # Import Kernel File widgets when Kernel Checkbutton is marked. if self.krn_var.get(): self.lat_lbl.grid_remove() self.lat_entry.grid_remove() self.k_lbl.grid_remove() self.k_entry.grid_remove() self.zen_lbl.grid_remove() self.zen_entry.grid_remove() self.azi_lbl.grid_remove() self.azi_entry.grid_remove() self.krn_lbl.grid(column=0, row=2) self.krn_ent.grid(column=1, columnspan=3, row=2) self.krn_btn.grid(column=4, row=2, sticky=W, padx=3) self.krn_chk.place_forget() self.krn_chk.place(relx=0.19, rely=.5) # Input parameter widgets when Kernel Checkbuttton is unmarked else: self.krn_lbl.grid_remove() self.krn_ent.grid_remove() self.krn_btn.grid_remove() self.lat_lbl.grid(column=0, row=3) self.lat_entry.grid(column=1, row=3) self.k_lbl.grid(column=2, row=3) self.k_entry.grid(column=3, row=3) self.zen_lbl.grid(column=0, row=4) self.zen_entry.grid(column=1, row=4) self.azi_lbl.grid(column=2, row=4) self.azi_entry.grid(column=3, row=4) self.krn_chk.place_forget() self.krn_chk.place(relx=0.22, rely=.41, anchor=CENTER) @staticmethod def open_url(url): """"Open a url""" webbrowser.open_new(url) def instructions(self): """Open instructions window.""" # Instantiates separate Toplevel instruction window. instr_window = Toplevel(self.root) instr_window.geometry('550x575+25+25') instr_window.title('Instructions') instr_window.wm_iconbitmap(constants.ICO) instr_window.resizable(False, False) # Creatse Scrollbar and Frame for containing other widgets. instr_scroll = Scrollbar(instr_window) instr_scroll.pack(fill=Y, side="right") instr_frame = Frame(instr_window, bg='white') instr_frame.pack(fill=BOTH, side="left") # Adds instruction text from constants and adds image of Cinzano's diagram. instr = Text(instr_frame, width=65, height=40, padx=10, pady=5, bd=0, wrap="word") instr.insert("end", constants.INSTR) cdiagram_file = Image.open("./static/cinzano_diagram.PNG") cdiagram_file = cdiagram_file.resize((500, 450), Image.ANTIALIAS) self.cdiag = ImageTk.PhotoImage(cdiagram_file) instr.image_create("end", image=self.cdiag) instr.tag_add("top", "1.0", "4.10") instr.tag_config("top", font='Times 12 bold') instr.tag_add("body", "5.0", "19.20") instr.tag_config("body", font='Times 12') instr.insert("end", constants.CDIAG) instr.pack() instr_scroll.config(command=instr.yview) def about(self): """Open an about window. Window gives authors, SET version number, and icon credit. """ # Instantiates a new Toplevel about window. about_window = Toplevel(self.root) about_window.geometry('350x335+25+25') about_window.title('About') about_window.wm_iconbitmap(constants.ICO) about_window.resizable(False, False) # Adds text to about window. about = Text(about_window, width=50, height=30, padx=10, pady=3) about.insert("end", constants.ABOUT) about.tag_add("abt", "1.0", "21.30") about.tag_config("abt", font='Times 10 bold', justify=CENTER) about.pack() def progress(self): """Construct a progress window to monitor darksky.""" # Instantiates a new Toplevel window and frame for progress bar and loading log. self.prg_window = Toplevel(self.root) self.prg_window.geometry('650x325+250+250') self.prg_window.title('Generating Artificial Skyglow Map...') self.prg_window.iconbitmap(constants.ICO) self.prg_window.resizable(False, False) prg_frame = Frame(self.prg_window) prg_frame.pack(fill=BOTH) # Creates Scrollbar, Progressbar, and Label for checking progress.. prg_scroll = Scrollbar(prg_frame) prg_scroll.pack(fill=Y, side="right") self.prg_bar = ttk.Progressbar(prg_frame, orient=HORIZONTAL, length=750, mode='indeterminate') self.prg_bar.pack() self.prg_bar.start() prg_lbl_txt = StringVar() prg_lbl = Label(prg_frame, textvariable=prg_lbl_txt) prg_lbl.pack() # Displays message log that prints from log file and starts darkskypy. self.prg_log = Text(prg_frame, width=90, padx=5, pady=5, relief="sunken") self.prg_log.pack() self.prg_log.insert( "end", "*****Progress Log*****\n=======================\n") self.prg_log.tag_add("abt", "1.0", "3.0") self.prg_log.tag_config("abt", font='Courier 12 bold', justify=CENTER) self.txt_redir = LogRedirector(self.prg_log) logger.addHandler(self.txt_redir) sys.stderr = StderrRedirector(self.prg_log) prg_lbl_txt.set("Start time: " + str(time.asctime())) self.no_progress = 0 def update_progress(self): """Update progress window to prevent it from freezing.""" self.prg_log.update() # if only one thread exists, stop progress bar and close window if len(threading.enumerate()) == 1: self.prg_bar.stop() self.no_progress += 1 if self.no_progress == 3: self.prg_window.withdraw() else: self.prg_bar.start() self.root.after(1000, self.update_progress) def generate_map(self): """Call darksky.sgmapper in background thread.""" # Acquires input arguments. lat_in, k_in, zen_in, azi_in, file_in, krn_file_in = 0, 0, 0, 0, '', '' if self.krn_var.get(): krn_file_in = self.krn_ent_var.get() else: lat_in = float(self.lat_entry.get()) k_in = float(self.k_entry.get()) zen_in = float(self.zen_entry.get()) azi_in = float(self.azi_entry.get()) file_in = self.file_log_var.get() self.progress() # Create new threads to run light propagation model simultaneously. p_thread = threading.Thread(target=self.update_progress()) t_thread = threading.Thread(target=darksky.sgmapper, args=(lat_in, k_in, zen_in, azi_in, file_in, krn_file_in)) t_thread.setDaemon(True) p_thread.start() t_thread.start() def generate_krn(self): """Start kernel generation in background threads.""" # Acquires input arguments csv_in, file_in, lat_in, k_in, hem = '', '', 0, 0, False csv_in = self.csv_file_var.get() file_in = self.file_log_var.get() lat_in = float(self.lat_entry.get()) k_in = float(self.k_entry.get()) hem = self.hem_var.get() self.progress() # Create new threads to run light propagation model simultaneously. p_thread = threading.Thread(target=self.update_progress()) with open(csv_in, "rb") as f: angle_list = loadtxt(f, delimiter=",", skiprows=1) p_thread.start() for angle_set in angle_list: t_thread = threading.Thread(target=darksky.generate_krn, args=(lat_in, k_in, angle_set[0], angle_set[1], file_in, hem)) t_thread.setDaemon(True) t_thread.start() def generate_mmap(self): """Start brightness map creation from kernels.""" # Acquires input arguments krn_folder_in, file_in, output_in, = '', '', '' krn_folder_in = self.krn_folder_var.get() file_in = self.file_log_var.get() output_in = self.output_folder_var.get() self.progress() # Create new threads to run light propagation model simultaneously. p_thread = threading.Thread(target=self.update_progress()) t_thread = threading.Thread(target=darksky.multisgmapper, args=(file_in, krn_folder_in, output_in)) t_thread.setDaemon(True) p_thread.start() t_thread.start() def generate_hem(self): """Generate hemisphere.""" sgmap_folder_in, lat_in, lon_in, = '', 0, 0 sgmap_folder_in = self.sgmap_folder_var.get() lat_in = float(self.lat_entry.get()) lon_in = float(self.lon_entry.get()) darksky.generate_hem(lat_in, lon_in, sgmap_folder_in)
class Visualizer(Toplevel, core.DrawListener): """ Base class for windows used for visualization of problems. Deals with many boilerplate TK tasks and has several features. - Registers blank listeners for common events and registers exit on close - Provides a "virtual coordinate system" that maps onto the window. This is specified as a position and a width/height. - Provides reverse transform from mouse coordinates back to "virtual coordinate system" - Allows posting drawing into the GUI thread. This can be overwhelmed if submissions are too fast. This should leverage TK's dirty/repaint scheme in some way in the future. """ def __init__(self, canvasWidth, canvasHeight, viewCenterX=0.0, viewCenterY=0.0, viewWidth=1.0, viewHeight=1.0, **kw): Toplevel.__init__(self, **kw) self.viewCenterX = viewCenterX self.viewCenterY = viewCenterY self.viewWidth = viewWidth self.viewHeight = viewHeight self.canvas = Canvas(self, width=canvasWidth, height=canvasHeight) self.canvas.pack() self.protocol("WM_DELETE_WINDOW", self.onClose) self.bind("<Configure>", self.onResize) def setView(self, viewCenterX, viewCenterY, viewWidth, viewHeight): self.viewCenterX = viewCenterX self.viewCenterY = viewCenterY self.viewWidth = viewWidth self.viewHeight = viewHeight def bindWithTransform(self, eventName, handler): """ Binds non-standard handlers to events. These handlers receive the initial event object, but also an additional point parameter which holds the event's location in the "virtual coordinate system" as a numpy array. :param eventName: :param handler: a handler function with 2 args (point,event) :return: """ self.bind( eventName, lambda event: handler( self.transformCanvasToPoint((event.x, event.y)), event)) def drawInBackground(self, drawable, **kwargs): """Draw the given drawable in the GUI thread. drawable should not be touched while drawing.""" core.inGUIThread(lambda: self.drawToCanvas(drawable, **kwargs)) def drawToCanvas(self, drawable, **kwargs): """Draw the given drawable, applying virtual coordinates transform. Must be called from GUI THREAD!""" self.canvas.delete(tk.ALL) drawable.draw(self, **kwargs) self.transformCanvas() def transformCanvas(self): """Transforms all objects drawn on the canvas in the "virtual coordinate system" to the window's coordinates.""" canvas = self.canvas width = canvas.winfo_width() height = canvas.winfo_height() canvas.move("all", -self.viewCenterX, -self.viewCenterY) canvas.scale("all", 0.0, 0.0, width / self.viewWidth, -height / self.viewHeight) canvas.move("all", width / 2.0, height / 2.0) def transformCanvasToPoint(self, canvasPoint): """ Given a point on the canvas, such as a mouse coordinate, transform it to the "virtual coordinate system". :param canvasPoint: point to transform :return: (transX, transY) """ width = self.canvas.winfo_width() height = self.canvas.winfo_height() transX = self.viewCenterX + self.viewWidth * (canvasPoint[0] - width / 2.0) / width transY = self.viewCenterY - self.viewHeight * (canvasPoint[1] - height / 2.0) / height return np.array((transX, transY), np.double) def pixelVecToScale(self, vec): """ Scale the given vector, expressed in pixels, to the transform, currently in use. This allows, things like offsets and the radius of points to always be displayed with the same absolute size on the screen. """ return vec * np.array( (self.viewWidth / self.canvas.winfo_width(), self.viewHeight / self.canvas.winfo_height()), np.double) def scaleVecToPixels(self, vec): return vec * np.array( (self.canvas.winfo_width() / self.viewWidth, self.canvas.winfo_height() / self.viewHeight), np.double) def onDraw(self, drawable, **kwargs): """Callback for DrawListener. This can be used by a background calculation thread to signal the GUI to draw a new state.""" self.drawInBackground(drawable) def onResize(self, event): pass def onClose(self): os._exit(0)
class Application(Frame, object): """The application main class.""" WIDTH, HEIGHT = 1280, 720 BG = 'white' FONT = 'Verdana' FILE_OPEN_OPTIONS = { 'mode': 'rb', 'title': 'Choose *.json file', 'defaultextension': '.json', 'filetypes': [('JSON file', '*.json')] } DEFAULTS = 'default_settings.yaml' def __init__(self, master=None): """Creates application main window with sizes self.WIDTH and self.HEIGHT. :param master: instance - Tkinter.Tk instance """ super(Application, self).__init__(master) self.master.title('Engine Game') self.master.geometry('{}x{}'.format(self.WIDTH, self.HEIGHT)) self.master.protocol('WM_DELETE_WINDOW', self.exit) self.source = None self._map = None self.points = None self.lines = None self.captured_point = None self.x0 = None self.y0 = None self.scale_x = None self.scale_y = None self.font_size = None self.coordinates = {} self.captured_lines = {} self.canvas_obj = AttrDict() self.icons = { 0: PhotoImage(file=join('icons', 'player_city.png')), 1: PhotoImage(file=join('icons', 'city.png')), 2: PhotoImage(file=join('icons', 'market.png')), 3: PhotoImage(file=join('icons', 'store.png')), 4: PhotoImage(file=join('icons', 'point.png')), 5: PhotoImage(file=join('icons', 'player_train.png')), 6: PhotoImage(file=join('icons', 'train.png')), 7: PhotoImage(file=join('icons', 'crashed_train.png')), 8: PhotoImage(file=join('icons', 'collision.png')), 9: PhotoImage(file=join('icons', 'play.png')), 10: PhotoImage(file=join('icons', 'play_pressed.png')), 11: PhotoImage(file=join('icons', 'stop.png')), 12: PhotoImage(file=join('icons', 'stop_pressed.png')) } self.queue_requests = { 0: self.set_status_bar, 1: self.set_player_idx, 2: self.build_map, 3: self.refresh_map, 4: self.set_available_games, 99: self.bot_control } self.settings_window = None if exists(expanduser(self.DEFAULTS)): with open(expanduser(self.DEFAULTS), 'r') as cfg: defaults = DefaultsDict.from_yaml(cfg) self.host = None if not defaults.host else str(defaults.host) self.port = None if not defaults.port else int(defaults.port) self.timeout = None if not defaults.timeout else int(defaults.timeout) self.username = None if not defaults.username else str(defaults.username) self.password = None if not defaults.password else str(defaults.password) else: self.host, self.port, self.timeout, self.username, self.password = None, None, None, None, None self.player_idx = None self.posts = {} self.trains = {} self.select_game_window = False self.available_games = None self.game = None self.num_players = None self.num_turns = None self.bot = Bot() self.bot_thread = None self.menu = Menu(self) filemenu = Menu(self.menu) filemenu.add_command(label='Open file', command=self.file_open) filemenu.add_command(label='Server settings', command=self.open_server_settings) filemenu.add_command(label='Select game', command=self.select_game) filemenu.add_command(label='Exit', command=self.exit) self.menu.add_cascade(label='Menu', menu=filemenu) master.config(menu=self.menu) self._status_bar = StringVar() self.label = Label(master, textvariable=self._status_bar) self.label.pack() self.frame = Frame(self) self.frame.bind('<Configure>', self._resize_frame) self.canvas = Canvas(self.frame, bg=self.BG, scrollregion=(0, 0, self.winfo_width(), self.winfo_height())) self.canvas.bind('<Button-1>', self._capture_point) self.canvas.bind('<Motion>', self._move_point) self.canvas.bind('<B1-ButtonRelease>', self._release_point) self.canvas.bind('<Configure>', self._resize_canvas) hbar = Scrollbar(self.frame, orient=HORIZONTAL) hbar.pack(side=BOTTOM, fill=X) hbar.config(command=self.canvas.xview) vbar = Scrollbar(self.frame, orient=VERTICAL) vbar.pack(side=RIGHT, fill=Y) vbar.config(command=self.canvas.yview) self.canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set) self.canvas.pack(fill=BOTH, expand=True) self.play = Label(self.canvas, bg='white') self.play.configure(image=self.icons[9]) self.play.bind('<Button-1>', self._play_press) self.play.bind('<B1-ButtonRelease>', self._play_release) self.stop = Label(self.canvas, bg='white') self.stop.configure(image=self.icons[11]) self.stop.bind('<Button-1>', self._stop_press) self.stop.bind('<B1-ButtonRelease>', self._stop_release) self.frame.pack(fill=BOTH, expand=True) self.weighted = IntVar(value=1) self.weighted_check = Checkbutton(self, text='Proportionally to length', variable=self.weighted, command=self._proportionally) self.weighted_check.pack(side=LEFT) self.show_weight = IntVar() self.show_weight_check = Checkbutton(self, text='Show length', variable=self.show_weight, command=self.show_weights) self.show_weight_check.pack(side=LEFT) self.pack(fill=BOTH, expand=True) self.requests_executor() self.get_available_games() self.set_status_bar('Click Play to start the game') self.play.place(rely=0.5, relx=0.5, anchor=CENTER) @property def map(self): """Returns the actual map.""" return self._map @map.setter def map(self, value): """Clears previously drawn map and assigns a new map to self._map.""" self.clear_map() self.canvas.configure(scrollregion=(0, 0, self.canvas.winfo_width(), self.canvas.winfo_height())) self.x0, self.y0 = self.canvas.winfo_width() / 2, self.canvas.winfo_height() / 2 self._map = value @staticmethod def midpoint(x_start, y_start, x_end, y_end): """Calculates a midpoint coordinates between two points. :param x_start: int - x coordinate of the start point :param y_start: int - y coordinate of the start point :param x_end: int - x coordinate of the end point :param y_end: int - y coordinate of the end point :return: 2-tuple of a midpoint coordinates """ return (x_start + x_end) / 2, (y_start + y_end) / 2 def _resize_frame(self, event): """Calculates new font size each time frame size changes. :param event: Tkinter.Event - Tkinter.Event instance for Configure event :return: None """ self.font_size = int(0.0125 * min(event.width, event.height)) def _resize_canvas(self, event): """Redraws map each time Canvas size changes. Scales map each time visible part of Canvas is enlarged. :param event: Tkinter.Event - Tkinter.Event instance for Configure event :return: None """ if self.map: k = min(float(event.width) / float(self.x0 * 2), float(event.height) / float(self.y0 * 2)) self.scale_x, self.scale_y = self.scale_x * k, self.scale_y * k self.x0, self.y0 = self.x0 * k, self.y0 * k self.redraw_map() self.redraw_trains() x_start, y_start, x_end, y_end = self.canvas.bbox('all') x_start = 0 if x_start > 0 else x_start y_start = 0 if y_start > 0 else y_start self.canvas.configure(scrollregion=(x_start, y_start, x_end, y_end)) def _proportionally(self): """Rebuilds map and redraws trains.""" self.build_map() self.redraw_trains() def _capture_point(self, event): """Stores captured point and it's lines. :param event: Tkinter.Event - Tkinter.Event instance for ButtonPress event :return: None """ x, y = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y) obj_ids = self.canvas.find_overlapping(x - 5, y - 5, x + 5, y + 5) if not obj_ids: return for obj_id in obj_ids: if obj_id in self.canvas_obj.point.keys(): self.captured_point = obj_id point_idx = self.canvas_obj.point[obj_id]['idx'] self.captured_lines = {} for line_id, attr in self.canvas_obj.line.items(): if attr['start_point'] == point_idx: self.captured_lines[line_id] = 'start_point' if attr['end_point'] == point_idx: self.captured_lines[line_id] = 'end_point' if self.weighted.get(): self.weighted.set(0) def _release_point(self, event): """Writes new coordinates for a moved point and resets self.captured_point and self.captured_lines. :param event: Tkinter.Event - Tkinter.Event instance for ButtonRelease event :return: None """ if self.captured_point: idx = self.canvas_obj.point[self.captured_point]['idx'] x, y = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y) self.coordinates[idx] = (x, y) self.points[idx]['x'], self.points[idx]['y'] = (x - self.x0) / self.scale_x, (y - self.y0) / self.scale_y self.captured_point = None self.captured_lines = {} def _move_point(self, event): """Moves point and its lines. Moves weights if self.show_weight is set to 1. In case some point is moved beyond Canvas border Canvas scrollregion is resized correspondingly. :param event: Tkinter.Event - Tkinter.Event instance for Motion event :return: None """ if self.captured_point: new_x, new_y = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y) self.canvas.coords(self.captured_point, new_x, new_y) indent_y = self.icons[self.canvas_obj.point[self.captured_point]['icon']].height() / 2 + self.font_size if self.canvas_obj.point[self.captured_point]['text_obj']: self.canvas.coords(self.canvas_obj.point[self.captured_point]['text_obj'], new_x, new_y - indent_y) self.coordinates[self.canvas_obj.point[self.captured_point]['idx']] = (new_x, new_y) self.canvas.configure(scrollregion=self.canvas.bbox('all')) for line_id, attr in self.captured_lines.items(): line_attrs = self.canvas_obj.line[line_id] if attr == 'start_point': x, y = self.coordinates[line_attrs['end_point']] self.canvas.coords(line_id, new_x, new_y, x, y) else: x, y = self.coordinates[line_attrs['start_point']] self.canvas.coords(line_id, x, y, new_x, new_y) if self.show_weight.get(): mid_x, mid_y = self.midpoint(new_x, new_y, x, y) self.canvas.coords(line_attrs['weight_obj'][1], mid_x, mid_y) r = self.font_size * len(str(line_attrs['weight'])) self.canvas.coords(line_attrs['weight_obj'][0], mid_x - r, mid_y - r, mid_x + r, mid_y + r) self.redraw_trains() def _play_press(self, _): """Draws play button pressed icon.""" self.play.configure(image=self.icons[10]) def _play_release(self, _): """Draws play button icon and calls bot_control method.""" self.play.configure(image=self.icons[9]) self.bot_control() def _stop_press(self, _): """Draws stop button pressed icon.""" self.stop.configure(image=self.icons[12]) def _stop_release(self, _): """Draws stop buton icon and calls bot_control method.""" self.stop.configure(image=self.icons[11]) self.bot_control() def set_player_idx(self, value): """Sets a player idx value.""" self.player_idx = value def file_open(self): """Opens file dialog and builds and draws a map once a file is chosen. Stops bot if its started.""" path = tkFileDialog.askopenfile(parent=self.master, **self.FILE_OPEN_OPTIONS) if path: if self.bot_thread: self.bot_control() self.posts, self.trains = {}, {} self.source = path.name self.weighted_check.configure(state=NORMAL) self.build_map() def open_server_settings(self): """Opens server settings window.""" ServerSettings(self, title='Server settings') def select_game(self): """Opens select game window.""" self.select_game_window = True SelectGame(self, title='Select game') self.select_game_window = False self.set_status_bar('Click Play to start the game') def exit(self): """Closes application and stops bot if its started.""" if self.bot_thread: self.bot_control() self.master.destroy() def bot_control(self): """Starts bot for playing the game or stops it if it is started.""" if not self.bot_thread: self.bot_thread = Thread(target=self.bot.start, kwargs={ 'host': self.host, 'port': self.port, 'time_out': self.timeout, 'username': self.username, 'password': self.password, 'game': self.game, 'num_players': self.num_players, 'num_turns': self.num_turns}) self.bot_thread.start() else: self.bot.stop() self.bot_thread.join() self.bot_thread = None def get_available_games(self): """Requests a list of available games.""" if self.select_game_window: self.bot.get_available_games(host=self.host, port=self.port, time_out=self.timeout) self.after(1000, self.get_available_games) def set_available_games(self, games): """Sets new value for available games list.""" self.available_games = games def set_status_bar(self, value): """Assigns new status bar value and updates it. :param value: string - status bar string value :return: None """ self._status_bar.set(value) self.label.update() def build_map(self, source=None): """Builds and draws new map. :param source: string - source string; could be JSON string or path to *.json file. :return: None """ if source: self.source = source if self.source: self.map = Graph(self.source, weighted=self.weighted.get()) self.set_status_bar('Map title: {}'.format(self.map.name)) self.points, self.lines = self.map.get_coordinates() self.draw_map() def draw_map(self): """Draws map by prepared coordinates.""" self.draw_lines() self.draw_points() def clear_map(self): """Clears previously drawn map and resets coordinates and scales.""" self.canvas.delete('all') self.scale_x, self.scale_y = None, None self.coordinates = {} def redraw_map(self): """Redraws existing map by existing coordinates.""" if self.map: self.coordinates = {} for obj_id in self.canvas_obj.line: self.canvas.delete(obj_id) self.draw_lines() self.redraw_points() def redraw_points(self): """Redraws map points by existing coordinates.""" if self.map: for obj_id, attrs in self.canvas_obj.point.items(): if attrs['text_obj']: self.canvas.delete(attrs['text_obj']) self.canvas.delete(obj_id) self.draw_points() def redraw_trains(self): """Redraws existing trains.""" if self.trains and hasattr(self.canvas_obj, 'train'): for obj_id, attrs in self.canvas_obj.train.items(): self.canvas.delete(attrs['text_obj']) self.canvas.delete(obj_id) self.draw_trains() @prepare_coordinates def draw_points(self): """Draws map points by prepared coordinates.""" point_objs = {} captured_point_idx = self.canvas_obj.point[self.captured_point]['idx'] if self.captured_point else None for idx in self.points.keys(): x, y = self.coordinates[idx] if self.posts and idx in self.posts.keys(): post_type = self.posts[idx]['type'] if post_type == 1: status = '{}/{} {}/{} {}/{}'.format(self.posts[idx]['population'], self.posts[idx]['population_capacity'], self.posts[idx]['product'], self.posts[idx]['product_capacity'], self.posts[idx]['armor'], self.posts[idx]['armor_capacity']) elif post_type == 2: status = '{}/{}'.format(self.posts[idx]['product'], self.posts[idx]['product_capacity']) else: status = '{}/{}'.format(self.posts[idx]['armor'], self.posts[idx]['armor_capacity']) image_id = 0 if post_type == 1 and self.posts[idx]['player_idx'] == self.player_idx else post_type point_id = self.canvas.create_image(x, y, image=self.icons[image_id]) y -= (self.icons[post_type].height() / 2) + self.font_size text_id = self.canvas.create_text(x, y, text=status, font="{} {}".format(self.FONT, self.font_size)) else: post_type = 4 point_id = self.canvas.create_image(x, y, image=self.icons[post_type]) text_id = None point_objs[point_id] = {'idx': idx, 'text_obj': text_id, 'icon': post_type} self.captured_point = point_id if idx == captured_point_idx else self.captured_point self.canvas_obj['point'] = point_objs @prepare_coordinates def draw_lines(self): """Draws map lines by prepared coordinates and shows their weights if self.show_weight is set to 1.""" line_objs, captured_lines_idx = {}, {} if self.captured_lines: for line_id in self.captured_lines.keys(): captured_lines_idx[self.canvas_obj.line[line_id]['idx']] = line_id for idx, attrs in self.lines.items(): x_start, y_start = self.coordinates[attrs['start_point']] x_stop, y_stop = self.coordinates[attrs['end_point']] line_id = self.canvas.create_line(x_start, y_start, x_stop, y_stop) line_objs[line_id] = {'idx': idx, 'weight': attrs['weight'], 'start_point': attrs['start_point'], 'end_point': attrs['end_point'], 'weight_obj': ()} if idx in captured_lines_idx.keys(): self.captured_lines[line_id] = self.captured_lines.pop(captured_lines_idx[idx]) self.canvas_obj['line'] = line_objs self.show_weights() @prepare_coordinates def draw_trains(self): """Draws trains by prepared coordinates.""" trains = {} for train in self.trains.values(): start_point = self.lines[train['line_idx']]['start_point'] end_point = self.lines[train['line_idx']]['end_point'] weight = self.lines[train['line_idx']]['weight'] position = train['position'] x_start, y_start = self.coordinates[start_point] x_end, y_end = self.coordinates[end_point] delta_x, delta_y = int((x_start - x_end) / weight) * position, int((y_start - y_end) / weight) * position x, y = x_start - delta_x, y_start - delta_y if train['cooldown'] > 0: icon = 7 status = None else: icon = 5 if train['player_idx'] == self.player_idx else 6 status = '{}/{}'.format(train['goods'], train['goods_capacity']) indent_y = self.icons[icon].height() / 2 train_id = self.canvas.create_image(x, y - indent_y, image=self.icons[icon]) text_id = self.canvas.create_text(x, y - (2 * indent_y + self.font_size), text=status, font="{} {}".format(self.FONT, self.font_size)) if status else None trains[train_id] = {'icon': icon, 'text_obj': text_id} self.canvas_obj['train'] = trains def show_weights(self): """Shows line weights when self.show_weight is set to 1 and hides them when it is set to 0.""" if not self.canvas_obj: return if self.show_weight.get(): for line in self.canvas_obj.line.values(): if line['weight_obj']: for obj in line['weight_obj']: self.canvas.itemconfigure(obj, state='normal') else: x_start, y_start = self.coordinates[line['start_point']] x_end, y_end = self.coordinates[line['end_point']] x, y = self.midpoint(x_start, y_start, x_end, y_end) value = line['weight'] size = self.font_size r = int(size) * len(str(value)) oval_id = self.canvas.create_oval(x - r, y - r, x + r, y + r, fill=self.BG, width=0) text_id = self.canvas.create_text(x, y, text=value, font="{} {}".format(self.FONT, str(size))) line['weight_obj'] = (oval_id, text_id) else: for line in self.canvas_obj.line.values(): if line['weight_obj']: for obj in line['weight_obj']: self.canvas.itemconfigure(obj, state='hidden') def requests_executor(self): """Dequeues and executes requests. Assigns corresponding label to bot control button.""" if not self.bot.queue.empty(): request_type, request_body = self.bot.queue.get_nowait() if request_type == 99 and request_body: self.open_server_settings() request_body = None if request_body is not None: self.queue_requests[request_type](request_body) else: self.queue_requests[request_type]() if self.bot_thread and self.bot_thread.is_alive(): if self.play.place_info(): self.play.place_forget() self.stop.place(rely=0.99, relx=0.995, anchor=SE) else: if self.stop.place_info(): self.stop.place_forget() self.play.place(rely=0.5, relx=0.5, anchor=CENTER) self.after(50, self.requests_executor) def refresh_map(self, dynamic_objects): """Refreshes map with passed dynamic objects. :param dynamic_objects: dict - dict of dynamic objects :return: None """ for post in dynamic_objects['posts']: self.posts[post['point_idx']] = post for train in dynamic_objects['trains']: self.trains[train['idx']] = train self.redraw_points() self.redraw_trains()
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()
class Scrolling_Area(Frame, object): def __init__(self, master, width=None, anchor=N, height=None, mousewheel_speed = 2, scroll_horizontally=True, xscrollbar=None, scroll_vertically=True, yscrollbar=None, outer_background=None, inner_frame=Frame, **kw): Frame.__init__(self, master, class_=self.__class__) if outer_background: self.configure(background=outer_background) self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1) self._width = width self._height = height self.canvas = Canvas(self, background=outer_background, highlightthickness=0, width=width, height=height) self.canvas.grid(row=0, column=0, sticky=N+E+W+S) if scroll_vertically: if yscrollbar is not None: self.yscrollbar = yscrollbar else: self.yscrollbar = Scrollbar(self, orient=VERTICAL) self.yscrollbar.grid(row=0, column=1,sticky=N+S) self.canvas.configure(yscrollcommand=self.yscrollbar.set) self.yscrollbar['command']=self.canvas.yview else: self.yscrollbar = None if scroll_horizontally: if xscrollbar is not None: self.xscrollbar = xscrollbar else: self.xscrollbar = Scrollbar(self, orient=HORIZONTAL) self.xscrollbar.grid(row=1, column=0, sticky=E+W) self.canvas.configure(xscrollcommand=self.xscrollbar.set) self.xscrollbar['command']=self.canvas.xview else: self.xscrollbar = None self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) self.innerframe = inner_frame(self.canvas, **kw) self.innerframe.pack(anchor=anchor) self.canvas.create_window(0, 0, window=self.innerframe, anchor='nw', tags="inner_frame") self.canvas.bind('<Configure>', self._on_canvas_configure) Mousewheel_Support(self).add_support_to(self.canvas, xscrollbar=self.xscrollbar, yscrollbar=self.yscrollbar) @property def width(self): return self.canvas.winfo_width() @width.setter def width(self, width): self.canvas.configure(width= width) @property def height(self): return self.canvas.winfo_height() @height.setter def height(self, height): self.canvas.configure(height = height) def set_size(self, width, height): self.canvas.configure(width=width, height = height) def _on_canvas_configure(self, event): width = max(self.innerframe.winfo_reqwidth(), event.width) height = max(self.innerframe.winfo_reqheight(), event.height) self.canvas.configure(scrollregion="0 0 %s %s" % (width, height)) self.canvas.itemconfigure("inner_frame", width=width, height=height) def update_viewport(self): self.update() window_width = self.innerframe.winfo_reqwidth() window_height = self.innerframe.winfo_reqheight() if self._width is None: canvas_width = window_width else: canvas_width = min(self._width, window_width) if self._height is None: canvas_height = window_height else: canvas_height = min(self._height, window_height) self.canvas.configure(scrollregion="0 0 %s %s" % (window_width, window_height), width=canvas_width, height=canvas_height) self.canvas.itemconfigure("inner_frame", width=window_width, height=window_height)
class Screen(Observer): def __init__(self, parent, bg="white"): self.canvas = Canvas(parent, bg=bg) self.canvas.bind("<Configure>", self.resize) self.width = int(self.canvas.cget("width")) self.height = int(self.canvas.cget("height")) print("parent", parent.cget("width"), parent.cget("height")) self.magnitude = Scale(parent, length=250, orient="horizontal", label="Magnitude", sliderlength=20, showvalue=0, from_=0, to=10, tickinterval=1, relief="sunken") self.frequency = Scale(parent, length=250, orient="horizontal", label="Frequency", sliderlength=20, showvalue=0, from_=0, to=10, tickinterval=1, relief="sunken") self.phase = Scale(parent, length=250, orient="horizontal", label="Phase", sliderlength=20, showvalue=0, from_=0, to=10, tickinterval=1, relief="sunken") def update(self, model): print("View update") signal = model.get_signal() self.plot_signal(signal) def get_magnitude(self): return self.magnitude def get_frequency(self): return self.frequency def get_phase(self): return self.phase def plot_signal(self, signal, color="red"): w, h = self.canvas.winfo_width(), self.canvas.winfo_height() width, height = int(w), int(h) print(self.canvas.find_withtag("signal")) if self.canvas.find_withtag("signal"): self.canvas.delete("signal") if signal and len(signal) > 1: plot = [(x * width, height / 2.0 * (y + 1)) for (x, y) in signal] signal_id = self.canvas.create_line(plot, fill=color, smooth=1, width=3, tags="signal") return def grid(self, steps): w, h = self.canvas.cget("width"), self.canvas.cget("height") width, height = int(w), int(h) # self.canvas.create_line(10,height/2,width,height/2,arrow="last") # self.canvas.create_line(10,height-5,10,5,arrow="last") step = (width - 10) / steps * 1. for t in range(1, steps + 2): x = t * step self.canvas.create_line(x, 0, x, height) self.canvas.create_line(0, x, width, x) def packing(self): self.canvas.pack() self.magnitude.pack() self.frequency.pack() self.phase.pack() self.canvas.pack(expand=1, fill="both", padx=6) self.magnitude.pack(expand=1, fill="x", padx=2) self.frequency.pack(expand=1, fill="x", padx=2) self.phase.pack(expand=1, fill="x", padx=2) def resize(self, event): wscale = float(event.width) / self.width hscale = float(event.height) / self.height self.width = event.width self.height = event.height print("resize", wscale, hscale) # resize the canvas #self.config(width=self.width, height=self.height) scale_xy = self.width * 1.0 / self.height # rescale all the objects tagged with the "all" tag self.canvas.scale("all", 0, 0, wscale, hscale)
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: self.enter_task(event) 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 global MAP_CANVAS MAP_CANVAS = Canvas(master, width=CANVAS_W, height=CANVAS_H, bg='gray85', highlightthickness=0) MAP_CANVAS.pack(side='right', padx=50) MAP_CANVAS.bind("<Button-1>", callback) global CANVAS_PTR CANVAS_PTR = MAP_CANVAS self.master.update() w = MAP_CANVAS.winfo_width() h = MAP_CANVAS.winfo_height() # Overlay a grid for i in range(0, w, SQ_SIZE): if i != 0: MAP_CANVAS.create_line(i, 0, i, h, dash=1) for i in range(0, h, SQ_SIZE): if i != 0: 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=140, bg=BUTTONS_BKG_COLOUR, highlightthickness=1, highlightbackground='dim grey') buttons_frame.place(x=40, y=230) # 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=270) 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=300) ''' 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 = 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()
class HackPlot(object): def __init__(self, parent, move_mode, show_path, use_event_bars, log_levels): self.canvas = Canvas(parent, bg="white") self.listbox = Listbox(parent, width=20, bg="white", state="disabled", disabledforeground="black") self.canvas.bind("<Configure>", self.redraw) self.canvas.bind("<ButtonPress-1>", self.mousedown) self.canvas.bind("<ButtonRelease-1>", self.mouseup) self.canvas.bind("<Motion>", self.mousemove) self.canvas.bind("<Leave>", self.mouseleave) self.canvas.bind("<ButtonPress-3>", self.cancelzoom) self.move_mode = move_mode self.show_path = show_path self.use_event_bars = use_event_bars self.log_levels = log_levels self.reset() def redraw(self, event): self.canvas.delete("all") self.legend = [] self.draw_boundary() self.zoom_trace = None self.show_textlogs() for name in self.plots: self.draw_plot(name) self.draw_legend() def reset(self): self.x_low = -0.5 self.x_high = 0.5 self.y_low = -0.5 self.y_high = 0.5 self.mouse_start = None self.color_index = 0 self.compute_width_height() self.draw_boundary() self.plots = {} self.legend = [] self.event_bars = [] self.logs = {} self.coord_text = None self.zoom_trace = None self.redraw(None) def compute_width_height(self): self.plot_width = self.x_high - self.x_low self.plot_height = self.y_high - self.y_low # Draw outline of plot area and axis ticks def draw_boundary(self): for x in self.get_ticks(self.x_low, self.x_high): screen_x, _ = self.screen_coords(x, 0) self.canvas.create_line(screen_x, self.canvas.winfo_height() * 0.1, screen_x, self.canvas.winfo_height() * 0.9, fill="light grey") self.canvas.create_text(screen_x, self.canvas.winfo_height() * 0.95, text=str(x)) for y in self.get_ticks(self.y_low, self.y_high): _, screen_y = self.screen_coords(0, y) self.canvas.create_line(self.canvas.winfo_width() * 0.1, screen_y, self.canvas.winfo_width() * 0.9, screen_y, fill="light grey") self.canvas.create_text(self.canvas.winfo_width() * 0.05, screen_y, text=str(y)) self.canvas.create_line(self.canvas.winfo_width() * 0.1, self.canvas.winfo_height() * 0.1, self.canvas.winfo_width() * 0.9, self.canvas.winfo_height() * 0.1, self.canvas.winfo_width() * 0.9, self.canvas.winfo_height() * 0.9, self.canvas.winfo_width() * 0.1, self.canvas.winfo_height() * 0.9, self.canvas.winfo_width() * 0.1, self.canvas.winfo_height() * 0.1) def draw_legend(self): legend_width = 0 legend_height = 0 # Clear the legend, since new plots don't necessarily appear last for oid in self.legend: self.canvas.delete(oid) for name in self.plots: # Width = widest text, increase height with number of plots legend_width = max(legend_width, len(name) * 6) legend_height += 15 # Add some padding legend_width += 10 legend_height += 10 if self.plots != {}: self.legend.append( self.canvas.create_rectangle(self.canvas.winfo_width() - legend_width, 0, self.canvas.winfo_width(), legend_height, fill="white")) index = 0 for name in self.plots: self.legend.append( self.canvas.create_text(self.canvas.winfo_width() - 5, index * 15 + 5, text=name, fill=self.plots[name].color, anchor=NE)) index += 1 def get_ticks(self, bound_low, bound_high): size = bound_high - bound_low # step is size rounded down to next power of 10 step = 10**math.floor(math.log10(size)) # Adjust the step so there are good number of ticks if size / step > 6: step *= 2 elif size / step < 1.2: step /= 5 elif size / step < 2: step /= 2 return [ i * step for i in range(int(math.ceil(bound_low / step)), int(math.ceil(bound_high / step + 1e-3))) ] def screen_coords(self, x, y): screen_x = ((x - self.x_low) / self.plot_width * 0.8 + 0.1) * self.canvas.winfo_width() screen_y = ((self.y_high - y) / self.plot_height * 0.8 + 0.1) * self.canvas.winfo_height() return (screen_x, screen_y) def plot_coords(self, x, y): plot_x = (float(x) / self.canvas.winfo_width() - 0.1) / 0.8 * self.plot_width + self.x_low plot_y = self.y_high - (float(y) / self.canvas.winfo_height() - 0.1) / 0.8 * self.plot_height return (plot_x, plot_y) def add_plot(self, xvals, yvals, name): self.plots[name] = Plot() self.plots[name].xvals = xvals self.plots[name].yvals = yvals self.plots[name].color = colors[self.color_index] self.color_index = (self.color_index + 1) % len(colors) self.draw_plot(name) self.draw_legend() def remove_plot(self, name): for oid in self.plots[name].points: self.canvas.delete(oid) self.plots.pop(name) self.draw_legend() def add_textlog(self, strings, name): # Each entry is pair of (first number in string) and (string with ending newline removed) self.logs[name] = [(int(re.search("\\d+", string).group()), string[:-1]) for string in strings] self.show_textlogs() def remove_textlog(self, name): self.logs.pop(name) self.show_textlogs() def draw_plot(self, name): color = self.plots[name].color points = [] for x, y in itertools.izip(self.plots[name].xvals, self.plots[name].yvals): if x >= self.x_low and x <= self.x_high and y >= self.y_low and y <= self.y_high: screen_x, screen_y = self.screen_coords(x, y) points.append( self.canvas.create_rectangle(screen_x - 1, screen_y - 1, screen_x + 1, screen_y + 1, outline=color)) self.plots[name].points = points def show_textlogs(self): for oid in self.event_bars: self.canvas.delete(oid) self.event_bars = [] # Combine all logs into chronological order logs = [] for _, log in self.logs.iteritems(): logs += log logs.sort() # Needs to be normal state to add and remove elements self.listbox["state"] = NORMAL self.listbox.delete(0, END) for timestamp, string in logs: # Check whether the checkbox matching the start of the string is off level_included = True for level in self.log_levels: if string.startswith(level[1]) and level[0].get() == 0: level_included = False if timestamp >= self.x_low and timestamp <= self.x_high and level_included: if self.show_path.get() == 0: # Log format is [level]time:/path/to/file.cpp:line: message here # To remove directory name, replace first ':' to last '/' before a ':' with a single ':' string = ":".join(re.split(":[^:]*/", string)) self.listbox.insert(END, string) screen_x, _ = self.screen_coords(float(timestamp), 0) if self.use_event_bars.get(): self.event_bars.append( self.canvas.create_line( screen_x, self.canvas.winfo_height() * 0.1, screen_x, self.canvas.winfo_height() * 0.9, fill="grey")) self.listbox["state"] = DISABLED def fit_x(self): self.x_low = 1e100 self.x_high = -1e100 # For x range, check data and text logs for _, plot in self.plots.iteritems(): self.x_low = min(self.x_low, min(plot.xvals)) self.x_high = max(self.x_high, max(plot.xvals)) for _, logs in self.logs.iteritems(): self.x_low = min(self.x_low, logs[0][0]) self.x_high = max(self.x_high, logs[-1][0]) if self.x_low == self.x_high: # Add to range to avoid dividing bx 0 self.x_low -= 0.5 self.x_high += 0.5 elif self.x_low > self.x_high: # There is no data, reset x range self.x_low = -0.5 self.x_high = 0.5 self.compute_width_height() self.redraw(None) def fit_y(self): self.y_low = 1e100 self.y_high = -1e100 for _, plot in self.plots.iteritems(): self.y_low = min(self.y_low, min(plot.yvals)) self.y_high = max(self.y_high, max(plot.yvals)) if self.y_low == self.y_high: # Add to range to avoid dividing by 0 self.y_low -= 0.5 self.y_high += 0.5 elif self.y_low > self.y_high: # There is no data, reset y range self.y_low = -0.5 self.y_high = 0.5 self.compute_width_height() self.redraw(None) def mousedown(self, event): self.mouse_start = self.plot_coords(event.x, event.y) def mouseup(self, event): mouse_end = self.plot_coords(event.x, event.y) if self.mouse_start == None: return if self.mouse_start[0] == mouse_end[0] or self.mouse_start[ 1] == mouse_end[1]: # This would require dividing by 0 self.mouse_start = None return if self.move_mode.get() == "zoomin" and self.mouse_start != None: # Set plot bounds to selection bounds self.x_low = min(self.mouse_start[0], mouse_end[0]) self.x_high = max(self.mouse_start[0], mouse_end[0]) self.y_low = min(self.mouse_start[1], mouse_end[1]) self.y_high = max(self.mouse_start[1], mouse_end[1]) elif self.move_mode.get() == "zoomout" and self.mouse_start != None: selection_x_low = min(self.mouse_start[0], mouse_end[0]) selection_x_high = max(self.mouse_start[0], mouse_end[0]) selection_y_low = min(self.mouse_start[1], mouse_end[1]) selection_y_high = max(self.mouse_start[1], mouse_end[1]) # Set plot bounds such that current bounds fit in selection, ie, # scale zone around selection be ratio of sizes self.x_low -= (selection_x_low - self.x_low) * self.plot_width / ( selection_x_high - selection_x_low) self.x_high += (self.x_high - selection_x_high) * self.plot_width / ( selection_x_high - selection_x_low) self.y_low -= (selection_y_low - self.y_low) * self.plot_height / ( selection_y_high - selection_y_low) self.y_high += (self.y_high - selection_y_high) * self.plot_height / ( selection_y_high - selection_y_low) self.compute_width_height() self.redraw(None) self.mouse_start = None def mousemove(self, event): mouse_end = self.plot_coords(event.x, event.y) if self.move_mode.get() == "pan" and self.mouse_start != None: self.x_low += self.mouse_start[0] - mouse_end[0] self.x_high += self.mouse_start[0] - mouse_end[0] self.y_low += self.mouse_start[1] - mouse_end[1] self.y_high += self.mouse_start[1] - mouse_end[1] self.redraw(None) elif self.move_mode.get() in ["zoomin", "zoomout" ] and self.mouse_start != None: self.canvas.delete(self.zoom_trace) mouse_start_screen = self.screen_coords(self.mouse_start[0], self.mouse_start[1]) bound_left = min(mouse_start_screen[0], event.x) bound_right = max(mouse_start_screen[0], event.x) bound_top = min(mouse_start_screen[1], event.y) bound_bottom = max(mouse_start_screen[1], event.y) self.zoom_trace = self.canvas.create_rectangle( bound_left, bound_top, bound_right, bound_bottom) if self.coord_text != None: self.canvas.delete(self.coord_text) self.coord_text = self.canvas.create_text(10, 10, text="({:.6}, {:.6})".format( mouse_end[0], mouse_end[1]), anchor=NW) def mouseleave(self, event): if self.coord_text != None: self.canvas.delete(self.coord_text) self.coord_text = None self.cancelzoom(None) def cancelzoom(self, event): self.mouse_start = None self.canvas.delete(self.zoom_trace)
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 TkProgessBar(Frame): """ TkListboxMulticolumn component which can display multi-sortable listbox """ def __init__(self, master, cnf={}, **kw): """ Construct a listbox widget with one or many column and label field for header Valid resource names: background, bd, bg, borderwidth, class, colormap, fg, font, foreground, height, highlightbackground, """ Frame.__init__(self, master) self._value = kw.get('value', 0.0) # Create canvas for drawing in self._canvas = Canvas( self, bg=kw.get('bg', 'white'), width=kw.get('width', 300), height=kw.get('height', 20), relief=kw.get('relief', 'sunken'), border=kw.get('border', 1) ) self._canvas.pack(fill='both', expand='yes') # Drawing a rectangle self._rect = self._canvas.create_rectangle( 0, 0, 0, self._canvas.winfo_reqheight(), fill=kw.get('fillcolor', 'blue'), width=0 ) # Drawing a text area self._text = self._canvas.create_text( self._canvas.winfo_reqwidth()/2, self._canvas.winfo_reqheight()/2, text='', fill=kw.get('textcolor', 'gray') ) self.bind('<Configure>', self._update_coords) def _update_coords(self, event): '''Updates the position of the text and rectangle inside the canvas when the size of the widget gets changed.''' # looks like we have to call update_idletasks() twice to make sure # to get the results we expect self._canvas.update_idletasks() self._canvas.coords(self._text, self._canvas.winfo_width()/2, self._canvas.winfo_height()/2) self._canvas.coords(self._rect, 0, 0, self._canvas.winfo_width()*self._value, self._canvas.winfo_height()) self._canvas.update_idletasks() def get(self, first, last=None): """ return percent and text value """ return self._value, self._canvas.itemcget(self._text, 'text') def set(self, value=0.0, text=None): ''' Set different values. ''' #make the value failsafe: if value < 0.0: value = 0.0 elif value > 1.0: value = 1.0 self._value = value if text == None: #if no text is specified use the default percentage string: text = str(int(round(100 * value))) + ' %' self._canvas.coords(self._rect, 0, 0, self._canvas.winfo_width()*value, self._canvas.winfo_height()) self._canvas.itemconfigure(self._text, text=text) self._canvas.update_idletasks()
class Cube(MatrixHelpers): last_x = 0 last_y = 0 def __init__(self, root): self.root = root self.init_data() self.create_canvas() self.create_frame() self.create_control() self.epsilon = lambda d: d * 0.01 def init_data(self): self.cube = self.transpose_matrix([[-100, -100, -100], [-100, 100, -100], [-100, -100, 100], [-100, 100, 100], [ 100, -100, -100], [ 100, 100, -100], [ 100, -100, 100], [ 100, 100, 100]]) # print(self.cube) #[(-100, -100, -100, -100, 100, 100, 100, 100), # (-100, 100, -100, 100, -100, 100, -100, 100), # (-100, -100, 100, 100, -100, -100, 100, 100)] def create_canvas(self): self.canvas = Canvas( self.root, width=400, height=400) self.canvas.pack(fill=BOTH, expand=YES) def create_frame(self): self.frame = Frame( self.root, width=400, height=400) self.frame.pack(fill=BOTH, expand=YES) def create_control(self): self.rotX = Button(self.frame,text="Draw",command=self.rotaX) self.rotX.pack() self.rotX = Button(self.frame,text="Rotate along X",command=self.rotaX) self.rotX.pack() self.rotY = Button(self.frame,text="Rotate along Y",command=self.rotaY) self.rotY.pack() def draw_cube(self): cube_points = [[0, 1, 2, 4], [3, 1, 2, 7], [5, 1, 4, 7], [6, 2, 4, 7]] ''' 2..........6 . . .. . . . . 0..........4 . . 3 . 7 . . . . . . . . 1..........5 ''' w = self.canvas.winfo_width() / 2 h = self.canvas.winfo_height() / 2 self.canvas.delete(ALL) for i in cube_points: for j in i: self.canvas.create_line(self.translate_vector(self.cube[0][i[0]], self.cube[1][i[0]], w, h), self.translate_vector(self.cube[0][j], self.cube[1][j], w, h)) self.canvas.create_text(self.translate_vector(self.cube[0][i[0]], self.cube[1][i[0]], w, h), text=str("{0:.2f}".format(self.cube[0][i[0]])) + " , " + str("{0:.2f}".format(self.cube[1][i[0]])) + " , " + str("{0:.2f}".format(self.cube[2][i[0]]))) self.canvas.create_text(self.translate_vector(self.cube[0][j], self.cube[1][j], w, h), text=str("{0:.2f}".format(self.cube[0][j])) + " , " + str("{0:.2f}".format(self.cube[1][j])) + " , " + str("{0:.2f}".format(self.cube[2][j]))) def rotaX(self): self.cube = self.rotate_along_x(self.epsilon(5), self.cube) self.draw_cube() def draw(self): self.cube = self.rotate_along_x(0, self.cube) self.draw_cube() def rotaY(self): self.cube = self.rotate_along_y(self.epsilon(5), self.cube) self.draw_cube()
class SimulationCanvas( object ): """A canvas where blocks can be dragged around and connected up""" size = ( width, height ) = ( 550, 300 ) def __init__( self, frame ): # Create the canvas self.canvas = Canvas( frame, width=self.width, height=self.height, relief=RIDGE, background=colours["background"], borderwidth=1 ) # Add event handlers for dragable items self.canvas.tag_bind ( "DRAG", "<ButtonPress-1>", self.mouse_down ) #self.canvas.tag_bind ("DRAG", "<ButtonRelease-1>", self.mouse_release) self.canvas.tag_bind ( "DRAG", "<Enter>", self.enter ) self.canvas.tag_bind ( "DRAG", "<Leave>", self.leave ) self.canvas.pack( side=TOP ) # Some default locations self.PREVIEW_WIDTH = 80 self.PREVIEW_LOCATION = ( self.PREVIEW_X, self.PREVIEW_Y ) = ( 15, 30 ) # Draw a "preview" area self.canvas.create_line( self.PREVIEW_WIDTH, 0, self.PREVIEW_WIDTH, self.height, dash=True ) # A dict indexed by unique ID of elements in the canvas. self.blocks = {} def preview_actor( self, codefile ): """ Display a preview of an actor or compisite actor in the canvas, it will be dragable into desired position """ logging.debug( "Creating a preview of %(name)s on simulation canvas." % {'name':codefile.name} ) logging.debug( "Deleting any existing items still tagged 'preview'" ) self.canvas.delete( "preview" ) block = CanvasBlock( self.canvas, codefile, *self.PREVIEW_LOCATION ) self.blocks[block.id] = block def mouse_down( self, event ): logging.debug( "The mouse was pressed at (%d, %d)" % ( event.x, event.y ) ) logging.debug( "The mouse went down on a block. Binding mouse release..." ) selected = self.canvas.gettags( "current" ) logging.debug( "Currently selected items tags are %s" % selected.__repr__() ) self.selected_name = [tag for tag in selected if tag.startswith( "name:" ) ][0][5:] self.selected_id = [tag for tag in selected if tag.startswith( "id:" ) ][0][3:] self.selected_type = [tag for tag in selected if tag.startswith( "type:" ) ][0][5:] logging.debug( "Block selected was %s with id:%s" % ( self.selected_name, self.selected_id ) ) #self.canvas.addtag( 'Selected', 'withtag', self.selected_id ) logging.debug( "Current blocks are: %s" % self.blocks ) #self.blocks[block_id].set_colour( colours['selected'] ) if self.selected_type == "block" or self.selected_type == "text": self.blocks[self.selected_id].select(event.x, event.y) self.canvas.bind( "<ButtonRelease-1>", self.block_move_mouse_release ) elif self.selected_type.startswith("input") or self.selected_type.startswith("output"): self.blocks[self.selected_id].select_port(self.selected_type) self.canvas.bind( "<ButtonRelease-1>", self.port_connect_mouse_release ) else: logging.info("Tried to select %s" % self.selected_type) def block_move_mouse_release( self, event ): logging.debug( "The mouse was released at (%d, %d)" % ( event.x, event.y ) ) self.canvas.bind( "<ButtonRelease-1>", lambda e: None ) if event.x >= 0 and event.x <= self.canvas.winfo_width() \ and event.y >= 0 and event.y <= self.canvas.winfo_height(): logging.debug( "Valid move inside canvas. Relocating block." ) self.blocks[self.selected_id].move_to(event.x, event.y) if event.x >= self.PREVIEW_WIDTH: if self.blocks[self.selected_id].is_preview(): logging.info( "Moved out of preview zone, adding new component to model" ) #TODO HERE - add to model compiler or what ever... self.blocks[self.selected_id].unselect() else: self.blocks[self.selected_id].preview() else: logging.info( "Invalid move." ) def port_connect_mouse_release( self, event ): logging.debug( "The mouse was released at (%d, %d)" % ( event.x, event.y ) ) self.canvas.bind( "<ButtonRelease-1>", lambda e: None ) if event.x >= 0 and event.x <= self.canvas.winfo_width() \ and event.y >= 0 and event.y <= self.canvas.winfo_height(): logging.debug( "Valid location inside canvas." ) event.widget.itemconfigure( "Selected", fill="#000000" ) event.widget.itemconfigure( "type:text", fill="#000000" ) #block = self.canvas.gettags("Selected") #logging.debug("Block moved was made up of these components: %s" % block.__repr__()) self.canvas.dtag( "Selected", "Selected" ) else: logging.info( "Invalid wiring." ) def enter( self, event ): logging.debug( "Enter" ) def leave( self, event ): logging.debug( "Leaving" )
class Scrolling_Area(Frame, object): def __init__(self, master, width=None, anchor=N, height=None, mousewheel_speed = 2, scroll_horizontally=True, xscrollbar=None, scroll_vertically=True, yscrollbar=None, background=None, inner_frame=Frame, **kw): Frame.__init__(self, master, class_="Scrolling_Area", background=background) self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1) self._width = width self._height = height self.canvas = Canvas(self, background=background, highlightthickness=0, width=width, height=height) self.canvas.grid(row=0, column=0, sticky=N+E+W+S) if scroll_vertically: if yscrollbar is not None: self.yscrollbar = yscrollbar else: self.yscrollbar = Scrollbar(self, orient=VERTICAL) self.yscrollbar.grid(row=0, column=1,sticky=N+S) self.canvas.configure(yscrollcommand=self.yscrollbar.set) self.yscrollbar['command']=self.canvas.yview else: self.yscrollbar = None if scroll_horizontally: if xscrollbar is not None: self.xscrollbar = xscrollbar else: self.xscrollbar = Scrollbar(self, orient=HORIZONTAL) self.xscrollbar.grid(row=1, column=0, sticky=E+W) self.canvas.configure(xscrollcommand=self.xscrollbar.set) self.xscrollbar['command']=self.canvas.xview else: self.xscrollbar = None self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) self.innerframe = inner_frame(self.canvas, **kw) self.innerframe.pack(anchor=anchor) self.canvas.create_window(0, 0, window=self.innerframe, anchor='nw', tags="inner_frame") self.canvas.bind('<Configure>', self._on_canvas_configure) Mousewheel_Support(self).add_support_to(self.canvas, xscrollbar=self.xscrollbar, yscrollbar=self.yscrollbar) @property def width(self): return self.canvas.winfo_width() @width.setter def width(self, width): self.canvas.configure(width= width) @property def height(self): return self.canvas.winfo_height() @height.setter def height(self, height): self.canvas.configure(height = height) def set_size(self, width, height): self.canvas.configure(width=width, height = height) def _on_canvas_configure(self, event): width = max(self.innerframe.winfo_reqwidth(), event.width) height = max(self.innerframe.winfo_reqheight(), event.height) self.canvas.configure(scrollregion="0 0 %s %s" % (width, height)) self.canvas.itemconfigure("inner_frame", width=width, height=height) def update_viewport(self): self.update() window_width = self.innerframe.winfo_reqwidth() window_height = self.innerframe.winfo_reqheight() if self._width is None: canvas_width = window_width else: canvas_width = min(self._width, window_width) if self._height is None: canvas_height = window_height else: canvas_height = min(self._height, window_height) self.canvas.configure(scrollregion="0 0 %s %s" % (window_width, window_height), width=canvas_width, height=canvas_height) self.canvas.itemconfigure("inner_frame", width=window_width, height=window_height)
class Screen(Observer): def __init__(self, parent, bg="white"): self.menu_bar = MenuBar(parent) self.canvas = Canvas(parent, bg=bg, name="screen") self.frameControl = Frame(parent) self.frameLabelSignals = LabelFrame(self.frameControl, text="Signaux", padx=20, pady=20) self.frameLabelMode = LabelFrame(self.frameControl, text="Mode", padx=20, pady=20) self.panelControl = ttk.Notebook(self.frameLabelSignals) self.checkbox_signalX = Checkbutton(self.frameLabelMode, text="Signal X") self.checkbox_signalY = Checkbutton(self.frameLabelMode, text="Signal Y") self.checkbox_XY = Checkbutton(self.frameLabelMode, text="XY") self.panel_control_page = [] # contient les références de mes curseurs for p in parent.get_models(): self.addPage(p.get_name()) def addPage(self, name): page = ttk.Frame(self.panelControl) self.panelControl.add(page, text='signal ' + name) visible_checkbox = Checkbutton(page, text="Afficher") magnitude = Scale(page, length=250, orient="horizontal", label="Amplitude", sliderlength=20, showvalue=0, from_=0, to=5, tickinterval=1, name="magnitudeScale") frequency = Scale(page, length=250, orient="horizontal", label="Frequency", sliderlength=20, showvalue=0, from_=0, to=25, tickinterval=5, name="frequencyScale") phase = Scale(page, length=250, orient="horizontal", label="Phase", sliderlength=20, showvalue=0, from_=0, to=20, tickinterval=5, name="phaseScale") visible_checkbox.pack(fill="x", pady=6) magnitude.pack(expand=1, fill="both", pady=6) frequency.pack(expand=1, fill="both", pady=6) phase.pack(expand=1, fill="both", pady=6) self.panel_control_page.append({ 'visible': visible_checkbox, 'magnitude': magnitude, 'frequency': frequency, 'phase': phase }) def update(self, model): if type(model) == list: for i, m in enumerate(model): signal = m.get_signal() #self.plot_signal(signal, m.get_color()) self.plot_signal(m) else: signal = model.get_signal() self.plot_signal(model) self.grid(6, 8) def get_panel_control_index(self): return self.panelControl.index('current') def get_canvas(self): return self.canvas def get_panel_control_page(self): return self.panel_control_page def get_magnitude(self, index): return self.panel_control_page[index]['magnitude'] def get_frequency(self, index): return self.panel_control_page[index]['frequency'] def get_phase(self, index): return self.panel_control_page[index]['phase'] def get_visible(self, index): return self.panel_control_page[index]['visible'] def get_checkbox_signalX(self): return self.checkbox_signalX def get_checkbox_signalY(self): return self.checkbox_signalY def get_checkbox_XY(self): return self.checkbox_XY def plot_signal(self, model): w, h = self.canvas.winfo_width(), self.canvas.winfo_height() width, height = int(w), int(h) signal = model.get_signal() name = model.get_name() color = model.get_color() if self.canvas.find_withtag("signal" + name): self.canvas.delete("signal" + name) if signal and len(signal) > 1 and model.is_visible(): plot = [(x * width, height / 2.0 * (y + 1)) for (x, y) in signal] self.canvas.create_line(plot, fill=color, smooth=1, width=3, tags="signal" + name) self.canvas.scale("signal" + name, width / 2, height / 2, 1.0, 0.25) def grid(self, row, col): w, h = self.canvas.winfo_width(), self.canvas.winfo_height() width, height = int(w), int(h) if self.canvas.find_withtag("grid"): self.canvas.delete("grid") # dessin des axes X et Y self.canvas.create_line(5, height / 2, width, height / 2, arrow="last", tags=('grid', 'axe-x')) self.canvas.create_line(width / 2, height - 5, width / 2, 5, arrow="last", tags=('grid', 'axe-y')) # dessin des lignes verticales for c in range(1, int(row / 2) + 1): stepW = width / row xd = width / 2 + c * stepW xg = width / 2 - c * stepW #Creation des lignes verticales self.canvas.create_line(xd, height - 5, xd, 5, dash=1, tags=('grid', 'vertical-line'), fill='grey') #cote droit self.canvas.create_line(xg, height - 5, xg, 5, dash=1, tags=('grid', 'vertical-line'), fill='grey') #cote gauche #Creation des tirets sur x self.canvas.create_line(xd, height / 2 - 4, xd, height / 2 + 4, tags=('grid', 'horizontal-line'), fill='grey') self.canvas.create_line(xg, height / 2 - 4, xg, height / 2 + 4, tags=('grid', 'horizontal-line'), fill='grey') # dessin des lignes horizontales for r in range(1, int(col / 2) + 1): stepH = height / col yB = height / 2 + r * stepH yH = height / 2 - r * stepH #Creation des lignes horizontales self.canvas.create_line(5, yB, width, yB, dash=1, tags=('grid', 'horizontal-line'), fill='grey') self.canvas.create_line(5, yH, width, yH, dash=1, tags=('grid', 'horizontal-line'), fill='grey') #Creation des tirets sur y self.canvas.create_line(width / 2 - 4, yB, width / 2 + 4, yB, tags=('grid', 'vertical-line'), fill='grey') self.canvas.create_line(width / 2 - 4, yH, width / 2 + 4, yH, tags=('grid', 'vertical-line'), fill='grey') def packing(self): self.menu_bar.pack(fill='x') self.canvas.pack(side=LEFT, expand=1, fill="both", padx=6, pady=6) self.panelControl.pack(side=RIGHT, expand=1, fill="both", pady=6) self.frameLabelSignals.pack(expand=1, fill="both") self.frameLabelMode.pack(expand=1, fill="both") self.checkbox_signalX.pack(side=LEFT) self.checkbox_signalY.pack(side=LEFT) self.checkbox_XY.pack(side=RIGHT) self.frameControl.pack(side=RIGHT, expand=1, fill="both", pady=6)
class SimulationCanvas(object): """A canvas where blocks can be dragged around and connected up""" size = (width, height) = (550, 300) def __init__(self, frame): # Create the canvas self.canvas = Canvas(frame, width=self.width, height=self.height, relief=RIDGE, background=colours["background"], borderwidth=1) # Add event handlers for dragable items self.canvas.tag_bind("DRAG", "<ButtonPress-1>", self.mouse_down) #self.canvas.tag_bind ("DRAG", "<ButtonRelease-1>", self.mouse_release) self.canvas.tag_bind("DRAG", "<Enter>", self.enter) self.canvas.tag_bind("DRAG", "<Leave>", self.leave) self.canvas.pack(side=TOP) # Some default locations self.PREVIEW_WIDTH = 80 self.PREVIEW_LOCATION = (self.PREVIEW_X, self.PREVIEW_Y) = (15, 30) # Draw a "preview" area self.canvas.create_line(self.PREVIEW_WIDTH, 0, self.PREVIEW_WIDTH, self.height, dash=True) # A dict indexed by unique ID of elements in the canvas. self.blocks = {} def preview_actor(self, codefile): """ Display a preview of an actor or compisite actor in the canvas, it will be dragable into desired position """ logging.debug("Creating a preview of %(name)s on simulation canvas." % {'name': codefile.name}) logging.debug("Deleting any existing items still tagged 'preview'") self.canvas.delete("preview") block = CanvasBlock(self.canvas, codefile, *self.PREVIEW_LOCATION) self.blocks[block.id] = block def mouse_down(self, event): logging.debug("The mouse was pressed at (%d, %d)" % (event.x, event.y)) logging.debug( "The mouse went down on a block. Binding mouse release...") selected = self.canvas.gettags("current") logging.debug("Currently selected items tags are %s" % selected.__repr__()) self.selected_name = [ tag for tag in selected if tag.startswith("name:") ][0][5:] self.selected_id = [tag for tag in selected if tag.startswith("id:")][0][3:] self.selected_type = [ tag for tag in selected if tag.startswith("type:") ][0][5:] logging.debug("Block selected was %s with id:%s" % (self.selected_name, self.selected_id)) #self.canvas.addtag( 'Selected', 'withtag', self.selected_id ) logging.debug("Current blocks are: %s" % self.blocks) #self.blocks[block_id].set_colour( colours['selected'] ) if self.selected_type == "block" or self.selected_type == "text": self.blocks[self.selected_id].select(event.x, event.y) self.canvas.bind("<ButtonRelease-1>", self.block_move_mouse_release) elif self.selected_type.startswith( "input") or self.selected_type.startswith("output"): self.blocks[self.selected_id].select_port(self.selected_type) self.canvas.bind("<ButtonRelease-1>", self.port_connect_mouse_release) else: logging.info("Tried to select %s" % self.selected_type) def block_move_mouse_release(self, event): logging.debug("The mouse was released at (%d, %d)" % (event.x, event.y)) self.canvas.bind("<ButtonRelease-1>", lambda e: None) if event.x >= 0 and event.x <= self.canvas.winfo_width() \ and event.y >= 0 and event.y <= self.canvas.winfo_height(): logging.debug("Valid move inside canvas. Relocating block.") self.blocks[self.selected_id].move_to(event.x, event.y) if event.x >= self.PREVIEW_WIDTH: if self.blocks[self.selected_id].is_preview(): logging.info( "Moved out of preview zone, adding new component to model" ) #TODO HERE - add to model compiler or what ever... self.blocks[self.selected_id].unselect() else: self.blocks[self.selected_id].preview() else: logging.info("Invalid move.") def port_connect_mouse_release(self, event): logging.debug("The mouse was released at (%d, %d)" % (event.x, event.y)) self.canvas.bind("<ButtonRelease-1>", lambda e: None) if event.x >= 0 and event.x <= self.canvas.winfo_width() \ and event.y >= 0 and event.y <= self.canvas.winfo_height(): logging.debug("Valid location inside canvas.") event.widget.itemconfigure("Selected", fill="#000000") event.widget.itemconfigure("type:text", fill="#000000") #block = self.canvas.gettags("Selected") #logging.debug("Block moved was made up of these components: %s" % block.__repr__()) self.canvas.dtag("Selected", "Selected") else: logging.info("Invalid wiring.") def enter(self, event): logging.debug("Enter") def leave(self, event): logging.debug("Leaving")
class Viewer(Frame): def __init__(self, master,x=600,y=200, onLeft=None, onRight=None, **kwargs): self.root=master self.xsize=x self.ysize=y self.onLeft=onLeft self.onRight=onRight self.ratio=100. Frame.__init__(self, master,width=x,height=y, **kwargs) self.canvas = Canvas(self, width=x, height=y, background="white") self.xsb = Scrollbar(self, orient="horizontal", command=self.canvas.xview) self.ysb = Scrollbar(self, orient="vertical", command=self.canvas.yview) self.canvas.configure(yscrollcommand=self.ysb.set, xscrollcommand=self.xsb.set) self.canvas.configure(scrollregion=(0,0,x,y)) self.xsb.grid(row=1, column=0, sticky="ew") self.ysb.grid(row=0, column=1, sticky="ns") self.canvas.grid(row=0, column=0, sticky="nsew") self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(0, weight=1) self.canvas.bind("<Button-1>", self.clickL) self.canvas.bind("<Button-3>", self.clickR) # This is what enables using the mouse: self.canvas.bind("<ButtonPress-1>", self.move_start) self.canvas.bind("<B1-Motion>", self.move_move) #linux scroll self.canvas.bind("<Button-4>", self.zoomerP) self.canvas.bind("<Button-5>", self.zoomerM) self.canvas.bind_all("<Prior>", self.zoomerP) self.canvas.bind_all("<Next>", self.zoomerM) self.canvas.bind_all("E", self.zoomExtens) #windows scroll self.canvas.bind_all("<MouseWheel>",self.zoomer) def reset(self): pass def set_title(self, title): self.root.title( title) #move def move_start(self, event): self.canvas.scan_mark(event.x, event.y) return True def move_move(self, event): self.canvas.scan_dragto(event.x, event.y, gain=1) return True #windows zoom def zoomer(self,event): if (event.delta > 0): self.ratio *= 1.1 elif (event.delta < 0): self.ratio *= 0.9 self.redraw() def redraw(self): self.canvas.delete("all") self.canvas.configure(scrollregion = self.canvas.bbox("all")) def zoomExtens(self, *args): x0,y0,x1,y1 = self.canvas.bbox("all") xlen=x1-x0 ylen=y1-y0 height=self.canvas.winfo_height() width=self.canvas.winfo_width() unfit=min(width/float(xlen), height/float(ylen)) self.ratio*=unfit self.redraw() # """" if xlen and ylen: self ratio*= self.canvas.scale("all", xlen/2., ylen/2., float(self.xsize)/xlen, float(self.ysize)/ylen) self.canvas.configure(scrollregion = self.canvas.bbox("all")) """ #linux zoom def zoomerP(self,event): self.canvas.scale("all", event.x, event.y, 1.1, 1.1) self.canvas.configure(scrollregion = self.canvas.bbox("all")) def zoomerM(self,event): self.canvas.scale("all", event.x, event.y, 0.9, 0.9) self.canvas.configure(scrollregion = self.canvas.bbox("all")) def pose2p(self, pose): x,y=pose[:2] return int(x*self.ratio), -int(y*self.ratio) def line2p(self, line): if type(line[0]) in (float, int): line=zip(line[::2],line[1::2]) return map(self.pose2p, line) def p2m(self, x, y): return x/self.ratio, -y/self.ratio def create_line(self, coords, **kwargs): return self.canvas.create_line(self.line2p(coords), **kwargs) def create_polygon(self, coords, **kwargs): return self.canvas.create_polygon(self.line2p(coords), **kwargs) def delete(self, object): self.canvas.delete(object) def clickL(self, event): if self.onLeft: x,y=self.p2m(int(self.canvas.canvasx(event.x)), int(self.canvas.canvasy(event.y))) self.onLeft(x,y) return True def clickR(self, event): if self.onRight: x,y=self.p2m(int(self.canvas.canvasx(event.x)), int(self.canvas.canvasy(event.y))) self.onRight(x,y) return True