mirror of
https://github.com/Sygil-Dev/sygil-webui.git
synced 2024-12-14 05:58:18 +03:00
adding canvas tools(flet ui)
This commit is contained in:
parent
b110e31bd2
commit
784840c50e
@ -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
|
||||
|
@ -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(
|
||||
[
|
||||
|
@ -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(
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user