def run(self): print 'RUNNING' r = lambda: random.randint(0, 255) while True: Canvas.clear() Canvas.draw_rect((0, 0), (200, 200), fill_style='#%02X%02X%02X' % (r(), r(), r())) sleep(random.uniform(0.03, 1))
class Window(object): def __init__(self, width: int, height: int, pixels: ndarray): self.pixels = pixels self.width = width self.height = height self.canvas = Canvas(width, height, pixels) # setup key handlers key_esc = 27 self.handlers = { key_esc: self.exit } # self.v1 = Vertex(Vector(0, 0), Color.cyan()) # self.v2 = Vertex(Vector(300, 100), Color.red()) # self.v3 = Vertex(Vector(200, 300), Color.green()) model_path = "illidan.model" texture_path = "illidan.texture" self.mesh = Mesh(model_path, texture_path) def clear(self): self.canvas.clear() pass def update(self, dt): pass def draw(self): # self.canvas.draw_triangle(self.v1, self.v2, self.v3) self.canvas.draw_mesh(self.mesh) def mouse_event(self, button, state, x, y): print('mouse event', button, state, x, y) # 0, left button # 2, right button # 0, state press # 1, state release def exit(self): sys.exit(0) def cmd404(self): pass def key_event(self, key, key_is_down): print('key event', key, key_is_down) cmd = self.handlers.get(key, self.cmd404) cmd()
class Window(object): def __init__(self, width: int, height: int, pixels: ndarray): self.pixels = pixels self.width = width self.height = height self.canvas = Canvas(width, height, pixels) # setup key handlers key_esc = 27 self.handlers = {key_esc: self.exit} # self.v1 = Vertex(Vector(0, 0), Color.cyan()) # self.v2 = Vertex(Vector(300, 100), Color.red()) # self.v3 = Vertex(Vector(200, 300), Color.green()) model_path = "illidan.model" texture_path = "illidan.texture" self.mesh = Mesh(model_path, texture_path) def clear(self): self.canvas.clear() pass def update(self, dt): pass def draw(self): # self.canvas.draw_triangle(self.v1, self.v2, self.v3) self.canvas.draw_mesh(self.mesh) def mouse_event(self, button, state, x, y): print('mouse event', button, state, x, y) # 0, left button # 2, right button # 0, state press # 1, state release def exit(self): sys.exit(0) def cmd404(self): pass def key_event(self, key, key_is_down): print('key event', key, key_is_down) cmd = self.handlers.get(key, self.cmd404) cmd()
class Window(object): def __init__(self, pixels, width, height): self.pixels = pixels self.width = width self.height = height self.canvas = Canvas(width, height, pixels) # setup key handlers key_esc = 27 self.handlers = { key_esc: self.exit } self.v1 = Vertex(Vector(0, 0), Color.cyan()) self.v2 = Vertex(Vector(300, 100), Color.red()) self.v3 = Vertex(Vector(200, 300), Color.white()) self.v4 = Vertex(Vector(300, 0), Color.green()) def clear(self): self.canvas.clear() pass def update(self, dt): pass def draw(self): self.canvas.draw_triangle(self.v1, self.v2, self.v4) self.canvas.draw_triangle(self.v1, self.v2, self.v3) def mouse_event(self, button, state, x, y): print('mouse event', button, state, x, y) # 0, left button # 2, right button # 0, state press # 1, state release def exit(self): sys.exit(0) def cmd404(self): pass def key_event(self, key, key_is_down): print('key event', key, key_is_down) cmd = self.handlers.get(key, self.cmd404) cmd()
class Main(object): def __init__(self): self.tracker = Tracker() self.canvas = Canvas() def run(self): self.tracker.start() while True: point = self.tracker.get_last_datapoint() self.canvas.setfg(point["pos"][0] * fg_mul + gapping, point["pos"][1] * fg_mul + gapping) self.canvas.setmg(point["pos"][0] * mg_mul + gapping, point["pos"][1] * mg_mul + gapping) self.canvas.setbg(point["pos"][0] * bg_mul + gapping, point["pos"][1] * bg_mul + gapping) self.canvas.draw() time.sleep(0.05) self.canvas.clear()
class MainPage(tkinter.Frame): def __init__(self, parent, controller): super().__init__(parent) self.config(bg="white") self.canvas = Canvas(self) # Add ghostscript and miktex to path os.environ[ "PATH"] += os.pathsep + "C:\\Program Files\\MiKTeX\\miktex\\bin\\x64\\" os.environ[ "PATH"] += os.pathsep + "C:\\Program Files (x86)\\gs\\gs9.52\\bin\\" # Make sure the ORDERS_FOLDER exists cwd = get_current_directory() if not os.path.isdir(f"{cwd}/{ORDERS_FOLDER}"): os.mkdir(f"{cwd}/{ORDERS_FOLDER}") # Menubar menubar = tkinter.Menu(self) filemenu = tkinter.Menu(menubar, tearoff=0) filemenu.add_command(label="Last opp", command=self.load_file) filemenu.add_command(label="Lagre", command=self.save) filemenu.add_separator() filemenu.add_command(label="Eksporter", command=self.export) filemenu.add_separator() filemenu.add_command(label="Slett", command=self.delete_file) menubar.add_cascade(label="Fil", menu=filemenu) tkinter.Tk.config(controller, menu=menubar) # Top label automatic_calculation_label = tkinter.Label( self, text="Automatisk utregning", font=("", 20), bg="white") automatic_calculation_label.pack(side="top", fill="x", pady=10) # Frame containing the total width entries total_width_frame = tkinter.Frame(self, bg="white") total_width_frame.grid_columnconfigure(0, weight=2) total_width_frame.grid_columnconfigure(3, weight=1) total_width_frame.pack(side="top", fill="x", pady=10) # The left total width entry total_length_l_label = tkinter.Label(total_width_frame, text="Total lengde venstre: ", bg="white") total_length_l_label.grid(row=0, column=1, padx=10, sticky="w") self.total_length_l = tkinter.StringVar() total_length_l_entry = tkinter.Entry(total_width_frame, text=self.total_length_l, bg="white") total_length_l_entry.grid(row=1, column=1, padx=10, sticky="w") # The rigth total width entry total_width_r_label = tkinter.Label(total_width_frame, text="Total lengde høyre:", bg="white") total_width_r_label.grid(row=0, column=2, padx=10, sticky="w") self.total_length_r = tkinter.StringVar() total_width_r_entry = tkinter.Entry(total_width_frame, text=self.total_length_r, bg="white") total_width_r_entry.grid(row=1, column=2, padx=10, sticky="w") # Customer name label customer_name_label = tkinter.Label(total_width_frame, text="Kundenavn", bg="white") customer_name_label.grid(row=0, column=4, padx=10, sticky="w") self.customer_name = tkinter.StringVar() self.customer_name_entry = tkinter.Entry(total_width_frame, text=self.customer_name, bg="white") self.customer_name_entry.grid(row=1, column=4, padx=10) # Order number label order_number_label = tkinter.Label(total_width_frame, text="Ordrenummer", bg="white") order_number_label.grid(row=0, column=5, padx=10, sticky="w") self.order_number = tkinter.StringVar() self.order_number_entry = tkinter.Entry(total_width_frame, text=self.order_number, bg="white") self.order_number_entry.grid(row=1, column=5, padx=10) # Frame containing top row of buttons and inputs top_frame = tkinter.Frame(self, bg="white") top_frame.grid_columnconfigure(2, weight=1) top_frame.grid_columnconfigure(6, weight=1) top_frame.pack(side="top", fill="x") # Reset button self.reset_button = tkinter.Button( top_frame, text="Reset", command=lambda: [self.canvas.clear(), self.update_packaging_list()]) self.reset_button.grid(row=0, column=0, sticky="n") # Undo button self.undo_button = tkinter.Button( top_frame, text="Angre", command=lambda: [self.canvas.undo(), self.update_packaging_list()]) self.undo_button.grid(row=0, column=1, sticky="n") # Dropdown for type of glass self.glass_type_dropdown = tkinter.StringVar() self.glass_type_dropdown.set("Klart") glass_type_dropdown_menu = tkinter.OptionMenu(top_frame, self.glass_type_dropdown, *["Klart", "Frostet"]) glass_type_dropdown_menu.grid(row=0, column=2, padx=10, sticky="n") # Dropdown for wallmoun/post on left side self.auto_left_item_dropdown = tkinter.StringVar() self.auto_left_item_dropdown.set("Veggskinne") auto_left_item_dropdown_menu = tkinter.OptionMenu( top_frame, self.auto_left_item_dropdown, *["Veggskinne", "Stolpe"]) auto_left_item_dropdown_menu.grid(row=0, column=3, padx=40, sticky="ne") auto_left_item_dropdown_menu.config(width=DROPDOWN_WIDTH) # Frame for glass size entries auto_glass_frame = tkinter.Frame(top_frame, bg="white") auto_glass_frame.grid(row=0, column=4, padx=10, sticky="n") # Labels for glass size entries glass_width_label = tkinter.Label(auto_glass_frame, text="Global bredde: ", bg="white") glass_width_label.grid(row=0, column=0) glass_height_label = tkinter.Label(auto_glass_frame, text="Global høyde: ", bg="white") glass_height_label.grid(row=1, column=0) # Entry for glass width for automatic calculation self.auto_glass_width = tkinter.StringVar() auto_glass_width_entry = tkinter.Entry(auto_glass_frame, text=self.auto_glass_width) auto_glass_width_entry.grid(row=0, column=1) auto_glass_width_entry.insert(0, 60) # Entry for glass height for automatic calculation self.auto_glass_height = tkinter.StringVar() auto_glass_height_entry = tkinter.Entry(auto_glass_frame, text=self.auto_glass_height) auto_glass_height_entry.grid(row=1, column=1) auto_glass_height_entry.insert(0, 60) # Dropdown for wallmoun/post on right side self.auto_right_item_dropdown = tkinter.StringVar() self.auto_right_item_dropdown.set("Stolpe") auto_right_item_dropdown_menu = tkinter.OptionMenu( top_frame, self.auto_right_item_dropdown, *["Veggskinne", "Stolpe"]) auto_right_item_dropdown_menu.grid(row=0, column=5, padx=40, sticky="nw") auto_right_item_dropdown_menu.config(width=DROPDOWN_WIDTH) # Dropdown for shipping self.shipping_dropdown = tkinter.StringVar() self.shipping_dropdown.set("Sendes") shipping_dropdown_menu = tkinter.OptionMenu( top_frame, self.shipping_dropdown, *["Sendes", "Hentes", "Monteres"]) shipping_dropdown_menu.grid(row=0, column=6, padx=10, sticky="ne") # Frame for the packaging list self.packaging_frame = tkinter.Frame(top_frame, bg="white") self.packaging_frame.grid(row=0, column=7, padx=20, sticky="e") # Create a table for the packaging list self.packaging_table = ttk.Treeview(self.packaging_frame, height=1) self.packaging_table["columns"] = ("#1", "#2") self.packaging_table.column("#0", width=150, anchor="center") self.packaging_table.column("#1", width=100, anchor="center") self.packaging_table.column("#2", width=100, anchor="center") self.packaging_table.heading("#0", text="Type", anchor="center") self.packaging_table.heading("#1", text="Størrelse", anchor="center") self.packaging_table.heading("#2", text="Antall", anchor="center") self.packaging_table.pack(side="top", fill="x") # Place the canvas in middle self.canvas.pack(side="top", fill="both", expand=1) # Label for manual buttons/entries section automatic_calculation_label = tkinter.Label(self, text="Manuel utregning", font=("", 20), bg="white") automatic_calculation_label.pack(side="top", fill="x", pady=10) # Bottom frame for manual buttons/inputs bottom_frame = tkinter.Frame(self, bg="white") bottom_frame.pack(side="top", fill="x", pady=20) bottom_frame.grid_columnconfigure(0, weight=1) bottom_frame.grid_columnconfigure(6, weight=1) # Button for adding wallmount self.wallmount_button = tkinter.Button( bottom_frame, text="Veggskinne", command=lambda: self.add_item(Wallmount)) self.wallmount_button.grid(row=0, column=1, padx=10, sticky="e") # Button for adding post self.post_button = tkinter.Button(bottom_frame, text="Stolpe", command=lambda: self.add_item(Post)) self.post_button.grid(row=0, column=2, padx=10) # Button for adding glass self.glass_button = tkinter.Button( bottom_frame, text="Glass", command=lambda: self.add_item(Glass)) self.glass_button.grid(row=0, column=3, padx=10) # Labels for glass size entries glass_width_label = tkinter.Label(bottom_frame, text="Individuell bredde: ", bg="white") glass_width_label.grid(row=0, column=4) glass_height_label = tkinter.Label(bottom_frame, text="Individuell høyde: ", bg="white") glass_height_label.grid(row=1, column=4) # Entry for glass width self.manual_glass_width = tkinter.StringVar() glass_width_entry = tkinter.Entry(bottom_frame, text=self.manual_glass_width) glass_width_entry.grid(row=0, column=5) glass_width_entry.insert(0, 60) # Entry for glass height self.manual_glass_height = tkinter.StringVar() glass_height_entry = tkinter.Entry(bottom_frame, text=self.manual_glass_height) glass_height_entry.grid(row=1, column=5, sticky="n") glass_height_entry.insert(0, 60) # Button for adding polygon glass self.polygon_button = tkinter.Button( bottom_frame, text="Skrå glass", command=lambda: self.add_item(GlassPolygon)) self.polygon_button.grid(row=0, column=6, padx=10, sticky="e") # Entry for height of polygon glass self.polygon_glass_height = tkinter.StringVar() polygon_entry = tkinter.Entry(bottom_frame, text=self.polygon_glass_height) polygon_entry.insert(0, 20) polygon_entry.grid(row=0, column=7, padx=10) # Add eventlistener to customer_name/order_number to resize entries self.customer_name.trace_add( "write", lambda n, i, m: self.resize_entry(self.customer_name_entry)) self.order_number.trace_add( "write", lambda n, i, m: self.resize_entry(self.order_number_entry)) # Add eventlistener to glass type to change color of glass self.glass_type_dropdown.trace_add( "write", lambda n, i, m: self.canvas.change_glass_type()) # Add eventlisteners to every entry in the # automatic section to call auto_calculate setattr( self.total_length_l, "trace_id", self.total_length_l.trace_add( "write", lambda n, i, m: self.auto_calculate())) setattr( self.total_length_r, "trace_id", self.total_length_r.trace_add( "write", lambda n, i, m: self.auto_calculate())) setattr( self.auto_glass_width, "trace_id", self.auto_glass_width.trace_add( "write", lambda n, i, m: self.auto_calculate())) setattr( self.auto_glass_height, "trace_id", self.auto_glass_height.trace_add( "write", lambda n, i, m: self.auto_calculate())) setattr( self.auto_left_item_dropdown, "trace_id", self.auto_left_item_dropdown.trace_add( "write", lambda n, i, m: self.auto_calculate())) setattr( self.auto_right_item_dropdown, "trace_id", self.auto_right_item_dropdown.trace_add( "write", lambda n, i, m: self.auto_calculate())) def resize_entry(self, entry): width = len(entry.get()) if width > 20: entry.configure(width=width) else: entry.configure(width=20) def validate_and_get_entry(self, entry, less_than_value=0, greater_than_value=10000): """ Validates the value in the given entry. Returns Decimal object of value if it passes, returns False otherwise If entry contains non-numbers, these are removed. Commas are also replaced with periods. """ # Remove all non-numbers from entry_val, and replace comma with period entry_val = re.sub("[^0-9,\.]", "", entry.get()).replace(",", ".") # Need to remove trace before entry.set, or it will be activated if getattr(entry, "trace_id", False): entry.trace_vdelete("w", entry.trace_id) entry.set(entry_val) entry.trace_id = entry.trace_add( "write", lambda n, i, m: self.auto_calculate()) else: entry.set(entry_val) if entry_val == "": return False try: value = Decimal(entry_val) if value < less_than_value or value > greater_than_value: return False return value except: return False def get_auto_glass_width(self): return self.validate_and_get_entry(self.auto_glass_width) def get_auto_glass_height(self): return self.validate_and_get_entry(self.auto_glass_height) def get_total_length_l(self): return self.validate_and_get_entry(self.total_length_l) def get_total_length_r(self): return self.validate_and_get_entry(self.total_length_r) def get_left_item(self): return Wallmount if self.auto_left_item_dropdown.get( ) == "Veggskinne" else Post def get_right_item(self): return Wallmount if self.auto_right_item_dropdown.get( ) == "Veggskinne" else Post def get_glass_color(self): return "blue" if self.glass_type_dropdown.get() == "Klart" else "red" def auto_calculate(self): # This is not in the if test because it can be empty total_length_l = self.validate_and_get_entry(self.total_length_l) total_length_r = self.validate_and_get_entry(self.total_length_r) if not (total_length_l := self.validate_and_get_entry(self.total_length_l)) or \ not (glass_width := self.validate_and_get_entry(self.auto_glass_width)) or \ not (height := self.validate_and_get_entry(self.auto_glass_height)):
class Display: wire = None brightness = BRIGHTNESS.FULL canvas = None visualizers = iter(all_visualizers) cur_visual = None def __init__(self, size, wire, brightness, visualizer): assert brightness in [BRIGHTNESS.OFF, BRIGHTNESS.ONE, BRIGHTNESS.TWO, BRIGHTNESS.THREE, BRIGHTNESS.FULL] self.wire = wire self.canvas = Canvas(size) self.set_brightness(brightness) self.cur_visual = all_visualizers[visualizer] # set the iterator to the value that matches the visualizer parameter while True: try: if self.cur_visual == self.visualizers.next(): break except: self.visualizers = iter(all_visualizers) pass @classmethod def dump_defaults(cls): return {"brightness": BRIGHTNESS.FULL, "visualizer": 0} def dump_settings(self): return {"brightness": self.brightness, "visualizer": all_visualizers.index(self.cur_visual)} def set_brightness(self, brightness, remember=True): if brightness < BRIGHTNESS.OFF or brightness > BRIGHTNESS.FULL: raise Exception, "Unknown brightness code %d" % brightness if remember: self.brightness = brightness grfb = Grfb() grfb.brightness = BRIGHTNESS.map[brightness] self.wire.send(grfb.serialize()) def next_brightness(self): if self.brightness - 1 < BRIGHTNESS.OFF: self.set_brightness(BRIGHTNESS.FULL) else: self.set_brightness(self.brightness - 1) def next_visualizer(self): try: visu = self.visualizers.next() self.wire.send(visu.serialize()) self.cur_visual = visu except: self.visualizers = iter(all_visualizers) self.next_visualizer() def visualizer_on(self): self.wire.send(self.cur_visual.serialize()) def visualizer_off(self): self.wire.send(VisuNone().serialize()) def show(self, transition): self.canvas.prepare_transmission() grfe = Grfe() grfe.transition = transition grfe.bitmap = self.canvas.bitmap self.wire.send(grfe.serialize()) def clear(self): self.canvas.clear() self.show(TRANSITION.NONE)
gameover = False while(not gameover): with Listener(on_press=on_press) as ls: def time_out(period_sec: int): time.sleep(period_sec) # Listen to keyboard for period_sec seconds ls.stop() os.system('cls' if os.name == 'nt' else 'clear') Thread(target=time_out, args=(0.5,)).start() ls.join() #move entities ball.collision(canvas) ball.move() snake.move() pedal.move(canvas) canvas.clear() canvas.createBorder() if(snake.detectColission(canvas) or ball.getgameOver()): gameover = True #print entities canvas = snake.drawSnake(canvas) canvas = pedal.print(canvas) canvas = ball.print(canvas) canvas.print() print("your score: ",ball.score) os.system('cls' if os.name == 'nt' else 'clear') print("Loser your score was: ",ball.score)
class TimePicker(BaseUIElement): def __init__(self, i, o, name="TimePicker"): BaseUIElement.__init__(self, i, o, name) self.c = Canvas(self.o) self.font = self.c.load_font("Fixedsys62.ttf", 32) self.current_hour = 12 self.current_minute = 30 self.accepted_value = False # Position 0 = hour, position 1 = minute self.position = 0 def get_return_value(self): if self.accepted_value: return {'hour': self.current_hour, 'minute': self.current_minute} else: return None def generate_keymap(self): return { "KEY_RIGHT": "move_right", "KEY_LEFT": "move_left", "KEY_UP": "increase_one", "KEY_DOWN": "decrease_one", "KEY_ENTER": "accept_value", "KEY_F1": "exit_time_picker" } def move_right(self): if self.position == 0: self.position = 1 self.refresh() def move_left(self): if self.position == 1: self.position = 0 self.refresh() def increase_one(self): if self.position == 0: if self.current_hour == 23: self.current_hour = 0 else: self.current_hour = min(23, self.current_hour + 1) elif self.position == 1: if self.current_minute == 59: self.current_minute = 0 else: self.current_minute = min(59, self.current_minute + 1) self.refresh() def decrease_one(self): if self.position == 0: if self.current_hour == 0: self.current_hour = 23 else: self.current_hour = max(0, self.current_hour - 1) elif self.position == 1: if self.current_minute == 0: self.current_minute = 59 else: self.current_minute = max(0, self.current_minute - 1) self.refresh() def idle_loop(self): sleep(0.1) def exit_time_picker(self): self.deactivate() def accept_value(self): self.accepted_value = True self.deactivate() def draw_clock(self): self.c.clear() # Draw the clock string centered on the screen clock_string = "{:02d}:{:02d}".format(self.current_hour, self.current_minute) clock_text_bounds = self.c.get_text_bounds(clock_string, font=self.font) width_padding = (self.c.width - clock_text_bounds[0]) / 2 height_padding = (self.c.height - clock_text_bounds[1]) / 2 self.c.text(clock_string, (width_padding, height_padding - 2), font=self.font) # Draw the arrows either on the left or right side depending on whether hours or minutes are being edited bx = 0 if self.position == 0: bx = 0 elif self.position == 1: bx = self.c.width / 2 - width_padding + 6 # Base coordinates for arrows triangle_top = ((bx + width_padding + 6, height_padding - 5), (bx + self.c.width / 2 - 10, height_padding - 5), (bx + width_padding - 2 + ((self.c.width / 2 - width_padding) / 2), height_padding - 15)) triangle_bottom = ((bx + width_padding + 6, self.c.height - height_padding + 5), (bx + self.c.width / 2 - 10, self.c.height - height_padding + 5), (bx + width_padding - 2 + ((self.c.width / 2 - width_padding) / 2), self.c.height - height_padding + 15)) self.c.polygon(triangle_top, fill="white") self.c.polygon(triangle_bottom, fill="white") self.c.display() def refresh(self): self.draw_clock()
def test_Canvas_clear(): playfield = Canvas(2, 2) playfield.draw(0, 0, "a") playfield.draw(1, 1, "b") playfield.clear() assert playfield.getCanvas() == " \n \n"
class Game: def __init__(self, height=0, width=0): if (height < 10): height = 10 if (width < 20): width = 20 height = height + 2 #borders width = width + 2 #borders self.__height = height self.__width = width self.__snake = Snake((width - 2) // 2, height // 2, 5) self.__pongPaddle = PongPaddle(4, height) self.__ball = Ball(random.randint(3, width - 2), random.randint(1, height - 2)) self.__create_walls() self.__canvas = Canvas(height, width) self.__is_over = False self.__score = 0 self.__render() def width(self): return self.__width def height(self): return self.__height def is_over(self): return self.__is_over def score(self): return self.__score def __render(self): self.__canvas.clear() for wall in self.__walls: wall.draw(self.__canvas) self.__snake.draw(self.__canvas) self.__pongPaddle.draw(self.__canvas) self.__ball.draw(self.__canvas) self.__canvas.show() def __update(self): if (not self.is_over()): self.__update_snake() self.__update_ball() if (self.__scored()): self.__snake.grow() if (self.__ball.x() > 2): self.__update_pongPaddle() def __update_snake(self): self.__snake.update() if (self.__snake.cut_itself() or self.__snake_goes_outside()): self.__is_over = True def __update_ball(self): while (self.__ball_vs_snake_collision() or self.__ball_vs_pongPaddle_collision() or self.__ball_goes_outside()): self.__ball.random_direction() self.__ball = self.__ball.update() def __update_pongPaddle(self): self.__pongPaddle.update(self.__ball) def __ball_vs_snake_collision(self): return (self.__snake.has_ball_collision(self.__ball.update())) def __ball_vs_pongPaddle_collision(self): return (self.__pongPaddle.has_ball_collision(self.__ball.update())) def __ball_goes_outside(self): ball = self.__ball.update() return (ball.x() < 1 or ball.x() > self.width() - 2 or ball.y() < 1 or ball.y() > self.height() - 2) def __snake_goes_outside(self): head = self.__snake.head() return (head.x() < 3 or head.x() > self.width() - 2 or head.y() < 1 or head.y() > self.height() - 2) def __scored(self): if (self.__ball.x() < 2): self.__score = self.__score + 1 return True return False def __create_walls(self): self.__walls = [] for x in range(self.width()): self.__walls.append(Wall(x, 0)) self.__walls.append(Wall(x, self.height() - 1)) for y in range(1, self.height()): self.__walls.append(Wall(0, y)) self.__walls.append(Wall(self.width() - 1, y)) def move_left(self): self.__snake.try_set_direction_left() self.__update() self.__render() def move_right(self): self.__snake.try_set_direction_right() self.__update() self.__render() def move_up(self): self.__snake.try_set_direction_up() self.__update() self.__render() def move_down(self): self.__snake.try_set_direction_down() self.__update() self.__render()
class MainWindow(QMainWindow): def __init__(self): super(QWidget, self).__init__() self.setWindowTitle("My Label Tool") self.canvas = Canvas(self) self.dirty = False # set True indicates there exists unsaved changes self.label_list = LabelListWidget() self.shape_dock = QDockWidget(self.tr(u"Grasp list"), self) self.shape_dock.setObjectName(u"Grasp list") self.shape_dock.setWidget(self.label_list) # connection self.canvas.shapesAdded.connect(self.label_list.addShapes) self.canvas.shapesRemoved.connect(self.label_list.removeShapes) self.canvas.shapesSelectionChanged.connect( self.label_list.changeShapesSelection) self.canvas.shapesAreaChanged.connect(self.label_list.updateShapesArea) # self.label_list.shapesAdded.connect(self.canvas.addShapes) self.label_list.shapesRemoved.connect(self.canvas.removeShapes) self.label_list.shapesSelectionChanged.connect( self.canvas.changeShapesSelection) self.label_list.shapeVisibleChanged.connect( self.canvas.changeShapesVisible) self.label_list.shapesOrderChanged.connect( self.canvas.changeShapesOrder) self.label_list.reconnectCanvasDataRequest.connect( self._reconnectCanvasAndLabel) self.file_list = FileListWidget() self.file_list.filesSelectionChanged.connect( self._changeFilesSelection) self.file_list.fileLabeledChanged.connect( self._changeFileLabeled) # 是否完成标注 self.file_dock = QDockWidget(self.tr(u"File list"), self) self.file_dock.setObjectName(u"File list") self.file_dock.setWidget(self.file_list) # set dirty self.canvas.shapesAdded.connect(self.setDirty) self.canvas.shapesRemoved.connect(self.setDirty) self.canvas.shapesAreaChanged.connect(self.setDirty) self.label_list.shapesRemoved.connect(self.setDirty) self.label_list.shapesOrderChanged.connect(self.setDirty) self.file_list.fileLabeledChanged.connect(self.setDirty) # setup ui features = QDockWidget.DockWidgetFeatures() self.shape_dock.setFeatures(features | QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.shape_dock.setVisible(True) self.file_dock.setFeatures(features | QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.file_dock.setVisible(True) self.setCentralWidget(self.canvas) self.addDockWidget(Qt.RightDockWidgetArea, self.file_dock) self.addDockWidget(Qt.RightDockWidgetArea, self.shape_dock) # project result self.image_folder = None self.image_files = None self.output_folder = None self.output_name = None # image_file_name = os.path.join(image_folder, image_files[working_idx]) self.results = {"image_folder": "unknown", "image_files": {}} # results: # image_folder: xxx # image_files: # "00001.jpg": # "labeled": True # "shapes": # [ # {"id": xxx, "points": xxx}, # {"id": xxx, "points": xxx}, # ... # ], # "00002.jpg": # ... openProject = action.new_action( self, self.tr("Open Project"), lambda: self.importProject(self.openProjectDialog()), None, "open-project.png") saveProject = action.new_action(self, self.tr("Save Project"), self.saveProject, "Ctrl+S", "save.png") openImages = action.new_action( self, self.tr("Open Images"), lambda: self.importImages(self.openImagesDialog()), # lambda: self.openImagesDialog(), None, "open-images.png") openDir = action.new_action( self, self.tr("Open Dir"), lambda: self.importDirImages(self.openDirDialog()), None, "open-dir.png") openPrevImg = action.new_action(self, self.tr("Prev Image"), self.openPrevImg, "A", "prev.png") openNextImg = action.new_action(self, self.tr("Next Image"), self.openNextImg, "D", "next.png") createMode = action.new_action( self, self.tr("Create Mode"), lambda: self.canvas.setMode(self.canvas.CREATE), "Ctrl+N", "create.png") editMode = action.new_action( self, self.tr("Edit Mode"), lambda: self.canvas.setMode(self.canvas.EDIT), "Ctrl+E", "edit.png") fitWindow = action.new_action( self, self.tr("Fit Window"), lambda: self.canvas.adjustPainter("fit_window"), None, "fit-window.png") # fitWidth = action.new_action( # self, # self.tr("Fit Width"), # lambda: self.canvas.adjustPainter("fit_width"), # None, # "fit-width.png" # ) # # fitHeight = action.new_action( # self, # self.tr("Fit Height"), # lambda: self.canvas.adjustPainter("fit_height"), # None, # "fit-height.png" # ) fitOrigin = action.new_action( self, self.tr("Origin Size"), lambda: self.canvas.adjustPainter("origin_size"), None, "origin-size.png") changeOutputDir = action.new_action(self, self.tr("Change Output Dir"), self.changeOutputDir, None, "open-dir.png") self.actions = utils.Struct(openPrevImg=openPrevImg, openNextImg=openNextImg) self.tool_bar = self.addToolBar_( "Tools", [ openProject, # openImages, openDir, openPrevImg, openNextImg, saveProject, createMode, editMode, fitWindow, # fitHeight, # fitWidth, fitOrigin ]) self.menus = utils.Struct(file=self.addMenu(self.tr("File")), edit=self.addMenu(self.tr("Edit")), view=self.addMenu(self.tr("View"))) action.add_actions(self.menus.file, [ openProject, openImages, openDir, None, saveProject, changeOutputDir ]) action.add_actions(self.menus.edit, [createMode, editMode]) action.add_actions( self.menus.view, [ fitWindow, # fitHeight, # fitWidth, fitOrigin ]) def _reconnectCanvasAndLabel(self): self.label_list.reconnectCanvasData(self.canvas.shapes) def _changeFilesSelection(self, selected, deselected): assert len(selected) <= 1, "Single selection mode" assert len(deselected) <= 1, "Single selection mode" if len(deselected): # save current work print("[INFO] [from_app] Saving current work...") current_file = self.image_files[deselected[0]] self.results["image_files"][current_file][ "shapes"] = self.canvas.exportShapes() if len(selected): # load new file current_file = self.image_files[selected[0]] print("[INFO] [from_app] Loading data for image {}...".format( current_file)) if current_file not in self.results["image_files"]: self.canvas.clear() else: self.canvas.loadShapes( self.results["image_files"][current_file]["shapes"]) if self.image_folder is not None: # relative path self.canvas.loadImage( os.path.join(self.image_folder, current_file)) else: # absolute path self.canvas.loadImage(current_file) self.setClean() def _changeFileLabeled(self, index: int, labeled: bool): file = self.image_files[index] self.results["image_files"][file]["labeled"] = labeled def setDirty(self): self.dirty = True def setClean(self): self.dirty = False def isDirty(self): return self.dirty def addMenu(self, title, actions=None): menu = self.menuBar().addMenu(title) if actions: action.add_actions(menu, actions) return menu def addToolBar_(self, title, actions=None): tool_bar = ToolBar(title) tool_bar.setObjectName("{}ToolBar".format(title)) tool_bar.setOrientation(Qt.Vertical) tool_bar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) if actions: action.add_actions(tool_bar, actions) self.addToolBar(Qt.LeftToolBarArea, tool_bar) return tool_bar def openProjectDialog(self): path = QFileDialog.getOpenFileName(self, self.tr("Open Project"), "./", self.tr("Project File (*.json)"))[0] return path def openImagesDialog(self): paths = QFileDialog.getOpenFileNames( self, self.tr("Open Images"), "./", self.tr("Image Files ({})".format(" ".join( ["*." + ext for ext in IMAGE_EXTENTIONS]))))[0] return paths def openDirDialog(self): path = QFileDialog.getExistingDirectory( self, self.tr("Open Directory"), "./", # QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks # QFileDialog.DontUseNativeDialog | QFileDialog.DontResolveSymlinks # QFileDialog.DontResolveSymlinks QFileDialog.ShowDirsOnly) if len(path) == 0: path = None print("[INFO] [from app] Choose dir = {}".format(path)) return path def importProject(self, path: str): if not path: return # clean the current content self.file_list.clear() self.canvas.clear() with open(path, "r", encoding="utf-8") as j: self.results = json.load(j) self.image_folder = self.results["image_folder"].lower() \ if self.results["image_folder"].lower() != "absolute_path" \ else None self.image_files = list(self.results["image_files"].keys()) self.image_files.sort() # check if file exists if self.image_folder is None: # absolute path found, not_found = [], [] for file in self.image_files: if os.path.exists(file): found.append(file) else: not_found.append(file) self.image_files = found if len(not_found): box = QMessageBox(self) box.setIcon(QMessageBox.Warning) box.setText("{} file(s) cannot be found.".format( len(not_found))) box.setInformativeText("Do you want the project to keep them?") box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) box.setDefaultButton(QMessageBox.No) box.setDetailedText( "The following file(s) cannot be found:\n\n" + "\n".join([" - " + f for f in not_found])) ret = box.exec() if ret == QMessageBox.No: for f in not_found: self.results["image_files"].pop(f) else: # relative path if not os.path.exists(self.image_folder): box = QMessageBox(self) box.setIcon(QMessageBox.Critical) box.setText("Directory not found. Import project failed.") box.setInformativeText("Select directory: {}".format( self.image_folder)) box.setStandardButtons(QMessageBox.Ok) box.setDefaultButton(QMessageBox.Ok) box.exec() return else: found, not_found = [], [] for file in self.image_files: if os.path.exists(os.path.join(self.image_folder, file)): found.append(file) else: not_found.append(file) self.image_files = found if len(not_found): box = QMessageBox(self) box.setIcon(QMessageBox.Warning) box.setText( "{} file(s) in directory \"{}\" cannot be found.". format(len(not_found), self.image_folder)) box.setInformativeText( "Do you want the project to keep them?") box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) box.setDefaultButton(QMessageBox.No) box.setDetailedText( "The following file(s) cannot be found:\n\n" + "\n".join([" - " + f for f in not_found])) ret = box.exec() if ret == QMessageBox.No: for f in not_found: self.results["image_files"].pop(f) self.file_list.addFiles(self.image_files) for i, file in enumerate(self.image_files): self.file_list[i].setCheckState( Qt.Checked if self. results["image_files"][file]["labeled"] else Qt.Unchecked) self.file_list.selectNext() box = QMessageBox(self) box.setIcon(QMessageBox.Question) box.setText("Continue working on this opened project?") box.setInformativeText( "If not, you may have to choose another output path" " when you save the project.") box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) box.setDefaultButton(QMessageBox.Yes) ret = box.exec() if ret == QMessageBox.Yes: self.output_folder, self.output_name = os.path.split(path) if self.output_folder == "": self.output_folder = "." self.setClean() else: self.setDirty() def importImages(self, paths: List[str]): if len(paths) == 0: return # clean the current content self.file_list.clear() self.canvas.clear() self.image_folder = None self.image_files = paths self.image_files.sort() self.file_list.addFiles(self.image_files) self.results = { "image_folder": "absolute_path", "image_files": {f: { "labeled": False, "shapes": [] } for f in self.image_files} } self.file_list.selectNext() self.setDirty() def importDirImages(self, path: str): if not path: return # clean the current content self.file_list.clear() self.canvas.clear() # self.label_list.clear() # label_list will automatically clear since its .removeShapes() # has been connected to canvas' .removeShapes() # load new files self.image_folder = path self.image_files = [] for ext in IMAGE_EXTENTIONS: # ["jpg", "png"] self.image_files.extend( glob.glob(os.path.join(self.image_folder, "*.{}".format(ext)))) self.image_files = [os.path.split(f)[-1] for f in self.image_files] # remove dir self.image_files.sort() self.file_list.addFiles(self.image_files) self.results = { "image_folder": path, "image_files": {f: { "labeled": False, "shapes": [] } for f in self.image_files} } self.file_list.selectNext() self.setDirty() def openNextImg(self): print("[INFO] Open next image triggered.") current_select, next_select = self.file_list.selectNext() # self.changeFilesSelection() will be triggered to process canvas. if current_select is not None: self.file_list[current_select].setCheckState(Qt.Checked) # may trigger setDirty() if check state changes def openPrevImg(self): print("[INFO] Open previous image triggered.") current_select, prev_select = self.file_list.selectPrev() # self._changeFilesSelection() will be triggered to process canvas. if current_select is not None: self.file_list[current_select].setCheckState(Qt.Checked) def saveProject(self): print("[INFO] [from app] Saving current work...") selected = [i.row() for i in self.file_list.selectedIndexes()] assert len(selected) <= 1, "Single selection mode." if len(selected): current_file = self.image_files[selected[0]] self.results["image_files"][current_file][ "shapes"] = self.canvas.exportShapes() self.file_list[selected[0]].setCheckState(Qt.Checked) if self.output_folder is None: self.output_folder = self.openDirDialog() if self.output_folder is None: return None # cancel saving if None selected time_stamp = time.strftime("%m%d%H%M%S", time.localtime()) self.output_name = "proj_" + time_stamp + ".json" path = os.path.join(self.output_folder, self.output_name) print("[INFO] [from app] Saving project to {}...".format(path)) with open(path, "w", encoding="utf-8") as j: json.dump(self.results, j, ensure_ascii=False, indent=4) self.setClean() # set clean, no unsaved changes return path def changeOutputDir(self): self.output_folder = self.openDirDialog() return self.output_folder def resizeEvent(self, e: QResizeEvent): super(MainWindow, self).resizeEvent(e) self.canvas.adjustPainter("fit_window") def closeEvent(self, e: QCloseEvent): if not self.dirty: # no unsaved changes e.accept() else: box = QMessageBox(self) box.setIcon(QMessageBox.Question) box.setText( "Save before closing? Or press cancel to back to canvas.") box.setStandardButtons(QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) box.setDefaultButton(QMessageBox.Yes) ret = box.exec() if ret == QMessageBox.Yes: out_path = self.saveProject() if out_path is None: box = QMessageBox(self) box.setIcon(QMessageBox.Information) box.setText( "Saving project canceled. Will go back to canvas.") box.setStandardButtons(QMessageBox.Ok) box.setDefaultButton(QMessageBox.Ok) box.exec() e.ignore() else: e.accept() elif ret == QMessageBox.No: e.accept() else: e.ignore()
def draw_grid(self): contents = self.el.get_displayed_contents() pointer = self.el.pointer full_entries_shown = self.get_entry_count_per_screen() entries_shown = min(len(contents), full_entries_shown) disp_entry_positions = range( self.first_displayed_entry, self.first_displayed_entry + entries_shown) for i in copy(disp_entry_positions): if i not in range(len(contents)): disp_entry_positions.remove(i) c = Canvas(self.o) # Calculate margins step_width = c.width / self.el.cols if not self.entry_width else self.entry_width step_height = c.height / self.el.rows # Create a special canvas for drawing text - making sure it's cropped text_c = Canvas(MockOutput(step_width, step_height)) # Calculate grid index item_x = (pointer - self.first_displayed_entry) % self.el.cols item_y = (pointer - self.first_displayed_entry) // self.el.rows # Draw horizontal and vertical lines if self.draw_lines: for x in range(1, self.el.cols): c.line((x * step_width, 0, x * step_width, c.height)) for y in range(1, self.el.rows): c.line((0, y * step_height, c.width, y * step_height)) # Draw the app names for i, index in enumerate(disp_entry_positions): entry = contents[index] icon = None text = None if isinstance(entry, Entry): text = entry.text if entry.icon: icon = entry.icon else: text = entry[0] if icon: coords = ((i % self.el.cols) * step_width, (i // self.el.rows) * step_height) c.image.paste(icon, coords) else: text_c.clear() text_bounds = c.get_text_bounds(text, font=self.el.font) x_cord = (i % self.el.cols ) * step_width #+(step_width-text_bounds[0])/2 y_cord = (i // self.el.rows) * step_height + ( step_height - text_bounds[1]) / 2 text_c.text(text, (0, 0), font=self.el.font) c.image.paste(text_c.image, (x_cord, y_cord)) # Invert the selected cell selected_x = (item_x) * step_width selected_y = (item_y) * step_height c.invert_rect((selected_x, selected_y, selected_x + step_width, selected_y + step_height)) return c.get_image()
class GraphicEditor(cmd.Cmd): """ Class to handle commandline input and call the appropriate classes. Extends the Cmd class from the built-in module cmd. """ prompt = "(editor)->" def do_I(self, input_line): """Initialize a new canvas (old canvas is discarded)""" M, N = input_line.split(' ') try: M = int(M) N = int(N) except: print("Only integers accepted.") return False if M < 0 or N < 0: print('Canvas dimensions must be positive.') return False self.canvas = Canvas(M, N) def do_X(self, input_line): """Exits the editor""" return True def do_C(self, input_line): """Clear the canvas""" self.canvas.clear() print("Canvas clear.") def do_L(self, input_line): """Draws a pixel on the current canvas""" X, Y, C = input_line.split(' ') validator = IndexValidator(self.canvas) try: X = int(X) Y = int(Y) validator.v_validate(X) validator.v_validate(Y) except: print('Only integers accepted') return False self.canvas.set_pixel(X, Y, C) def do_V(self, input_line): """Command to draw a vertical line""" X, Y1, Y2, C = input_line.split(' ') validador = IndexValidator(self.canvas) try: X = int(X) Y1 = int(Y1) Y2 = int(Y2) validador.h_validate(X) validador.v_validate(Y1) validador.v_validate(Y2) except: print('Only integers accepted and must be inside limits.') return False self.canvas.draw_vertical_segment(X, Y1, Y2, C) def do_H(self, input_line): """Command to draw an horizontal line""" X1, X2, Y, C = input_line.split(' ') validator = IndexValidator(self.canvas) try: X1 = int(X1) X2 = int(X2) Y = int(Y) validator.h_validate(X1) validator.h_validate(X2) validator.v_validate(Y) except: print('Only integers accepted and must be inside limits.') return False self.canvas.draw_horizontal_segment(Y, X1, X2, C) def do_K(self, input_line): """Command to draw a rectangle""" X1, Y1, X2, Y2, C = input_line.split(' ') validator = IndexValidator(self.canvas) try: X1 = int(X1) Y1 = int(Y1) X2 = int(X2) Y2 = int(Y2) validator.h_validate(X1) validator.h_validate(X2) validator.v_validate(Y1) validator.v_validate(Y2) except: print('Only integers accepted and must be inside limits.') return False self.canvas.draw_rectangle(Y1, X1, Y2, X2, C) def do_F(self, input_line): """Command to paint a region""" X, Y, C = input_line.split(' ') validator = IndexValidator(self.canvas) try: X = int(X) Y = int(Y) except: print('Only integers accepted and must be inside limits.') return False self.canvas.paint_region(Y, X, C) def do_S(self, input_line): """Command to save the canvas in the path provided in the filename""" writer = CanvasWriter(self.canvas) writer.set_filename(input_line) writer.write()
def test_clear_canvas(self): canvas = Canvas(5, 6) canvas.set_pixel(3, 3, 'X') canvas.clear() self.assertEqual(self.new_canvas, canvas.canvas)
class GUI: def __init__(self, window_scale_factor): # Initialize the pygame library pygame.init() pygame.font.init() # Set up the drawing window self.window_size = ([window_scale_factor[0]*28, window_scale_factor[1]*28]) pygame.display.set_caption('AI Number Prediction') self.screen = pygame.display.set_mode(self.window_size) self.running = True # Set up external objects self.paint_brush = PaintBrush() self.canvas = Canvas(self.window_size, (28, 28)) self.prediction_text = ["Prediction: ", "", "Certainty: ", ""] self.predicted_prob = 0 def __poll_events(self): # Did the user click the window close button? for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False # Clear the screen if the user clicks right button if pygame.mouse.get_pressed()[2]: self.canvas.clear() def __map(self, value, start_1, stop_1, start_2, stop_2): return interp(value,[start_1, stop_1],[start_2, stop_2]) def __lerp_RGB(self, a, b, t): return ( a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t, a[2] + (b[2] - a[2]) * t, ) def __get_prediction_color(self, predicted_prob): ''' Linear interpolates between RED, YELLOW and GREEN ''' if predicted_prob < 0.5: t = self.__map(predicted_prob, 0, 0.5, 0, 1) return self.__lerp_RGB(RED, YELLOW, t) else: t = self.__map(predicted_prob, 0.5, 1, 0, 1) return self.__lerp_RGB(YELLOW, GREEN, t) def __on_paint_brush_usage(self): if self.paint_brush.using: # Get mouse grid position grid_pos_x = math.floor(self.paint_brush.pos[0] / self.canvas.cell_dimensions[0]) grid_pos_y = math.floor(self.paint_brush.pos[1] / self.canvas.cell_dimensions[1]) # Paint with the brush for x in range(grid_pos_x - self.paint_brush.size[0], grid_pos_x + self.paint_brush.size[1]): for y in range(grid_pos_y - self.paint_brush.size[2], grid_pos_y + self.paint_brush.size[3]): if x >= 0 and y >= 0 and x < self.canvas.grid_w and y < self.canvas.grid_h: self.canvas.grid[x][y].color = self.paint_brush.color self.canvas.grid[x][y].draw(self.canvas.surface) self.canvas.np_arry[y][x] = 1 def reset_prediction_output(self): self.prediction_text[1] = "" self.prediction_text[3] = "" def __draw_text(self): font_size_1 = 13 font_size_2 = 16 text_pos = (15, 15) # Load font myfont_1 = pygame.font.Font(pygame.font.get_default_font(), font_size_1) myfont_2 = pygame.font.Font(pygame.font.get_default_font(), font_size_2) # Row 1 textsurface = myfont_1.render(self.prediction_text[0], True, WHITE, BLACK) self.screen.blit(textsurface, text_pos) x_offset = text_pos[0] + textsurface.get_width() textsurface = myfont_2.render(self.prediction_text[1], True, CUSTOM, BLACK) self.screen.blit(textsurface, (text_pos[0] + x_offset, text_pos[1])) # Row 2 textsurface = myfont_1.render(self.prediction_text[2], True, WHITE, BLACK) self.screen.blit(textsurface, (text_pos[0], text_pos[1] + font_size_2)) x_offset = text_pos[0] + textsurface.get_width() textsurface = myfont_2.render(self.prediction_text[3], True, self.__get_prediction_color(self.predicted_prob), BLACK) self.screen.blit(textsurface, (text_pos[0] + x_offset, text_pos[1] + font_size_2)) def __draw(self): self.__on_paint_brush_usage() self.canvas.draw(self.screen) self.__draw_text() # Flip the display pygame.display.flip() def __update(self): self.paint_brush.update() def render(self): while(self.running): self.__poll_events() self.__update() self.__draw() # Done! Time to quit. pygame.quit()
class ROISelector(QObject, Ui_ROI): def __init__(self, files): super(ROISelector, self).__init__(None) self.mainwindow = QMainWindow() self.setupUi(self.mainwindow) self.image_list = files self.current_index = 170 self.current_image_name = None self.mode = 'crop' self.set_icons() self.connect_buttons() self.previously_selected_button = self.crop_btn self.scene = Canvas(self.mainwindow) self.image_display.setScene(self.scene) self.setup_threads() self.set_initial_image() self.has_roi = False self.roi_file = None def setup_threads(self): self.worker_thread = QThread(self.mainwindow) self.worker = ProcessWorker(self.image_list) self.worker.moveToThread(self.worker_thread) self.worker_thread.finished.connect(self.worker.deleteLater) self.worker_thread.started.connect(self.worker.work) self.worker.image_changed.connect(self.set_image) def set_initial_image(self): self.scene.setImage(self.image_list[0]) def connect_buttons(self): self.save_btn.clicked.connect(self.on_save) self.crop_btn.clicked.connect(self.on_crop) self.lines_btn.clicked.connect(self.on_lines) self.clear_btn.clicked.connect(self.on_clear) self.start_btn.clicked.connect(self.on_start) self.next_btn.clicked.connect(self.on_next) self.import_action.triggered.connect(self.on_import) self.export_action.triggered.connect(self.on_save) def on_clear(self): self.scene.clear() def on_import(self): filename, _ = QFileDialog.getOpenFileName( self.mainwindow, 'Import a region of interest', None, 'JSON(*.json)') if not filename: return roi = None with open(filename, 'r') as fd: roi = json.load(fd) self.roi_file = filename self.scene.draw_roi(roi) self.has_roi = True print('roi: ', roi) def on_next(self): self.current_index += 1 self.current_image_name = self.image_list[self.current_index] img = QImage(self.current_image_name) self.set_image(img) def on_save(self): print('saving') self.mode = 'save' self.scene.set_mode(self.mode) self.previously_selected_button.setEnabled(True) self.previously_selected_button = self.save_btn self.save_btn.setEnabled(False) graphics = self.scene.graphics_items() filename, _ = QFileDialog.getSaveFileName(self.mainwindow, 'Save region of interest', None, 'JSON(*.json)') self.roi_file = filename with open(filename, 'w') as fd: json.dump(graphics, fd) self.has_roi = True print('Saved region of interest to {}'.format(filename)) def on_crop(self): print('cropping') self.mode = 'crop' self.scene.set_mode(self.mode) self.previously_selected_button.setEnabled(True) self.previously_selected_button = self.crop_btn self.crop_btn.setEnabled(False) def on_lines(self): print('drawing lines') self.mode = 'lines' self.scene.set_mode(self.mode) self.previously_selected_button.setEnabled(True) self.previously_selected_button = self.lines_btn self.lines_btn.setEnabled(False) def set_icons(self): save_icon = QIcon('icons/save.svg') crop_icon = QIcon('icons/crop.svg') line_icon = QIcon('icons/draw_lines.svg') reset_icon = QIcon('icons/reset.svg') start_icon = QIcon('icons/start.svg') next_icon = QIcon('icons/next.svg') self.save_btn.setIcon(save_icon) self.crop_btn.setIcon(crop_icon) self.lines_btn.setIcon(line_icon) self.clear_btn.setIcon(reset_icon) self.start_btn.setIcon(start_icon) self.next_btn.setIcon(next_icon) def on_start(self): if self.roi_file is None: return with open(self.roi_file, 'r') as fd: points = json.load(fd) self.worker.cropper.add_roi(points['lines']) self.worker_thread.start() def wheelEvent(self, event): print('Wheeeeeeeeeeeel') def show(self): self.mainwindow.show() def enqueue(self, filename_list): self.image_list.extend(filename_list) self.current_image_name = self.image_list[self.current_index] @pyqtSlot(QImage) def set_image(self, img): pixmap = QPixmap.fromImage(img) self.scene.set_qimage(pixmap) #self.scene.setImage(self.current_image_name) def set_data_directory(self, path): self.url_bar.setText(path)
class DatePicker(BaseUIElement): # Grid dimensions GRID_WIDTH = 7 GRID_HEIGHT = 5 MONTH_NAMES = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] init_strftime_template = '%Y-%m-%d' def __init__(self, i, o, name="DatePicker", year=None, month=None, day=None, callback=None, starting_sunday=False, init_strftime=None, return_strftime=None): # Init BaseUIElement and canvas BaseUIElement.__init__(self, i, o, name) self.c = Canvas(self.o) # Attributes to store the current values self.current_month = 1 self.current_year = 2018 self.starting_weekday = 0 # Store values of optional parameters self.starting_sunday = starting_sunday self.return_strftime = return_strftime self.callback = callback # Top-left cell is (0, 0) self.selected_option = {'x': 0, 'y': 0} self.calendar_grid = [] # Keep track whether Enter has been pressed self.accepted_value = False # Instance of calendar class for generating the calendar self.cal = calendar.Calendar() # If an init_strftime has been provided set the starting date to it if isinstance(init_strftime, basestring): time_object = datetime.datetime.strptime( init_strftime, self.init_strftime_template) self._set_month_year(time_object.month, time_object.year) self.set_current_day(time_object.day) else: # Set the month and year to either the current month/year or a given argument temp_month = datetime.datetime.now().month temp_year = datetime.datetime.now().year if month != None: temp_month = month if year != None: temp_year = year self._set_month_year(temp_month, temp_year) # Set the day to either the current day or a given argument if day != None: self.set_current_day(day) else: self.set_current_day(datetime.datetime.now().day) def get_current_day(self): """Return the currently selected day of the month""" return self.calendar_grid[(self.selected_option['y']) * self.GRID_WIDTH + self.selected_option['x']] def get_days_of_current_month(self): """Return a list of the days of the month""" days = filter( None, list(self.cal.itermonthdays(self.current_year, self.current_month))) return list(sorted(days)) def set_current_day(self, day): """Set the currently selected day""" index = self.calendar_grid.index(day) x = int(index % self.GRID_WIDTH) y = int(index / self.GRID_WIDTH) self.selected_option = {'x': x, 'y': y} def get_return_value(self, check_accepted=True): """Calculate the value to be returned or given as a parameter to the callback""" if self.accepted_value or not check_accepted: # Needs to be updated for python3 to use str instead of basestring # Return either a strftime string or a dict containing the date if isinstance(self.return_strftime, basestring): selected_date = datetime.date(self.current_year, self.current_month, self.get_current_day()) return selected_date.strftime(self.return_strftime) else: return { 'month': self.current_month, 'year': self.current_year, 'day': self.get_current_day() } else: return None def generate_keymap(self): return { "KEY_RIGHT": "move_right", "KEY_LEFT": "move_left", "KEY_UP": "move_up", "KEY_DOWN": "move_down", "KEY_ENTER": "accept_value", "KEY_F3": "move_to_previous_month", "KEY_F4": "move_to_next_month", "KEY_F1": "deactivate" } def idle_loop(self): sleep(0.1) # Move the cursor around def move_right(self): # -----------> # If day is last, move to the first day of the next month if self.get_current_day() == self.get_days_of_current_month()[-1]: self._move_to_next_month() self.set_current_day(1) # If weekday is Sunday, move to the next Monday elif self.selected_option['x'] == self.GRID_WIDTH - 1: self.set_current_day(self.get_current_day() + 1) else: self._move_cursor(1, 0) self.refresh() def move_left(self): # <----------- # If day is 1st, move to the last day of the prev. month if self.get_current_day() == 1: self._move_to_previous_month() self.set_current_day(self.get_days_of_current_month()[-1]) # If weekday is Monday, move to the previous Sunday elif self.selected_option['x'] == 0: self.set_current_day(self.get_current_day() - 1) else: self._move_cursor(-1, 0) self.refresh() def move_up(self): # ^^^^^^^^^^ # TODO: If week is first, move to the last same weekday of the next month if self.selected_option['y'] == 0: self.selected_option['y'] = self.GRID_HEIGHT - 1 self._move_to_previous_month() else: self._move_cursor(0, -1) self.refresh() def move_down(self): # TODO: If week is last, move to the first same weekday of the prev. month if self.selected_option['y'] == self.GRID_HEIGHT - 1: self.selected_option['y'] = 0 self._move_to_next_month() else: self._move_cursor(0, 1) self.refresh() # Switch between months - TODO def _move_to_next_month(self): """Moving to the next month - without refresh() (for internal use)""" if self.current_month < 12: self._set_month_year(self.current_month + 1, self.current_year) elif self.current_month == 12: self._set_month_year(1, self.current_year + 1) else: raise ValueError("Weird month value: {}".format( self.current_month)) def move_to_next_month(self): """Moving to the next month - with refresh() (key callback)""" self._move_to_next_month() self.refresh() def _move_to_previous_month(self): """Moving to the previous month - without refresh() (for internal use)""" if self.current_month > 1: self._set_month_year(self.current_month - 1, self.current_year) elif self.current_month == 1: self._set_month_year(12, self.current_year - 1) else: raise ValueError("Weird month value: {}".format( self.current_month)) def move_to_previous_month(self): """Moving to the previous month - with refresh() (key callback)""" self._move_to_previous_month() self.refresh() def accept_value(self): # Check for a provided callback if callable(self.callback): self.to_background() self.callback(self.get_return_value(check_accepted=False)) self.to_foreground() else: self.accepted_value = True self.deactivate() def draw_calendar(self): """Draw the calendar view""" self.c.clear() # Create the year - month header string year_month = "{} - {}".format(self.MONTH_NAMES[self.current_month - 1], self.current_year) # Display the week number in the top left corner week_num = datetime.date(self.current_year, self.current_month, self.get_current_day()).isocalendar()[1] self.c.text(str(week_num), (4, 0)) # Draw 'year - month' centered at the top of the screen month_year_text_bounds = self.c.get_text_bounds(year_month) centered_cords = self.c.get_centered_text_bounds(year_month) self.c.text(year_month, (centered_cords[0], 0)) # Draw calendar grid # Calculate margin between vertical/horizontal lines step_width = self.c.width / self.GRID_WIDTH step_height = (self.c.height - month_year_text_bounds[1]) / self.GRID_HEIGHT # Draw lines for x in range(step_width, self.c.width - step_width, step_width): self.c.line( (x + 1, month_year_text_bounds[1], x + 1, step_height * 6)) for y in range(step_height, self.c.height, step_height): self.c.line((0, y, self.c.width, y)) # Draw dates i = self.starting_weekday for i in range(len(self.calendar_grid)): date = self.calendar_grid[i] if date == -1: continue # Jump to the first line if it's reached the last cell if i >= (self.GRID_WIDTH * self.GRID_HEIGHT): i = 0 date_text_bounds = self.c.get_text_bounds(str(date)) # Calculate the coordinates for the date string x_cord = ( i%self.GRID_WIDTH)*step_width + \ ( (step_width-date_text_bounds[0])/2 ) y_cord = ( i//self.GRID_WIDTH)*step_height + \ step_height+ \ ( (step_height-date_text_bounds[1])/2 ) self.c.text(str(date), (x_cord + 1, y_cord + 1)) # Increase the counter and continue to the next date, import for positioning i += 1 # Highlight selected option selected_x = (self.selected_option['x']) * step_width selected_y = (self.selected_option['y']) * step_height + step_height self.c.invert_rect( (selected_x + 1, selected_y + 1, selected_x + step_width + 1, selected_y + step_height)) self.c.display() def refresh(self): self.draw_calendar() # Moves the cursor def _move_cursor(self, delta_x, delta_y): if self._check_movable_field(self.selected_option['x'] + delta_x, self.selected_option['y'] + delta_y): self.selected_option['x'] += delta_x self.selected_option['y'] += delta_y # Check whether the desired movement is viable def _check_movable_field(self, new_x, new_y): # New movement would definitely be out of grid limit = (new_x) + (new_y) * self.GRID_WIDTH if limit >= len(self.calendar_grid): return False if (self.calendar_grid[(new_x) + (new_y) * self.GRID_WIDTH] != -1 and new_x < self.GRID_WIDTH and new_x >= 0 and new_y < self.GRID_HEIGHT and new_y >= 0): return True else: return False # Set the current month/year to display def _set_month_year(self, month, year): # Set new month and year self.current_month = month self.current_year = year # Clear the calendar grid self.calendar_grid = [] # Get the weekday of the first day of the month first_day, _ = calendar.monthrange(self.current_year, self.current_month) if self.starting_sunday: first_day += 1 self.starting_weekday = first_day i = 0 # Assign -1 to empty cells for i in range(first_day): self.calendar_grid.append(-1) # Set the cursor to the first viable cell self.selected_option['x'] = i + 1 i = first_day for date in self.cal.itermonthdays(self.current_year, self.current_month): if date == 0: continue if i >= self.GRID_WIDTH * self.GRID_HEIGHT: self.calendar_grid[i % (self.GRID_WIDTH * self.GRID_HEIGHT)] = date else: self.calendar_grid.append(date) i += 1 # Assign -1 to empty cells for i in range(self.GRID_WIDTH * self.GRID_HEIGHT - i): self.calendar_grid.append(-1)