diff --git a/modules/ui.json b/modules/ui.json deleted file mode 100644 index 0954578..0000000 --- a/modules/ui.json +++ /dev/null @@ -1,158 +0,0 @@ -{ - "CTk": { - "fg_color": ["gray95", "gray10"] - }, - "CTkToplevel": { - "fg_color": ["gray95", "gray10"] - }, - "CTkFrame": { - "corner_radius": 0, - "border_width": 0, - "fg_color": ["gray90", "gray13"], - "top_fg_color": ["gray85", "gray16"], - "border_color": ["gray65", "gray28"] - }, - "CTkButton": { - "corner_radius": 0, - "border_width": 0, - "fg_color": ["#2aa666", "#1f538d"], - "hover_color": ["#3cb666", "#14375e"], - "border_color": ["#3e4a40", "#949A9F"], - "text_color": ["#f3faf6", "#f3faf6"], - "text_color_disabled": ["gray74", "gray60"] - }, - "CTkLabel": { - "corner_radius": 0, - "fg_color": "transparent", - "text_color": ["gray14", "gray84"] - }, - "CTkEntry": { - "corner_radius": 0, - "border_width": 2, - "fg_color": ["#F9F9FA", "#343638"], - "border_color": ["#979DA2", "#565B5E"], - "text_color": ["gray14", "gray84"], - "placeholder_text_color": ["gray52", "gray62"] - }, - "CTkCheckbox": { - "corner_radius": 0, - "border_width": 3, - "fg_color": ["#2aa666", "#1f538d"], - "border_color": ["#3e4a40", "#949A9F"], - "hover_color": ["#3cb666", "#14375e"], - "checkmark_color": ["#f3faf6", "gray90"], - "text_color": ["gray14", "gray84"], - "text_color_disabled": ["gray60", "gray45"] - }, - "CTkSwitch": { - "corner_radius": 1000, - "border_width": 3, - "button_length": 0, - "fg_color": ["#939BA2", "#4A4D50"], - "progress_color": ["#2aa666", "#1f538d"], - "button_color": ["gray36", "#D5D9DE"], - "button_hover_color": ["gray20", "gray100"], - "text_color": ["gray14", "gray84"], - "text_color_disabled": ["gray60", "gray45"] - }, - "CTkRadiobutton": { - "corner_radius": 1000, - "border_width_checked": 6, - "border_width_unchecked": 3, - "fg_color": ["#2aa666", "#1f538d"], - "border_color": ["#3e4a40", "#949A9F"], - "hover_color": ["#3cb666", "#14375e"], - "text_color": ["gray14", "gray84"], - "text_color_disabled": ["gray60", "gray45"] - }, - "CTkProgressBar": { - "corner_radius": 1000, - "border_width": 0, - "fg_color": ["#939BA2", "#4A4D50"], - "progress_color": ["#2aa666", "#1f538d"], - "border_color": ["gray", "gray"] - }, - "CTkSlider": { - "corner_radius": 1000, - "button_corner_radius": 1000, - "border_width": 6, - "button_length": 0, - "fg_color": ["#939BA2", "#4A4D50"], - "progress_color": ["gray40", "#AAB0B5"], - "button_color": ["#2aa666", "#1f538d"], - "button_hover_color": ["#3cb666", "#14375e"] - }, - "CTkOptionMenu": { - "corner_radius": 0, - "fg_color": ["#2aa666", "#1f538d"], - "button_color": ["#3cb666", "#14375e"], - "button_hover_color": ["#234567", "#1e2c40"], - "text_color": ["#f3faf6", "#f3faf6"], - "text_color_disabled": ["gray74", "gray60"] - }, - "CTkComboBox": { - "corner_radius": 0, - "border_width": 2, - "fg_color": ["#F9F9FA", "#343638"], - "border_color": ["#979DA2", "#565B5E"], - "button_color": ["#979DA2", "#565B5E"], - "button_hover_color": ["#6E7174", "#7A848D"], - "text_color": ["gray14", "gray84"], - "text_color_disabled": ["gray50", "gray45"] - }, - "CTkScrollbar": { - "corner_radius": 1000, - "border_spacing": 4, - "fg_color": "transparent", - "button_color": ["gray55", "gray41"], - "button_hover_color": ["gray40", "gray53"] - }, - "CTkSegmentedButton": { - "corner_radius": 0, - "border_width": 2, - "fg_color": ["#979DA2", "gray29"], - "selected_color": ["#2aa666", "#1f538d"], - "selected_hover_color": ["#3cb666", "#14375e"], - "unselected_color": ["#979DA2", "gray29"], - "unselected_hover_color": ["gray70", "gray41"], - "text_color": ["#f3faf6", "#f3faf6"], - "text_color_disabled": ["gray74", "gray60"] - }, - "CTkTextbox": { - "corner_radius": 0, - "border_width": 0, - "fg_color": ["gray100", "gray20"], - "border_color": ["#979DA2", "#565B5E"], - "text_color": ["gray14", "gray84"], - "scrollbar_button_color": ["gray55", "gray41"], - "scrollbar_button_hover_color": ["gray40", "gray53"] - }, - "CTkScrollableFrame": { - "label_fg_color": ["gray80", "gray21"] - }, - "DropdownMenu": { - "fg_color": ["gray90", "gray20"], - "hover_color": ["gray75", "gray28"], - "text_color": ["gray14", "gray84"] - }, - "CTkFont": { - "macOS": { - "family": "Avenir", - "size": 18, - "weight": "normal" - }, - "Windows": { - "family": "Corbel", - "size": 18, - "weight": "normal" - }, - "Linux": { - "family": "Montserrat", - "size": 18, - "weight": "normal" - } - }, - "URL": { - "text_color": ["gray74", "gray60"] - } -} diff --git a/modules/ui.py b/modules/ui.py index a8c6522..2d3ade4 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -4,13 +4,26 @@ import customtkinter as ctk from typing import Callable, Tuple import cv2 from PIL import Image, ImageOps +import tkinterdnd2 as tkdnd import modules.globals import modules.metadata -from modules.face_analyser import get_one_face, get_unique_faces_from_target_image, get_unique_faces_from_target_video, add_blank_map, has_valid_map, simplify_maps +from modules.face_analyser import ( + get_one_face, + get_unique_faces_from_target_image, + get_unique_faces_from_target_video, + add_blank_map, + has_valid_map, + simplify_maps, +) from modules.capturer import get_video_frame, get_video_frame_total from modules.processors.frame.core import get_frame_processors_modules -from modules.utilities import is_image, is_video, resolve_relative_path, has_image_extension +from modules.utilities import ( + is_image, + is_video, + resolve_relative_path, + has_image_extension, +) ROOT = None POPUP = None @@ -20,18 +33,18 @@ ROOT_WIDTH = 600 PREVIEW = None PREVIEW_MAX_HEIGHT = 700 -PREVIEW_MAX_WIDTH = 1200 -PREVIEW_DEFAULT_WIDTH = 960 +PREVIEW_MAX_WIDTH = 1200 +PREVIEW_DEFAULT_WIDTH = 960 PREVIEW_DEFAULT_HEIGHT = 540 POPUP_WIDTH = 750 POPUP_HEIGHT = 810 -POPUP_SCROLL_WIDTH = 740, +POPUP_SCROLL_WIDTH = 740 POPUP_SCROLL_HEIGHT = 700 POPUP_LIVE_WIDTH = 900 POPUP_LIVE_HEIGHT = 820 -POPUP_LIVE_SCROLL_WIDTH = 890, +POPUP_LIVE_SCROLL_WIDTH = 890 POPUP_LIVE_SCROLL_HEIGHT = 700 MAPPER_PREVIEW_MAX_HEIGHT = 100 @@ -58,7 +71,104 @@ target_label_dict_live = {} img_ft, vid_ft = modules.globals.file_types -def init(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.CTk: +class DragDropButton(ctk.CTkButton): + def __init__(self, master, **kwargs): + super().__init__(master, **kwargs) + self.drop_target_register(tkdnd.DND_FILES) + self.dnd_bind("<>", self.drop) + + def drop(self, event): + file_path = event.data + if file_path.startswith("{"): + file_path = file_path[1:-1] + self.handle_drop(file_path) + + def handle_drop(self, file_path): + pass + + +class SourceButton(DragDropButton): + def handle_drop(self, file_path): + if is_image(file_path): + modules.globals.source_path = file_path + global RECENT_DIRECTORY_SOURCE + RECENT_DIRECTORY_SOURCE = os.path.dirname(modules.globals.source_path) + image = render_image_preview(modules.globals.source_path, (200, 200)) + source_label.configure(image=image) + source_label.configure(text="") + + +class SourceMapperButton(DragDropButton): + def __init__(self, master, map, button_num, **kwargs): + super().__init__(master, **kwargs) + self.map = map + self.button_num = button_num + + def handle_drop(self, file_path): + if is_image(file_path): + update_popup_source(self.master, self.map, self.button_num, file_path) + + +class TargetButton(DragDropButton): + def handle_drop(self, file_path): + global RECENT_DIRECTORY_TARGET + if is_image(file_path) or is_video(file_path): + modules.globals.target_path = file_path + RECENT_DIRECTORY_TARGET = os.path.dirname(modules.globals.target_path) + if is_image(file_path): + image = render_image_preview(modules.globals.target_path, (200, 200)) + target_label.configure(image=image) + target_label.configure(text="") + elif is_video(file_path): + video_frame = render_video_preview(file_path, (200, 200)) + target_label.configure(image=video_frame) + target_label.configure(text="") + + +class DragDropLabel(ctk.CTkLabel): + def __init__(self, master, **kwargs): + super().__init__(master, **kwargs) + self.drop_target_register(tkdnd.DND_FILES) + self.dnd_bind("<>", self.drop) + + def drop(self, event): + file_path = event.data + if file_path.startswith("{"): + file_path = file_path[1:-1] + self.handle_drop(file_path) + + def handle_drop(self, file_path): + pass + + +class SourceLabel(DragDropLabel): + def handle_drop(self, file_path): + if is_image(file_path): + modules.globals.source_path = file_path + global RECENT_DIRECTORY_SOURCE + RECENT_DIRECTORY_SOURCE = os.path.dirname(modules.globals.source_path) + image = render_image_preview(modules.globals.source_path, (200, 200)) + source_label.configure(image=image) + source_label.configure(text="") + + +class TargetLabel(DragDropLabel): + def handle_drop(self, file_path): + global RECENT_DIRECTORY_TARGET + if is_image(file_path) or is_video(file_path): + modules.globals.target_path = file_path + RECENT_DIRECTORY_TARGET = os.path.dirname(modules.globals.target_path) + if is_image(file_path): + image = render_image_preview(modules.globals.target_path, (200, 200)) + target_label.configure(image=image) + target_label.configure(text="") + elif is_video(file_path): + video_frame = render_video_preview(file_path, (200, 200)) + target_label.configure(image=video_frame) + target_label.configure(text="") + + +def init(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd.TkinterDnD.Tk: global ROOT, PREVIEW ROOT = create_root(start, destroy) @@ -67,90 +177,225 @@ def init(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.CTk: return ROOT -def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.CTk: +def create_root( + start: Callable[[], None], destroy: Callable[[], None] +) -> tkdnd.TkinterDnD.Tk: global source_label, target_label, status_label - ctk.deactivate_automatic_dpi_awareness() - ctk.set_appearance_mode('system') - ctk.set_default_color_theme(resolve_relative_path('ui.json')) + ctk.set_appearance_mode("dark") + ctk.set_default_color_theme("blue") # Use a built-in theme - root = ctk.CTk() + root = tkdnd.TkinterDnD.Tk() root.minsize(ROOT_WIDTH, ROOT_HEIGHT) - root.title(f'{modules.metadata.name} {modules.metadata.version} {modules.metadata.edition}') - root.configure() - root.protocol('WM_DELETE_WINDOW', lambda: destroy()) + root.title( + f"{modules.metadata.name} {modules.metadata.version} {modules.metadata.edition}" + ) + root.configure(bg="gray12") + root.protocol("WM_DELETE_WINDOW", lambda: destroy()) - source_label = ctk.CTkLabel(root, text=None) + source_label = SourceLabel( + root, + text="Drag & Drop\nSource Image Here", + text_color="gray", + font=("Arial", 16), + justify="center", + ) source_label.place(relx=0.1, rely=0.1, relwidth=0.3, relheight=0.25) - target_label = ctk.CTkLabel(root, text=None) + target_label = TargetLabel( + root, + text="Drag & Drop\nTarget Image/Video Here", + text_color="gray", + font=("Arial", 16), + justify="center", + ) target_label.place(relx=0.6, rely=0.1, relwidth=0.3, relheight=0.25) - select_face_button = ctk.CTkButton(root, text='Select a face', cursor='hand2', command=lambda: select_source_path()) + select_face_button = SourceButton( + root, + text="Select a face", + cursor="hand2", + command=lambda: select_source_path(), + fg_color=("gray75", "gray25"), # Modern button color + hover_color=("gray85", "gray35"), + corner_radius=10, # Rounded corners + ) select_face_button.place(relx=0.1, rely=0.4, relwidth=0.3, relheight=0.1) - swap_faces_button = ctk.CTkButton(root, text='↔', cursor='hand2', command=lambda: swap_faces_paths()) + swap_faces_button = ctk.CTkButton( + root, + text="↔", + cursor="hand2", + command=lambda: swap_faces_paths(), + fg_color=("gray75", "gray25"), + hover_color=("gray85", "gray35"), + corner_radius=10, + ) swap_faces_button.place(relx=0.45, rely=0.4, relwidth=0.1, relheight=0.1) - select_target_button = ctk.CTkButton(root, text='Select a target', cursor='hand2', command=lambda: select_target_path()) + select_target_button = TargetButton( + root, + text="Select a target", + cursor="hand2", + command=lambda: select_target_path(), + fg_color=("gray75", "gray25"), + hover_color=("gray85", "gray35"), + corner_radius=10, + ) select_target_button.place(relx=0.6, rely=0.4, relwidth=0.3, relheight=0.1) keep_fps_value = ctk.BooleanVar(value=modules.globals.keep_fps) - keep_fps_checkbox = ctk.CTkSwitch(root, text='Keep fps', variable=keep_fps_value, cursor='hand2', command=lambda: setattr(modules.globals, 'keep_fps', not modules.globals.keep_fps)) + keep_fps_checkbox = ctk.CTkSwitch( + root, + text="Keep fps", + variable=keep_fps_value, + cursor="hand2", + command=lambda: setattr( + modules.globals, "keep_fps", not modules.globals.keep_fps + ), + fg_color=("gray75", "gray25"), # Modern switch color + progress_color=("DodgerBlue", "DodgerBlue"), + ) keep_fps_checkbox.place(relx=0.1, rely=0.6) keep_frames_value = ctk.BooleanVar(value=modules.globals.keep_frames) - keep_frames_switch = ctk.CTkSwitch(root, text='Keep frames', variable=keep_frames_value, cursor='hand2', command=lambda: setattr(modules.globals, 'keep_frames', keep_frames_value.get())) + keep_frames_switch = ctk.CTkSwitch( + root, + text="Keep frames", + variable=keep_frames_value, + cursor="hand2", + command=lambda: setattr( + modules.globals, "keep_frames", keep_frames_value.get() + ), + fg_color=("gray75", "gray25"), + progress_color=("DodgerBlue", "DodgerBlue"), + ) keep_frames_switch.place(relx=0.1, rely=0.65) - # for FRAME PROCESSOR ENHANCER tumbler: - enhancer_value = ctk.BooleanVar(value=modules.globals.fp_ui['face_enhancer']) - enhancer_switch = ctk.CTkSwitch(root, text='Face Enhancer', variable=enhancer_value, cursor='hand2', command=lambda: update_tumbler('face_enhancer',enhancer_value.get())) + enhancer_value = ctk.BooleanVar(value=modules.globals.fp_ui["face_enhancer"]) + enhancer_switch = ctk.CTkSwitch( + root, + text="Face Enhancer", + variable=enhancer_value, + cursor="hand2", + command=lambda: update_tumbler("face_enhancer", enhancer_value.get()), + fg_color=("gray75", "gray25"), + progress_color=("DodgerBlue", "DodgerBlue"), + ) enhancer_switch.place(relx=0.1, rely=0.7) keep_audio_value = ctk.BooleanVar(value=modules.globals.keep_audio) - keep_audio_switch = ctk.CTkSwitch(root, text='Keep audio', variable=keep_audio_value, cursor='hand2', command=lambda: setattr(modules.globals, 'keep_audio', keep_audio_value.get())) + keep_audio_switch = ctk.CTkSwitch( + root, + text="Keep audio", + variable=keep_audio_value, + cursor="hand2", + command=lambda: setattr(modules.globals, "keep_audio", keep_audio_value.get()), + fg_color=("gray75", "gray25"), + progress_color=("DodgerBlue", "DodgerBlue"), + ) keep_audio_switch.place(relx=0.6, rely=0.6) many_faces_value = ctk.BooleanVar(value=modules.globals.many_faces) - many_faces_switch = ctk.CTkSwitch(root, text='Many faces', variable=many_faces_value, cursor='hand2', command=lambda: setattr(modules.globals, 'many_faces', many_faces_value.get())) + many_faces_switch = ctk.CTkSwitch( + root, + text="Many faces", + variable=many_faces_value, + cursor="hand2", + command=lambda: setattr(modules.globals, "many_faces", many_faces_value.get()), + fg_color=("gray75", "gray25"), + progress_color=("DodgerBlue", "DodgerBlue"), + ) many_faces_switch.place(relx=0.6, rely=0.65) - # Add color correction toggle button color_correction_value = ctk.BooleanVar(value=modules.globals.color_correction) - color_correction_switch = ctk.CTkSwitch(root, text='Fix Blueish Cam\n(force cv2 to use RGB instead of BGR)', variable=color_correction_value, cursor='hand2', command=lambda: setattr(modules.globals, 'color_correction', color_correction_value.get())) + color_correction_switch = ctk.CTkSwitch( + root, + text="Fix Blueish Cam -\nforce cv2 to\nuse RGB instead of BGR", + variable=color_correction_value, + cursor="hand2", + command=lambda: setattr( + modules.globals, "color_correction", color_correction_value.get() + ), + fg_color=("gray75", "gray25"), + progress_color=("DodgerBlue", "DodgerBlue"), + ) color_correction_switch.place(relx=0.6, rely=0.70) -# nsfw_value = ctk.BooleanVar(value=modules.globals.nsfw_filter) -# nsfw_switch = ctk.CTkSwitch(root, text='NSFW filter', variable=nsfw_value, cursor='hand2', command=lambda: setattr(modules.globals, 'nsfw_filter', nsfw_value.get())) -# nsfw_switch.place(relx=0.6, rely=0.7) - map_faces = ctk.BooleanVar(value=modules.globals.map_faces) - map_faces_switch = ctk.CTkSwitch(root, text='Map faces', variable=map_faces, cursor='hand2', command=lambda: setattr(modules.globals, 'map_faces', map_faces.get())) + map_faces_switch = ctk.CTkSwitch( + root, + text="Map faces", + variable=map_faces, + cursor="hand2", + command=lambda: setattr(modules.globals, "map_faces", map_faces.get()), + fg_color=("gray75", "gray25"), + progress_color=("DodgerBlue", "DodgerBlue"), + ) map_faces_switch.place(relx=0.1, rely=0.75) - start_button = ctk.CTkButton(root, text='Start', cursor='hand2', command=lambda: analyze_target(start, root)) + start_button = ctk.CTkButton( + root, + text="Start", + cursor="hand2", + command=lambda: analyze_target(start, root), + fg_color=("DodgerBlue", "DodgerBlue"), # Modern button color + hover_color=("RoyalBlue", "RoyalBlue"), + corner_radius=10, + ) start_button.place(relx=0.15, rely=0.80, relwidth=0.2, relheight=0.05) - stop_button = ctk.CTkButton(root, text='Destroy', cursor='hand2', command=lambda: destroy()) + stop_button = ctk.CTkButton( + root, + text="Destroy", + cursor="hand2", + command=lambda: destroy(), + fg_color=("gray75", "gray25"), + hover_color=("gray85", "gray35"), + corner_radius=10, + ) stop_button.place(relx=0.4, rely=0.80, relwidth=0.2, relheight=0.05) - preview_button = ctk.CTkButton(root, text='Preview', cursor='hand2', command=lambda: toggle_preview()) + preview_button = ctk.CTkButton( + root, + text="Preview", + cursor="hand2", + command=lambda: toggle_preview(), + fg_color=("gray75", "gray25"), + hover_color=("gray85", "gray35"), + corner_radius=10, + ) preview_button.place(relx=0.65, rely=0.80, relwidth=0.2, relheight=0.05) - live_button = ctk.CTkButton(root, text='Live', cursor='hand2', command=lambda: webcam_preview(root)) + live_button = ctk.CTkButton( + root, + text="Live", + cursor="hand2", + command=lambda: webcam_preview(root), + fg_color=("gray75", "gray25"), + hover_color=("gray85", "gray35"), + corner_radius=10, + ) live_button.place(relx=0.40, rely=0.86, relwidth=0.2, relheight=0.05) - status_label = ctk.CTkLabel(root, text=None, justify='center') + status_label = ctk.CTkLabel(root, text=None, justify="center") status_label.place(relx=0.1, rely=0.9, relwidth=0.8) - donate_label = ctk.CTkLabel(root, text='Deep Live Cam', justify='center', cursor='hand2') + donate_label = ctk.CTkLabel( + root, text="Deep Live Cam", justify="center", cursor="hand2" + ) donate_label.place(relx=0.1, rely=0.95, relwidth=0.8) - donate_label.configure(text_color=ctk.ThemeManager.theme.get('URL').get('text_color')) - donate_label.bind('