diff --git a/webui/flet/scripts/flet_asset_manager.py b/webui/flet/scripts/flet_asset_manager.py index 657e0c3..cd01883 100644 --- a/webui/flet/scripts/flet_asset_manager.py +++ b/webui/flet/scripts/flet_asset_manager.py @@ -48,10 +48,10 @@ class AssetManager(ft.Container): tab.content.margin = margin - class AssetPanel(ft.Container): pass + class LayerPanel(ft.Container): def update_layers(self): self.layers = self.content.content.controls @@ -152,9 +152,11 @@ class LayerPanel(ft.Container): self.layers.insert(index, layer) self.update_layers() + class LayerSlot(ft.Container): pass + def layer_left_click(e: ft.TapEvent): index = layer_panel.get_layer_index_from_position(e.local_y) if index >= len(layer_panel.layers): @@ -181,6 +183,8 @@ def on_layer_drag(e: ft.DragUpdateEvent): def drop_layer(e: ft.DragEndEvent): layer_panel.layer_being_moved = None + +# LayerPanel == ft.Container layer_panel = LayerPanel( content = ft.GestureDetector( content = ft.Column( @@ -203,6 +207,8 @@ layer_panel.visible_layers = [] layer_panel.layer_being_moved = None layer_panel.layer_last_index = 0 + +# AssetPanel == ft.Container asset_panel = AssetPanel( content = ft.Column( controls = [ @@ -223,6 +229,8 @@ asset_manager_dragbar = ft.GestureDetector( content = ft.VerticalDivider(), ) + +# AssetManager == ft.Container asset_manager = AssetManager( content = ft.Row( controls = [ @@ -258,9 +266,9 @@ asset_manager = AssetManager( ) asset_manager.tabs = asset_manager.content.controls[0].controls[0].tabs -asset_manager.dragbar = asset_manager_dragbar asset_manager.layer_panel = layer_panel asset_manager.asset_panel = asset_panel +asset_manager.dragbar = asset_manager_dragbar ''' # keep track of which layers are visible diff --git a/webui/flet/scripts/flet_canvas.py b/webui/flet/scripts/flet_canvas.py index 53b2052..8ea7556 100644 --- a/webui/flet/scripts/flet_canvas.py +++ b/webui/flet/scripts/flet_canvas.py @@ -32,6 +32,7 @@ class Canvas(ft.Container): def refresh_canvas(self): self.overlay.refresh_canvas_overlay() + self.page.update() def set_current_tool(self, tool): self.page.current_tool = tool @@ -92,8 +93,25 @@ class Canvas(ft.Container): self.image_stack.get_scaled_size() self.align_canvas(e) -def pan_canvas(e): - canvas.pan_canvas(e) + def set_current_tool(self, tool): + if tool == 'pan': + self.overlay.controls.pop(2) + self.overlay.controls.insert(2,pan_tool) + elif tool == 'move': + self.overlay.controls.pop(2) + self.overlay.controls.insert(2,move_tool) + elif tool == 'box_select': + self.overlay.controls.pop(2) + self.overlay.controls.insert(2,box_select_tool) + elif tool == 'brush': + self.overlay.controls.pop(2) + self.overlay.controls.insert(2,brush_tool) + elif tool == 'fill': + self.overlay.controls.pop(2) + self.overlay.controls.insert(2,fill_tool) + else: + pass + self.update() class ImageStack(ft.Container): def add_canvas_background(self): @@ -112,6 +130,8 @@ class ImageStack(ft.Container): ), ) canvas_bg.image = image + canvas_bg.offset_x = 0 + canvas_bg.offset_y = 0 self.canvas_bg = canvas_bg self.content.controls.append(canvas_bg) @@ -144,14 +164,17 @@ class ImageStack(ft.Container): ), ) layer_image.image = image + layer_image.offset_x = 0 + layer_image.offset_y = 0 self.center_layer(layer_image) self.content.controls.append(layer_image) + self.page.tool_manager.enable_tools() canvas.refresh_canvas() def get_preview(self): stack = [] for layer in self.content.controls: - stack.append(layer.image) + stack.append(layer) return flet_utils.get_preview_from_stack(self.page.canvas_size, stack) def get_scaled_size(self): @@ -159,28 +182,44 @@ class ImageStack(ft.Container): self.scaled_height = self.height * self.scale def center_layer(self, layer_image): + layer_image.offset_x = 0 + layer_image.offset_y = 0 layer_image.left = (self.width * 0.5) - (layer_image.width * 0.5) layer_image.top = (self.height * 0.5) - (layer_image.height * 0.5) def align_layer(self, layer_image): - layer_image.left = (self.width * 0.5) - (layer_image.width * 0.5) - layer_image.top = (self.height * 0.5) - (layer_image.height * 0.5) + layer_image.left = ((self.width - layer_image.width) * 0.5) + layer_image.offset_x + layer_image.top = ((self.height - layer_image.height) * 0.5) + layer_image.offset_y - def drag_layer(self, e): + def move_layer(self, e: ft.DragUpdateEvent): + index = self.page.active_layer.index + layer = self.content.controls[index+1] + layer.offset_x += e.delta_x + layer.offset_y += e.delta_y + self.align_layer(layer) + self.update() + + def finish_move_layer(self, e: ft.DragEndEvent): + canvas.refresh_canvas() + + def resize_layer(self, e: ft.DragUpdateEvent): pass - def resize_layer(self, e): + def box_select(self, e): pass - def draw_on_layer(self, e): + def bucket_fill(self, e): pass - def paint_on_layer(self, e): - pass class LayerImage(ft.Container): pass + +class CanvasGestures(ft.GestureDetector): + pass + + class CanvasOverlay(ft.Stack): def refresh_canvas_overlay(self): self.refresh_canvas_size_display() @@ -199,9 +238,7 @@ class CanvasOverlay(ft.Stack): self.page.property_manager.set_preview_image(preview) -def pan_canvas(e): - canvas.pan_canvas(e) - +# ImageStack == ft.Container image_stack = ImageStack( width = 4096, height = 4096, @@ -224,6 +261,8 @@ canvas_cover = ft.Container( opacity = 0.5, ) + +# LayerImage == ft.Container canvas_preview = LayerImage( width = 4096, height = 4096, @@ -238,12 +277,68 @@ canvas_preview = LayerImage( ) -canvas_gestures = ft.GestureDetector( - mouse_cursor = ft.MouseCursor.MOVE, +# CanvasGestures == ft.GestureDetector +def pan_canvas(e): + canvas.pan_canvas(e) + +pan_tool = CanvasGestures( + mouse_cursor = ft.MouseCursor.GRAB, drag_interval = 10, on_pan_update = pan_canvas, ) +def select_layer(e): + pass + +def move_layer(e): + image_stack.move_layer(e) + +def finish_move_layer(e): + image_stack.finish_move_layer(e) + +move_tool = CanvasGestures( + mouse_cursor = ft.MouseCursor.MOVE, + drag_interval = 10, + on_pan_start = select_layer, + on_pan_update = move_layer, + on_pan_end = finish_move_layer, +) + +def set_select_start(e): + pass + +def draw_select_box(e): + pass + +def get_box_select(e): + pass + +box_select_tool = CanvasGestures( + mouse_cursor = ft.MouseCursor.GRAB, + drag_interval = 10, + on_pan_start = set_select_start, + on_pan_update = draw_select_box, + on_pan_end = get_box_select, +) + +def draw_on_layer(e): + pass + +brush_tool = CanvasGestures( + mouse_cursor = ft.MouseCursor.GRAB, + drag_interval = 10, + on_pan_update = draw_on_layer, +) + +def fill_selection(e): + pass + +fill_tool = CanvasGestures( + mouse_cursor = ft.MouseCursor.GRAB, + drag_interval = 10, + on_tap = fill_selection, +) + canvas_size_display = ft.Container( content = ft.Text( value = "test", @@ -305,11 +400,13 @@ canvas_tools.center = center_canvas_button canvas_tools.zoom_in = zoom_in_button canvas_tools.zoom_out = zoom_out_button + +# CanvasOverlay == ft.Stack canvas_overlay = CanvasOverlay( [ canvas_cover, canvas_preview, - canvas_gestures, + pan_tool, canvas_size_display, canvas_tools, ], @@ -321,7 +418,7 @@ canvas_overlay.size_display = canvas_size_display canvas_overlay.tools = canvas_tools - +# Canvas = ft.Container canvas = Canvas( content = ft.Stack( [ diff --git a/webui/flet/scripts/flet_tool_manager.py b/webui/flet/scripts/flet_tool_manager.py index 7aa2531..faa846f 100644 --- a/webui/flet/scripts/flet_tool_manager.py +++ b/webui/flet/scripts/flet_tool_manager.py @@ -7,19 +7,20 @@ import flet as ft from scripts import flet_utils def open_gallery(e): - e.control.page.open_gallery(e) + e.page.open_gallery(e) def blank_layer(e): - e.control.page.asset_manager.add_blank_layer(e) + e.page.asset_manager.add_blank_layer(e) def load_image(e): - e.control.page.file_picker.pick_files(file_type = 'image', allow_multiple = True) + e.page.file_picker.pick_files(file_type = 'image', allow_multiple = True) def tool_select(e): toolbox.clear_tools() - e.control.page.current_tool = e.control.data['label'] + e.page.current_tool = e.control.data['label'] + e.page.canvas.set_current_tool(e.control.data['label']) e.control.selected = True - e.control.page.update() + e.page.update() class Action(): @@ -28,6 +29,8 @@ class Action(): self.icon = icon self.tooltip = tooltip self.on_click = on_click + self.disabled = False + action_list = [ Action('gallery', ft.icons.DASHBOARD_OUTLINED, 'Gallery', open_gallery), @@ -35,20 +38,24 @@ action_list = [ Action('load image', ft.icons.IMAGE_OUTLINED, 'Load image as layer', load_image), ] + class Tool(): - def __init__(self, label, icon, tooltip, on_click): + def __init__(self, label, icon, tooltip): self.label = label self.icon = icon self.tooltip = tooltip - self.on_click = on_click + self.on_click = tool_select + self.disabled = True + tool_list = [ - Tool('move', ft.icons.OPEN_WITH_OUTLINED, 'Move layer(s)', tool_select), - Tool('select', ft.icons.HIGHLIGHT_ALT_OUTLINED, 'Select tool', tool_select), - Tool('brush', ft.icons.BRUSH_OUTLINED, 'Brush tool', tool_select), - Tool('fill', ft.icons.FORMAT_COLOR_FILL_OUTLINED, 'Fill tool', tool_select), + Tool('move', ft.icons.OPEN_WITH_OUTLINED, 'Move layer(s)'), + Tool('select', ft.icons.HIGHLIGHT_ALT_OUTLINED, 'Select tool'), + Tool('brush', ft.icons.BRUSH_OUTLINED, 'Brush tool'), + Tool('fill', ft.icons.FORMAT_COLOR_FILL_OUTLINED, 'Fill tool'), ] + class ToolManager(ft.Container): def setup(self): self.toolbox.get_tools() @@ -82,6 +89,11 @@ class ToolManager(ft.Container): toolbox.height = self.page.toolbox_height self.update() + def enable_tools(self): + for tool in self.toolbox.content.controls: + tool.disabled = False + self.update() + class ToolBox(ft.Container): def get_tools(self): for action in action_list: @@ -109,6 +121,7 @@ class ToolBox(ft.Container): tooltip = button_info.tooltip, data = {'label':button_info.label}, on_click = button_info.on_click, + disabled = button_info.disabled, ) return button @@ -120,6 +133,7 @@ class ToolBox(ft.Container): class ToolPropertyPanel(ft.Container): pass + # ToolBox == ft.Container toolbox = ToolBox( clip_behavior = 'antiAlias', @@ -148,6 +162,7 @@ tool_divider = ft.GestureDetector( ), ) + # ToolPropertyPanel == ft.Container tool_properties = ToolPropertyPanel( content = ft.Column( @@ -165,6 +180,7 @@ tool_manager_dragbar = ft.GestureDetector( content = ft.VerticalDivider(), ) + # ToolManager = ft.Container tool_manager = ToolManager( content = ft.Row( diff --git a/webui/flet/scripts/flet_utils.py b/webui/flet/scripts/flet_utils.py index abf0cd5..e6af36f 100644 --- a/webui/flet/scripts/flet_utils.py +++ b/webui/flet/scripts/flet_utils.py @@ -99,14 +99,17 @@ def get_canvas_background(path): # takes list of Image(s) as arg # returns single composite of all images -def get_preview_from_stack(size, images): +def get_preview_from_stack(size, stack): preview = create_blank_image(size) canvas_width = size[0] canvas_height = size[1] - for image in images: + for layer in stack: + image = layer.image # need to crop images for composite - x0, y0 = (image.width - canvas_width) * 0.5, (image.height - canvas_height) * 0.5 - x1, y1 = x0 + canvas_width, y0 + canvas_height + x0 = ((image.width - canvas_width) * 0.5) - layer.offset_x + y0 = ((image.height - canvas_height) * 0.5) - layer.offset_y + x1 = x0 + canvas_width + y1 = y0 + canvas_height box = (x0, y0, x1, y1) cropped_image = image.crop(box) preview = Image.alpha_composite(preview,cropped_image)