Exemplo n.º 1
0
class LayerManager(ttk.LabelFrame):
    def __init__(self, canvas_window, project, *args, **kwargs):
        ttk.LabelFrame.__init__(self, *args, **kwargs)
        self.project = project
        self.canvas_window = canvas_window
        self.thumbnails = []
        self.tiles = []
        self.canvas_height = 700
        self.trash_image = load_tk_image_from_bytes_array(trash_bytes)
        self.copy_image = load_tk_image_from_bytes_array(copy_bytes_wide)
        self.up_image = load_tk_image_from_bytes_array(up_arrow_bytes)
        self.down_image = load_tk_image_from_bytes_array(down_arrow_bytes)
        self.name_image = load_tk_image_from_bytes_array(name_symbol_bytes)
        self.merge_image = load_tk_image_from_bytes_array(
            merge_down_symbol_bytes)
        self.new_image = load_tk_image_from_bytes_array(plus_symbol_bytes)
        self.new_from_image_image = load_tk_image_from_bytes_array(
            new_layer_from_image_bytes)
        self.up_carret_image = load_tk_image_from_bytes_array(up_carret_bytes)
        self.down_carret_image = load_tk_image_from_bytes_array(
            down_carret_bytes)

        self.nextid = 0
        self.configure(text="Frames")
        frame_tools_frame = Frame(self)
        frame_tools_frame.pack(side="top", fill="x", expand="False")
        self.new_frame_symbol = load_tk_image_from_bytes_array(
            plus_symbol_bytes)
        l = Label(frame_tools_frame, image=self.new_frame_symbol)
        l.pack(side="left")
        l.bind("<Button-1>", self.new_frame)

        self.canvas = Canvas(self, relief="sunken")
        self.canvas.config(width=200, height=700, highlightthickness=0)
        self.scrollbar = Scrollbar(self)
        self.scrollbar.config(command=self.on_scroll_bar)
        self.canvas.config(yscrollcommand=self.scrollbar.set)
        self.scrollbar.pack(side="right", fill="y")
        self.canvas.pack(side="right", expand=True, fill="both")
        self.canvas_frame = Frame(self.canvas, border=0, highlightthickness=0)
        self.canvas_frame.bind("<MouseWheel>", self._on_mouse_wheel)
        self.canvas.create_window(0, 0, window=self.canvas_frame, anchor='nw')
        self.canvas.bind("<MouseWheel>", self._on_mouse_wheel)
        self.canvas_frame.config(width=200, height=self.winfo_height())
        self.canvas.config(scrollregion=(0, 0, 200, self.canvas_height))
        self.canvas.bind("<Enter>", self.mouse_enter)
        self.canvas.bind("<Leave>", self.mouse_leave)
        self.canvas.bind("<Motion>", self.on_mouse_move)
        self.canvas.bind("<Button-1>", self.on_click)
        self.canvas.after_idle(self.canvas_window.refresh)
        self.bind("<MouseWheel>", self._on_mouse_wheel)

    def new_frame(self, event=None):
        self.project.new_frame()
        self.canvas_window.refresh()

    def rename_frame(self, frame):
        name = simpledialog.askstring(
            "Rename Frame",
            f"What would you like to rename Frame: {frame.id} to?")
        if name:
            frame.set_id(name)
            self.canvas_window.refresh()

    def ask_delete_frame(self):
        if len(self.project.frames) == 1:
            messagebox.showwarning("Warning", "Cannot delete last frame.")
            return
        return messagebox.askyesno(
            "Delete",
            "Are you sure you wish to delete this frame?\nThis cannot be undone."
        )

    def delete_frame(self, frame):
        if self.ask_delete_frame():
            self.project.del_frame(frame)
            self.project.selected_frame = self.project.frames[0]
            self.canvas.after_idle(self.canvas_window.refresh)

    def copy_frame(self, frame):
        self.project.copy_frame(frame)
        self.canvas.after_idle(self.canvas_window.refresh)

    def promote_frame(self, frame):
        self.project.promote_frame(frame)
        self.canvas.after_idle(self.canvas_window.refresh)

    def demote_frame(self, frame):
        self.project.demote_frame(frame)
        self.canvas.after_idle(self.canvas_window.refresh)

    def toggle_collapsed(self, frame):
        self.project.toggle_collapsed(frame)
        self.canvas.after_idle(self.canvas_window.refresh)

    def rename_layer(self, frame, layer):
        name = simpledialog.askstring(
            "Rename Layer",
            f"What would you like to rename Layer: {layer.id} to?")
        if name:
            layer.set_id(name)
            self.canvas.after_idle(self.canvas_window.refresh)

    def new_layer_from_image(self, frame):
        path = filedialog.askopenfilename()
        if path:
            image = Image.open(path)
            layer = frame.new_layer_from_image(image)
            self.canvas.after_idle(self.canvas_window.refresh)

    def new_layer(self, frame):
        layer = frame.new_layer()
        frame.selected_layer = layer
        self.canvas.after_idle(self.canvas_window.refresh)

    def ask_delete_layer(self, frame, layer):
        if len(frame.layers) == 1:
            messagebox.showwarning("Warning", "Cannot delete last layer.")
            return
        return messagebox.askyesno(
            "Delete Layer?",
            f"Are you sure you wish to delete this layer?\n{layer.id}")

    def delete_layer(self, frame, layer):
        if self.ask_delete_layer(frame, layer):
            frame.del_layer(layer)
            frame.selected_layer = frame.layers[0]
        self.canvas.after_idle(self.canvas_window.refresh)

    def copy_layer(self, frame, layer):
        frame.copy_layer(layer)
        self.canvas.after_idle(self.canvas_window.refresh)

    def promote_layer(self, frame, layer):
        frame.promote_layer(layer)
        self.canvas.after_idle(self.canvas_window.refresh)

    def demote_layer(self, frame, layer):
        frame.demote_layer(layer)
        self.canvas.after_idle(self.canvas_window.refresh)

    def merge_layer_down(self, frame, layer):
        frame.merge_layer_down(layer)
        self.canvas.after_idle(self.canvas_window.refresh)

    def mouse_enter(self, event):
        pass

    def mouse_leave(self, event):
        pass

    def on_click(self, event):
        y = int(event.y + (float(self.canvas.yview()[0]) * self.canvas_height))
        x = event.x
        for t in self.tiles:
            if t.is_in_row(y):
                mode = t.on_click(x, y)
                if not mode:
                    t.activate()
                    if type(t) is FrameTile:
                        self.project.selected_frame = t.frame
                    elif type(t) is LayerTile:
                        self.project.selected_frame = t.frame
                        t.frame.selected_layer = t.layer
                    self.canvas_window.refresh()
            else:
                t.deactivate()

    def on_mouse_move(self, event):
        y = int(event.y + (float(self.canvas.yview()[0]) * self.canvas_height))
        x = event.x
        for t in self.tiles:
            if t.active:
                if t.is_in_row(y): continue
                else: t.deactivate()
            elif t.is_in_row(y): t.activate()

    def refresh(self, event=None):
        self.winfo_toplevel().update_idletasks()
        self.canvas.delete("all")
        self.thumbnails = []
        self.tiles = []
        if self.project.frames:
            i = 0
            y_offset = 10
            y_padding = 10
            tile_height = 80
            x = 10
            width = 80
            height = tile_height
            child_offset = 0.5 * tile_height
            for f in self.project.frames:
                y = i * tile_height + y_offset + i * y_padding
                t = FrameTile(self, f)
                self.tiles.append(t)
                t.set_dimensions(x, y, width, height)
                self.place_tile(t)
                i += 1
                firstlayer = True
                layers = []
                if f.layers:
                    if f.collapsed:
                        continue

                    for l in f.layers:
                        floffset = x + 0.5 * child_offset
                        flyoffset = y + tile_height
                        if firstlayer:
                            firstlayer = False
                            self.canvas.create_line(
                                floffset, flyoffset, floffset,
                                flyoffset + y_padding + 0.5 * tile_height)
                        else:
                            self.canvas.create_line(
                                floffset, y + 0.5 * child_offset, floffset,
                                flyoffset + y_padding + 0.5 * tile_height)
                        self.canvas.create_line(
                            floffset,
                            flyoffset + y_padding + 0.5 * tile_height,
                            x + child_offset,
                            flyoffset + y_padding + 0.5 * tile_height,
                        )
                        y = i * tile_height + y_offset + i * y_padding
                        L = LayerTile(self, l, f)
                        L.set_dimensions(x + child_offset, y, width, height)
                        self.place_tile(L)
                        self.tiles.append(L)
                        i += 1

            height = i * (tile_height + y_padding) + y_offset
            frameheight = self.canvas_frame.winfo_height()
            height = height if height > frameheight else frameheight
            self.canvas_height = height
            self.canvas_frame.config(width=200, height=self.winfo_height())
            self.canvas.config(scrollregion=(0, 0, 200, self.canvas_height))
        else:
            print("No frames")

    def place_tile(self, tile):
        tn = ImageTk.PhotoImage(tile.get_thumbnail(tile.height - 8))
        self.thumbnails.append(tn)
        tile.references.append(
            self.canvas.create_image(tile.x + 0.5 * tile.width,
                                     tile.y + 0.5 * tile.height,
                                     image=tn))
        if type(tile) is FrameTile:
            if tile.frame is self.project.selected_frame:
                tile.references.append(
                    self.canvas.create_rectangle(tile.x,
                                                 tile.y,
                                                 tile.x + tile.width,
                                                 tile.y + tile.height,
                                                 outline="#000000",
                                                 width=3))
            else:
                tile.references.append(
                    self.canvas.create_rectangle(tile.x,
                                                 tile.y,
                                                 tile.x + tile.width,
                                                 tile.y + tile.height,
                                                 outline="#000000",
                                                 width=1))
        elif type(tile) is LayerTile:
            if tile.layer is self.project.selected_frame.selected_layer:
                tile.references.append(
                    self.canvas.create_rectangle(tile.x,
                                                 tile.y,
                                                 tile.x + tile.width,
                                                 tile.y + tile.height,
                                                 outline="#000000",
                                                 width=3))
            else:
                tile.references.append(
                    self.canvas.create_rectangle(tile.x,
                                                 tile.y,
                                                 tile.x + tile.width,
                                                 tile.y + tile.height,
                                                 outline="#000000",
                                                 width=1))
        if tile.active: self.activate_tile()
        tile.references.append(
            self.canvas.create_text(tile.x + tile.width + 10,
                                    tile.y,
                                    font="CourierNew 8",
                                    text=tile.id,
                                    anchor="nw"))

    def activate_tile(self, tile):
        tile.active_references.extend([
            self.canvas.create_image(tile.trash_x,
                                     tile.trash_y,
                                     anchor="nw",
                                     image=self.trash_image),
            self.canvas.create_image(tile.copy_x,
                                     tile.copy_y,
                                     anchor="nw",
                                     image=self.copy_image),
            self.canvas.create_image(tile.up_x,
                                     tile.up_y,
                                     anchor="nw",
                                     image=self.up_image),
            self.canvas.create_image(tile.down_x,
                                     tile.down_y,
                                     anchor="nw",
                                     image=self.down_image),
            self.canvas.create_image(tile.name_x,
                                     tile.name_y,
                                     anchor="nw",
                                     image=self.name_image),
        ])

        if type(tile) is FrameTile:
            if tile.frame.collapsed: carret_image = self.down_carret_image
            else: carret_image = self.up_carret_image
            tile.active_references.extend([
                self.canvas.create_image(tile.new_x,
                                         tile.new_y,
                                         anchor="nw",
                                         image=self.new_image),
                self.canvas.create_image(tile.new_from_image_x,
                                         tile.new_from_image_y,
                                         anchor="nw",
                                         image=self.new_from_image_image),
                self.canvas.create_image(tile.carret_x,
                                         tile.carret_y,
                                         anchor="nw",
                                         image=carret_image),
            ])
        elif type(tile) is LayerTile:
            tile.active_references.append(
                self.canvas.create_image(tile.merge_x,
                                         tile.merge_y,
                                         anchor="nw",
                                         image=self.merge_image))

    def deactivate_tile(self, tile):
        self.canvas.create_rectangle(tile.x,
                                     tile.y,
                                     tile.x + tile.width,
                                     tile.y + tile.height,
                                     outline="#000000",
                                     width=1)
        for r in tile.active_references:
            self.canvas.delete(r)

    def _on_mouse_wheel(self, event):
        if platform.system() == 'Windows':
            self.canvas.yview_scroll(-1 * int(event.delta / 120), 'units')
        elif platform.system() == 'Darwin':
            self.canvas.yview_scroll(-1 * int(event.delta), 'units')
        else:
            if event.num == 4:
                self.canvas.yview_scroll(-1, 'units')
            elif event.num == 5:
                self.canvas.yview_scroll(1, 'units')

    def on_scroll_bar(self, move_type, move_units, __=None):
        if move_type == "moveto":
            self.canvas.yview("moveto", move_units)
