From 2904e3119f4b0b65c78f9716233bc97f908579b3 Mon Sep 17 00:00:00 2001 From: James David Clarke Date: Wed, 10 Jan 2024 06:50:04 +0000 Subject: [PATCH] Started on GUI and seperating code so GUI and CLI can share it --- tools/Texture_Converter.py | 90 ++++++++------- tools/libtextureconverter/cli.py | 0 tools/libtextureconverter/common.py | 50 +++++++++ tools/libtextureconverter/gui.py | 164 ++++++++++++++++++++++++++++ 4 files changed, 262 insertions(+), 42 deletions(-) create mode 100644 tools/libtextureconverter/cli.py create mode 100644 tools/libtextureconverter/common.py create mode 100644 tools/libtextureconverter/gui.py diff --git a/tools/Texture_Converter.py b/tools/Texture_Converter.py index 65ee378dc..7d01b82eb 100755 --- a/tools/Texture_Converter.py +++ b/tools/Texture_Converter.py @@ -15,6 +15,7 @@ from collections import Counter from libtextureconverter.utils import detect_pixel_size, target_dir, colorize, colorize_alpha, handle_default_minecraft_texture, find_all_minecraft_resourcepacks from libtextureconverter.convert import convert_textures from libtextureconverter.config import SUPPORTED_MINECRAFT_VERSION, working_dir, mineclone2_path, appname, home +from libtextureconverter.gui import main as launch_gui # Argument parsing description_text = f"""This is the official MineClone 2 Texture Converter. @@ -45,60 +46,65 @@ verbose = args.verbose # If False, textures will be put into MineClone 2 directories. make_texture_pack = True # Adjust as needed -if args.default: - base_dir = handle_default_minecraft_texture(home, output_dir) +if __name__ == "__main__": + if len(sys.argv) == 1: + # No arguments supplied, launch the GUI + launch_gui() + else: + if args.default: + base_dir = handle_default_minecraft_texture(home, output_dir) -if base_dir == None and not args.all: - print( -"""ERROR: You didn't tell me the path to the Minecraft resource pack. -Mind-reading has not been implemented yet. + if base_dir == None and not args.all: + print( + """ERROR: You didn't tell me the path to the Minecraft resource pack. + Mind-reading has not been implemented yet. -Try this: - """+appname+""" -i + Try this: + """+appname+""" -i -For the full help, use: - """+appname+""" -h""") - sys.exit(2); + For the full help, use: + """+appname+""" -h""") + sys.exit(2); -### END OF SETTINGS ### + ### END OF SETTINGS ### -resource_packs = [] + resource_packs = [] -if args.all: - for resource_path in find_all_minecraft_resourcepacks(): - resource_packs.append(resource_path) + if args.all: + for resource_path in find_all_minecraft_resourcepacks(): + resource_packs.append(resource_path) -if make_texture_pack and args.input: - resource_packs.append(args.input) + if make_texture_pack and args.input: + resource_packs.append(args.input) -for base_dir in resource_packs: - tex_dir = base_dir + "/assets/minecraft/textures" + for base_dir in resource_packs: + tex_dir = base_dir + "/assets/minecraft/textures" - # Get texture pack name (from directory name) - bdir_split = base_dir.split("/") - output_dir_name = bdir_split[-1] - if len(output_dir_name) == 0: - if len(bdir_split) >= 2: - output_dir_name = base_dir.split("/")[-2] - else: - # Fallback - output_dir_name = "New_MineClone_2_Texture_Pack" + # Get texture pack name (from directory name) + bdir_split = base_dir.split("/") + output_dir_name = bdir_split[-1] + if len(output_dir_name) == 0: + if len(bdir_split) >= 2: + output_dir_name = base_dir.split("/")[-2] + else: + # Fallback + output_dir_name = "New_MineClone_2_Texture_Pack" - # ENTRY POINT - if make_texture_pack and not os.path.isdir(output_dir+"/"+output_dir_name): - os.mkdir(output_dir+"/"+output_dir_name) + # ENTRY POINT + if make_texture_pack and not os.path.isdir(output_dir+"/"+output_dir_name): + os.mkdir(output_dir+"/"+output_dir_name) - # If, set to convert all resourcepacks, then autodetect pixel size - if args.all: - PXSIZE = None + # If, set to convert all resourcepacks, then autodetect pixel size + if args.all: + PXSIZE = None - if PXSIZE is None: - PXSIZE = detect_pixel_size(base_dir) - tempfile1 = tempfile.NamedTemporaryFile() - tempfile2 = tempfile.NamedTemporaryFile() + if PXSIZE is None: + PXSIZE = detect_pixel_size(base_dir) + tempfile1 = tempfile.NamedTemporaryFile() + tempfile2 = tempfile.NamedTemporaryFile() - convert_textures(make_texture_pack, dry_run, verbose, base_dir, tex_dir, tempfile1, tempfile2, output_dir, output_dir_name, mineclone2_path, PXSIZE) + convert_textures(make_texture_pack, dry_run, verbose, base_dir, tex_dir, tempfile1, tempfile2, output_dir, output_dir_name, mineclone2_path, PXSIZE) - tempfile1.close() - tempfile2.close() + tempfile1.close() + tempfile2.close() diff --git a/tools/libtextureconverter/cli.py b/tools/libtextureconverter/cli.py new file mode 100644 index 000000000..e69de29bb diff --git a/tools/libtextureconverter/common.py b/tools/libtextureconverter/common.py new file mode 100644 index 000000000..6e69775e7 --- /dev/null +++ b/tools/libtextureconverter/common.py @@ -0,0 +1,50 @@ +import shutil, csv, os, tempfile, sys, argparse, glob +from PIL import Image +from collections import Counter + +from libtextureconverter.utils import detect_pixel_size, target_dir, colorize, colorize_alpha, handle_default_minecraft_texture, find_all_minecraft_resourcepacks +from libtextureconverter.convert import convert_textures +from libtextureconverter.config import SUPPORTED_MINECRAFT_VERSION, working_dir, mineclone2_path, appname, home +from libtextureconverter.gui import main as launch_gui + +def convert_resource_packs(resource_packs, output_dir, PXSIZE): + for base_dir in resource_packs: + print(f"Converting resource pack: {base_dir}") + + # Autodetect pixel size if not provided + if not PXSIZE: + pixel_size = detect_pixel_size(base_dir) + else: + pixel_size = PXSIZE + # Construct the path to the textures within the resource pack + tex_dir = os.path.join(base_dir, "assets", "minecraft", "textures") + + # Determine the name of the output directory for the converted texture pack + output_dir_name = os.path.basename(os.path.normpath(base_dir)) + + # Create the output directory if it doesn't exist + output_path = os.path.join(output_dir, output_dir_name) + if not os.path.isdir(output_path): + os.makedirs(output_path, exist_ok=True) + + # Temporary files for conversion (if needed by your conversion process) + tempfile1 = tempfile.NamedTemporaryFile(delete=False) + tempfile2 = tempfile.NamedTemporaryFile(delete=False) + + try: + # Perform the actual conversion + convert_textures( + base_dir=base_dir, + tex_dir=tex_dir, + temp_files=(tempfile1.name, tempfile2.name), + output_dir=output_path, + pixel_size=pixel_size + ) + finally: + # Clean up temporary files + tempfile1.close() + os.unlink(tempfile1.name) + tempfile2.close() + os.unlink(tempfile2.name) + + print(f"Finished converting resource pack: {base_dir}") diff --git a/tools/libtextureconverter/gui.py b/tools/libtextureconverter/gui.py new file mode 100644 index 000000000..cf563f32c --- /dev/null +++ b/tools/libtextureconverter/gui.py @@ -0,0 +1,164 @@ +import tkinter as tk +from tkinter import filedialog, messagebox, ttk, font +import time +import threading + +class TextureConverterGUI: + def __init__(self, root): + self.root = root + self.root.title("Choose resource packs to convert") + + self.create_widgets() + + def create_widgets(self): + + # Frame for instructions + self.instruction_frame = tk.Frame(self.root) + self.instruction_frame.pack(fill='x', padx=10, pady=10) + tk.Label(self.instruction_frame, text="Do you want to convert installed resource packs, or convert a single zip file?").pack(side='left', fill='x', expand=True) + + # Table-like structure using Treeview + self.tree = ttk.Treeview(self.root, columns=('Convert', 'Description'), show='headings') + self.tree.heading('Convert', text='Convert') + self.tree.heading('Description', text='Description') + + # Inserting options into the table + entries = [ + ('all', 'Find Minecraft resource packs installed in your minecraft folders and convert those automatically'), + ('default', 'Convert the default resource pack'), + ('other', 'Choose a file to convert manually') + ] + + for entry in entries: + self.tree.insert('', 'end', values=entry) + + + + # Button Frame + self.button_frame = tk.Frame(self.root) + self.button_frame.pack(fill='x', padx=10, pady=10, side='bottom') # Ensure the buttons are at the bottom + # Create and pack the buttons separately + self.ok_button = tk.Button(self.button_frame, text="OK", command=self.confirm_selection) + self.ok_button.pack(side=tk.RIGHT, padx=5) + self.cancel_button = tk.Button(self.button_frame, text="Cancel", command=self.cancel_conversion) + self.cancel_button.pack(side=tk.RIGHT) + + self.tree.pack(fill='both', expand=True, padx=10, pady=10) + + self.root.after(1, self.adjust_column_widths) + + def adjust_column_widths(self): + self.root.update_idletasks() # Update the geometry of the widgets + + # Measure and set the column widths + convert_width = tk.font.Font().measure('Convert') + 20 + description_width = max( + tk.font.Font().measure(self.tree.set(item, 'Description')) for item in self.tree.get_children() + ) + 20 + + # Apply the column widths + self.tree.column('Convert', width=convert_width, anchor='center') + self.tree.column('Description', width=description_width, anchor='w') + + # Calculate the height for each row + row_height = tk.font.Font().metrics('linespace') + 2 + + # Adjust the Treeview height + num_items = len(self.tree.get_children()) + tree_height = (row_height * num_items) * 1.8 + self.tree.config(height=num_items) + + # Calculate the total height needed + total_height = self.instruction_frame.winfo_height() + self.button_frame.winfo_height() + tree_height + 20 + + # Calculate the total width needed + total_width = convert_width + description_width + 20 + + # Set the size of the window based on content + self.root.geometry(f"{int(total_width)}x{int(total_height)}") + + # Prevent the window from resizing smaller than it should + self.root.minsize(int(total_width), int(total_height)) + + # Update the idle tasks to recalculate sizes, may help to remove extra space + self.root.update_idletasks() + + + def confirm_selection(self): + self.cancel_button.config(state=tk.NORMAL) + selected_item = self.tree.focus() + selection = self.tree.item(selected_item) + option = selection['values'][0] + self.show_loading_screen(option) + + def set_min_window_size(self): + self.root.update_idletasks() # Update the geometry of the widgets + self.root.minsize(self.root.winfo_width(), self.root.winfo_height()) + + + + def show_loading_screen(self, option): + # Display a non-blocking loading message + self.loading_label = tk.Label(self.root, text="Converting textures, please wait...", fg="blue") + self.loading_label.pack() + + # Start the conversion process in a separate thread + conversion_thread = threading.Thread(target=self.perform_conversion, args=(option,), daemon=True) + conversion_thread.start() + + # Disable the OK button while the conversion is in progress + self.ok_button.config(state=tk.DISABLED) + self.cancel_button.config(state=tk.NORMAL) + + def perform_conversion(self, option): + # Example names, replace with actual texture pack names after conversion + texture_pack_names = ["Texture Pack 1", "Texture Pack 2", "Texture Pack 3"] + # Simulate a time-consuming process + + # Perform the selected action + if option == 'all': + self.convert_all() + elif option == 'default': + self.convert_default() + elif option == 'other': + self.open_folder_dialog() + + # Remove the loading message and update the conversion status + self.loading_label.pack_forget() + messagebox.showinfo("Conversion Complete", f"Resource Packs '{', '.join(texture_pack_names)}' converted.") + + # Re-enable the OK button after the conversion is done + self.ok_button.config(state=tk.NORMAL) + + def convert_all(self): + # Simulate a conversion process + print("Converting all resource packs") + time.sleep(2) # Simulate some time for conversion + + def convert_default(self): + # Simulate a conversion process + print("Converting default resource pack") + time.sleep(2) # Simulate some time for conversion + + def open_folder_dialog(self): + folder_selected = filedialog.askdirectory() + if folder_selected: + # Simulate a conversion process + print(f"Folder selected for conversion: {folder_selected}") + time.sleep(2) # Simulate some time for conversion + + def cancel_conversion(self): + # Placeholder for cancel action, you may need to implement actual cancellation logic + print("Conversion cancelled by user.") + self.loading_label.pack_forget() + self.ok_button.config(state=tk.NORMAL) + self.cancel_button.config(state=tk.DISABLED) + +def main(): + root = tk.Tk() + app = TextureConverterGUI(root) + app.adjust_column_widths() + root.mainloop() + +if __name__ == "__main__": + main()