More updates to flet ui. (#1720)

# Description
finished de-spagetti-fication.(mostly)
all elements are now in their own modules.
elements can call one another's functions via
self.page.<module>.<function>
changed messages window to list_view for smoother scrolling.
changed gallery to grid view. <-- just looks nicer, also smoother
scrolling.
added uploads. can add images as layers, from both uploads and gallery.
added preview to properties panel.
working canvas. <-- only pan/zoom functions work for now.
To Do:
-compose proper config, to give main access to needed settings. then
integrate them.
    -add needed tools to toolbar, add functions to tools in canvas.
    -add properties to property panel
-add multi-user support? in case someone wants multiple clients
connecting to same server.
    -add more comments/docs to code. 

# Checklist:

- [x] I have changed the base branch to `dev`
- [x] I have performed a self-review of my own code
- [ ] I have commented my code in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
This commit is contained in:
Alejandro Gil 2022-12-21 06:58:24 -08:00 committed by GitHub
commit 84225f995d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1745 additions and 1429 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 898 KiB

View File

@ -0,0 +1,257 @@
# flet_layer_manager.py
# Flet imports
import flet as ft
# utils imports
from scripts import flet_utils
class AssetManager(ft.Container):
def setup(self):
self.width = self.page.left_panel_width
self.bgcolor = self.page.primary_color
self.padding = self.page.container_padding
self.margin = self.page.container_margin
self.set_tab_text_size(self.page.text_size)
self.set_tab_bgcolor(self.page.secondary_color)
self.set_tab_padding(self.page.container_padding)
self.set_tab_margin(self.page.container_margin)
self.dragbar.content.width = self.page.vertical_divider_width
self.dragbar.content.color = self.page.tertiary_color
def add_blank_layer(self, e):
self.layer_panel.add_blank_layer(e)
def add_image_as_layer(self, image):
self.layer_panel.add_image_as_layer(image)
def add_images_as_layers(self, images):
self.layer_panel.add_images_as_layers(images)
def set_tab_text_size(self, size):
for tab in self.tabs:
tab.tab_content.size = size
def set_tab_bgcolor(self, color):
for tab in self.tabs:
tab.content.bgcolor = color
def set_tab_padding(self, padding):
for tab in self.tabs:
tab.content.padding = padding
def set_tab_margin(self, margin):
for tab in self.tabs:
tab.content.margin = margin
class AssetPanel(ft.Container):
pass
class LayerPanel(ft.Container):
def update_layers(self):
self.layers = self.content.content.controls
self.update_layer_indexes()
self.update_visible_layers()
self.update()
def update_layer_indexes(self):
count = 0
for layer in self.layers:
layer.index = count
count += 1
def update_visible_layers(self):
self.visible_layers = []
for layer in self.layers:
if layer.visible:
self.visible_layers.append(layer)
def make_layer_active(self, index):
for i, layer in enumerate(self.layers):
layer.active = False
if i == index:
layer.active = True
def add_layer_slot(self, image):
label = ft.TextField(
value = image.filename,
focused_border_color = self.page.tertiary_color,
text_size = self.page.text_size,
content_padding = ft.padding.only(left = 12, top = 0, right = 0, bottom = 0),
expand = True,
)
handle = ft.Icon(
name = ft.icons.DRAG_HANDLE,
tooltip = 'drag to move',
)
layer_slot = LayerSlot(
content = ft.Row(
controls = [
label,
handle,
],
height = self.page.icon_size * 2,
expand = True,
),
)
layer_slot.label = label
layer_slot.index = 0
layer_slot.visible = True
layer_slot.active = False
layer_slot.image = image
self.content.content.controls.insert(0,layer_slot)
self.layers = self.content.content.controls
self.update_layer_indexes()
self.make_layer_active(0)
self.update()
def add_blank_layer(self, e):
image = flet_utils.create_blank_image(self.page.canvas_size)
self.add_layer_slot(image)
self.page.canvas.add_layer_image(image)
self.page.message("added blank layer to canvas")
def add_image_as_layer(self, image):
self.add_layer_slot(image)
self.page.canvas.add_layer_image(image)
self.page.message(f'added "{image.filename}" as layer')
def add_images_as_layers(self, images):
for image in images:
self.add_image_as_layer(image)
class LayerSlot(ft.Container):
pass
def layer_left_click(e):
pass
layer_panel = LayerPanel(
content = ft.GestureDetector(
content = ft.Column(
controls = [],
expand = True,
scroll = 'hidden',
),
drag_interval = 10,
on_tap = layer_left_click,
),
)
layer_panel.layers = []
layer_panel.visible_layers = []
layer_panel.active_layer = None
layer_panel.layer_being_moved = None
layer_panel.layer_last_index = 0
asset_panel = AssetPanel(
content = ft.Column(
controls = [
ft.Text("Under Construction"),
],
),
)
def resize_asset_manager(e: ft.DragUpdateEvent):
e.page.left_panel_width = max(250, e.page.left_panel_width + e.delta_x)
asset_manager.width = e.page.left_panel_width
e.page.update()
asset_manager_dragbar = ft.GestureDetector(
mouse_cursor = ft.MouseCursor.RESIZE_COLUMN,
drag_interval = 50,
on_pan_update = resize_asset_manager,
content = ft.VerticalDivider(),
)
asset_manager = AssetManager(
content = ft.Row(
controls = [
ft.Column(
controls = [
ft.Tabs(
selected_index = 0,
animation_duration = 300,
tabs = [
ft.Tab(
content = layer_panel,
tab_content = ft.Text(
value = "Layers",
),
),
ft.Tab(
content = asset_panel,
tab_content = ft.Text(
value = "Assets",
),
),
],
),
],
alignment = 'start',
expand = True
),
asset_manager_dragbar,
],
expand = True,
),
clip_behavior = 'antiAlias',
)
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
'''
# keep track of which layers are visible
def show_hide_layer(self, e):
parent = e.control.data['parent']
if parent.data['visible']:
parent.data['visible'] = False
parent.opacity = 0.5
e.control.icon = ft.icons.VISIBILITY_OFF
else:
parent.data['visible'] = True
parent.opacity = 1.0
e.control.icon = ft.icons.VISIBILITY
self.update_visible_layer_list()
parent.update()
self.page.refresh_canvas()
def update_visible_layer_list(self):
self.page.visible_layer_list = []
layer_list = self.page.layer_list
for layer in layer_list:
if layer.data['type'] == 'slot':
if layer.content.content.controls[1].data['visible']:
self.page.visible_layer_list.append(layer)
# keep track of which layers are active
def lock_unlock_layer(self, e):
parent = e.control.data['parent']
if parent.data['locked']:
parent.data['locked'] = False
e.control.icon = ft.icons.LOCK_OPEN_OUTLINED
else:
parent.data['locked'] = True
e.control.icon = ft.icons.LOCK_OUTLINED
self.update_active_layer_list()
parent.update()
def update_active_layer_list(self):
self.page.active_layer_list = []
layer_list = self.page.layer_list
for layer in layer_list:
if layer.data['type'] == 'slot':
if not layer.content.content.controls[1].data['locked']:
self.page.active_layer_list.append(layer)
'''

View File

@ -7,16 +7,318 @@ import flet as ft
from scripts import flet_utils
class Canvas(ft.Container):
def empty_function(self):
def setup(self):
self.bgcolor = self.page.secondary_color
self.padding = self.page.container_padding
self.margin = self.page.container_margin
self.overlay.tools.center = self.page.icon_size
self.overlay.tools.zoom_in = self.page.icon_size
self.overlay.tools.zoom_out = self.page.icon_size
self.overlay.size_display.content.color = self.page.text_color
self.overlay.size_display.content.size = self.page.text_size
self.add_canvas_background()
self.center_canvas(self)
self.refresh_canvas()
self.update()
def lock_canvas(self):
self.overlay.cover.lock_canvas()
def unlock_canvas(self):
self.overlay.cover.unlock_canvas()
def refresh_canvas(self):
self.overlay.refresh_canvas_overlay()
def set_current_tool(self, tool):
self.page.current_tool = tool
def add_canvas_background(self):
self.image_stack.add_canvas_background()
def add_layer_image(self, image):
self.image_stack.add_layer_image(image)
self.update()
def get_image_stack_preview(self):
return self.image_stack.get_preview()
def center_canvas(self, e):
width, height = self.page.get_viewport_size()
self.image_stack.offset_x = 0
self.image_stack.offset_y = 0
self.image_stack.left = (width * 0.5) - (self.image_stack.width * 0.5)
self.image_stack.top = (height * 0.5) - (self.image_stack.height * 0.5)
self.overlay.preview.left = self.image_stack.left
self.overlay.preview.top = self.image_stack.top
self.update()
def align_canvas(self, e):
width, height = self.page.get_viewport_size()
self.image_stack.left = (width * 0.5) - (self.image_stack.width * 0.5) + self.image_stack.offset_x
self.image_stack.top = (height * 0.5) - (self.image_stack.height * 0.5) + self.image_stack.offset_y
self.overlay.preview.left = self.image_stack.left
self.overlay.preview.top = self.image_stack.top
self.update()
def pan_canvas(self, e: ft.DragUpdateEvent):
self.image_stack.offset_x += e.delta_x
self.image_stack.offset_y += e.delta_y
width, height = self.page.get_viewport_size()
self.image_stack.offset_x = max(self.image_stack.offset_x, (width - self.image_stack.width) * 0.5)
self.image_stack.offset_y = max(self.image_stack.offset_y, (height - self.image_stack.height) * 0.5)
self.image_stack.offset_x = min(self.image_stack.offset_x, (self.image_stack.width - width) * 0.5)
self.image_stack.offset_y = min(self.image_stack.offset_y, (self.image_stack.height - height) * 0.5)
self.align_canvas(e)
def zoom_in(self, e):
if self.image_stack.scale >= 4.0:
self.image_stack.scale = 4.0
else:
self.image_stack.scale += 0.05
self.image_stack.get_scaled_size()
self.overlay.preview.scale = self.image_stack.scale
self.align_canvas(e)
def zoom_out(self, e):
if self.image_stack.scale <= 0.1:
self.image_stack.scale = 0.1
else:
self.image_stack.scale -= 0.05
self.overlay.preview.scale = self.image_stack.scale
self.image_stack.get_scaled_size()
self.align_canvas(e)
def pan_canvas(e):
canvas.pan_canvas(e)
class ImageStack(ft.Container):
def add_canvas_background(self):
image = self.page.canvas_background
canvas_bg = LayerImage(
left = 0,
top = 0,
width = self.width,
height = self.height,
content = ft.Image(
src_base64 = flet_utils.convert_image_to_base64(image),
width = 256,
height = 256,
repeat = 'repeat',
gapless_playback = True,
),
)
canvas_bg.image = image
self.canvas_bg = canvas_bg
self.content.controls.append(canvas_bg)
def add_layer_image(self, image):
layer_image = LayerImage(
left = 0,
top = 0,
width = image.width,
height = image.height,
content = ft.Image(
src = f'{image.path}',
width = image.width,
height = image.height,
gapless_playback = True,
),
)
layer_image.image = image
self.center_layer(layer_image)
self.content.controls.append(layer_image)
canvas.refresh_canvas()
def get_preview(self):
stack = []
for layer in self.content.controls:
stack.append(layer.image)
return flet_utils.get_preview_from_stack(self.page.canvas_size, stack)
def get_scaled_size(self):
self.scaled_width = self.width * self.scale
self.scaled_height = self.height * self.scale
def center_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)
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)
def drag_layer(self, e):
pass
def resize_layer(self, e):
pass
class ImageStack(ft.GestureDetector):
def center_image_stack(self):
self.left = (self.page.workspace_width * 0.5) - (self.page.canvas_size[0] * 0.5) - 4,
self.top = (self.page.workspace_height * 0.5) - (self.page.canvas_size[1] * 0.5) - 4,
canvas.update()
def draw_on_layer(self, e):
pass
def paint_on_layer(self, e):
pass
class LayerImage(ft.Container):
pass
class CanvasOverlay(ft.Stack):
def refresh_canvas_overlay(self):
self.refresh_canvas_size_display()
self.refresh_canvas_preview()
def refresh_canvas_size_display(self):
self.size_display.content.value = str(self.page.canvas_size)
self.update()
def refresh_canvas_preview(self):
preview = canvas.get_image_stack_preview()
self.preview.content.src_base64 = flet_utils.convert_image_to_base64(preview)
self.preview.content.width = preview.width
self.preview.content.height = preview.height
self.preview.image = preview
self.page.property_manager.set_preview_image(preview)
def pan_canvas(e):
canvas.pan_canvas(e)
image_stack = ImageStack(
width = 4096,
height = 4096,
left = 0,
top = 0,
scale = 1.0,
content = ft.Stack(),
)
image_stack.offset_x = 0
image_stack.offset_y = 0
image_stack.scaled_width = image_stack.width
image_stack.scaled_height = image_stack.height
canvas_cover = ft.Container(
content = None,
expand = True,
bgcolor = 'black',
opacity = 0.5,
)
canvas_preview = LayerImage(
width = 4096,
height = 4096,
padding = 0,
margin = 0,
image_fit = ft.ImageFit.CONTAIN,
alignment = ft.alignment.center,
content = ft.Image(
src_base64 = None,
gapless_playback = True,
),
)
canvas_gestures = ft.GestureDetector(
mouse_cursor = ft.MouseCursor.MOVE,
drag_interval = 10,
on_pan_update = pan_canvas,
)
canvas_size_display = ft.Container(
content = ft.Text(
value = "test",
),
left = 4,
bottom = 4,
padding = 4,
border_radius = 10,
opacity = 0.5,
bgcolor = 'black',
)
def center_canvas(e):
canvas.center_canvas(e)
center_canvas_button = ft.IconButton(
content = ft.Icon(ft.icons.FILTER_CENTER_FOCUS_OUTLINED),
tooltip = 'center canvas',
on_click = center_canvas,
)
def zoom_in_canvas(e):
canvas.zoom_in(e)
zoom_in_button = ft.IconButton(
content = ft.Icon(ft.icons.ZOOM_IN_OUTLINED),
tooltip = 'zoom in canvas',
on_click = zoom_in_canvas,
)
def zoom_out_canvas(e):
canvas.zoom_out(e)
zoom_out_button = ft.IconButton(
content = ft.Icon(ft.icons.ZOOM_OUT_OUTLINED),
tooltip = 'zoom out canvas',
on_click = zoom_out_canvas,
)
canvas_tools = ft.Container(
content = ft.Column(
controls = [
center_canvas_button,
zoom_in_button,
zoom_out_button,
],
horizontal_alignment = 'end',
),
top = 4,
right = 4,
padding = 4,
border_radius = 10,
opacity = 0.5,
bgcolor = 'black',
disabled = False,
)
canvas_tools.center = center_canvas_button
canvas_tools.zoom_in = zoom_in_button
canvas_tools.zoom_out = zoom_out_button
canvas_overlay = CanvasOverlay(
[
canvas_cover,
canvas_preview,
canvas_gestures,
canvas_size_display,
canvas_tools,
],
)
canvas_overlay.cover = canvas_cover
canvas_overlay.preview = canvas_preview
canvas_overlay.size_display = canvas_size_display
canvas_overlay.tools = canvas_tools
canvas = Canvas(
content = ft.Stack(
[
image_stack,
canvas_overlay,
],
),
clip_behavior = 'antiAlias',
alignment = ft.alignment.center,
expand = True,
)
canvas.image_stack = image_stack
canvas.overlay = canvas_overlay

