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