🚧 Add new UI

This commit is contained in:
Clement Desmidt 2023-06-02 17:37:00 +02:00
parent a149ab71bb
commit e333af776c
8 changed files with 112 additions and 61 deletions

View File

@ -1,6 +1,8 @@
import os import os
import sys import sys
from tkinter import *
import customtkinter
from src.window.app import App from src.window.app import App
@ -8,7 +10,10 @@ def main():
if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
os.chdir(sys._MEIPASS) os.chdir(sys._MEIPASS)
root = Tk() customtkinter.set_appearance_mode("system")
customtkinter.set_default_color_theme("dark-blue")
root = customtkinter.CTk()
root.title("Drawing Training!") root.title("Drawing Training!")
root.geometry("300x600") root.geometry("300x600")

View File

@ -1,3 +1,4 @@
pillow~=9.5.0 pillow~=9.5.0
pyinstaller pyinstaller
pygame~=2.4.0 pygame~=2.4.0
customtkinter~=5.1.3

View File

@ -11,7 +11,7 @@ class ImagePlaceholder:
self.images = images.copy() self.images = images.copy()
self.image_label = Label(self.image_window.window) self.image_label = Label(self.image_window.window)
self.image_label.bind('<Configure>', lambda event: self.resize_image(True)) self.image_label.bind('<Configure>', lambda event: self.apply_options())
self.image_label.pack(side=TOP, fill=BOTH, expand=1) self.image_label.pack(side=TOP, fill=BOTH, expand=1)
def display_new_image(self): def display_new_image(self):

View File