View File

@ -0,0 +1,140 @@
# flet_file_manager.py
# Flet imports
import flet as ft
# other imports
from math import pi
from typing import Dict
from loguru import logger
# utils imports
from scripts import flet_utils
class UploadWindow(ft.AlertDialog):
def upload_file(self, e):
if file_picker.result is not None and file_picker.result.files is not None:
file_list = []
for f in file_picker.result.files:
upload_url = e.page.get_upload_url(f.name, 600)
img = ft.FilePickerUploadFile(f.name,upload_url)
file_list.append(img)
file_picker.upload(file_list)
def upload_complete(self, e):
self.progress_bars.clear()
self.selected_files.controls.clear()
e.page.close_uploads(e)
e.page.asset_manager.add_images_as_layers(file_picker.images)
file_picker.images.clear()
e.page.message('File upload(s) complete.')
def get_image_from_uploads(self, name):
return flet_utils.get_image_from_uploads(name)
def get_file_display(self, name, progress):
display = ft.Row(
controls = [
progress,
ft.Text(name),
],
)
return display
class ImportWindow(ft.AlertDialog):
pass
selected_files = ft.Column(
scroll = 'auto',
tight = True,
controls = [],
);
progress_bars: Dict[str, ft.ProgressBar] = {}
def upload_file(e):
uploads.upload_file(e)
def close_upload_window(e):
e.page.close_uploads(e)
uploads = UploadWindow(
title = ft.Text("Confirm file upload(s)"),
content = selected_files,
actions_alignment = "center",
actions = [
ft.ElevatedButton("UPLOAD", on_click = upload_file),
ft.TextButton("CANCEL", on_click = close_upload_window),
],
)
uploads.selected_files = selected_files
uploads.progress_bars = progress_bars
def import_file(e):
e.page.close_imports(e)
def close_import_window(e):
e.page.close_imports(e)
imports = ImportWindow(
title = ft.Text("Confirm file import(s)"),
content = selected_files,
actions_alignment = "center",
actions = [
ft.ElevatedButton("IMPORT", on_click = import_file),
ft.TextButton("CANCEL", on_click = close_import_window),
],
)
imports.selected_files = selected_files
imports.progress_bars = progress_bars
def pick_images(e: ft.FilePickerResultEvent):
progress_bars.clear()
selected_files.controls.clear()
file_picker.images.clear()
# check to see if files or directory were chosen
if e.files is not None and e.path is None:
for f in e.files:
prog = ft.ProgressRing(
width = 12,
height = 12,
stroke_width = 2,
value = 0,
color = 'blue',
)
progress_bars[f.name] = prog
selected_files.controls.append(uploads.get_file_display(f.name,prog))
file_picker.pending += 1
# upload if remote, import if local
if e.page.web:
e.page.open_uploads(e)
else:
e.page.open_imports(e)
def on_image_upload(e: ft.FilePickerUploadEvent):
if e.error:
e.page.message(f"Upload error occurred! Failed to fetch '{e.file_name}'.",1)
file_picker.pending -= 1
else:
# update progress bars
progress_bars[e.file_name].value = e.progress
progress_bars[e.file_name].update()
if e.progress >= 1:
file_picker.pending -= 1
file_picker.images.append(uploads.get_image_from_uploads(e.file_name))
if file_picker.pending <= 0:
file_picker.pending = 0
uploads.upload_complete(e)
file_picker = ft.FilePicker(
on_result = pick_images,
on_upload = on_image_upload
)
file_picker.pending = 0
file_picker.images = []

