class GUI(): def __init__(self): self.root = ThemedTk(theme="radiance") INIT_WIDTH, INIT_HEIGHT = self.root.winfo_screenwidth( ), self.root.winfo_screenheight() boldStyle = ttk.Style() boldStyle.configure("Bold.TButton", font=('Sans', '12', 'bold')) #icon_loc = os.path.join(os.getcwd(),ICON_NAME) #img = ImageTk.PhotoImage(master = self.root, file=icon_loc) #self.root.wm_iconbitmap(img) #self.root.ttk.call('wm', 'iconphoto', self.root._w, img) self.root.title("Form Labeller") self.root.maxsize(INIT_WIDTH, INIT_HEIGHT) self.supported_formats = SUPPORTED_FORMATS self.left_frame = Frame(self.root, width=BUTTON_WIDTH) self.top_frame1 = Frame(self.left_frame, width=BUTTON_WIDTH, height=int(INIT_HEIGHT / 2)) self.top_frame = Frame(self.left_frame, width=BUTTON_WIDTH, height=INIT_HEIGHT - int(INIT_HEIGHT / 2)) self.bottom_frame = Frame(self.root, width=INIT_WIDTH - BUTTON_WIDTH) self.load_image_directory_button = Button(self.top_frame1, text='Open Folder', command=self.load_directory, width=int(BUTTON_WIDTH), style="Bold.TButton") self.load_image_directory_button.grid(row=OPEN_FOLDER_ROW, columnspan=2, sticky=tk.W + tk.E) self.prev_img_button = Button(self.top_frame1, text='← Prev', command=self.previous_img, state=tk.DISABLED, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.prev_img_button.grid(row=PREV_ROW, column=0, sticky=tk.W + tk.E) self.next_img_button = Button(self.top_frame1, text='Next → ', command=self.next_img, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.next_img_button.grid(row=NEXT_COL, column=1, sticky=tk.W + tk.E) self.save_image_button = Button(self.top_frame1, text='Save ', command=self.saver, width=int(BUTTON_WIDTH), style="Bold.TButton") self.save_image_button.grid(row=SAVE_ROW, columnspan=2, sticky=tk.W + tk.E) self.delete_poly_button = Button(self.top_frame, text='Delete Selected', command=self.delete_selected, width=int(BUTTON_WIDTH), style="Bold.TButton") self.delete_poly_button.grid(row=DEL_SELECTED_ROW, columnspan=2, sticky=tk.W + tk.E) self.type_choices = TYPE_CHOICES self.variable = StringVar(self.top_frame) self.variable.set(self.type_choices[0]) self.type_options = OptionMenu(self.top_frame, self.variable, *self.type_choices, style="Bold.TButton") self.type_options.config(width=int(BUTTON_WIDTH / 2)) self.type_options.grid(row=DROP_DOWN_ROW, column=0) self.save_type_button = Button(self.top_frame, text='Save Type', command=self.save_type, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.save_type_button.grid(row=SAVE_TYPE_ROW, column=1, sticky=tk.W + tk.E) self.deselect_all_button = Button(self.top_frame, text='Deselect All', command=self.deselect_all, width=BUTTON_WIDTH, style="Bold.TButton") self.deselect_all_button.grid(row=DESELECT_ALL_ROW, columnspan=2, sticky=tk.W + tk.E) self.select_all_button = Button(self.top_frame, text='Select All', command=self.select_all, width=BUTTON_WIDTH, style="Bold.TButton") self.select_all_button.grid(row=SELECT_ALL_ROW, columnspan=2, sticky=tk.W + tk.E) self.draw_poly_button = Button(self.top_frame, text='Draw Poly', command=self.draw_poly_func, width=BUTTON_WIDTH, style="Bold.TButton") self.draw_poly_button.grid(row=DRAW_POLY_ROW, columnspan=2, sticky=tk.W + tk.E) self.draw_rect_button = Button(self.top_frame, text='Draw Rectangle', command=self.draw_rect_func, width=BUTTON_WIDTH, style="Bold.TButton") self.draw_rect_button.grid(row=DRAW_RECT_ROW, columnspan=2, sticky=tk.W + tk.E) self.delete_all_button = Button(self.top_frame, text='Delete All', command=self.delete_all, width=BUTTON_WIDTH, style="Bold.TButton") self.save_poly_button = Button(self.top_frame, text='Save Poly', command=self.save_drawing, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.discard_poly_button = Button(self.top_frame, text='Discard Poly', command=self.discard_drawing, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.save_rect_button = Button(self.top_frame, text='Save Rect', command=self.save_drawing, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.discard_rect_button = Button(self.top_frame, text='Discard Rect', command=self.discard_drawing, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.show_type_button = Button(self.top_frame, text='Show Type', command=self.show_type, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.show_type_button.grid(row=SHOW_TYPE_ROW, column=0, columnspan=1, sticky=tk.W + tk.E) self.hide_type_button = Button(self.top_frame, text='Hide Type', command=self.hide_type, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.hide_type_button.grid(row=HIDE_TYPE_ROW, columnspan=1, column=1, sticky=tk.W + tk.E) self.make_tight_button = Button(self.top_frame, text='Make Tight', command=self.make_tight, width=int(BUTTON_WIDTH / 2), style="Bold.TButton") self.make_tight_button.grid(row=MAKE_TIGHT_ROW, columnspan=2, column=0, sticky=tk.W + tk.E) self.threshold_scale = Scale(self.top_frame, from_=0, to=255, orient=HORIZONTAL, width=int(BUTTON_WIDTH / 2), label="Binary Threshold") self.threshold_scale.set(128) self.threshold_scale.grid(row=THRESHOLD_ROW, columnspan=2, column=0, sticky=tk.W + tk.E) self.tight_save_button = Button(self.top_frame, text='Accept Tight', command=self.save_tight) self.tight_discard_button = Button(self.top_frame, text='Discard Tight', command=self.discard_tight) self.canvas = Canvas(self.bottom_frame, width=INIT_WIDTH - BUTTON_WIDTH, height=INIT_HEIGHT, borderwidth=1) self.image_name = None #self.image_path = os.path.join('imgs','img1.jpg') self.image_dir = None self.images_in_dir = None self.curr_idx = None self.img_cnv = None #self.img_cnv = ImageOnCanvas(self.root,self.canvas,self.image_path) self.drawing_obj = None self.tight_box_obj = None self.left_frame.pack(side=tk.LEFT) self.top_frame1.pack(side=tk.TOP) self.top_frame.pack(side=tk.BOTTOM) self.bottom_frame.pack(side=tk.LEFT) self.canvas.pack() self.hide_buttons() self.load_image_directory_button.config(state="normal") def save_tight(self): self.tight_box_obj.save_tight_box() self.tight_save_button.grid_forget() self.tight_discard_button.grid_forget() self.make_tight_button.grid(row=MAKE_TIGHT_ROW, columnspan=2, sticky=tk.W + tk.E) self.show_buttons() self.tight_box_obj = None def discard_tight(self): self.tight_box_obj.discard_tight_box() self.tight_save_button.grid_forget() self.tight_discard_button.grid_forget() self.make_tight_button.grid(row=MAKE_TIGHT_ROW, columnspan=2, sticky=tk.W + tk.E) self.show_buttons() self.tight_box_obj = None def show_type(self): for poly in self.img_cnv.polygons: if poly.select_poly: poly.show_type() def hide_type(self): for poly in self.img_cnv.polygons: poly.unshow_type() def hide_buttons(self): self.load_image_directory_button.config(state=tk.DISABLED) self.save_image_button.config(state=tk.DISABLED) self.delete_poly_button.config(state=tk.DISABLED) self.save_type_button.config(state=tk.DISABLED) self.deselect_all_button.config(state=tk.DISABLED) self.select_all_button.config(state=tk.DISABLED) self.delete_all_button.config(state=tk.DISABLED) self.show_type_button.config(state=tk.DISABLED) self.hide_type_button.config(state=tk.DISABLED) self.make_tight_button.config(state=tk.DISABLED) def show_buttons(self): self.load_image_directory_button.config(state="normal") self.save_image_button.config(state="normal") self.delete_poly_button.config(state="normal") self.save_type_button.config(state="normal") self.deselect_all_button.config(state="normal") self.select_all_button.config(state="normal") self.delete_all_button.config(state="normal") self.show_type_button.config(state="normal") self.hide_type_button.config(state="normal") self.draw_poly_button.config(state="normal") self.draw_rect_button.config(state="normal") self.make_tight_button.config(state="normal") def select_all(self): for poly in self.img_cnv.polygons: poly.select_polygon() def deselect_all(self): self.hide_type() for poly in self.img_cnv.polygons: poly.deselect_poly() def delete_all(self): result = messagebox.askyesno("Confirm Delete All", "Delete All Annotations?") if not result: return self.select_all() self.delete_selected() #self.img_cnv.polygons_mutex.acquire() #for poly in self.img_cnv.polygons: # poly.delete_self() #self.img_cnv.polygons_mutex.release() def save_type(self): selected_option = self.variable.get() self.img_cnv.polygons_mutex.acquire() for poly in self.img_cnv.polygons: if poly.select_poly == True: if selected_option == "None": poly.poly_type = None else: poly.poly_type = selected_option #poly.unshow_type() #poly.show_type() self.img_cnv.polygons_mutex.release() self.variable.set(self.type_choices[0]) #self.deselect_all() def load_new_img(self): self.canvas.delete('all') self.img_cnv = None path = os.path.join(self.image_dir, self.image_name) self.img_cnv = ImageOnCanvas(self.root, self.canvas, path) logger("LOADED: " + self.img_cnv.image_path) def load_directory(self): while True: selection = filedialog.askdirectory() if selection == () or selection == '': return self.root.directory = selection self.image_dir = self.root.directory file_names = os.listdir(self.image_dir) self.images_in_dir = [] self.curr_idx = None self.image_name = None for name in file_names: if name.split('.')[-1] in self.supported_formats: self.images_in_dir.append(name) if len(self.images_in_dir) == 0: self.pop_up("No supported images in the selected directory") else: break self.show_buttons() self.next_img() def pop_up(self, text): top = Toplevel() top.title("ERROR") msg = Message(top, text=text) msg.pack() button = Button(top, text="Dismiss", command=top.destroy) button.pack() def next_img(self): if self.curr_idx == None: self.curr_idx = -1 self.curr_idx = self.curr_idx + 1 if self.curr_idx >= len(self.images_in_dir): self.pop_up("Done with Images in this directory") self.curr_idx = self.curr_idx - 1 return if self.curr_idx > 0: self.prev_img_button.config(state="normal") self.image_name = self.images_in_dir[self.curr_idx] self.load_new_img() self.root.title("Form Labeller - " + self.image_name + "(" + str(self.curr_idx + 1) + "/" + str(len(self.images_in_dir)) + ")") def previous_img(self): if self.curr_idx == 1: self.curr_idx = -1 self.prev_img_button.config(state=tk.DISABLED) else: self.curr_idx = self.curr_idx - 2 self.next_img() def delete_selected(self): to_be_deleted = [] for i, poly in enumerate(self.img_cnv.polygons): if poly.select_poly == True: poly.delete_self() to_be_deleted.append(i) j = 0 for idx in to_be_deleted: self.img_cnv.polygons.pop(idx - j) self.img_cnv.bbs.pop(idx - j) self.img_cnv.poly_type.pop(idx - j) j = j + 1 def start_gui(self): self.root.mainloop() def saver(self): logger("Saving: " + self.img_cnv.image_path) self.save_image_button.config(state=tk.DISABLED) self.img_cnv.save_json(self.root.directory) self.save_image_button.config(state="normal") def draw_poly_func(self): self.deselect_all() self.img_cnv.drawing_polygon = True self.draw_poly_button.grid_forget() self.save_poly_button.grid(row=DRAW_POLY_ROW, column=0, sticky=tk.W + tk.E) self.discard_poly_button.grid(row=DRAW_POLY_ROW, column=1, sticky=tk.W + tk.E) self.hide_buttons() self.draw_rect_button.config(state=tk.DISABLED) self.drawing_obj = DrawPoly(self.bottom_frame, self.canvas, self.img_cnv, RADIUS) def draw_rect_func(self): self.deselect_all() self.img_cnv.drawing_polygon = True self.draw_rect_button.grid_forget() self.save_rect_button.grid(row=DRAW_RECT_ROW, column=0, sticky=tk.W + tk.E) self.discard_rect_button.grid(row=DRAW_RECT_ROW, column=1, sticky=tk.W + tk.E) self.hide_buttons() self.draw_poly_button.config(state=tk.DISABLED) self.drawing_obj = DrawRect(self.bottom_frame, self.canvas, self.img_cnv, RADIUS) def save_drawing(self): self.show_buttons() self.img_cnv.drawing_polygon = False new_poly_pts = self.drawing_obj.pt_coords print("Trying to save polygon with pts:", str(new_poly_pts)) for pt in self.drawing_obj.points: self.canvas.delete(pt) if self.img_cnv.scale_factor != None: for i in range(len(new_poly_pts)): for j in range(2): new_poly_pts[i][ j] = new_poly_pts[i][j] / self.img_cnv.scale_factor self.img_cnv.add_poly(new_poly_pts) #self.img_cnv.bbs.append(new_poly_pts) #self.img_cnv.draw_bbs([self.img_cnv.bbs[-1]]) #debug (1, str(type(self.drawing_obj))) if isinstance(self.drawing_obj, DrawRect): self.save_rect_button.grid_forget() self.discard_rect_button.grid_forget() self.draw_rect_button.grid(row=DRAW_RECT_ROW, columnspan=2, sticky=tk.W + tk.E) elif isinstance(self.drawing_obj, DrawPoly): self.save_poly_button.grid_forget() self.discard_poly_button.grid_forget() self.draw_poly_button.grid(row=DRAW_POLY_ROW, columnspan=2, sticky=tk.W + tk.E) self.drawing_obj.delete_self() self.drawing_obj = None def discard_drawing(self): self.show_buttons() self.img_cnv.drawing_polygon = False #for pt in self.drawing_obj.points: # self.canvas.delete(pt) self.drawing_obj.delete_self() if isinstance(self.drawing_obj, DrawRect): self.save_rect_button.grid_forget() self.discard_rect_button.grid_forget() self.draw_rect_button.grid(row=DRAW_RECT_ROW, columnspan=2, sticky=tk.W + tk.E) elif isinstance(self.drawing_obj, DrawPoly): self.save_poly_button.grid_forget() self.discard_poly_button.grid_forget() self.draw_poly_button.grid(row=DRAW_POLY_ROW, columnspan=2, sticky=tk.W + tk.E) self.drawing_obj = None def make_tight(self): self.hide_buttons() self.tight_box_obj = TightBox(self.root, self.img_cnv, self.threshold_scale.get()) self.tight_box_obj.tight_box() self.make_tight_button.grid_forget() self.tight_save_button.grid(row=MAKE_TIGHT_ROW, column=0, columnspan=1, sticky=tk.W + tk.E) self.tight_discard_button.grid(row=MAKE_TIGHT_ROW, column=1, columnspan=1, sticky=tk.W + tk.E)
class GUI(Frame): def __init__(self, parent): Frame.__init__(self, parent, name="frame") self.parent = parent self.initUI() def getFilePath(self): currdir = os.getcwd() tempdir = filedialog.askdirectory(master=self, initialdir=currdir, title='Please select a directory') self.ent1.delete(0, END) self.ent1.insert(0, tempdir) def initUI(self): self.parent.title("backup client") self.pack(fill=BOTH, expand=True) self.grid_columnconfigure(6, weight=1) self.grid_rowconfigure(9, weight=1) # display config info in txt box f1 = Frame(self) lblConfig = Label(f1, text="Config Settings:") txtConfig = Text(f1, height=4, width=40) s3Host = config['S3']['s3.server'] msg = "s3.server: " + s3Host + '\n' encPass = config['DEFAULT']['file.encryption_password'] msg = msg + "encryption_pass: "******"s3.access_key: " + s3AccessKey + '\n' txtConfig.insert('end', msg) txtConfig.configure(state='disabled') f1.grid(row=0, column=0, sticky="nsew") lblConfig.pack(side="top", anchor="w", padx=10) txtConfig.pack(side="top", anchor="w", padx=10) # run timer fTimer = Frame(self) lbl3 = Label(fTimer, text="Run Time: ") self.lbl4 = Label(fTimer, text="N/A") fTimer.grid(row=0, column=1, sticky=W, padx=20, pady=20) lbl3.pack(side="top") self.lbl4.pack(side="top") # backup / restore radio button fRadio = Frame(self) self.br = StringVar(fRadio, "backup") lblJobType = Label(fRadio, text="Job Type:") self.rbBackup = Radiobutton(fRadio, text="backup", variable=self.br, value="backup", command=self.onSelectRadio) self.rbRestore = Radiobutton(fRadio, text="restore", variable=self.br, value="restore", command=self.onSelectRadio) fRadio.grid(row=0, column=2, sticky=W) lblJobType.pack(side="top") self.rbBackup.pack(side="left") self.rbRestore.pack(side="left") # horizontal line on this row sp1 = Separator(self, orient=HORIZONTAL) sp1.grid(row=3, column=0, columnspan=6, sticky='ew', padx=10, pady=20) # inputDir entry with FileDialog f2 = Frame(self) lblSrc = Label(f2, text="SOURCE INFO") self.lbl1 = Label(f2, text="Src Directory:") self.ent1 = Entry(f2, width=40) b1 = Button(f2, text="Browse", width=8, command=self.getFilePath) f2.grid(row=4, column=0, sticky=W, padx=10, pady=10) lblSrc.pack(side="top") self.lbl1.pack(side="top", anchor=W) self.ent1.pack(side="left", anchor=W) b1.pack(side="left", anchor=E) # vertical separator sp3 = Separator(self, orient=VERTICAL) sp3.grid(row=4, column=1, sticky='ns', padx=20, pady=10, rowspan=2) # s3 bucket selection fBucket = Frame(self) lblTgt = Label(fBucket, text="TARGET INFO") lblBucket = Label(fBucket, text="S3 bucket:") buckets = backup_util.getBucketList(config) options = list() self.selectedBucket = StringVar(fBucket) for bucket in buckets: options.append(bucket.name) self.bucketMenu = OptionMenu(fBucket, self.selectedBucket, *options) self.bucketMenu.config(width=30) fBucket.grid(row=4, column=2, sticky=W, padx=10, pady=10) lblTgt.pack(side="top") lblBucket.pack(side="top", anchor=W) self.bucketMenu.pack(side="top") # s3 folder entry f3 = Frame(self) lblFolder = Label(f3, text="S3 Folder:") self.ent2 = Entry(f3, width=30) f3.grid(row=5, column=2, sticky=W, padx=10) lblFolder.pack(side="top", anchor=W) self.ent2.pack(side="top", anchor=W) # horizontal line on this row sp2 = Separator(self, orient=HORIZONTAL) sp2.grid(row=6, column=0, columnspan=6, sticky='ew', padx=10, pady=20) # buttons (backup/stop/reset/restore) fButtons = Frame(self) self.backupBtn = Button(fButtons, text="Backup", command=self.onBackup) self.restoreBtn = Button(fButtons, text="Restore", command=self.onRestore) self.stopBtn = Button(fButtons, text="Stop", command=self.onStop) self.resetBtn = Button(fButtons, text="Reset", command=self.onResetBtn) fButtons.grid(row=7, column=0, sticky=W, padx=10, pady=10) self.backupBtn.pack(side="left") self.restoreBtn.pack(side="left") self.restoreBtn.config(state=DISABLED) self.stopBtn.pack(side="left") self.resetBtn.pack(side="left") # progress bar self.pbar = Progressbar(self, mode='indeterminate') self.pbar.grid(row=7, column=1, columnspan=1, sticky=W + E) # a couple of checkbox items fchkbox = Frame(self) self.quitOnEnd = IntVar(fchkbox, 0) self.chkboxQuitOnEnd = Checkbutton(fchkbox, text="quit upon completion", variable=self.quitOnEnd, command=self.onSelectedQoe) self.doEncrypt = IntVar(fchkbox, 1) self.chkboxEncrypt = Checkbutton(fchkbox, text="encrypt data", variable=self.doEncrypt, command=self.onCheckEncrypt) fchkbox.grid(row=7, column=2, sticky=W, padx=10) self.chkboxQuitOnEnd.pack(side="top", anchor="w") self.chkboxEncrypt.pack(side="top", anchor="w") # scrolled txt f4 = Frame(self) f4.grid_columnconfigure(1, weight=1) f4.grid(row=8, column=0, columnspan=7, rowspan=5, padx=10, pady=10, sticky=(N, E, S, W)) lblStatus = Label(f4, text="//Job Status//") self.txt = scrolledtext.ScrolledText(f4) lblStatus.pack(side="top") self.txt.pack(side="top", fill=BOTH, expand=True) # check to make sure we could list the buckets if (len(buckets) == 0): messagebox.showerror(title="bucket error", message="could not list buckets") def onCheckEncrypt(self): print("doEncrypt: [{}]".format(self.doEncrypt.get())) def onSelectedQoe(self): print("quitOnEnd: [{}]".format(self.quitOnEnd.get())) def onSelectRadio(self): # set value of lbl for inputDir if (self.br.get() == "restore"): self.lbl1.config(text="Restore Directory:") self.backupBtn.config(state=DISABLED) self.restoreBtn.config(state=NORMAL) else: self.lbl1.config(text="Input Directory:") self.backupBtn.config(state=NORMAL) self.restoreBtn.config(state=DISABLED) # # start button clicked # def onBackup(self): backup_util.stopFlag = False # check to make sure we have values if (not self.ent1.get()): messagebox.showerror("Error", "inputDir is empty") return if (not self.ent2.get()): messagebox.showerror("Error", "s3Folder is empty") return inputDir = str(self.ent1.get()) folder = str(self.ent2.get()) # start timer self.starttime = timeit.default_timer() self.backupBtn.config(state=DISABLED) self.txt.delete("1.0", END) useQ = True self.t = ThreadedBackupTask(inputDir, folder, q, config, logger, useQ, self.doEncrypt.get(), self.selectedBucket.get()) self.t.start() # start progress bar self.pbar.start(DELAY2) # look for values self.after(DELAY1, self.onGetValue) # # restore button clicked # def onRestore(self): backup_util.stopFlag = False # check to see if we have input data if (not self.ent1.get()): messagebox.showerror("Error", "inputDir is empty") return if (not self.ent2.get()): messagebox.showerror("Error", "s3Folder is empty") return inputDir = str(self.ent1.get()) folder = str(self.ent2.get()) # start timer self.starttime = timeit.default_timer() self.restoreBtn.config(state=DISABLED) self.backupBtn.config(state=DISABLED) self.txt.delete("1.0", END) useQ = True self.t = ThreadedRestoreTask(inputDir, folder, q, config, logger, useQ, self.selectedBucket.get()) self.t.start() # start progress bar & look for values self.pbar.start(DELAY2) self.after(DELAY1, self.onGetValue) def onStop(self): backup_util.stopFlag = True print("set stop flag: {}".format(str())) self.t.join() self.onGetValue() def onResetBtn(self): self.initUI() # check for messages on q # process msgs - increment progress bar def onGetValue(self): # get some timing self.checktime = timeit.default_timer() runTime = self.checktime - self.starttime minutes = int(runTime / 60) seconds = round(runTime % 60, 0) msg = "{}m {}s".format(minutes, seconds) self.lbl4.config(text=msg) try: while (q.qsize() > 0): msg = q.get(0) lines = int(self.txt.index('end').split('.')[0]) - 1 if (lines > 500): self.txt.delete('1.0', '2.0') self.txt.insert('end', msg) self.txt.insert('end', "\n") self.txt.yview('end') except Empty: print("queue is empty") # if process is still alive - set timer and go again if (self.t.is_alive()): self.after(DELAY1, self.onGetValue) return else: self.pbar.stop() self.backupBtn.config(state=NORMAL) self.restoreBtn.config(state=DISABLED) if (self.quitOnEnd.get() == 1): sys.exit(0)