@ -3,6 +3,7 @@ import os
import subprocess import subprocess
import sys import sys
from tkinter import * from tkinter import *
import customtkinter
from src.util import Util from src.util import Util
@ -19,32 +20,34 @@ class Toolbar:
toolbar = Frame(self.image_window.window, bd=1, relief=RAISED) toolbar = Frame(self.image_window.window, bd=1, relief=RAISED)
toolbar.pack(side=BOTTOM, fill=X) toolbar.pack(side=BOTTOM, fill=X)
next_button = Button(toolbar, relief=FLAT, compound=LEFT, text="next ➡️", command=self.image_window.next_image) next_button = customtkinter.CTkButton(toolbar, compound=LEFT, text="next ➡️",
command=self.image_window.next_image)
next_button.pack(side=LEFT, padx=0, pady=0) next_button.pack(side=LEFT, padx=0, pady=0)
self.bw_button = Button(toolbar, relief=FLAT, compound=LEFT, text="black&white", self.bw_button = customtkinter.CTkButton(toolbar, compound=LEFT, text="black&white",
command=self.toggle_black_white) command=self.toggle_black_white)
self.bw_button.pack(side=LEFT, padx=0, pady=0) self.bw_button.pack(side=LEFT, padx=0, pady=0)
self.mirror_button = Button(toolbar, relief=FLAT, compound=LEFT, command=self.toggle_mirror, self.mirror_button = customtkinter.CTkButton(toolbar, compound=LEFT, command=self.toggle_mirror,
text="mirror") text="mirror")
self.mirror_button.pack(side=LEFT, padx=0, pady=0) self.mirror_button.pack(side=LEFT, padx=0, pady=0)
open_folder_button = Button(toolbar, relief=FLAT, compound=LEFT, command=self.open_folder, text="open folder") open_folder_button = customtkinter.CTkButton(toolbar, compound=LEFT, command=self.open_folder,
text="open folder")
open_folder_button.pack(side=LEFT, padx=0, pady=0) open_folder_button.pack(side=LEFT, padx=0, pady=0)
self.always_on_top_button = Button(toolbar, relief=FLAT, compound=LEFT, command=self.toggle_always_on_top, self.always_on_top_button = customtkinter.CTkButton(toolbar, compound=LEFT, command=self.toggle_always_on_top,
text="always on top") text="always on top")
self.always_on_top_button.pack(side=LEFT, padx=0, pady=0) self.always_on_top_button.pack(side=LEFT, padx=0, pady=0)
self.fullscreen_button = Button(toolbar, relief=FLAT, compound=LEFT, command=self.toggle_fullscreen, self.fullscreen_button = customtkinter.CTkButton(toolbar, compound=LEFT, command=self.toggle_fullscreen,
text="fullscreen") text="fullscreen")
self.fullscreen_button.pack(side=LEFT, padx=0, pady=0) self.fullscreen_button.pack(side=LEFT, padx=0, pady=0)
timer_button = Button(toolbar, relief=FLAT, compound=LEFT, command=self.toggle_timer, text="timer") timer_button = customtkinter.CTkButton(toolbar, compound=LEFT, command=self.toggle_timer, text="timer")
timer_button.pack(side=LEFT, padx=0, pady=0) timer_button.pack(side=LEFT, padx=0, pady=0)
self.timer_label = Label(toolbar, text=self.timer) self.timer_label = customtkinter.CTkLabel(toolbar, text=str(self.timer), text_color=Util.get_default_button_color())
self.timer_label.pack(side=RIGHT, ipadx=20) self.timer_label.pack(side=RIGHT, ipadx=20)
def display_new_timer(self): def display_new_timer(self):
@ -69,13 +72,13 @@ class Toolbar:
def toggle_black_white(self): def toggle_black_white(self):
self.image_window.option["bw"] = not self.image_window.option["bw"] self.image_window.option["bw"] = not self.image_window.option["bw"]
self.bw_button.config(bg="blue" if self.image_window.option["bw"] else "grey85") self.bw_button.configure(fg_color=Util.get_default_active_button_color() if self.image_window.option["bw"] else Util.get_default_button_color())
self.image_window.image.apply_options() self.image_window.image.apply_options()
def toggle_mirror(self): def toggle_mirror(self):
self.image_window.option["mirror"] = not self.image_window.option["mirror"] self.image_window.option["mirror"] = not self.image_window.option["mirror"]
self.mirror_button.config(bg="blue" if self.image_window.option["mirror"] else "grey85") self.mirror_button.configure(fg_color=Util.get_default_active_button_color() if self.image_window.option["mirror"] else Util.get_default_button_color())
self.image_window.image.apply_options() self.image_window.image.apply_options()
@ -96,10 +99,10 @@ class Toolbar:
def toggle_always_on_top(self): def toggle_always_on_top(self):
self.image_window.option["always_on_top"] = not self.image_window.option["always_on_top"] self.image_window.option["always_on_top"] = not self.image_window.option["always_on_top"]
if self.image_window.option["always_on_top"]: if self.image_window.option["always_on_top"]:
self.always_on_top_button.config(bg="blue") self.always_on_top_button.configure(fg_color=Util.get_default_active_button_color())
self.stay_on_top() self.stay_on_top()
else: else:
self.always_on_top_button.config(bg="grey85") self.always_on_top_button.configure(fg_color=Util.get_default_active_button_color())
self.image_window.window.after_cancel(self.always_on_top_check) self.image_window.window.after_cancel(self.always_on_top_check)
def stay_on_top(self): def stay_on_top(self):
@ -109,6 +112,6 @@ class Toolbar:
def toggle_fullscreen(self): def toggle_fullscreen(self):
self.image_window.option["fullscreen"] = not self.image_window.option["fullscreen"] self.image_window.option["fullscreen"] = not self.image_window.option["fullscreen"]
self.fullscreen_button.config(bg="blue" if self.image_window.option["fullscreen"] else "grey85") self.fullscreen_button.configure(fg_color=Util.get_default_active_button_color() if self.image_window.option["fullscreen"] else Util.get_default_button_color())
self.image_window.window.attributes("-fullscreen", self.image_window.option["fullscreen"]) self.image_window.window.attributes("-fullscreen", self.image_window.option["fullscreen"])

