mirror of
https://github.com/sd-webui/stable-diffusion-webui.git
synced 2024-12-14 23:02:00 +03:00
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:
commit
84225f995d
BIN
webui/flet/assets/images/default_grid_texture.png
Executable file
BIN
webui/flet/assets/images/default_grid_texture.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 898 KiB |
257
webui/flet/scripts/flet_asset_manager.py
Normal file
257
webui/flet/scripts/flet_asset_manager.py
Normal 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)
|
||||
|
||||
|
||||
'''
|
@ -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
|
||||
|
||||
|
140
webui/flet/scripts/flet_file_manager.py
Normal file
140
webui/flet/scripts/flet_file_manager.py
Normal 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 = []
|
||||
|
@ -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 = []
|
||||
|
@ -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()
|
||||
|
123
webui/flet/scripts/flet_messages.py
Normal file
123
webui/flet/scripts/flet_messages.py
Normal 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
|
||||
|
281
webui/flet/scripts/flet_property_manager.py
Normal file
281
webui/flet/scripts/flet_property_manager.py
Normal 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
|
||||
|
@ -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",
|
||||
)
|
||||
|
||||
|
112
webui/flet/scripts/flet_titlebar.py
Normal file
112
webui/flet/scripts/flet_titlebar.py
Normal 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
|
||||
|
192
webui/flet/scripts/flet_tool_manager.py
Normal file
192
webui/flet/scripts/flet_tool_manager.py
Normal 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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user