View File

@ -8,86 +8,145 @@ from scripts import flet_utils
class GalleryWindow(ft.AlertDialog):
def empty(self):
pass
def setup(self):
self.refresh_galleries()
def get_gallery_images(self, gallery_name):
return flet_utils.get_gallery_images(gallery_name)
def refresh_galleries(self):
self.refresh_gallery('uploads')
self.refresh_gallery('outputs')
def refresh_gallery(self, gallery_name):
index = None
if gallery_name == 'uploads':
index = 0
self.uploads_gallery.get_gallery_display(gallery_name)
elif gallery_name == 'outputs':
index = 1
self.outputs_gallery.get_gallery_display(gallery_name)
else:
page.message(f'{gallery_name} gallery not found.', 1)
return None
gallery_window.content.content.tabs[index].content = get_gallery_display(gallery_name)
def get_gallery_images(self, gallery_name):
return flet_utils.get_gallery_images(gallery_name)
def select_image(self, e):
if e.control.border :
e.control.border = None
if e.control.image in self.selected_images:
self.selected_images.remove(e.control.image)
e.control.update()
else:
e.control.border = ft.border.all(2, e.page.tertiary_color)
self.selected_images.append(e.control.image)
e.control.update()
class GalleryDisplay(ft.Container):
def get_gallery_display(self, gallery_name):
gallery_display = ft.Stack(
[
ft.Row(
controls = None,
wrap = False,
scroll = 'always',
expand = True,
),
ft.Column(
controls = [
ft.Row(
controls = [
ft.IconButton(
height = page.height * 0.75,
icon_size = 50,
content = ft.Icon(ft.icons.ARROW_CIRCLE_LEFT_OUTLINED),
tooltip = 'previous image',
on_click = None,
),
ft.IconButton(
height = page.height * 0.75,
icon_size = 50,
content = ft.Icon(ft.icons.ARROW_CIRCLE_RIGHT_OUTLINED),
tooltip = 'next image',
on_click = None,
),
],
expand = True,
alignment = 'spaceBetween',
),
],
alignment = 'center',
),
],
self.content = ft.GridView(
controls = None,
padding = 0,
runs_count = 3,
run_spacing = 12,
spacing = 12,
expand = True,
)
gallery = get_gallery_images(gallery_name)
if len(gallery) < 1:
gallery_display.controls[0].controls.append(
gallery = gallery_window.get_gallery_images(gallery_name)
if not gallery:
self.content.controls.append(
ft.Image(
src = '/images/chickens.jpg',
tooltip = 'Nothing here but us chickens!',
gapless_playback = True,
)
)
return gallery_display
for i in range(len(gallery)):
image = gallery[i]
image_name = list(image.keys())[0]
image_path = image[image_name]['img_path']
image_data = None
if 'info_path' in image[image_name]:
image_data = image[image_name]['info_path']
gallery_display.controls[0].controls.append(
ft.Image(
src = image_path,
tooltip = image_name,
return
for image in gallery:
gallery_image = GalleryImage(
content = ft.Image(
src = image.path,
tooltip = image.filename,
width = image.width,
height = image.height,
gapless_playback = True,
)
),
image_fit = ft.ImageFit.CONTAIN,
height = image.height,
width = image.width,
padding = 0,
margin = 0,
border = None,
on_click = gallery_window.select_image
)
return gallery_display
gallery_image.image = image
self.content.controls.append(gallery_image)
class GalleryImage(ft.Container):
pass
def add_as_new_layer(e):
if gallery_window.selected_images:
e.page.asset_manager.add_images_as_layers(gallery_window.selected_images)
gallery_window.selected_images.clear()
for tab in gallery_window.content.content.tabs:
for image in tab.content.content.controls:
image.border = None
image.update()
def save_to_disk(e):
pass
def remove_from_gallery(e):
pass
uploads_gallery = GalleryDisplay(
content = None,
clip_behavior = 'antiAlias',
)
outputs_gallery = GalleryDisplay(
content = None,
clip_behavior = 'antiAlias',
)
# GalleryWindow == ft.AlertDialog
gallery_window = GalleryWindow(
title = ft.Text('Gallery'),
content = ft.Container(
content = ft.Tabs(
selected_index = 0,
animation_duration = 300,
tabs = [
ft.Tab(
text = "Uploads",
content = uploads_gallery,
),
ft.Tab(
text = "Outputs",
content = outputs_gallery,
),
],
),
),
actions = [
ft.ElevatedButton(
text = "Add As New Layer",
icon = ft.icons.ADD_OUTLINED,
on_click = add_as_new_layer,
),
ft.ElevatedButton(
text = "Save",
icon = ft.icons.SAVE_OUTLINED,
on_click = save_to_disk,
),
ft.ElevatedButton(
text = "Discard",
icon = ft.icons.DELETE_OUTLINED,
on_click = remove_from_gallery,
),
],
actions_alignment="end",
)
gallery_window.uploads_gallery = uploads_gallery
gallery_window.outputs_gallery = outputs_gallery
gallery_window.selected_images = []

View File

@ -1,288 +0,0 @@
# flet_layer_manager.py
# Flet imports
import flet as ft
from scripts import flet_utils
class LayerManager(ft.Container):
# first make a column to hold the layers
def make_layer_holder(self):
layer_holder = ft.DragTarget(
group = 'layer',
content = ft.Column(
spacing = 0,
scroll = 'auto',
controls = [],
),
on_will_accept = self.layer_will_accept,
on_accept = self.layer_accept,
on_leave = self.layer_leave,
)
return layer_holder
# make a slot for each layer to go in
def make_layer_slot(self):
layer_slot = LayerSlot(
group = 'layer',
content = ft.Container(
content = self.make_layer_display(),
),
on_will_accept = self.layer_slot_will_accept,
on_accept = self.layer_slot_accept,
on_leave = self.layer_slot_leave,
data = {
'index': -1,
'type': 'slot',
'has_spacer': False,
'image': None,
}
)
return layer_slot
# make the display for the layer
def make_layer_display(self):
try:
self.layer_count += 1
except AttributeError:
self.layer_count = 1
layer_display = ft.Column(
controls = [
ft.Container(
content = ft.Divider(
height = 10,
color = ft.colors.BLACK,
),
visible = False,
),
ft.Container(
content = ft.Row(
controls = [],
),
data = {
'visible':True,
'locked':False,
},
bgcolor = ft.colors.WHITE30,
padding = 4,
),
],
spacing = 0,
)
layer_show_hide = ft.IconButton(
icon = ft.icons.VISIBILITY,
tooltip = 'show/hide',
on_click = self.show_hide_layer,
data = {'parent':layer_display.controls[1]},
)
layer_lock_unlock = ft.IconButton(
icon = ft.icons.LOCK_OPEN_OUTLINED,
tooltip = 'lock/unlock',
on_click = self.lock_unlock_layer,
data = {'parent':layer_display.controls[1]},
)
layer_label = ft.TextField(
value = ("layer_" + str(self.layer_count)),
data = {'parent':layer_display.controls[1]},
content_padding = 10,
expand = True,
)
layer_handle = ft.GestureDetector(
content = ft.Draggable(
group = 'layer',
content = ft.Icon(
name = ft.icons.DRAG_HANDLE,
data = {'parent':layer_display.controls[1]},
tooltip = 'drag to move',
),
),
on_secondary_tap = self.layer_right_click
)
layer_display.controls[1].content.controls.extend([layer_show_hide,layer_lock_unlock,layer_label,layer_handle])
return layer_display
# update all layer info
def update_layers(self):
self.page.layer_list = self.content.content.controls
self.update_layer_indexes()
self.update_visible_layer_list()
self.update_active_layer_list()
self.update()
self.page.refresh_canvas()
# keep track of which layers are visible
def show_hide_layer(self, e):
parent = e.control.data['parent']
if parent.data['visible']:
parent.data['visible'] = False
parent.opacity = 0.5
e.control.icon = ft.icons.VISIBILITY_OFF
else:
parent.data['visible'] = True
parent.opacity = 1.0
e.control.icon = ft.icons.VISIBILITY
self.update_visible_layer_list()
parent.update()
self.page.refresh_canvas()
def update_visible_layer_list(self):
self.page.visible_layer_list = []
layer_list = self.page.layer_list
for layer in layer_list:
if layer.data['type'] == 'slot':
if layer.content.content.controls[1].data['visible']:
self.page.visible_layer_list.append(layer)
# keep track of which layers are active
def lock_unlock_layer(self, e):
parent = e.control.data['parent']
if parent.data['locked']:
parent.data['locked'] = False
e.control.icon = ft.icons.LOCK_OPEN_OUTLINED
else:
parent.data['locked'] = True
e.control.icon = ft.icons.LOCK_OUTLINED
self.update_active_layer_list()
parent.update()
def update_active_layer_list(self):
self.page.active_layer_list = []
layer_list = self.page.layer_list
for layer in layer_list:
if layer.data['type'] == 'slot':
if not layer.content.content.controls[1].data['locked']:
self.page.active_layer_list.append(layer)
# handle layer shuffling
def update_layer_indexes(self):
layer_list = self.page.layer_list
index = 0
for layer in layer_list:
if layer.data['type'] == 'slot':
layer.data['index'] = index
index += 1
def move_layer_slot(self, index):
layer_list = self.page.layer_list
self.data['layer_being_moved'] = layer_list.pop(index)
self.data['layer_last_index'] = index
self.update_layers()
def insert_layer_slot(self, index):
layer_list = self.page.layer_list
layer_list.insert(index,self.data['layer_being_moved'])
self.data['layer_being_moved'] = None
self.data['layer_last_index'] = -1
self.update_layers()
def layer_slot_will_accept(self, e):
if not self.data['layer_being_moved']:
return
layer_list = self.page.layer_list
index = e.control.data['index']
e.control.show_layer_spacer()
self.update_layers()
def layer_slot_accept(self, e):
if not self.data['layer_being_moved']:
return
layer_list = self.page.layer_list
index = e.control.data['index']
e.control.hide_layer_spacer()
self.insert_layer_slot(index)
def layer_slot_leave(self, e):
layer_list = self.page.layer_list
index = e.control.data['index']
e.control.hide_layer_spacer()
if self.data['layer_being_moved']:
return
self.move_layer_slot(index)
# catch layers that are dropped outside slots
def layer_will_accept(self, e):
if not self.data['layer_being_moved']:
return
layer_list = self.page.layer_list
if layer_list:
if layer_list[-1].data['type'] != 'spacer':
layer_list.append(
ft.Container(
content = ft.Divider(height = 10,color = ft.colors.BLACK),
data = {'type':'spacer'}
)
)
else:
layer_list.append(
ft.Container(
content = ft.Divider(height = 10,color = ft.colors.BLACK),
data = {'type':'spacer'}
)
)
self.update_layers()
def layer_accept(self, e):
if not self.data['layer_being_moved']:
return
layer_list = self.page.layer_list
if layer_list:
if layer_list[-1].data['type'] == 'spacer':
layer_list.pop(-1)
layer_list.append(self.data['layer_being_moved'])
self.data['layer_being_moved'] = None
self.update_layers()
def layer_leave(self, e):
if not self.data['layer_being_moved']:
return
layer_list = self.page.layer_list
if layer_list:
if layer_list[-1].data['type'] == 'spacer':
layer_list.pop(-1)
self.update_layers()
# handle toolbar functions
def add_blank_layer(self, e):
layer_list = self.page.layer_list
layer_slot = self.make_layer_slot()
layer_slot.data['image'] = flet_utils.create_blank_image()
layer_list.append(layer_slot)
self.page.message("added blank layer to canvas")
self.update_layers()
def add_images_as_layers(self, images):
layer_list = self.page.layer_list
for img in images:
if images[img] == None:
continue
layer_slot = self.make_layer_slot()
layer_slot.set_layer_slot_name(img)
layer_slot.data['image'] = images[img]
layer_list.append(layer_slot)
self.page.message(f'added "{img}" as layer')
self.update_layers()
# fetch layer option on right click
def layer_right_click(self,e):
pass
# make each layer slot a target
class LayerSlot(ft.DragTarget):
def set_layer_slot_name(self, name):
self.content.content.controls[1].content.controls[1].value = name
def show_layer_spacer(self):
if not self.data['has_spacer']:
self.data['has_spacer'] = True
self.content.content.controls[0].visible = True
self.update()
def hide_layer_spacer(self):
if self.data['has_spacer']:
self.data['has_spacer'] = False
self.content.content.controls[0].visible = False
self.update()

View File

@ -0,0 +1,123 @@
# flet_messages.py
# Flet imports
import flet as ft
# utils imports
from scripts import flet_utils
class Messages(ft.Container):
def setup(self):
self.height = self.page.bottom_panel_height
self.bgcolor = self.page.primary_color
self.padding = self.page.container_padding
self.margin = self.page.container_margin
self.set_tab_text_size(self.page.text_size)
self.set_tab_bgcolor(self.page.secondary_color)
self.set_tab_padding(self.page.container_padding)
self.set_tab_margin(self.page.container_margin)
self.dragbar.content.height = self.page.divider_height
self.dragbar.content.color = self.page.tertiary_color
def set_tab_text_size(self, size):
for tab in self.tabs:
tab.tab_content.size = size
def set_tab_bgcolor(self, color):
for tab in self.tabs:
tab.content.bgcolor = color
def set_tab_padding(self, padding):
for tab in self.tabs:
tab.content.padding = padding
def set_tab_margin(self, margin):
for tab in self.tabs:
tab.content.margin = margin
def resize_messages(self, e: ft.DragUpdateEvent):
self.page.bottom_panel_height = max(100, self.page.bottom_panel_height - e.delta_y)
self.height = self.page.bottom_panel_height
self.page.update()
def message(self, text, err = 0):
if err:
text = "ERROR: " + text
self.add_message_to_messages(err,text)
flet_utils.log_message(text)
def prune_messages(self):
if len(message_list.controls) > self.page.max_message_history:
message_list.controls.pop(0)
message_list.update()
def add_message_to_messages(self,err,text):
if err:
msg = ft.Text(value = text, color = ft.colors.RED)
else:
msg = ft.Text(value = text)
message_list.controls.append(msg)
self.prune_messages()
message_list = ft.ListView(
spacing = 4,
auto_scroll = True,
controls = [],
)
messages_panel = ft.Container(
content = message_list,
)
video_editor_panel = ft.Column(
expand = True,
controls = [ft.Text("Under Construction")]
)
def resize_messages(e):
messages.resize_messages(e)
messages_dragbar = ft.GestureDetector(
mouse_cursor = ft.MouseCursor.RESIZE_ROW,
drag_interval = 50,
on_pan_update = resize_messages,
content = ft.Divider(),
)
messages = Messages(
content = ft.Stack(
controls = [
messages_dragbar,
ft.Tabs(
selected_index = 0,
animation_duration = 300,
tabs = [
ft.Tab(
content = messages_panel,
tab_content = ft.Text(
value = 'Messages',
),
),
ft.Tab(
content = video_editor_panel,
tab_content = ft.Text(
value = 'Video Editor',
),
),
],
),
],
),
clip_behavior = 'antiAlias',
)
messages.dragbar = messages_dragbar
messages.tabs = messages.content.controls[1].tabs
messages.messages_panel = messages_panel
messages.video_editor_panel = video_editor_panel
messages.message_list = message_list

View File

@ -0,0 +1,281 @@
# flet_property_manager.py
# Flet imports
import flet as ft
# utils imports
from scripts import flet_utils
class PropertyManager(ft.Container):
def setup(self):
self.width = self.page.right_panel_width
self.bgcolor = self.page.primary_color
self.padding = self.page.container_padding
self.margin = self.page.container_margin
self.set_tab_text_size(self.page.text_size)
self.set_tab_bgcolor(self.page.secondary_color)
self.set_tab_padding(self.page.container_padding)
self.set_tab_margin(self.page.container_margin)
self.dragbar.content.width = self.page.vertical_divider_width
self.dragbar.content.color = self.page.tertiary_color
self.property_panel.preview.width = self.page.right_panel_width
self.property_panel.preview_dragbar.content.content.height = self.page.divider_height
self.property_panel.preview_dragbar.content.content.color = self.page.tertiary_color
self.property_panel.canvas_properties_divider.content.height = self.page.divider_height
self.property_panel.canvas_properties_divider.content.color = self.page.tertiary_color
self.property_panel.layer_properties_divider.content.height = self.page.divider_height
self.property_panel.layer_properties_divider.content.color = self.page.tertiary_color
def set_tab_text_size(self, size):
for tab in self.tabs:
tab.tab_content.size = size
def set_tab_bgcolor(self, color):
for tab in self.tabs:
tab.content.content.bgcolor = color
def set_tab_padding(self, padding):
for tab in self.tabs:
tab.content.padding = padding
def set_tab_margin(self, margin):
for tab in self.tabs:
tab.content.margin = margin
def set_preview_size(self, width):
self.property_panel.preview.width = width
def set_preview_image(self, image):
self.property_panel.preview.content.src_base64 = flet_utils.convert_image_to_base64(image)
self.property_panel.update()
class PropertyPanel(ft.Container):
def resize_preview(self, e):
self.preview.height = max(200, self.preview.height + e.delta_y)
self.update()
preview_pane = ft.Container(
content = ft.Image(
src_base64 = None,
gapless_playback = True,
),
image_fit = ft.ImageFit.CONTAIN,
bgcolor = 'black',
height = 200,
padding = 0,
margin = 0,
)
def resize_preview(e):
property_panel.resize_preview(e)
preview_dragbar = ft.GestureDetector(
mouse_cursor = ft.MouseCursor.RESIZE_ROW,
drag_interval = 50,
on_pan_update = resize_preview,
content = ft.Container(
content = ft.Divider(),
margin = 0,
padding = 0,
),
)
def get_canvas_properties(e):
return ft.Column(
controls = [
ft.Row(
controls = [
ft.TextField(
label = 'Width',
value = e.page.canvas_size[0],
text_align = 'center',
content_padding = 0,
expand = 1,
),
ft.TextField(
label = 'Height',
value = e.page.canvas_size[1],
text_align = 'center',
content_padding = 0,
expand = 1,
),
],
),
],
)
def open_close_canvas_properties(e):
if canvas_property_header.open:
e.control.icon = ft.icons.ARROW_RIGHT
e.control.icon_color = None
canvas_property_header.open = False
canvas_property_header.controls.pop()
canvas_property_header.update()
else:
e.control.icon = ft.icons.ARROW_DROP_DOWN
e.control.icon_color = e.page.tertiary_color
canvas_property_header.open = True
canvas_property_header.controls.append(get_canvas_properties(e))
canvas_property_header.update()
canvas_property_header = ft.Column(
controls = [
ft.TextButton(
text = "Canvas Properties",
icon = ft.icons.ARROW_RIGHT,
on_click = open_close_canvas_properties,
),
],
)
canvas_property_header.open = False
canvas_property_divider = ft.Container(
content = ft.Divider(),
margin = 0,
padding = 0,
)
def get_layer_properties(e):
return ft.Column(
controls = [
ft.Row(
controls = [
ft.TextField(
label = 'Width',
value = e.page.active_layer.image.width,
text_align = 'center',
content_padding = 0,
expand = 1,
),
ft.TextField(
label = 'Height',
value = e.page.active_layer.image_height,
text_align = 'center',
content_padding = 0,
expand = 1,
),
],
),
],
)
def open_close_layer_properties(e):
if layer_property_header.open:
e.control.icon = ft.icons.ARROW_RIGHT
e.control.icon_color = None
layer_property_header.open = False
layer_property_header.controls.pop()
layer_property_header.update()
else:
e.control.icon = ft.icons.ARROW_DROP_DOWN
e.control.icon_color = e.page.tertiary_color
layer_property_header.open = True
layer_property_header.controls.append(get_layer_properties(e))
layer_property_header.update()
layer_property_header = ft.Column(
controls = [
ft.TextButton(
text = "Layer Properties",
icon = ft.icons.ARROW_RIGHT,
on_click = open_close_layer_properties,
disabled = True,
),
],
)
layer_property_header.open = False
layer_property_divider = ft.Container(
content = ft.Divider(),
margin = 0,
padding = 0,
)
property_panel = PropertyPanel(
content = ft.Column(
controls = [
preview_pane,
preview_dragbar,
canvas_property_header,
canvas_property_divider,
layer_property_header,
layer_property_divider,
],
),
)
property_panel.preview = preview_pane
property_panel.preview_dragbar = preview_dragbar
property_panel.canvas_properties = canvas_property_header
property_panel.canvas_properties_divider = canvas_property_divider
property_panel.layer_properties = layer_property_header
property_panel.layer_properties_divider = layer_property_divider
output_panel = PropertyPanel(
content = ft.Column(
controls = [
ft.Text("Under Construction."),
],
),
)
def resize_property_manager(e: ft.DragUpdateEvent):
e.page.right_panel_width = max(250, e.page.right_panel_width - e.delta_x)
property_manager.width = e.page.right_panel_width
property_panel.preview.width = e.page.right_panel_width
e.page.update()
property_manager_dragbar = ft.GestureDetector(
mouse_cursor = ft.MouseCursor.RESIZE_COLUMN,
drag_interval = 50,
on_pan_update = resize_property_manager,
content = ft.VerticalDivider()
)
property_manager = PropertyManager(
content = ft.Row(
controls = [
property_manager_dragbar,
ft.Column(
controls = [
ft.Tabs(
selected_index = 0,
animation_duration = 300,
tabs = [
ft.Tab(
content = property_panel,
tab_content = ft.Text(
value = "Properties",
),
),
ft.Tab(
content = output_panel,
tab_content = ft.Text(
value = "Output",
),
),
],
),
],
alignment = 'start',
expand = True
),
ft.VerticalDivider(
width = 4,
opacity = 0,
),
],
expand = True,
),
clip_behavior = 'antiAlias',
)
property_manager.tabs = property_manager.content.controls[1].controls[0].tabs
property_manager.dragbar = property_manager_dragbar
property_manager.property_panel = property_panel
property_manager.output_panel = output_panel

View File

@ -2,10 +2,15 @@
# Flet imports
import flet as ft
# utils imports
from scripts import flet_utils
class SettingsWindow(ft.AlertDialog):
def setup(self,settings):
self.get_settings_window_tabs(settings)
def get_settings_window_tab_page_setting_slider(self,settings,section,setting,display_width):
setting_slider = []
setting_value = None
@ -14,7 +19,7 @@ class SettingsWindow(ft.AlertDialog):
elif settings[setting]['value_type'] == 'float':
setting_value = float(settings[setting]['value'])
else:
setting_value = settings[setting]['value']
setting_value = settings[setting]['value']
label = ft.Text(
value = setting,
text_align = 'center',
@ -155,3 +160,44 @@ class SettingsDisplay(ft.Row):
parent.data[0].update_settings_window_tab(parent.data[1])
self.page.update()
def apply_settings(e):
settings_window.update_settings_window()
def save_settings(e):
save_settings_to_config()
settings_window.update_settings_window()
def reset_settings(e):
reset_settings_from_config()
settings_window.update_settings_window()
# SettingsWindow == ft.AlertDialog
settings_window = SettingsWindow(
title = ft.Text("Settings"),
content = ft.Container(
content = ft.Tabs(
selected_index = 0,
animation_duration = 300,
tabs = None,
),
),
actions = [
ft.ElevatedButton(
text = "Apply",
icon = ft.icons.CHECK_CIRCLE,
on_click = apply_settings,
),
ft.ElevatedButton(
text = "Save",
icon = ft.icons.SAVE,
on_click = save_settings,
),
ft.ElevatedButton(
text = "Restore Defaults",
icon = ft.icons.RESTORE_FROM_TRASH_ROUNDED,
on_click = reset_settings,
),
],
actions_alignment = "end",
)

View File

@ -0,0 +1,112 @@
# flet_appbar.py
# Flet imports
import flet as ft
# utils imports
from scripts import flet_utils
class TitleBar(ft.Container):
def setup(self):
self.width = self.page.width
self.height = self.page.titlebar_height
self.title.size = self.page.titlebar_height * 0.5
self.title.color = self.page.tertiary_color
self.prompt.text_size = max(12, self.page.titlebar_height * 0.25)
self.prompt.focused_border_color = self.page.tertiary_color
self.layout_menu.controls[0].text_size = self.page.text_size
self.theme_switcher.size = self.page.titlebar_height
self.theme_switcher.icon_size = self.page.titlebar_height * 0.5
self.theme_switcher.tooltip = f"Click to change between the light and dark themes. Current {'(Light theme)' if self.page.theme_mode == 'light' else '(Dark theme)'}"
self.theme_switcher.on_click = self.page.change_theme_mode
self.settings_button.size = self.page.titlebar_height
self.settings_button.icon_size = self.page.titlebar_height * 0.5
self.settings_button.on_click = self.page.open_settings
title = ft.Text(
value = " Sygil ",
text_align = 'center',
)
prompt = ft.TextField(
value = "",
min_lines = 1,
max_lines = 1,
content_padding = ft.padding.only(left = 12, top = 0, right = 0, bottom = 0),
shift_enter = True,
autofocus = True,
expand = True,
tooltip = "Prompt to use for generation.",
hint_text = "A corgi wearing a top hat as an oil painting.",
)
generate_button = ft.ElevatedButton(
text = "Generate",
on_click = None,
)
def set_layout(e):
e.page.set_layout(e)
layout_menu = ft.Row(
alignment = 'start',
controls = [
ft.Dropdown(
options = [
ft.dropdown.Option(text="Default"),
ft.dropdown.Option(text="Textual Inversion"),
ft.dropdown.Option(text="Node Editor"),
],
value = 'Default',
text_size = 20,
# alignment = ft.alignment.center,
content_padding = ft.padding.only(left = 12, top = 0, right = 0, bottom = 0),
tooltip = "Switch between different workspaces",
on_change = set_layout,
)
],
)
layout_menu.text_size = layout_menu.controls[0].text_size
theme_switcher = ft.IconButton(
ft.icons.WB_SUNNY_OUTLINED,
)
settings_button = ft.IconButton(
icon = ft.icons.SETTINGS,
)
option_list = ft.Row(
controls = [
ft.Container(content = layout_menu),
ft.Container(content = theme_switcher),
ft.Container(content = settings_button),
],
alignment = 'end'
)
titlebar = TitleBar(
content = ft.Row(
controls = [
title,
prompt,
#generate_button,
option_list,
],
),
)
titlebar.title = title
titlebar.prompt = prompt
titlebar.generate_button = generate_button
titlebar.layout_menu = layout_menu
titlebar.theme_switcher = theme_switcher
titlebar.settings_button = settings_button

View File

@ -0,0 +1,192 @@
# flet_tool_manager.py
# Flet imports
import flet as ft
# utils imports
from scripts import flet_utils
def open_gallery(e):
e.control.page.open_gallery(e)
def blank_layer(e):
e.control.page.asset_manager.add_blank_layer(e)
def load_image(e):
e.control.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.control.selected = True
e.control.page.update()
class Action():
def __init__(self, label, icon, tooltip, on_click):
self.label = label
self.icon = icon
self.tooltip = tooltip
self.on_click = on_click
action_list = [
Action('gallery', ft.icons.DASHBOARD_OUTLINED, 'Gallery', open_gallery),
Action('blank layer', ft.icons.ADD_OUTLINED, 'Add blank layer', blank_layer),
Action('load image', ft.icons.IMAGE_OUTLINED, 'Load image as layer', load_image),
]
class Tool():
def __init__(self, label, icon, tooltip, on_click):
self.label = label
self.icon = icon
self.tooltip = tooltip
self.on_click = on_click
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),
]
class ToolManager(ft.Container):
def setup(self):
self.toolbox.get_tools()
self.width = self.page.tool_manager_width
self.bgcolor = self.page.primary_color
self.padding = self.page.container_padding
self.margin = self.page.container_margin
self.toolbox.bgcolor = self.page.secondary_color
self.toolbox.padding = self.page.container_padding
self.toolbox.margin = self.page.container_margin
self.tool_divider.height = self.page.divider_height
self.tool_divider.color = self.page.tertiary_color
self.tool_properties.bgcolor = self.page.secondary_color
self.tool_properties.padding = self.page.container_padding
self.tool_properties.margin = self.page.container_margin
self.dragbar.width = self.page.vertical_divider_width
self.dragbar.color = self.page.tertiary_color
def resize_tool_manager(self, e: ft.DragUpdateEvent):
self.page.tool_manager_width = max(50, self.page.tool_manager_width + e.delta_x)
tool_manager.width = self.page.tool_manager_width
self.page.update()
def resize_toolbox(self, e: ft.DragUpdateEvent):
min_height = (self.page.tool_manager_button_size * 2)
self.page.toolbox_height = max(min_height, self.page.toolbox_height + e.delta_y)
toolbox.height = self.page.toolbox_height
self.update()
class ToolBox(ft.Container):
def get_tools(self):
for action in action_list:
self.content.controls.append(self.make_button(action))
divider = ft.Container(
content = ft.Divider(
height = self.page.divider_height,
color = self.page.tertiary_color,
),
margin = 0,
padding = ft.padding.only(left = 10, top = 0, right = 0, bottom = 0),
)
self.content.controls.append(divider)
for tool in tool_list:
self.content.controls.append(self.make_button(tool))
tool_manager.update()
def make_button(self,button_info):
button = ft.IconButton(
width = self.page.icon_size * 2,
icon_size = self.page.icon_size,
content = ft.Icon(button_info.icon),
selected = False,
selected_icon_color = self.page.tertiary_color,
tooltip = button_info.tooltip,
data = {'label':button_info.label},
on_click = button_info.on_click,
)
return button
def clear_tools(self):
for control in self.content.controls:
control.selected = False
class ToolPropertyPanel(ft.Container):
pass
# ToolBox == ft.Container
toolbox = ToolBox(
clip_behavior = 'antiAlias',
content = ft.Row(
alignment = 'start',
wrap = True,
spacing = 0,
run_spacing = 0,
controls = [],
),
margin = 0,
padding = ft.padding.only(left = 15, top = 0, right = 0, bottom = 0),
)
def resize_toolbox(e):
tool_manager.resize_toolbox(e)
tool_divider = ft.GestureDetector(
mouse_cursor = ft.MouseCursor.RESIZE_ROW,
drag_interval = 50,
on_pan_update = resize_toolbox,
content = ft.Container(
content = ft.Divider(),
margin = 0,
padding = ft.padding.only(left = 10, top = 0, right = 0, bottom = 0),
),
)
# ToolPropertyPanel == ft.Container
tool_properties = ToolPropertyPanel(
content = ft.Column(
controls = [],
)
)
def resize_tool_manager(e):
tool_manager.resize_tool_manager(e)
tool_manager_dragbar = ft.GestureDetector(
mouse_cursor = ft.MouseCursor.RESIZE_COLUMN,
drag_interval = 50,
on_pan_update = resize_tool_manager,
content = ft.VerticalDivider(),
)
# ToolManager = ft.Container
tool_manager = ToolManager(
content = ft.Row(
controls = [
ft.Column(
controls = [
toolbox,
tool_divider,
tool_properties,
],
alignment = 'start',
expand = True,
),
tool_manager_dragbar,
],
expand = True,
),
clip_behavior = 'antiAlias',
)
tool_manager.toolbox = toolbox
tool_manager.tool_divider = tool_divider.content.content
tool_manager.tool_properties = tool_properties
tool_manager.dragbar = tool_manager_dragbar.content

View File

@ -66,8 +66,14 @@ path_to_uploads = "webui/flet/assets/uploads"
path_to_outputs = "webui/flet/assets/outputs"
# creates blank image (to do: take size as arg)
def create_blank_image():
img = Image.new('RGBA',(512,512),(0,0,0,0))
def create_blank_image(size):
try:
create_blank_image.count +=1
except AttributeError:
create_blank_image.count = 1
name = 'blank_layer_' + str(create_blank_image.count).zfill(2)
img = Image.new('RGBA',size,(0,0,0,1))
img.filename = name
return img
# takes name of image
@ -78,29 +84,32 @@ def get_image_from_uploads(name):
if os.path.exists(path_to_image):
image = Image.open(path_to_image)
image = image.convert("RGBA")
return {name:image}
image.filename = name
image.path = path_to_image
return image
else:
log_message(f'image not found: "{name}"')
return {name:None}
return None
def get_canvas_background(path):
image = Image.open(path)
image = image.resize((512,512))
image = image.convert("RGBA")
return image
# takes list of Image(s) as arg
# returns single composite of all images
def get_visible_from_image_stack(image_list):
visible_image = create_blank_image()
for image in image_list:
def get_preview_from_stack(size, images):
preview = create_blank_image(size)
canvas_width = size[0]
canvas_height = size[1]
for image in images:
# need to crop images for composite
x0, y0 = (image.width * 0.5) - 256, (image.height * 0.5) - 256
x1, y1 = x0 + 512, y0 + 512
x0, y0 = (image.width - canvas_width) * 0.5, (image.height - canvas_height) * 0.5
x1, y1 = x0 + canvas_width, y0 + canvas_height
box = (x0, y0, x1, y1)
cropped_image = image.crop(box)
visible_image = Image.alpha_composite(visible_image,cropped_image)
return visible_image
preview = Image.alpha_composite(preview,cropped_image)
return preview
# converts Image to base64 string
def convert_image_to_base64(image):
@ -117,26 +126,26 @@ def convert_image_to_base64(image):
# 'info_path' : path_to_yaml
def get_gallery_images(gallery_name):
path_to_gallery = None
images = []
files = []
if gallery_name == 'uploads':
path_to_gallery = path_to_uploads
elif gallery_name == 'outputs':
path_to_gallery = path_to_outputs
else:
log_message(f'gallery not found: "{gallery_name}"')
return None
images = []
files = []
return images
if os.path.exists(path_to_gallery):
files = os.listdir(path_to_gallery)
else:
return None
for f in files:
if f.endswith(('.jpg','.jpeg','.png')):
path_to_file = os.path.join('/uploads',f)
images.append({f:{'img_path':path_to_file}})
if f.endswith(('.yaml')):
path_to_file = os.path.join('/uploads',f)
images.append({f:{'info_path':path_to_file}})
image = Image.open(os.path.join(path_to_gallery,f))
image = image.convert("RGBA")
image.filename = f
image.path = os.path.join(gallery_name,f)
images.append(image)
return images

File diff suppressed because it is too large Load Diff