View File

@ -47,3 +47,9 @@ class Config(object):
if config_var not in Config._CONFIG: if config_var not in Config._CONFIG:
raise Exception(f"Please set the {config_var} variable in the config file {Config._CONFIG_FILE}") raise Exception(f"Please set the {config_var} variable in the config file {Config._CONFIG_FILE}")
return Config._CONFIG[config_var] return Config._CONFIG[config_var]
@staticmethod
def set_config_var(name, value):
assert Config._CONFIG
Config._CONFIG[name] = value
return Config

View File

@ -22,3 +22,29 @@ class Util:
time += str(seconds) + "s" time += str(seconds) + "s"
return time return time
@staticmethod
def format_time_to_seconds(time: str) -> int:
seconds = 0
hours = time.split("h")
if len(hours) > 1:
seconds += (60 * 60 * int(hours.pop(0)))
time = hours.pop(0)
minutes = time.split("m")
if len(minutes) > 1:
seconds += (60 * int(minutes.pop(0)))
time = minutes.pop(0)
seconds += int(time[0:-1]) if len(time) > 0 else 0
return seconds
@staticmethod
def get_default_button_color():
return "#3a7ebf", "#1f538d"
@staticmethod
def get_default_active_button_color():
return "gray29", "gray29"

View File

@ -1,10 +1,9 @@
from pathlib import Path
from tkinter import * from tkinter import *
from tkinter import filedialog from tkinter import filedialog
from pathlib import Path import customtkinter
from src.entity.config import Config from src.entity.config import Config
from src.util import Util from src.util import Util
from functools import partial
from src.window.image import ImageWindow from src.window.image import ImageWindow
from src.window.session import SessionWindow from src.window.session import SessionWindow
@ -22,41 +21,49 @@ class App:
self.selected_folder = "" self.selected_folder = ""
self.found_images = [] self.found_images = []
self.timer = 0 self.timer = 0
self.title = Label(root, text="Drawing Training") self.title = customtkinter.CTkLabel(root, text="Drawing Training")
self.title.pack() self.title.pack()
self.folder_selector = Button(root, text="Select a folder", command=self.select_folder) self.folder_selector = customtkinter.CTkButton(root, text="Select a folder", command=self.select_folder)
self.folder_selector.pack() self.folder_selector.pack()
self.folder_name = Label(root, text="Folder : " + self.selected_folder) self.folder_name = customtkinter.CTkLabel(root, text="Folder : " + self.selected_folder)
self.folder_name.pack() self.folder_name.pack()
self.images_len = Label(root, text="Found : " + str(len(self.found_images))) self.images_len = customtkinter.CTkLabel(root, text="Found : " + str(len(self.found_images)))
self.images_len.pack() self.images_len.pack()
self.button_frame = Frame(root) self.button_frame = Frame(root)
self.button_frame.pack(fill=X) self.button_frame.pack(fill=X)
timers = [30, 45, 60, 120, 300, 600] timers = [
self.buttons = [] Util.format_seconds(30),
i = 0 Util.format_seconds(45),
for i in timers: Util.format_seconds(60),
t = i Util.format_seconds(120),
new_button = Button(self.button_frame, text=Util.format_seconds(t), Util.format_seconds(300),
command=partial(self.set_timer_in_seconds, t)) Util.format_seconds(600),
self.buttons.append(new_button) "Custom"
self.button_frame.columnconfigure(i, weight=1) ]
new_button.grid(row=0, column=i, sticky=W + E) self.buttons = customtkinter.CTkSegmentedButton(
i += 1 root, values=timers,
command=self.set_timer_in_seconds
)
self.buttons.pack(fill=X)
new_button = Button(self.button_frame, text="Custom", command=self.custom_session) self.launch_button = customtkinter.CTkButton(root, text="Let's draw!", command=self.lets_draw, state="disabled")
self.buttons.append(new_button)
self.button_frame.columnconfigure(i, weight=1)
new_button.grid(row=0, column=i, sticky=W + E)
self.launch_button = Button(root, text="Let's draw!", command=self.lets_draw, state="disabled")
self.launch_button.pack(side="bottom") self.launch_button.pack(side="bottom")
self.read_config()
def read_config(self):
try:
self.selected_folder = Config.get_required_config_var("default_folder")
self.folder_name.configure(text="Folder : " + self.selected_folder)
self.find_images_in_folder()
except Exception:
pass
def lets_draw(self): def lets_draw(self):
self.image_window = ImageWindow(self) self.image_window = ImageWindow(self)
self.image_window.lets_draw(self.found_images.copy(), self.timer) self.image_window.lets_draw(self.found_images.copy(), self.timer)
@ -67,32 +74,33 @@ class App:
def select_folder(self): def select_folder(self):
self.selected_folder = filedialog.askdirectory() self.selected_folder = filedialog.askdirectory()
self.found_images = list( self.folder_name.configure(text="Folder : " + self.selected_folder)
p.resolve() for p in Path(self.selected_folder).glob("**/*") if p.suffix in {".jpg", ".gif", ".png"}) Config.set_config_var("default_folder", self.selected_folder).save()
self.folder_name.config(text="Folder : " + self.selected_folder) self.find_images_in_folder()
self.images_len.config(text="Found : " + str(len(self.found_images)))
self.check_lets_draw() self.check_lets_draw()
def find_images_in_folder(self):
if Path(self.selected_folder).exists():
self.found_images = list(
p.resolve() for p in Path(self.selected_folder).glob("**/*") if p.suffix in {".jpg", ".gif", ".png"}
)
self.images_len.configure(text="Found : " + str(len(self.found_images)))
def check_lets_draw(self): def check_lets_draw(self):
if self.selected_folder != "" and len(self.found_images) > 0 and (self.timer != 0 or self.custom): if self.selected_folder != "" and len(self.found_images) > 0 and (self.timer != 0 or self.custom):
self.launch_button.config(state="normal") self.launch_button.configure(state="normal")
else: else:
self.launch_button.config(state="disabled") self.launch_button.configure(state="disabled")
def set_timer_in_seconds(self, user_data): def set_timer_in_seconds(self, user_data):
self.custom = False self.custom = False
self.timer = user_data if user_data == "Custom":
for button in self.buttons: return self.custom_session()
if button['text'] == Util.format_seconds(self.timer):
button.config(bg="blue") self.timer = Util.format_time_to_seconds(user_data)
else:
button.config(bg="gray85")
self.check_lets_draw() self.check_lets_draw()
def set_custom(self, list_in_session): def set_custom(self, list_in_session):
self.custom = True self.custom = True
self.list_in_session = list_in_session self.list_in_session = list_in_session
self.check_lets_draw() self.check_lets_draw()
for button in self.buttons:
button.config(bg="gray85")
self.buttons[-1].config(bg="blue")

View File

@ -1,5 +1,7 @@
import random import random
from tkinter import * from tkinter import *
from customtkinter import CTkToplevel
from pygame import mixer from pygame import mixer
from src.element.image import ImagePlaceholder from src.element.image import ImagePlaceholder
from src.element.toolbar import Toolbar from src.element.toolbar import Toolbar
@ -10,7 +12,7 @@ class ImageWindow:
self.current_original_image = None self.current_original_image = None
self.app = app self.app = app
self.window = Toplevel(app.root) self.window = CTkToplevel(app.root)
self.window.title("Image") self.window.title("Image")
self.window.geometry("1280x1024") self.window.geometry("1280x1024")
self.window.protocol("WM_DELETE_WINDOW", self.on_closing) self.window.protocol("WM_DELETE_WINDOW", self.on_closing)