Exemplo n.º 2
0
class ClipBoardBox(ttk.Labelframe):
    def __init__(
        self,
        controller,
        *args,
    ):
        ttk.Labelframe.__init__(self, *args, text="Clipboard")
        self.clipboard = controller.clipboard

        self.thumbnails = []
        self.tiles = []
        self.canvas_height = 300
        self.trash_image = load_tk_image_from_bytes_array(trash_bytes)

        self.nextid = 0

        self.canvas = Canvas(self, relief="sunken")
        self.canvas.config(width=200,
                           height=self.canvas_height,
                           highlightthickness=0)
        self.scrollbar = Scrollbar(self)
        self.scrollbar.config(command=self.on_scroll_bar)
        self.canvas.config(yscrollcommand=self.scrollbar.set)
        self.scrollbar.pack(side="right", fill="y")
        self.canvas.pack(side="right", expand=True, fill="both")
        self.canvas_frame = Frame(self.canvas, border=0, highlightthickness=0)
        self.canvas_frame.bind("<MouseWheel>", self._on_mouse_wheel)
        self.canvas.create_window(0, 0, window=self.canvas_frame, anchor='nw')
        self.canvas.bind("<MouseWheel>", self._on_mouse_wheel)
        self.canvas_frame.config(width=200, height=self.winfo_height())
        self.canvas.config(scrollregion=(0, 0, 200, self.canvas_height))
        self.canvas.bind("<Enter>", self.mouse_enter)
        self.canvas.bind("<Leave>", self.mouse_leave)
        self.canvas.bind("<Motion>", self.on_mouse_move)
        self.canvas.bind("<Button-1>", self.on_click)
        self.canvas.after_idle(self.refresh)
        self.bind("<MouseWheel>", self._on_mouse_wheel)

        self.grip = ttk.Sizegrip(self)
        self.grip.place(relx=1.0, rely=1.0, anchor="se")
        self.grip.bind("<ButtonPress-1>", self.on_press)
        self.grip.bind("<B1-Motion>", self.on_resize)
        self.grip.bind("<ButtonRelease-1>", self.on_release)

    # def on_resize(self, event):
    # 	x_change = event.x_root - self.winfo_rootx()
    # 	x_change = 1 if x_change < 1 else x_change
    # 	y_change = event.y_root - self.winfo_rooty()
    # 	y_change = 1 if y_change < 1 else y_change
    # 	# self.minsize(self.winfo_reqwidth(), self.winfo_reqheight())
    # 	self.geometry("%sx%s" % (x_change, y_change))

    def on_press(self, event):
        self.grip["cursor"] = "bottom_right_corner"

    def on_resize(self, event):
        x_change = event.x_root - self.winfo_rootx()
        x_change = 1 if x_change < 1 else x_change
        y_change = event.y_root - self.winfo_rooty()
        y_change = 1 if y_change < 1 else y_change
        # self.minsize(self.winfo_reqwidth(), self.winfo_reqheight())
        self.geometry("%sx%s" % (x_change, y_change))

    def on_release(self, event):
        self.grip["cursor"] = "arrow"
        self.refresh()

    def mouse_enter(self, event):
        pass

    def mouse_leave(self, event):
        pass

    def on_click(self, event):
        y = int(event.y + (float(self.canvas.yview()[0]) * self.canvas_height))
        x = event.x
        for t in self.tiles:
            if t.is_in_row(y):
                mode = t.on_click(x, y)
                if not mode:
                    self.clipboard.selected_layer = t.layer
                    t.layer.activate()
                    self.refresh()
            else:
                t.deactivate()

    def on_mouse_move(self, event):
        y = int(event.y + (float(self.canvas.yview()[0]) * self.canvas_height))
        x = event.x
        for t in self.tiles:
            if t.active:
                if t.is_in_row(y): continue
                else: t.deactivate()
            elif t.is_in_row(y): t.activate()

    def refresh(self, event=None):
        self.winfo_toplevel().update_idletasks()
        self.canvas.delete("all")
        self.thumbnails = []
        self.tiles = []
        if self.clipboard.layers:
            i = 0
            y_offset = 10
            y_padding = 10
            tile_height = 80
            x = 10
            width = 80
            height = tile_height
            child_offset = 0.5 * tile_height
            for c in self.clipboard.layers:
                y = i * tile_height + y_offset + i * y_padding
                t = ClipTile(self, c)
                self.tiles.append(t)
                t.set_dimensions(x, y, width, height)
                self.place_tile(t)
                if c is self.clipboard.selected_layer: self.select_tile(t)

                i += 1

            height = i * tile_height + y_offset + i * y_padding
            frameheight = self.canvas_frame.winfo_height()
            height = height if height > frameheight else frameheight
            self.canvas_height = height
            self.canvas_frame.config(width=200, height=self.canvas_height)
            self.canvas.config(scrollregion=(0, 0, 200, self.canvas_height))

        else:
            pass

    def place_tile(self, tile):
        tn = ImageTk.PhotoImage(tile.get_thumbnail(tile.height))
        self.thumbnails.append(tn)
        tile.references.append(
            self.canvas.create_image(tile.x + 0.5 * tile.width,
                                     tile.y + 0.5 * tile.height,
                                     image=tn))
        tile.references.append(
            self.canvas.create_rectangle(tile.x,
                                         tile.y,
                                         tile.x + tile.width,
                                         tile.y + tile.height,
                                         outline="#000000",
                                         width=1))
        tile.references.append(
            self.canvas.create_text(tile.x + tile.width + 10,
                                    tile.y,
                                    font="CourierNew 8",
                                    text=tile.id,
                                    anchor="nw"))
        tile.references.append(
            self.canvas.create_text(
                tile.x + tile.width + 10,
                tile.y + 10,
                font="CourierNew 8",
                text=f"Size: {tile.layer.width}px x {tile.layer.height}px",
                anchor="nw"))

    def activate_tile(self, tile):
        tile.active_references.extend([
            self.canvas.create_rectangle(tile.x,
                                         tile.y,
                                         tile.x + tile.width,
                                         tile.y + tile.height,
                                         outline="#000000",
                                         width=2),
            self.canvas.create_image(tile.trash_x,
                                     tile.trash_y,
                                     anchor="nw",
                                     image=self.trash_image),
        ])

    def deactivate_tile(self, tile):
        self.canvas.create_rectangle(tile.x,
                                     tile.y,
                                     tile.x + tile.width,
                                     tile.y + tile.height,
                                     outline="#000000",
                                     width=1)
        for r in tile.active_references:
            self.canvas.delete(r)

    def select_tile(self, tile):
        tile.references.append(
            self.canvas.create_rectangle(tile.x,
                                         tile.y,
                                         tile.x + tile.width,
                                         tile.y + tile.height,
                                         outline="#000000",
                                         width=3))

    def _on_mouse_wheel(self, event):
        if platform.system() == 'Windows':
            self.canvas.yview_scroll(-1 * int(event.delta / 120), 'units')
        elif platform.system() == 'Darwin':
            self.canvas.yview_scroll(-1 * int(event.delta), 'units')
        else:
            if event.num == 4:
                self.canvas.yview_scroll(-1, 'units')
            elif event.num == 5:
                self.canvas.yview_scroll(1, 'units')

    def on_scroll_bar(self, move_type, move_units, __=None):
        if move_type == "moveto":
            self.canvas.yview("moveto", move_units)

    def delete_layer(self, layer):
        self.clipboard.del_layer(layer)
        self.clipboard.selected_layer = self.clipboard.layers[
            0] if self.clipboard.layers else None
        self.canvas.after_idle(self.refresh)