Compare commits

..

10 Commits

Author SHA1 Message Date
1a59ec3ec2 πŸ› Debug linux build 2024-09-13 17:53:55 +02:00
5941da9ae5 ✨ Add cheated pause
For #36
2024-06-17 14:16:58 +02:00
a8c0979ef1 ✨ Add not cheated pause
For #36
2024-06-14 17:35:28 +02:00
Shikiryu
328b7a0e49 πŸš€ Modify windows makefile 2024-06-10 21:49:04 +02:00
Shikiryu
ee8968cbab πŸ’„ Add progressbar as timer
+ remove one bug and updates dependencies
2024-05-17 23:39:29 +02:00
Shikiryu
33d6e9d4df πŸ’„ Add better displayed tooltip 2024-05-16 00:19:49 +02:00
3b17dff7be 🚧 Add icons in toolbar
For #17
2024-05-15 23:54:07 +02:00
d8b6e7bd8c πŸ› Transform Radiobutton to button to allow re-click
Fix #29
2024-05-15 17:25:18 +02:00
8087d326ef πŸ“ Add a README 2024-05-15 09:40:16 +02:00
7702a0bea3 πŸ’„ Add an app icon
Fix #15
2024-05-15 09:30:57 +02:00
12 changed files with 132 additions and 34 deletions

19
README.md Normal file
View File

@ -0,0 +1,19 @@
# 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
```

BIN
assets/icons/logo-dt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
assets/icons/pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

BIN
assets/icons/sand-clock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

View File

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

View File

@ -1,12 +1,20 @@
.PHONY: build dist
TOTAL_LOCATION := $(pip show customtkinter | grep Location)
LOCATION=!TOTAL_LOCATION:~0,10!
.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
build_linux:
rm -rf build dist drawingtraining.spec
$(ACTIVATE_VENV)
pyinstaller main.py --onefile -w --hidden-import="PIL._tkinter_finder" -n drawingtraining --add-data "assets:assets"
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\"
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"

View File

@ -1,5 +1,5 @@
pillow~=9.5.0
pyinstaller==5.12.0
pillow~=10.0.1
pyinstaller==5.13.1
pygame~=2.4.0
customtkinter~=5.1.3
configparser~=5.3.0

View File

@ -1,5 +1,7 @@
import copy
from tkinter import *
import PIL
from PIL import ImageTk, Image, ImageOps
@ -8,6 +10,7 @@ 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()
@ -16,6 +19,9 @@ 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
@ -35,7 +41,7 @@ class ImagePlaceholder:
if w < 21 or h < 21:
w = 1280
h = 1024
self.current_image.thumbnail((w - 20, h - 20), Image.ANTIALIAS)
self.current_image.thumbnail((w - 20, h - 20), PIL.Image.Resampling.LANCZOS)
if reload:
self.load_widget()
@ -56,3 +62,16 @@ 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,18 +1,21 @@
import copy
import os
import subprocess
import sys
from tkinter import *
from tkinter.ttk import Progressbar, Style
from tkinter.messagebox import *
from CTkToolTip import *
from PIL import ImageTk, Image, ImageOps
import customtkinter
from CTkToolTip import *
from PIL import ImageTk, Image
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
@ -26,52 +29,67 @@ 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.5, message="Next")
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)
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.5, message="Black and white image")
CTkToolTip(self.bw_button, delay=0.1, message="Black and white image", y_offset=-40, x_offset=-40)
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.5, message="Mirrored image")
CTkToolTip(self.mirror_button, delay=0.1, message="Mirrored image", y_offset=-40, x_offset=-40)
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.5, message="Open folder")
CTkToolTip(open_folder_button, delay=0.1, message="Open folder", y_offset=-40, x_offset=-40)
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.5, message="Always on top")
CTkToolTip(self.always_on_top_button, delay=0.1, message="Always on top", y_offset=-40, x_offset=-40)
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.5, message="Fullscreen")
CTkToolTip(self.fullscreen_button, delay=0.1, message="Fullscreen", y_offset=-40, x_offset=-40)
timer_button = customtkinter.CTkButton(toolbar, command=self.toggle_timer, text="",
image=ImageTk.PhotoImage(Image.open("assets/icons/timer.png")))
image=ImageTk.PhotoImage(Image.open("assets/icons/sand-clock.png")))
timer_button.pack(side=LEFT, padx=0, pady=0)
CTkToolTip(timer_button, delay=0.5, message="Toggle timer")
CTkToolTip(timer_button, delay=0.1, message="Toggle timer", y_offset=-40, x_offset=-40)
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:
@ -103,8 +121,11 @@ 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":
@ -133,3 +154,23 @@ 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

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

View File

@ -1,3 +1,4 @@
import tkinter
from pathlib import Path
from tkinter import *
from tkinter import filedialog
@ -33,8 +34,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)
self.button_frame.pack(fill=X)
self.button_frame = Frame(root, bg=root.cget("bg"))
self.button_frame.pack(fill=X, expand=True)
timers = [
Util.format_seconds(30),
@ -45,14 +46,15 @@ class App:
Util.format_seconds(600),
"Custom"
]
self.buttons = customtkinter.CTkSegmentedButton(
root, values=timers,
command=self.set_timer_in_seconds
)
self.buttons.pack(fill=X)
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.launch_button = customtkinter.CTkButton(root, text="Let's draw!", command=self.lets_draw, state="disabled")
self.launch_button.pack(side="bottom")
self.launch_button.pack(side=tkinter.BOTTOM)
self.read_config()
@ -73,11 +75,13 @@ class App:
self.session_window.open()
def select_folder(self):
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()
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 find_images_in_folder(self):
if Path(self.selected_folder).exists():
@ -93,6 +97,10 @@ 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_button_color() if i == self.selected_element_index else Util.get_default_active_button_color())
Util.get_default_active_button_color() if i == self.selected_element_index else Util.get_default_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_button_color() if i == self.selected_element_index else Util.get_default_active_button_color())
Util.get_default_active_button_color() if i == self.selected_element_index else Util.get_default_button_color())
)
else:
raise Exception("unknown type.")