1 Commits

Author SHA1 Message Date
d99478935d 🚧 Add icons in toolbar
For #17
2023-06-15 12:12:52 +02:00
14 changed files with 34 additions and 227 deletions

View File

@@ -1,19 +0,0 @@
# Drawing Training
Open Source alternative to [GestureDrawing!](https://cubebrush.co/advanches/products/d9q6yq/gesturedrawing)
## Authors
- [@shikiryu](https://git.shikiryu.com/Shikiryu)
## Installation
Install my-project with python
```bash
sudo apt install cmake build-essential tcl-dev tk-dev python3-tk
pip install -r requirements.txt
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 543 B

View File

@@ -1,6 +1,5 @@
import os
import sys
from tkinter import PhotoImage
import customtkinter
@@ -16,9 +15,7 @@ def main():
root = customtkinter.CTk()
root.title("Drawing Training!")
root.geometry("300x300")
icon = PhotoImage(file="assets/icons/logo-dt.png")
root.iconphoto(True, icon)
root.geometry("300x600")
App(root)

View File

@@ -1,14 +1,7 @@
.PHONY: build dist
.ONESHELL:
VENV_DIR=.venv
ACTIVATE_VENV:=. $(VENV_DIR)/bin/activate
LOCATION:= $(shell pip show customtkinter | grep Location | cut -c 11-)
install:
python3 -m venv "$(VENV_DIR)"
$(ACTIVATE_VENV)
pip install --upgrade --requirement requirements.txt
TOTAL_LOCATION := $(pip show customtkinter | grep Location)
LOCATION=!TOTAL_LOCATION:~0,10!
build_linux:
rm -rf build dist drawingtraining.spec
@@ -16,4 +9,4 @@ build_linux:
build_windows:
rm -rf build dist drawingtraining.spec
pyinstaller main.py --onefile -w --hidden-import="PIL._tkinter_finder" -n drawingtraining --add-data "assets;assets" --add-data "$(LOCATION)\customtkinter;customtkinter" --icon="assets/icons/logo-dt.png"
pyinstaller main.py --onefile -w --hidden-import="PIL._tkinter_finder" -n drawingtraining --add-data "assets;assets" --add-data "${LOCATION}\customtkinter;customtkinter\"

View File

@@ -1,8 +1,6 @@
pillow~=10.0.1
pyinstaller==5.13.1
pillow~=9.5.0
pyinstaller==5.12.0
pygame~=2.4.0
customtkinter~=5.1.3
configparser~=5.3.0
CTkToolTip~=0.4
requests~=2.32.3
CTkMenuBar~=0.8
CTkToolTip~=0.4

View File

@@ -1,7 +1,5 @@
import copy
from tkinter import *
import PIL
from PIL import ImageTk, Image, ImageOps
@@ -10,7 +8,6 @@ class ImagePlaceholder:
self.is_break = False
self.current_image = None
self.current_original_image = None
self.paused_original_image = None
self.image_window = image_window
self.images = images.copy()
@@ -19,9 +16,6 @@ class ImagePlaceholder:
self.image_label.pack(side=TOP, fill=BOTH, expand=1)
def display_new_image(self):
if len(self.images) == 0:
self.image_window.on_closing()
return
image_path = self.images.pop(0)
if image_path == "break":
self.is_break = True
@@ -41,7 +35,7 @@ class ImagePlaceholder:
if w < 21 or h < 21:
w = 1280
h = 1024
self.current_image.thumbnail((w - 20, h - 20), PIL.Image.Resampling.LANCZOS)
self.current_image.thumbnail((w - 20, h - 20), Image.ANTIALIAS)
if reload:
self.load_widget()
@@ -62,16 +56,3 @@ class ImagePlaceholder:
self.image_label.configure(bg="#e8d4bc" if self.is_break else "#FFFFFF")
self.image_label.configure(image=image_to_display)
self.image_label.image = image_to_display
def pause(self, pause=True, cheat=False):
if pause:
self.paused_original_image = self.current_original_image
if not cheat:
image_path = 'assets/images/break.jpg'
self.current_original_image = Image.open(image_path)
else:
self.current_original_image = self.paused_original_image
self.paused_original_image = None
self.current_image = copy.deepcopy(self.current_original_image)
self.apply_options()

View File

@@ -1,21 +1,18 @@
import copy
import os
import subprocess
import sys
from tkinter import *
from tkinter.ttk import Progressbar, Style
from tkinter.messagebox import *
import customtkinter
from CTkToolTip import *
from PIL import ImageTk, Image
from PIL import ImageTk, Image, ImageOps
import customtkinter
from src.util import Util
class Toolbar:
def __init__(self, image_window, timer):
self.timers = []
self.is_paused = False
self.current_image = None
self.current_original_image = None
self.image_window = image_window
@@ -29,67 +26,52 @@ class Toolbar:
next_button = customtkinter.CTkButton(toolbar, image=ImageTk.PhotoImage(Image.open("assets/icons/next.png")),
text="", command=self.image_window.next_image)
next_button.pack(side=LEFT, padx=0, pady=0)
CTkToolTip(next_button, delay=0.1, message="Next", y_offset=-40, x_offset=-40)
pause_button = customtkinter.CTkButton(toolbar, image=ImageTk.PhotoImage(Image.open("assets/icons/pause.png")),
text="", command=self.pause)
pause_button.pack(side=LEFT, padx=0, pady=0)
CTkToolTip(pause_button, delay=0.1, message="Next", y_offset=-40, x_offset=-40)
CTkToolTip(next_button, delay=0.5, message="Next")
self.bw_button = customtkinter.CTkButton(toolbar, image=ImageTk.PhotoImage(Image.open("assets/icons/black-and"
"-white.png")),
text="", command=self.toggle_black_white)
self.bw_button.pack(side=LEFT, padx=0, pady=0)
CTkToolTip(self.bw_button, delay=0.1, message="Black and white image", y_offset=-40, x_offset=-40)
CTkToolTip(self.bw_button, delay=0.5, message="Black and white image")
self.mirror_button = customtkinter.CTkButton(toolbar, command=self.toggle_mirror, text="",
image=ImageTk.PhotoImage(Image.open("assets/icons/flip.png")))
self.mirror_button.pack(side=LEFT, padx=0, pady=0)
CTkToolTip(self.mirror_button, delay=0.1, message="Mirrored image", y_offset=-40, x_offset=-40)
CTkToolTip(self.mirror_button, delay=0.5, message="Mirrored image")
open_folder_button = customtkinter.CTkButton(toolbar, command=self.open_folder, text="",
image=ImageTk.PhotoImage(Image.open("assets/icons/folder.png")))
open_folder_button.pack(side=LEFT, padx=0, pady=0)
CTkToolTip(open_folder_button, delay=0.1, message="Open folder", y_offset=-40, x_offset=-40)
CTkToolTip(open_folder_button, delay=0.5, message="Open folder")
self.always_on_top_button = customtkinter.CTkButton(toolbar, command=self.toggle_always_on_top, text="",
image=ImageTk.PhotoImage(
Image.open("assets/icons/copy.png")))
self.always_on_top_button.pack(side=LEFT, padx=0, pady=0)
CTkToolTip(self.always_on_top_button, delay=0.1, message="Always on top", y_offset=-40, x_offset=-40)
CTkToolTip(self.always_on_top_button, delay=0.5, message="Always on top")
self.fullscreen_button = customtkinter.CTkButton(toolbar, command=self.toggle_fullscreen, text="",
image=ImageTk.PhotoImage(
Image.open("assets/icons/maximize.png")))
self.fullscreen_button.pack(side=LEFT, padx=0, pady=0)
CTkToolTip(self.fullscreen_button, delay=0.1, message="Fullscreen", y_offset=-40, x_offset=-40)
CTkToolTip(self.fullscreen_button, delay=0.5, message="Fullscreen")
timer_button = customtkinter.CTkButton(toolbar, command=self.toggle_timer, text="",
image=ImageTk.PhotoImage(Image.open("assets/icons/sand-clock.png")))
image=ImageTk.PhotoImage(Image.open("assets/icons/timer.png")))
timer_button.pack(side=LEFT, padx=0, pady=0)
CTkToolTip(timer_button, delay=0.1, message="Toggle timer", y_offset=-40, x_offset=-40)
CTkToolTip(timer_button, delay=0.5, message="Toggle 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)
style = Style()
style.theme_use('default')
style.configure("black.Horizontal.TProgressbar", background='black')
self.progressbar = Progressbar(toolbar, length=280)
self.progressbar.pack(side=RIGHT, ipadx=20)
def display_new_timer(self):
if len(self.timers) == 0:
return
self.timer = self.timers.pop(0)
self.timer_label.configure(text=Util.format_seconds(self.timer))
self.timer_check = self.image_window.window.after(1000, self.update_timer, self.timer)
def update_timer(self, current):
current -= 1
self.progressbar['value'] = 100 - (current * 100 / self.timer)
if current == 10:
self.image_window.play_countdown()
if current > 0:
@@ -121,11 +103,8 @@ class Toolbar:
try:
self.timer_label.pack_info()
self.timer_label.pack_forget()
self.progressbar.pack_info()
self.progressbar.pack_forget()
except TclError:
self.timer_label.pack(side=RIGHT, ipadx=20)
self.progressbar.pack(side=RIGHT, ipadx=20)
def open_folder(self):
if sys.platform == "win32":
@@ -154,23 +133,3 @@ class Toolbar:
"fullscreen"] else Util.get_default_button_color())
self.image_window.window.attributes("-fullscreen", self.image_window.option["fullscreen"])
def pause(self):
cheating = False
if not self.is_paused:
cheating = askyesno("Pause", "Laisser l'image affichée ?")
self.is_paused = True
else:
self.is_paused = False
# timer is paused whatever happened
if self.timer_check is not None:
self.image_window.window.after_cancel(self.timer_check)
self.timer_check = None
else:
self.timer_check = self.image_window.window.after(
1000, self.update_timer, int((100-self.progressbar['value'])*self.timer/100)
)
self.image_window.image.pause(pause=self.is_paused, cheat=cheating)

View File

@@ -1,41 +0,0 @@
from datetime import datetime
import os
import io
import tempfile
import requests
from PIL import Image
class Generator(object):
def __init__(self, generator=None, folder=None):
self.selected_folder = folder
if generator == 'poses':
self.generate_poses()
def generate_poses(self):
dt = datetime.now()
ts = int(datetime.timestamp(dt))
url = 'https://quickposes.com/ajax/getPosesForSlider/Chiaroscuro?_=' + str(ts)
resp_json = requests.get(url=url)
if resp_json.status_code == 200:
data = resp_json.json()
c = 0
for src in data:
if os.path.exists(os.path.join(self.selected_folder, src['src'])):
continue
if c >= 3:
break
buffer = tempfile.SpooledTemporaryFile(max_size=1e9)
r = requests.get('https://quickposes.com/assets/poses/' + src['src'], stream=True)
if r.status_code == 200:
downloaded = 0
for chunk in r.iter_content(chunk_size=1024):
downloaded += len(chunk)
buffer.write(chunk)
buffer.seek(0)
i = Image.open(io.BytesIO(buffer.read()))
i.save(os.path.join(self.selected_folder, src['src']), quality=85)
buffer.close()
c += 1

View File

@@ -47,4 +47,4 @@ class Util:
@staticmethod
def get_default_active_button_color():
return "green", "green"
return "gray29", "gray29"

View File

@@ -1,30 +0,0 @@
import webbrowser
import customtkinter
from customtkinter import CTkToplevel
class AboutWindow:
def __init__(self, app):
self.app = app
self.window = CTkToplevel(app.root)
self.window.title("À propos")
self.window.geometry("600x300")
self.window.protocol("WM_DELETE_WINDOW", self.on_closing)
link_gesture_drawing = customtkinter.CTkLabel(self.window, text="Open Source alternative to GestureDrawing!")
link_gesture_drawing.pack()
link_gesture_drawing.bind("<Button-1>",
lambda e: self.open_link("https://cubebrush.co/advanches/products/d9q6yq/gesturedrawing"))
link_shikiryu = customtkinter.CTkLabel(self.window, text="by Shikiryu")
link_shikiryu.pack()
link_shikiryu.bind("<Button-1>", lambda e: self.open_link("https://shikiryu.com"))
@staticmethod
def open_link(url):
webbrowser.open_new(url)
def on_closing(self):
self.window.destroy()

View File

@@ -1,15 +1,11 @@
import tkinter
from pathlib import Path
from tkinter import *
from tkinter import filedialog
import customtkinter
from src.entity.config import Config
from src.entity.generator import Generator
from src.util import Util
from src.window.about import AboutWindow
from src.window.image import ImageWindow
from src.window.session import SessionWindow
from CTkMenuBar import *
class App:
@@ -25,17 +21,6 @@ class App:
self.selected_folder = ""
self.found_images = []
self.timer = 0
menu = CTkMenuBar(master=root)
generate_button = menu.add_cascade("Generate")
help_button = menu.add_cascade("Help")
dropdown = CustomDropdownMenu(widget=generate_button)
dropdown.add_option(option="Poses", command=lambda:self.download_poses('poses'))
about = CustomDropdownMenu(widget=help_button)
about.add_option(option="À propos", command=self.show_help)
self.title = customtkinter.CTkLabel(root, text="Drawing Training")
self.title.pack()
@@ -48,8 +33,8 @@ class App:
self.images_len = customtkinter.CTkLabel(root, text="Found : " + str(len(self.found_images)))
self.images_len.pack()
self.button_frame = Frame(root, bg=root.cget("bg"))
self.button_frame.pack(fill=X, expand=True)
self.button_frame = Frame(root)
self.button_frame.pack(fill=X)
timers = [
Util.format_seconds(30),
@@ -60,16 +45,14 @@ class App:
Util.format_seconds(600),
"Custom"
]
self.buttons = []
for i, timer in enumerate(timers):
new_button = customtkinter.CTkButton(self.button_frame, width=10, text=timer,
command=lambda t=timer: self.set_timer_in_seconds(t))
new_button.pack(side=tkinter.LEFT, fill=X, expand=True)
self.buttons.append(new_button)
self.buttons = customtkinter.CTkSegmentedButton(
root, values=timers,
command=self.set_timer_in_seconds
)
self.buttons.pack(fill=X)
self.launch_button = customtkinter.CTkButton(root, text="Let's draw!", command=self.lets_draw, state="disabled")
self.launch_button.pack(side=tkinter.BOTTOM)
self.launch_button.pack(side="bottom")
self.read_config()
@@ -81,9 +64,6 @@ class App:
except Exception:
pass
def show_help(self):
AboutWindow(self)
def lets_draw(self):
self.image_window = ImageWindow(self)
self.image_window.lets_draw(self.found_images.copy(), self.timer)
@@ -93,17 +73,11 @@ class App:
self.session_window.open()
def select_folder(self):
new_directory = filedialog.askdirectory()
if new_directory:
self.selected_folder = new_directory
self.folder_name.configure(text="Folder : " + self.selected_folder)
Config.set_config_var("default_folder", self.selected_folder).save()
self.find_images_in_folder()
self.check_lets_draw()
def download_poses(self, generator=None):
Generator(generator=generator, folder=self.selected_folder)
self.selected_folder = filedialog.askdirectory()
self.folder_name.configure(text="Folder : " + self.selected_folder)
Config.set_config_var("default_folder", self.selected_folder).save()
self.find_images_in_folder()
self.check_lets_draw()
def find_images_in_folder(self):
if Path(self.selected_folder).exists():
@@ -119,11 +93,6 @@ class App:
self.launch_button.configure(state="disabled")
def set_timer_in_seconds(self, user_data):
# resetting buttons states
for button in self.buttons:
button.configure(fg_color=(Util.get_default_button_color() if user_data != button.cget(
"text") else Util.get_default_active_button_color()))
self.custom = False
if user_data == "Custom":
return self.custom_session()

View File

@@ -45,14 +45,14 @@ class SessionWindow:
text=session.number_of_drawings + " drawings of " + Util.format_seconds(int(session.timer)) + " each",
command=partial(self.edit_element, i),
fg_color=(
Util.get_default_active_button_color() if i == self.selected_element_index else Util.get_default_button_color())
Util.get_default_button_color() if i == self.selected_element_index else Util.get_default_active_button_color())
)
elif isinstance(session, BreakElement):
new_session = CTkButton(self.left_column,
text="Break of " + Util.format_seconds(int(session.timer)) + " each",
command=partial(self.edit_element, i),
fg_color=(
Util.get_default_active_button_color() if i == self.selected_element_index else Util.get_default_button_color())
Util.get_default_button_color() if i == self.selected_element_index else Util.get_default_active_button_color())
)
else:
raise Exception("unknown type.")