before frames update
This commit is contained in:
@@ -55,7 +55,7 @@ def load_credentials():
|
|||||||
with open("config.enc", "rb") as file:
|
with open("config.enc", "rb") as file:
|
||||||
encrypted = file.read()
|
encrypted = file.read()
|
||||||
decrypted = fernet.decrypt(encrypted).decode()
|
decrypted = fernet.decrypt(encrypted).decode()
|
||||||
return json.loads(decrypted)
|
return json.loads(decrypted).get("credentials")
|
||||||
|
|
||||||
|
|
||||||
def get_wcapi():
|
def get_wcapi():
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class ConfigEncryptor:
|
|||||||
encrypted_data = self.fernet.encrypt(json_data.encode())
|
encrypted_data = self.fernet.encrypt(json_data.encode())
|
||||||
with open(self.filename, "wb") as encrypted_file:
|
with open(self.filename, "wb") as encrypted_file:
|
||||||
encrypted_file.write(encrypted_data)
|
encrypted_file.write(encrypted_data)
|
||||||
|
print("Credentials saved")
|
||||||
|
|
||||||
def get_key(self):
|
def get_key(self):
|
||||||
return self.key.decode()
|
return self.key.decode()
|
||||||
@@ -38,7 +39,11 @@ class ConfigEncryptor:
|
|||||||
with open(self.filename, "rb") as encrypted_file:
|
with open(self.filename, "rb") as encrypted_file:
|
||||||
encrypted_data = encrypted_file.read()
|
encrypted_data = encrypted_file.read()
|
||||||
decrypted_data = self.fernet.decrypt(encrypted_data).decode()
|
decrypted_data = self.fernet.decrypt(encrypted_data).decode()
|
||||||
return json.loads(decrypted_data)
|
config = json.loads(decrypted_data)
|
||||||
|
|
||||||
|
# Filter only relevant keys
|
||||||
|
keys_to_return = ["credentials", "options"]
|
||||||
|
return {key: config[key] for key in keys_to_return if key in config}
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
BIN
images/image-7.jpg
Normal file
BIN
images/image-7.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 105 KiB |
73
main.py
73
main.py
@@ -2,14 +2,12 @@
|
|||||||
Main module for the Image Processor application.
|
Main module for the Image Processor application.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import tkinter as tk
|
import customtkinter as ctk
|
||||||
from tkinter import ttk
|
|
||||||
import customtkinter
|
|
||||||
from ui.log_window import LogWindow
|
from ui.log_window import LogWindow
|
||||||
from ui.local_processing_tab import LocalProcessingTab
|
from ui.local_processing_tab import LocalProcessingTab
|
||||||
from ui.settings_tab import SettingsTab
|
from ui.settings_tab import SettingsTab
|
||||||
from config.decrypt_config import ConfigDecryptor, DECRYPTION_KEY
|
from config.decrypt_config import ConfigDecryptor, DECRYPTION_KEY
|
||||||
|
from config.encrypt_config import ConfigEncryptor
|
||||||
|
|
||||||
class ImageProcessorApp:
|
class ImageProcessorApp:
|
||||||
"""
|
"""
|
||||||
@@ -21,42 +19,69 @@ class ImageProcessorApp:
|
|||||||
Initialize the ImageProcessorApp.
|
Initialize the ImageProcessorApp.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
root (tk.Tk): The root Tkinter window.
|
root (ctk.CTk): The root CustomTkinter window.
|
||||||
"""
|
"""
|
||||||
self.root = root
|
self.root = root
|
||||||
self.root.title("Image Processor")
|
self.root.title("Image Processor")
|
||||||
self.root.geometry("500x450")
|
self.root.geometry("520x600")
|
||||||
|
|
||||||
self.tab_parent = ttk.Notebook(self.root)
|
# Create menu frame at the top
|
||||||
self.log_window = None
|
menu_frame = ctk.CTkFrame(self.root)
|
||||||
|
menu_frame.pack(side="top", fill="x")
|
||||||
|
|
||||||
self.local_processing_tab = LocalProcessingTab(
|
local_processing_button = ctk.CTkButton(menu_frame, text="Local Processing", command=self.show_local_processing_tab)
|
||||||
self.tab_parent, "Local Processing", self.open_log_window
|
local_processing_button.pack(side="left", padx=5, pady=5)
|
||||||
)
|
|
||||||
self.settings_tab = SettingsTab(self.tab_parent, "Settings")
|
|
||||||
|
|
||||||
self.tab_parent.pack(expand=True, fill="both")
|
settings_button = ctk.CTkButton(menu_frame, text="Settings", command=self.show_settings_tab)
|
||||||
|
settings_button.pack(side="left", padx=5, pady=5)
|
||||||
|
|
||||||
def open_log_window(self):
|
# Create main frame to hold tabs and log window
|
||||||
|
main_frame = ctk.CTkFrame(self.root)
|
||||||
|
main_frame.pack(expand=True, fill="both")
|
||||||
|
|
||||||
|
self.tab_parent = ctk.CTkFrame(main_frame)
|
||||||
|
self.tab_parent.grid(row=0, column=0, sticky="nsew")
|
||||||
|
|
||||||
|
self.log_frame = ctk.CTkFrame(main_frame)
|
||||||
|
self.log_frame.grid(row=1, column=0, sticky="nsew")
|
||||||
|
|
||||||
|
main_frame.grid_rowconfigure(0, weight=3)
|
||||||
|
main_frame.grid_rowconfigure(1, weight=1)
|
||||||
|
main_frame.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
|
self.log_window = LogWindow(self.log_frame)
|
||||||
|
|
||||||
|
self.local_processing_tab = LocalProcessingTab(self.tab_parent, self.log_window)
|
||||||
|
self.settings_tab = SettingsTab(self.tab_parent)
|
||||||
|
|
||||||
|
self.local_processing_tab.tab.grid(row=0, column=0, sticky="nsew")
|
||||||
|
self.settings_tab.tab.grid(row=0, column=0, sticky="nsew")
|
||||||
|
|
||||||
|
self.show_local_processing_tab()
|
||||||
|
|
||||||
|
def show_local_processing_tab(self):
|
||||||
"""
|
"""
|
||||||
Open the log window. If it already exists, bring it to the front.
|
Show the Local Processing tab.
|
||||||
"""
|
"""
|
||||||
if self.log_window is None or not self.log_window.winfo_exists():
|
self.local_processing_tab.tab.tkraise()
|
||||||
self.log_window = LogWindow(self.root)
|
|
||||||
else:
|
def show_settings_tab(self):
|
||||||
self.log_window.lift()
|
"""
|
||||||
|
Show the Settings tab.
|
||||||
|
"""
|
||||||
|
self.settings_tab.tab.tkraise()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""
|
"""
|
||||||
Run the Tkinter main loop.
|
Run the CustomTkinter main loop.
|
||||||
"""
|
"""
|
||||||
self.root.mainloop()
|
self.root.mainloop()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
decryptor = ConfigDecryptor(DECRYPTION_KEY)
|
decryptor = ConfigEncryptor(DECRYPTION_KEY)
|
||||||
config = decryptor.decrypt()
|
config = decryptor.load_config()
|
||||||
wc_url = config["url"]
|
wc_url = config["url"]
|
||||||
wc_consumer_key = config["consumer_key"]
|
wc_consumer_key = config["consumer_key"]
|
||||||
wc_consumer_secret = config["consumer_secret"]
|
wc_consumer_secret = config["consumer_secret"]
|
||||||
@@ -65,6 +90,8 @@ if __name__ == "__main__":
|
|||||||
except FileNotFoundError as e:
|
except FileNotFoundError as e:
|
||||||
print(f"File not found: {e}")
|
print(f"File not found: {e}")
|
||||||
|
|
||||||
root = customtkinter.CTk()
|
root = ctk.CTk()
|
||||||
|
ctk.set_appearance_mode("dark")
|
||||||
|
ctk.set_default_color_theme("blue")
|
||||||
app = ImageProcessorApp(root)
|
app = ImageProcessorApp(root)
|
||||||
app.run()
|
app.run()
|
||||||
|
|||||||
@@ -4,40 +4,39 @@ Module for the Local Processing Tab in the Image Processor application.
|
|||||||
|
|
||||||
import tempfile
|
import tempfile
|
||||||
import threading
|
import threading
|
||||||
import tkinter as tk
|
import customtkinter as ctk
|
||||||
from tkinter import ttk
|
|
||||||
from tkinter.scrolledtext import ScrolledText
|
from tkinter.scrolledtext import ScrolledText
|
||||||
from tkinter import Tk, Label, Button, Entry, Toplevel, StringVar, BooleanVar
|
from tkinter import StringVar, BooleanVar
|
||||||
from PIL import Image, ImageTk
|
from PIL import Image, ImageTk
|
||||||
from utils.file_operations import FileProcessor
|
from utils.file_operations import FileProcessor
|
||||||
from utils.image_processing import ImageProcessor
|
from utils.image_processing import ImageProcessor
|
||||||
from api.woocommerce_api import process_product_images, process_all_products
|
from api.woocommerce_api import process_product_images, process_all_products
|
||||||
from ui.options_window import OptionsWindow
|
from ui.options_window import OptionsWindow
|
||||||
from pprint import pformat, pprint
|
from pprint import pformat
|
||||||
from config.encrypt_config import ConfigEncryptor
|
from config.encrypt_config import ConfigEncryptor
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
class LocalProcessingTab:
|
class LocalProcessingTab:
|
||||||
"""
|
"""
|
||||||
Class for the Local Processing Tab in the Image Processor application.
|
Class for the Local Processing Tab in the Image Processor application.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, tab_parent, text, log):
|
def __init__(self, tab_parent, log_window):
|
||||||
"""
|
"""
|
||||||
Initialize the LocalProcessingTab.
|
Initialize the LocalProcessingTab.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
tab_parent (ttk.Notebook): The parent notebook widget.
|
tab_parent (ctk.CTkFrame): The parent frame widget.
|
||||||
text (str): The text to display on the tab.
|
log_window (LogWindow): The log window frame.
|
||||||
log (function): The function to log messages.
|
|
||||||
"""
|
"""
|
||||||
key = b"u4xTBY5Ns4WYdLvqMjEr138mpMmDEhhqTszKCcDy2cI="
|
key = b"u4xTBY5Ns4WYdLvqMjEr138mpMmDEhhqTszKCcDy2cI="
|
||||||
|
|
||||||
self.log = log
|
self.log_window = log_window
|
||||||
self.tab = ttk.Frame(tab_parent)
|
self.log = self.log_window.log_message
|
||||||
|
self.tab = ctk.CTkFrame(tab_parent)
|
||||||
self.root = self.tab.winfo_toplevel() # Store the root window reference
|
self.root = self.tab.winfo_toplevel() # Store the root window reference
|
||||||
tab_parent.add(self.tab, text=text)
|
|
||||||
self.config = ConfigEncryptor(key)
|
self.config = ConfigEncryptor(key)
|
||||||
self.log_window = None
|
|
||||||
|
|
||||||
self.canvas_width = 900
|
self.canvas_width = 900
|
||||||
self.canvas_height = 900
|
self.canvas_height = 900
|
||||||
@@ -48,7 +47,7 @@ class LocalProcessingTab:
|
|||||||
self.image_format = "AUTO"
|
self.image_format = "AUTO"
|
||||||
self.image_size = "contain"
|
self.image_size = "contain"
|
||||||
self.load_config()
|
self.load_config()
|
||||||
self.source_type = StringVar(value="local")
|
self.source_type = StringVar(value="directory")
|
||||||
self.checkbox_var = BooleanVar(value=False)
|
self.checkbox_var = BooleanVar(value=False)
|
||||||
self.file = FileProcessor()
|
self.file = FileProcessor()
|
||||||
self.image = ImageProcessor()
|
self.image = ImageProcessor()
|
||||||
@@ -58,8 +57,8 @@ class LocalProcessingTab:
|
|||||||
self.update_options()
|
self.update_options()
|
||||||
|
|
||||||
def load_config(self):
|
def load_config(self):
|
||||||
|
|
||||||
config = self.config.load_config()
|
config = self.config.load_config()
|
||||||
|
print(config)
|
||||||
if config:
|
if config:
|
||||||
if options := config.get("options"):
|
if options := config.get("options"):
|
||||||
self.canvas_width = options.get("canvas_width", 900)
|
self.canvas_width = options.get("canvas_width", 900)
|
||||||
@@ -71,125 +70,126 @@ class LocalProcessingTab:
|
|||||||
self.image_format = options.get("image_format", "AUTO")
|
self.image_format = options.get("image_format", "AUTO")
|
||||||
self.image_size = options.get("image_size", "contain")
|
self.image_size = options.get("image_size", "contain")
|
||||||
|
|
||||||
|
|
||||||
def create_log_window(self):
|
|
||||||
"""
|
|
||||||
Create and display the log window.
|
|
||||||
"""
|
|
||||||
if self.log_window and Toplevel.winfo_exists(self.log_window):
|
|
||||||
return
|
|
||||||
self.log_window = Toplevel()
|
|
||||||
self.log_window.title("Processing Log")
|
|
||||||
self.log_text = ScrolledText(
|
|
||||||
self.log_window, state="disabled", wrap="word", height=20, width=80
|
|
||||||
)
|
|
||||||
|
|
||||||
self.log_text.pack(expand=True, fill="both")
|
|
||||||
|
|
||||||
def log_message(self, message):
|
|
||||||
"""
|
|
||||||
Log a message to the log window.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
message (str): The message to log.
|
|
||||||
"""
|
|
||||||
if self.log_window:
|
|
||||||
self.log_text.config(state="normal")
|
|
||||||
self.log_text.insert(tk.END, message + "\n")
|
|
||||||
self.log_text.see(tk.END)
|
|
||||||
self.log_text.config(state="disabled")
|
|
||||||
self.log_text.update_idletasks()
|
|
||||||
|
|
||||||
def setup_ui(self):
|
def setup_ui(self):
|
||||||
"""
|
"""
|
||||||
Set up the user interface for the tab.
|
Set up the user interface for the tab.
|
||||||
"""
|
"""
|
||||||
# Source selection section
|
current_row = 0
|
||||||
self.source_label = Label(self.tab, text="Source Type:")
|
|
||||||
self.source_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")
|
|
||||||
|
|
||||||
self.source_dropdown = ttk.Combobox(
|
# Source selection section
|
||||||
|
self.source_label = ctk.CTkLabel(self.tab, anchor="w", width=500, text="Source Type:")
|
||||||
|
self.source_label.grid(row=current_row, column=0, columnspan=6, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
|
current_row += 1
|
||||||
|
|
||||||
|
self.source_dropdown = ctk.CTkComboBox(
|
||||||
self.tab,
|
self.tab,
|
||||||
textvariable=self.source_type,
|
variable=self.source_type,
|
||||||
values=["local", "product", "all_products"],
|
values=["directory", "file", "wp_image", "product", "all_products"],
|
||||||
state="readonly",
|
state="readonly",
|
||||||
|
command=self.update_options
|
||||||
)
|
)
|
||||||
self.source_dropdown.grid(row=1, column=0, padx=5, pady=5, sticky="w")
|
self.source_dropdown.grid(row=current_row, column=0, columnspan=2, padx=5, pady=5, sticky="w")
|
||||||
self.source_dropdown.bind(
|
self.source_dropdown.bind(
|
||||||
"<<ComboboxSelected>>", lambda e: self.update_options()
|
"<<ComboboxSelected>>", lambda e: self.update_options()
|
||||||
)
|
)
|
||||||
|
|
||||||
self.browse_button = ttk.Button(
|
|
||||||
self.tab, text="Browse", command=self.browse_directory_command
|
|
||||||
)
|
|
||||||
self.browse_button.grid(row=2, column=0, padx=5, pady=5, sticky="w")
|
|
||||||
|
|
||||||
# WooCommerce Product ID section
|
|
||||||
self.product_id_label = Label(self.tab, text="Product ID:")
|
|
||||||
self.product_id_label.grid(row=2, column=0, padx=5, pady=5, sticky="w")
|
|
||||||
|
|
||||||
self.product_id_entry = Entry(self.tab)
|
|
||||||
self.product_id_entry.grid(row=3, column=0, padx=5, pady=5, sticky="w")
|
|
||||||
|
|
||||||
# SKU section
|
|
||||||
self.additional_name_label = Label(self.tab, text="Add suffix:")
|
|
||||||
self.additional_name_label.grid(
|
|
||||||
row=2, column=1, padx=5, pady=5, sticky="w")
|
|
||||||
|
|
||||||
self.additional_name_entry = Entry(self.tab)
|
|
||||||
self.additional_name_entry.grid(
|
|
||||||
row=2, column=2, padx=5, pady=5, sticky="w")
|
|
||||||
|
|
||||||
# Options button
|
# Options button
|
||||||
self.options_button = ttk.Button(
|
self.options_button = ctk.CTkButton(
|
||||||
self.tab, text="Options", command=self.open_options_window
|
self.tab, text="Options", command=self.open_options_window
|
||||||
)
|
)
|
||||||
self.options_button.grid(row=2, column=3, columnspan=2, padx=5, pady=5, sticky="w")
|
self.options_button.grid(row=current_row, column=4, columnspan=2, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
self.button_start = Button(
|
current_row += 1
|
||||||
|
|
||||||
|
self.button_start = ctk.CTkButton(
|
||||||
self.tab, text="Start Processing", command=self.start_processing
|
self.tab, text="Start Processing", command=self.start_processing
|
||||||
)
|
)
|
||||||
self.button_start.grid(
|
self.button_start.grid(
|
||||||
row=1, column=3, columnspan=2, padx=5, pady=5, sticky="w"
|
row=current_row, column=4, columnspan=2, padx=5, pady=5, sticky="w"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.browse_button = ctk.CTkButton(
|
||||||
|
self.tab, text="Browse directory", command=self.browse_directory_command
|
||||||
|
)
|
||||||
|
self.browse_button.grid(row=current_row, column=0, columnspan=2, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
|
self.browse_file_button = ctk.CTkButton(
|
||||||
|
self.tab, text="Browse file", command=self.browse_file_command
|
||||||
|
)
|
||||||
|
self.browse_file_button.grid(row=current_row, column=0, columnspan=2, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
|
# WooCommerce Product ID section
|
||||||
|
self.product_id_button = ctk.CTkButton(self.tab, text="Get", width=25)
|
||||||
|
self.product_id_button.grid(row=2, column=2, columnspan=1, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
|
self.product_id_entry = ctk.CTkEntry(self.tab)
|
||||||
|
self.product_id_entry.grid(row=current_row, column=0, columnspan=2,padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
|
# SKU section
|
||||||
|
self.additional_name_label = ctk.CTkLabel(self.tab, text="Add suffix:")
|
||||||
|
self.additional_name_label.grid(
|
||||||
|
row=current_row, column=1, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
|
self.additional_name_entry = ctk.CTkEntry(self.tab)
|
||||||
|
self.additional_name_entry.grid(
|
||||||
|
row=current_row, column=2, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
|
current_row += 1
|
||||||
|
|
||||||
|
# Destination selection section
|
||||||
|
self.destionation_label = ctk.CTkLabel(self.tab, anchor="w", width=500, text="Destination Type:")
|
||||||
|
self.destionation_label.grid(row=current_row, column=0, columnspan=6, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
|
current_row += 1
|
||||||
|
|
||||||
|
self.destionation_dropdown = ctk.CTkComboBox(
|
||||||
|
self.tab,
|
||||||
|
variable=self.source_type,
|
||||||
|
values=["auto", "directory", "file", "wp_image", "product"],
|
||||||
|
state="readonly",
|
||||||
|
command=self.update_options
|
||||||
|
)
|
||||||
|
self.destionation_dropdown.grid(row=current_row, column=0, columnspan=2, padx=5, pady=5, sticky="w")
|
||||||
|
self.destionation_dropdown.bind(
|
||||||
|
"<<ComboboxSelected>>", lambda e: self.update_options()
|
||||||
|
)
|
||||||
|
|
||||||
|
current_row += 1
|
||||||
|
|
||||||
# Image previews
|
# Image previews
|
||||||
self.before_label = Label(self.tab, text="Before:")
|
self.before_label = ctk.CTkLabel(self.tab, text="Before:")
|
||||||
self.before_label.grid(row=5, column=0, padx=5, pady=5, sticky="w")
|
self.before_label.grid(row=current_row, column=0, padx=5, pady=5, sticky="w")
|
||||||
self.before_image_label = Label(self.tab)
|
|
||||||
self.before_image_label.grid(
|
|
||||||
row=6, column=0, padx=5, pady=5, sticky="w")
|
|
||||||
|
|
||||||
self.after_label = Label(self.tab, text="After:")
|
self.after_label = ctk.CTkLabel(self.tab, text="After:")
|
||||||
self.after_label.grid(row=5, column=1, padx=5, pady=5, sticky="w")
|
self.after_label.grid(row=current_row, column=3, padx=5, pady=5, sticky="w")
|
||||||
self.after_image_label = Label(self.tab)
|
|
||||||
|
current_row += 1
|
||||||
|
|
||||||
|
self.after_image_label = ctk.CTkLabel(self.tab, text="")
|
||||||
self.after_image_label.grid(
|
self.after_image_label.grid(
|
||||||
row=6, column=1, padx=5, pady=5, sticky="w")
|
row=current_row, column=3, columnspan=3, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
def update_options(self):
|
self.before_image_label = ctk.CTkLabel(self.tab, text="")
|
||||||
|
self.before_image_label.grid(
|
||||||
|
row=current_row, column=0, columnspan=3, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
|
def update_options(self, text=None):
|
||||||
"""
|
"""
|
||||||
Update the UI elements based on the selected source type.
|
Update the UI elements based on the selected source type.
|
||||||
"""
|
"""
|
||||||
if self.source_type.get() == "local":
|
self.product_id_button.grid_remove()
|
||||||
|
self.product_id_entry.grid_remove()
|
||||||
|
self.additional_name_label.grid_remove()
|
||||||
|
self.additional_name_entry.grid_remove()
|
||||||
|
self.browse_button.grid_remove()
|
||||||
|
self.browse_file_button.grid_remove()
|
||||||
|
if self.source_type.get() == "directory":
|
||||||
self.browse_button.grid()
|
self.browse_button.grid()
|
||||||
self.product_id_label.grid_remove()
|
|
||||||
self.product_id_entry.grid_remove()
|
|
||||||
self.additional_name_label.grid_remove()
|
|
||||||
self.additional_name_entry.grid_remove()
|
|
||||||
elif self.source_type.get() == "product":
|
elif self.source_type.get() == "product":
|
||||||
self.browse_button.grid_remove()
|
self.product_id_button.grid()
|
||||||
self.product_id_label.grid()
|
|
||||||
self.product_id_entry.grid()
|
self.product_id_entry.grid()
|
||||||
self.additional_name_label.grid_remove()
|
elif self.source_type.get() == "file":
|
||||||
self.additional_name_entry.grid_remove()
|
self.browse_file_button.grid()
|
||||||
else:
|
|
||||||
self.browse_button.grid_remove()
|
|
||||||
self.product_id_label.grid_remove()
|
|
||||||
self.product_id_entry.grid_remove()
|
|
||||||
self.product_id_label.grid()
|
|
||||||
self.product_id_entry.grid()
|
|
||||||
self.additional_name_label.grid_remove()
|
|
||||||
self.additional_name_entry.grid_remove()
|
|
||||||
self.update_previews()
|
self.update_previews()
|
||||||
|
|
||||||
def update_previews(self, before_path=None, after_path=None):
|
def update_previews(self, before_path=None, after_path=None):
|
||||||
@@ -200,21 +200,22 @@ class LocalProcessingTab:
|
|||||||
before_path (str, optional): The path to the 'before' image.
|
before_path (str, optional): The path to the 'before' image.
|
||||||
after_path (str, optional): The path to the 'after' image.
|
after_path (str, optional): The path to the 'after' image.
|
||||||
"""
|
"""
|
||||||
|
first_image_path = self.file.get_first_image_path()
|
||||||
|
if not before_path and not first_image_path:
|
||||||
|
first_image_path = "images/image-7.jpg" # Set the path to your image here
|
||||||
if before_path and after_path:
|
if before_path and after_path:
|
||||||
before_img = Image.open(before_path)
|
before_img = Image.open(before_path)
|
||||||
before_img.thumbnail((150, 150))
|
before_img.thumbnail((200, 200))
|
||||||
before_photo = ImageTk.PhotoImage(before_img)
|
before_photo = ImageTk.PhotoImage(before_img)
|
||||||
self.before_image_label.config(image=before_photo)
|
self.before_image_label.configure(image=before_photo)
|
||||||
self.before_image_label.image = before_photo
|
self.before_image_label.image = before_photo
|
||||||
|
|
||||||
after_img = Image.open(after_path)
|
after_img = Image.open(after_path)
|
||||||
after_img.thumbnail((150, 150))
|
after_img.thumbnail((200, 200))
|
||||||
after_photo = ImageTk.PhotoImage(after_img)
|
after_photo = ImageTk.PhotoImage(after_img)
|
||||||
self.after_image_label.config(image=after_photo)
|
self.after_image_label.configure(image=after_photo)
|
||||||
self.after_image_label.image = after_photo
|
self.after_image_label.image = after_photo
|
||||||
else:
|
elif first_image_path:
|
||||||
first_image_path = self.file.get_first_image_path()
|
|
||||||
if first_image_path:
|
|
||||||
with tempfile.NamedTemporaryFile(
|
with tempfile.NamedTemporaryFile(
|
||||||
suffix=".jpg", delete=False
|
suffix=".jpg", delete=False
|
||||||
) as temp_file:
|
) as temp_file:
|
||||||
@@ -223,15 +224,15 @@ class LocalProcessingTab:
|
|||||||
first_image_path, output_path, self.get_options()
|
first_image_path, output_path, self.get_options()
|
||||||
)
|
)
|
||||||
before_img = Image.open(first_image_path)
|
before_img = Image.open(first_image_path)
|
||||||
before_img.thumbnail((150, 150))
|
before_img.thumbnail((200, 200))
|
||||||
before_photo = ImageTk.PhotoImage(before_img)
|
before_photo = ImageTk.PhotoImage(before_img)
|
||||||
self.before_image_label.config(image=before_photo)
|
self.before_image_label.configure(image=before_photo)
|
||||||
self.before_image_label.image = before_photo
|
self.before_image_label.image = before_photo
|
||||||
|
|
||||||
after_img = Image.open(output_path)
|
after_img = Image.open(output_path)
|
||||||
after_img.thumbnail((150, 150))
|
after_img.thumbnail((200, 200))
|
||||||
after_photo = ImageTk.PhotoImage(after_img)
|
after_photo = ImageTk.PhotoImage(after_img)
|
||||||
self.after_image_label.config(image=after_photo)
|
self.after_image_label.configure(image=after_photo)
|
||||||
self.after_image_label.image = after_photo
|
self.after_image_label.image = after_photo
|
||||||
|
|
||||||
def set_image_preview(self, image_path, label):
|
def set_image_preview(self, image_path, label):
|
||||||
@@ -240,24 +241,41 @@ class LocalProcessingTab:
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
image_path (str): The path to the image file.
|
image_path (str): The path to the image file.
|
||||||
label (Label): The label to set the image on.
|
label (ctk.CTkLabel): The label to set the image on.
|
||||||
"""
|
"""
|
||||||
img = Image.open(image_path)
|
img = Image.open(image_path)
|
||||||
img.thumbnail((150, 150))
|
img.thumbnail((150, 150))
|
||||||
photo = ImageTk.PhotoImage(img)
|
photo = ImageTk.PhotoImage(img)
|
||||||
label.config(image=photo)
|
label.configure(image=photo)
|
||||||
label.image = photo
|
label.image = photo
|
||||||
|
|
||||||
|
def browse_file_command(self):
|
||||||
|
"""
|
||||||
|
Command to browse for a file.
|
||||||
|
"""
|
||||||
|
file = self.file.browse_files()
|
||||||
|
if file:
|
||||||
|
file_name = os.path.basename(file)
|
||||||
|
if len(file_name) > 20:
|
||||||
|
file_name = f"...{file_name[-20:]}"
|
||||||
|
self.browse_file_button.configure(text=file_name)
|
||||||
|
self.apply_options(self.get_options())
|
||||||
|
self.update_previews()
|
||||||
|
|
||||||
def browse_directory_command(self):
|
def browse_directory_command(self):
|
||||||
"""
|
"""
|
||||||
Command to browse for a directory.
|
Command to browse for a directory.
|
||||||
"""
|
"""
|
||||||
directory = self.file.browse_directory()
|
directory = self.file.browse_directory()
|
||||||
if directory:
|
if directory:
|
||||||
self.browse_button.config(text=directory)
|
dir_name = os.path.basename(directory)
|
||||||
|
if len(dir_name) > 20:
|
||||||
|
dir_name = f"...{dir_name[-20:]}"
|
||||||
|
self.browse_button.configure(text=dir_name)
|
||||||
self.apply_options(self.get_options())
|
self.apply_options(self.get_options())
|
||||||
self.update_previews()
|
self.update_previews()
|
||||||
|
|
||||||
|
|
||||||
def apply_canvas_size(self):
|
def apply_canvas_size(self):
|
||||||
"""
|
"""
|
||||||
Apply the canvas size settings and update previews.
|
Apply the canvas size settings and update previews.
|
||||||
@@ -276,7 +294,6 @@ class LocalProcessingTab:
|
|||||||
"""
|
"""
|
||||||
self.image.set_background_color(self.background_color)
|
self.image.set_background_color(self.background_color)
|
||||||
|
|
||||||
|
|
||||||
def get_options(self) -> dict:
|
def get_options(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get the current processing options.
|
Get the current processing options.
|
||||||
@@ -288,7 +305,7 @@ class LocalProcessingTab:
|
|||||||
"selected_directory": self.browse_button.cget("text"),
|
"selected_directory": self.browse_button.cget("text"),
|
||||||
"canvas_width": self.canvas_width,
|
"canvas_width": self.canvas_width,
|
||||||
"canvas_height": self.canvas_height,
|
"canvas_height": self.canvas_height,
|
||||||
"log_message": self.log_message,
|
"log_message": self.log, # Use the log method from the log_window
|
||||||
"format_log_message": self.pprint_log_message,
|
"format_log_message": self.pprint_log_message,
|
||||||
"update_previews": self.update_previews,
|
"update_previews": self.update_previews,
|
||||||
"product_id": self.product_id_entry.get(),
|
"product_id": self.product_id_entry.get(),
|
||||||
@@ -359,8 +376,7 @@ class LocalProcessingTab:
|
|||||||
options (dict): The options to apply.
|
options (dict): The options to apply.
|
||||||
"""
|
"""
|
||||||
if self.log_window:
|
if self.log_window:
|
||||||
self.log_window.destroy()
|
self.log_window.clear() # Clear the log window if it exists
|
||||||
self.log_window = None
|
|
||||||
self.canvas_width = options["canvas_width"]
|
self.canvas_width = options["canvas_width"]
|
||||||
self.canvas_height = options["canvas_height"]
|
self.canvas_height = options["canvas_height"]
|
||||||
self.template = options["template"]
|
self.template = options["template"]
|
||||||
@@ -383,17 +399,16 @@ class LocalProcessingTab:
|
|||||||
obj (object): The object to format and log.
|
obj (object): The object to format and log.
|
||||||
"""
|
"""
|
||||||
formatted_message = pformat(obj)
|
formatted_message = pformat(obj)
|
||||||
self.log_message(formatted_message)
|
self.log(formatted_message)
|
||||||
|
|
||||||
def start_processing(self):
|
def start_processing(self):
|
||||||
"""
|
"""
|
||||||
Start the image processing based on the selected options.
|
Start the image processing based on the selected options.
|
||||||
"""
|
"""
|
||||||
self.create_log_window()
|
|
||||||
source = self.source_type.get()
|
source = self.source_type.get()
|
||||||
options = self.get_options()
|
options = self.get_options()
|
||||||
|
|
||||||
if source == "local":
|
if source == "directory":
|
||||||
threading.Thread(
|
threading.Thread(
|
||||||
target=self.file.process_directory_with_logging, args=(options,)
|
target=self.file.process_directory_with_logging, args=(options,)
|
||||||
).start()
|
).start()
|
||||||
@@ -402,6 +417,11 @@ class LocalProcessingTab:
|
|||||||
target=process_product_images,
|
target=process_product_images,
|
||||||
args=(options,)
|
args=(options,)
|
||||||
).start()
|
).start()
|
||||||
|
elif source == "file":
|
||||||
|
threading.Thread(
|
||||||
|
target=self.file.proces_single_image,
|
||||||
|
args=(options,)
|
||||||
|
).start()
|
||||||
elif source == "all_products":
|
elif source == "all_products":
|
||||||
threading.Thread(
|
threading.Thread(
|
||||||
target=process_all_products,
|
target=process_all_products,
|
||||||
|
|||||||
@@ -1,18 +1,37 @@
|
|||||||
from tkinter import Toplevel, Text
|
import customtkinter as ctk
|
||||||
from pprint import pprint
|
|
||||||
|
|
||||||
class LogWindow(Toplevel):
|
class LogWindow:
|
||||||
def __init__(self, master=None, **kwargs):
|
def __init__(self, parent):
|
||||||
super().__init__(master, **kwargs)
|
self.frame = ctk.CTkFrame(parent)
|
||||||
self.title("Log Window")
|
self.frame.pack(expand=True, fill="both")
|
||||||
self.geometry("500x300")
|
|
||||||
self.text = Text(self)
|
|
||||||
self.text.pack(expand=True, fill="both")
|
|
||||||
self.protocol("WM_DELETE_WINDOW", self.hide)
|
|
||||||
|
|
||||||
def log(self, message):
|
self.log_text = ctk.CTkTextbox(self.frame, state="disabled", wrap="word", height=10)
|
||||||
self.text.insert("end", pprint(message) + "\n")
|
self.log_text.pack(side="left", expand=True, fill="both")
|
||||||
self.text.see("end")
|
|
||||||
|
|
||||||
def hide(self):
|
self.scrollbar = ctk.CTkScrollbar(self.frame, command=self.log_text.yview)
|
||||||
self.withdraw()
|
self.scrollbar.pack(side="right", fill="y")
|
||||||
|
|
||||||
|
self.log_text.configure(yscrollcommand=self.scrollbar.set)
|
||||||
|
|
||||||
|
def log_message(self, message):
|
||||||
|
self.log_text.configure(state="normal")
|
||||||
|
self.log_text.insert(ctk.END, message + "\n")
|
||||||
|
self.log_text.see(ctk.END)
|
||||||
|
self.log_text.configure(state="disabled")
|
||||||
|
self.log_text.update_idletasks()
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.log_text.configure(state="normal")
|
||||||
|
self.log_text.delete('1.0', ctk.END)
|
||||||
|
self.log_text.configure(state="disabled")
|
||||||
|
|
||||||
|
# Example usage
|
||||||
|
if __name__ == "__main__":
|
||||||
|
root = ctk.CTk()
|
||||||
|
log_window = LogWindow(root)
|
||||||
|
|
||||||
|
# Example log messages
|
||||||
|
log_window.log_message("This is a test message.")
|
||||||
|
log_window.log_message("Another test message.")
|
||||||
|
|
||||||
|
root.mainloop()
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import tkinter as tk
|
import customtkinter as ctk
|
||||||
from tkinter import ttk, colorchooser, messagebox
|
from tkinter import colorchooser, messagebox
|
||||||
from pprint import pprint
|
|
||||||
class OptionsWindow(tk.Toplevel):
|
|
||||||
|
class OptionsWindow(ctk.CTkToplevel):
|
||||||
def __init__(self, parent, apply_callback, current_options):
|
def __init__(self, parent, apply_callback, current_options):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.title("Options")
|
self.title("Options")
|
||||||
@@ -12,6 +13,8 @@ class OptionsWindow(tk.Toplevel):
|
|||||||
self.inputs = {}
|
self.inputs = {}
|
||||||
|
|
||||||
self.setup_ui()
|
self.setup_ui()
|
||||||
|
self.attributes('-topmost', True) # Ensure the window stays on top
|
||||||
|
self.lift() # Bring the window to the front
|
||||||
|
|
||||||
def setup_ui(self):
|
def setup_ui(self):
|
||||||
"""
|
"""
|
||||||
@@ -19,6 +22,14 @@ class OptionsWindow(tk.Toplevel):
|
|||||||
"""
|
"""
|
||||||
self.row_index = 0
|
self.row_index = 0
|
||||||
for name, details in self.options.items():
|
for name, details in self.options.items():
|
||||||
|
self.create_option(name, details)
|
||||||
|
|
||||||
|
self.create_apply_button()
|
||||||
|
|
||||||
|
def create_option(self, name, details):
|
||||||
|
"""
|
||||||
|
Create an option based on its type.
|
||||||
|
"""
|
||||||
if details["type"] == "number":
|
if details["type"] == "number":
|
||||||
self.add_number_input(
|
self.add_number_input(
|
||||||
name,
|
name,
|
||||||
@@ -38,8 +49,6 @@ class OptionsWindow(tk.Toplevel):
|
|||||||
elif details["type"] == "color":
|
elif details["type"] == "color":
|
||||||
self.add_color_picker(name, details["label"], details["default"])
|
self.add_color_picker(name, details["label"], details["default"])
|
||||||
|
|
||||||
self.create_apply_button()
|
|
||||||
|
|
||||||
def add_number_input(self, name, label, default, min_val, max_val):
|
def add_number_input(self, name, label, default, min_val, max_val):
|
||||||
"""
|
"""
|
||||||
Add a number input field.
|
Add a number input field.
|
||||||
@@ -51,10 +60,10 @@ class OptionsWindow(tk.Toplevel):
|
|||||||
min_val (int): The minimum value.
|
min_val (int): The minimum value.
|
||||||
max_val (int): The maximum value.
|
max_val (int): The maximum value.
|
||||||
"""
|
"""
|
||||||
lbl = tk.Label(self, text=label)
|
lbl = ctk.CTkLabel(self, text=label)
|
||||||
lbl.grid(row=self.row_index, columnspan=1, column=0, padx=5, pady=5, sticky="w")
|
lbl.grid(row=self.row_index, columnspan=1, column=0, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
entry = tk.Entry(self)
|
entry = ctk.CTkEntry(self)
|
||||||
entry.insert(0, str(default))
|
entry.insert(0, str(default))
|
||||||
entry.grid(row=self.row_index, columnspan=2, column=1, padx=5, pady=5, sticky="w")
|
entry.grid(row=self.row_index, columnspan=2, column=1, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
@@ -75,10 +84,10 @@ class OptionsWindow(tk.Toplevel):
|
|||||||
label (str): The label for the input field.
|
label (str): The label for the input field.
|
||||||
default (str): The default value.
|
default (str): The default value.
|
||||||
"""
|
"""
|
||||||
lbl = tk.Label(self, text=label)
|
lbl = ctk.CTkLabel(self, text=label)
|
||||||
lbl.grid(row=self.row_index, column=0, padx=5, pady=5, sticky="w")
|
lbl.grid(row=self.row_index, column=0, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
entry = tk.Entry(self)
|
entry = ctk.CTkEntry(self)
|
||||||
entry.insert(0, default)
|
entry.insert(0, default)
|
||||||
entry.grid(row=self.row_index, columnspan=2, column=1, padx=5, pady=5, sticky="w")
|
entry.grid(row=self.row_index, columnspan=2, column=1, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
@@ -94,8 +103,8 @@ class OptionsWindow(tk.Toplevel):
|
|||||||
label (str): The label for the input field.
|
label (str): The label for the input field.
|
||||||
default (bool): The default value.
|
default (bool): The default value.
|
||||||
"""
|
"""
|
||||||
var = tk.BooleanVar(value=default)
|
var = ctk.BooleanVar(value=default)
|
||||||
chk = tk.Checkbutton(self, text=label, variable=var)
|
chk = ctk.CTkCheckBox(self, text=label, variable=var)
|
||||||
chk.grid(row=self.row_index, column=0,
|
chk.grid(row=self.row_index, column=0,
|
||||||
columnspan=2, padx=5, pady=5, sticky="w")
|
columnspan=2, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
@@ -112,32 +121,24 @@ class OptionsWindow(tk.Toplevel):
|
|||||||
options (list): The list of options.
|
options (list): The list of options.
|
||||||
default (str): The default value.
|
default (str): The default value.
|
||||||
"""
|
"""
|
||||||
lbl = tk.Label(self, text=label)
|
lbl = ctk.CTkLabel(self, text=label)
|
||||||
lbl.grid(row=self.row_index, column=0, padx=5, pady=5, sticky="w")
|
lbl.grid(row=self.row_index, column=0, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
combo = ttk.Combobox(self, values=options, state="readonly")
|
combo = ctk.CTkComboBox(self, values=options, state="readonly")
|
||||||
combo.set(default)
|
combo.set(default)
|
||||||
combo.grid(row=self.row_index, columnspan=2, column=1, padx=5, pady=5, sticky="w")
|
combo.grid(row=self.row_index, columnspan=2, column=1, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
self.inputs[name] = {"type": "dropdown", "widget": combo}
|
self.inputs[name] = {"type": "dropdown", "widget": combo}
|
||||||
self.row_index += 1
|
self.row_index += 1
|
||||||
|
|
||||||
def check_transparent(self, var, color_entry, pick_button, color_preview):
|
def pick_color(self, button):
|
||||||
if var.get():
|
self.attributes('-topmost', False) # Temporarily disable topmost to allow colorchooser to be on top
|
||||||
color_entry.config(state="disabled")
|
color_code = colorchooser.askcolor(parent=self, title="Choose color")[1]
|
||||||
pick_button.config(state="disabled")
|
self.attributes('-topmost', True) # Re-enable topmost for this window
|
||||||
color_preview.config(bg="white")
|
|
||||||
else:
|
|
||||||
color_entry.config(state="normal")
|
|
||||||
pick_button.config(state="normal")
|
|
||||||
color_preview.config(bg=color_entry.get())
|
|
||||||
|
|
||||||
def pick_color(self, color_entry, color_preview):
|
|
||||||
color_code = colorchooser.askcolor(title="Choose color")[1]
|
|
||||||
if color_code:
|
if color_code:
|
||||||
color_entry.delete(0, tk.END)
|
button.configure(fg_color=color_code)
|
||||||
color_entry.insert(0, color_code)
|
self.inputs[button.name]["color"] = color_code
|
||||||
color_preview.config(bg=color_code)
|
|
||||||
|
|
||||||
def add_color_picker(self, name, label, default):
|
def add_color_picker(self, name, label, default):
|
||||||
"""
|
"""
|
||||||
@@ -148,36 +149,32 @@ class OptionsWindow(tk.Toplevel):
|
|||||||
label (str): The label for the color picker.
|
label (str): The label for the color picker.
|
||||||
default (str): The default color.
|
default (str): The default color.
|
||||||
"""
|
"""
|
||||||
if default == "transparent":
|
lbl = ctk.CTkLabel(self, text=label)
|
||||||
default = "#ffffff"
|
|
||||||
var = tk.BooleanVar(value=True)
|
|
||||||
else:
|
|
||||||
var = tk.BooleanVar(value=False)
|
|
||||||
lbl = tk.Label(self, text=label)
|
|
||||||
lbl.grid(row=self.row_index, column=0, padx=5, pady=5, sticky="w")
|
lbl.grid(row=self.row_index, column=0, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
color_preview = tk.Label(self, bg=default, width=2, height=1)
|
color_button = ctk.CTkButton(self, text="", width=30, command=lambda: self.pick_color(color_button))
|
||||||
color_preview.grid(row=self.row_index, column=1, padx=5, pady=5, sticky="w")
|
color_button.name = name
|
||||||
|
color_button.configure(fg_color=default)
|
||||||
|
color_button.grid(row=self.row_index, column=1, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
color_entry = tk.Entry(self)
|
chk_var = ctk.BooleanVar(value=(default == "transparent"))
|
||||||
color_entry.insert(0, default)
|
chk = ctk.CTkCheckBox(self, text="Transparent", variable=chk_var, command=lambda: self.check_transparent(chk_var, color_button))
|
||||||
color_entry.grid(row=self.row_index, column=2, padx=5, pady=5, sticky="w")
|
chk.grid(row=self.row_index, column=2, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
pick_button = tk.Button(self, text="Pick", command=lambda: self.pick_color(color_entry, color_preview))
|
self.inputs[name] = {"type": "color", "button": color_button, "transparent_var": chk_var, "color": default}
|
||||||
pick_button.grid(row=self.row_index, column=3, padx=5, pady=5, sticky="w")
|
|
||||||
|
|
||||||
|
|
||||||
chk = tk.Checkbutton(self, text="Transparent", variable=var, command=lambda: self.check_transparent(var, color_entry, pick_button, color_preview))
|
|
||||||
chk.grid(row=self.row_index, column=4, padx=5, pady=5, sticky="w")
|
|
||||||
|
|
||||||
self.inputs[name] = {"type": "color", "entry": color_entry, "transparent_var": var}
|
|
||||||
self.row_index += 1
|
self.row_index += 1
|
||||||
|
|
||||||
|
def check_transparent(self, var, button):
|
||||||
|
if var.get():
|
||||||
|
button.configure(state="disabled", fg_color="#ffffff")
|
||||||
|
else:
|
||||||
|
button.configure(state="normal")
|
||||||
|
|
||||||
def create_apply_button(self):
|
def create_apply_button(self):
|
||||||
"""
|
"""
|
||||||
Create the apply button.
|
Create the apply button.
|
||||||
"""
|
"""
|
||||||
apply_button = tk.Button(
|
apply_button = ctk.CTkButton(
|
||||||
self, text="Apply", command=self.apply_options)
|
self, text="Apply", command=self.apply_options)
|
||||||
apply_button.grid(row=self.row_index, column=0, columnspan=2, pady=10)
|
apply_button.grid(row=self.row_index, column=0, columnspan=2, pady=10)
|
||||||
|
|
||||||
@@ -205,10 +202,10 @@ class OptionsWindow(tk.Toplevel):
|
|||||||
elif details["type"] == "dropdown":
|
elif details["type"] == "dropdown":
|
||||||
options[name] = details["widget"].get()
|
options[name] = details["widget"].get()
|
||||||
elif details["type"] == "color":
|
elif details["type"] == "color":
|
||||||
if "value" in details:
|
if details["transparent_var"].get():
|
||||||
options[name] = details["value"]
|
|
||||||
else:
|
|
||||||
options[name] = "transparent"
|
options[name] = "transparent"
|
||||||
|
else:
|
||||||
|
options[name] = details["color"]
|
||||||
|
|
||||||
self.apply_callback(options)
|
self.apply_callback(options)
|
||||||
self.destroy()
|
self.destroy()
|
||||||
@@ -222,33 +219,7 @@ class OptionsWindow(tk.Toplevel):
|
|||||||
condition (function): The condition function that returns a boolean.
|
condition (function): The condition function that returns a boolean.
|
||||||
"""
|
"""
|
||||||
if condition():
|
if condition():
|
||||||
if self.inputs[name]["type"] == "number":
|
self.create_option(name, self.inputs[name])
|
||||||
self.add_number_input(
|
|
||||||
name,
|
|
||||||
self.inputs[name]["label"],
|
|
||||||
self.inputs[name]["default"],
|
|
||||||
self.inputs[name]["min"],
|
|
||||||
self.inputs[name]["max"],
|
|
||||||
)
|
|
||||||
elif self.inputs[name]["type"] == "text":
|
|
||||||
self.add_text_input(
|
|
||||||
name, self.inputs[name]["label"], self.inputs[name]["default"]
|
|
||||||
)
|
|
||||||
elif self.inputs[name]["type"] == "checkbox":
|
|
||||||
self.add_checkbox(
|
|
||||||
name, self.inputs[name]["label"], self.inputs[name]["default"]
|
|
||||||
)
|
|
||||||
elif self.inputs[name]["type"] == "dropdown":
|
|
||||||
self.add_dropdown(
|
|
||||||
name,
|
|
||||||
self.inputs[name]["label"],
|
|
||||||
self.inputs[name]["options"],
|
|
||||||
self.inputs[name]["default"],
|
|
||||||
)
|
|
||||||
elif self.inputs[name]["type"] == "color":
|
|
||||||
self.add_color_picker(
|
|
||||||
name, self.inputs[name]["label"], self.inputs[name]["default"]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Example usage
|
# Example usage
|
||||||
@@ -256,7 +227,7 @@ if __name__ == "__main__":
|
|||||||
def apply_options(options):
|
def apply_options(options):
|
||||||
print(options)
|
print(options)
|
||||||
|
|
||||||
root = tk.Tk()
|
root = ctk.CTk()
|
||||||
current_options = {
|
current_options = {
|
||||||
"canvas_width": {"type": "number", "label": "Width:", "default": 900, "min": 1, "max": 2540},
|
"canvas_width": {"type": "number", "label": "Width:", "default": 900, "min": 1, "max": 2540},
|
||||||
"canvas_height": {"type": "number", "label": "Height:", "default": 900, "min": 1, "max": 2540},
|
"canvas_height": {"type": "number", "label": "Height:", "default": 900, "min": 1, "max": 2540},
|
||||||
|
|||||||
@@ -1,60 +1,49 @@
|
|||||||
import tkinter as tk
|
import customtkinter as ctk
|
||||||
from tkinter import ttk
|
|
||||||
from api.woocommerce_api import save_credentials, load_credentials
|
from api.woocommerce_api import save_credentials, load_credentials
|
||||||
|
|
||||||
|
|
||||||
class SettingsTab:
|
class SettingsTab:
|
||||||
def __init__(self, tab_parent, text):
|
def __init__(self, tab_parent):
|
||||||
self.tab = ttk.Frame(tab_parent)
|
self.tab = ctk.CTkFrame(tab_parent)
|
||||||
tab_parent.add(self.tab, text=text)
|
self.tab.grid(row=0, column=0, sticky="nsew")
|
||||||
|
|
||||||
self.credentials = load_credentials()
|
self.credentials = load_credentials()
|
||||||
|
self.inputs = {}
|
||||||
self.setup_ui()
|
self.setup_ui()
|
||||||
|
|
||||||
def setup_ui(self):
|
def setup_ui(self):
|
||||||
url_label = tk.Label(self.tab, text="WooCommerce URL:")
|
settings_options = {
|
||||||
url_label.pack(pady=5)
|
"url": {"type": "text", "label": "WooCommerce URL:", "default": self.credentials.get('url', '')},
|
||||||
|
"consumer_key": {"type": "text", "label": "Consumer Key:", "default": self.credentials.get('consumer_key', '')},
|
||||||
|
"consumer_secret": {"type": "text", "label": "Consumer Secret:", "default": self.credentials.get('consumer_secret', '')},
|
||||||
|
"username": {"type": "text", "label": "Username:", "default": self.credentials.get('username', '')},
|
||||||
|
"password": {"type": "text", "label": "Password:", "default": self.credentials.get('password', ''), "show": "*"}
|
||||||
|
}
|
||||||
|
|
||||||
self.url_entry = tk.Entry(self.tab)
|
row_index = 0
|
||||||
self.url_entry.insert(0, self.credentials.get('url', ''))
|
for name, details in settings_options.items():
|
||||||
self.url_entry.pack(pady=5)
|
self.create_setting(name, details, row_index)
|
||||||
|
row_index += 1
|
||||||
|
|
||||||
consumer_key_label = tk.Label(self.tab, text="Consumer Key:")
|
save_button = ctk.CTkButton(self.tab, text="Save Credentials", command=self.save_credentials)
|
||||||
consumer_key_label.pack(pady=5)
|
save_button.grid(row=row_index, column=0, columnspan=2, pady=10)
|
||||||
|
|
||||||
self.consumer_key_entry = tk.Entry(self.tab)
|
def create_setting(self, name, details, row_index):
|
||||||
self.consumer_key_entry.insert(0, self.credentials.get('consumer_key', ''))
|
"""
|
||||||
self.consumer_key_entry.pack(pady=5)
|
Create a setting based on its type.
|
||||||
|
"""
|
||||||
|
lbl = ctk.CTkLabel(self.tab, text=details["label"])
|
||||||
|
lbl.grid(row=row_index, column=0, padx=5, pady=5, sticky="w")
|
||||||
|
|
||||||
consumer_secret_label = tk.Label(self.tab, text="Consumer Secret:")
|
if details["type"] == "text":
|
||||||
consumer_secret_label.pack(pady=5)
|
entry = ctk.CTkEntry(self.tab, show=details.get("show", None))
|
||||||
|
entry.insert(0, details["default"])
|
||||||
self.consumer_secret_entry = tk.Entry(self.tab, show="*")
|
entry.grid(row=row_index, column=1, padx=5, pady=5, sticky="w")
|
||||||
self.consumer_secret_entry.insert(0, self.credentials.get('consumer_secret', ''))
|
self.inputs[name] = entry
|
||||||
self.consumer_secret_entry.pack(pady=5)
|
|
||||||
|
|
||||||
username_label = tk.Label(self.tab, text="Username:")
|
|
||||||
username_label.pack(pady=5)
|
|
||||||
|
|
||||||
self.username_entry = tk.Entry(self.tab)
|
|
||||||
self.username_entry.insert(0, self.credentials.get('username', ''))
|
|
||||||
self.username_entry.pack(pady=5)
|
|
||||||
|
|
||||||
password_label = tk.Label(self.tab, text="Password:")
|
|
||||||
password_label.pack(pady=5)
|
|
||||||
|
|
||||||
self.password_entry = tk.Entry(self.tab, show="*")
|
|
||||||
self.password_entry.insert(0, self.credentials.get('password', ''))
|
|
||||||
self.password_entry.pack(pady=5)
|
|
||||||
|
|
||||||
save_button = tk.Button(self.tab, text="Save Credentials", command=self.save_credentials)
|
|
||||||
save_button.pack(pady=5)
|
|
||||||
|
|
||||||
def save_credentials(self):
|
def save_credentials(self):
|
||||||
save_credentials(
|
save_credentials(
|
||||||
self.url_entry.get(),
|
self.inputs["url"].get(),
|
||||||
self.consumer_key_entry.get(),
|
self.inputs["consumer_key"].get(),
|
||||||
self.consumer_secret_entry.get(),
|
self.inputs["consumer_secret"].get(),
|
||||||
self.username_entry.get(),
|
self.inputs["username"].get(),
|
||||||
self.password_entry.get()
|
self.inputs["password"].get()
|
||||||
)
|
)
|
||||||
@@ -11,6 +11,7 @@ class FileProcessor:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.selected_file = ""
|
||||||
self.selected_directory = ""
|
self.selected_directory = ""
|
||||||
|
|
||||||
def browse_directory(self):
|
def browse_directory(self):
|
||||||
@@ -23,6 +24,16 @@ class FileProcessor:
|
|||||||
self.selected_directory = filedialog.askdirectory()
|
self.selected_directory = filedialog.askdirectory()
|
||||||
return self.selected_directory
|
return self.selected_directory
|
||||||
|
|
||||||
|
def browse_files(self):
|
||||||
|
"""
|
||||||
|
Open a dialog to select a directory.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The selected directory path.
|
||||||
|
"""
|
||||||
|
self.selected_file = filedialog.askopenfilename()
|
||||||
|
return self.selected_file
|
||||||
|
|
||||||
def get_first_image_path(self):
|
def get_first_image_path(self):
|
||||||
"""
|
"""
|
||||||
Get the path of the first image in the selected directory.
|
Get the path of the first image in the selected directory.
|
||||||
@@ -30,6 +41,9 @@ class FileProcessor:
|
|||||||
Returns:
|
Returns:
|
||||||
str: The path to the first image, or None if no images found.
|
str: The path to the first image, or None if no images found.
|
||||||
"""
|
"""
|
||||||
|
if self.selected_file:
|
||||||
|
return self.selected_file
|
||||||
|
|
||||||
if not self.selected_directory:
|
if not self.selected_directory:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -159,6 +173,31 @@ class FileProcessor:
|
|||||||
os.remove(file_path)
|
os.remove(file_path)
|
||||||
self.log_message(f"Processed: {file_path}", log)
|
self.log_message(f"Processed: {file_path}", log)
|
||||||
|
|
||||||
|
def proces_single_image(self, options):
|
||||||
|
"""
|
||||||
|
Process images in the selected directory with logging.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
options (dict): Processing options.
|
||||||
|
"""
|
||||||
|
if not self.selected_file:
|
||||||
|
messagebox.showwarning(
|
||||||
|
"No File", "Please select a file.")
|
||||||
|
return
|
||||||
|
log = options.get("log_message", None)
|
||||||
|
self.log_message(
|
||||||
|
f"Processing started for file: {self.selected_file}", log
|
||||||
|
)
|
||||||
|
|
||||||
|
output_directory = self.create_output_directory(log)
|
||||||
|
image_paths = [self.selected_file]
|
||||||
|
|
||||||
|
self.process_images(image_paths, output_directory, options, log)
|
||||||
|
|
||||||
|
messagebox.showinfo("Process Complete",
|
||||||
|
"Image processing is complete.")
|
||||||
|
self.log_message("Processing complete.", log)
|
||||||
|
|
||||||
def generate_output_path(self, output_directory, file_path, options, product = None):
|
def generate_output_path(self, output_directory, file_path, options, product = None):
|
||||||
"""
|
"""
|
||||||
Generate the output path for resized images based on a template.
|
Generate the output path for resized images based on a template.
|
||||||
|
|||||||
Reference in New Issue
Block a user