diff --git a/scripts/folder_mangement/CreateFolder.py b/scripts/folder_mangement/CreateFolder.py new file mode 100644 index 0000000..3f13bcf --- /dev/null +++ b/scripts/folder_mangement/CreateFolder.py @@ -0,0 +1,93 @@ +import customtkinter as Ctk +import os +import scripts.get_sys_info as system_code +from ..SaveData import SaveData + +FONT = "Berlin Sans FB" + +class CreateFolder(Ctk.CTkFrame): + def __init__(self,master, output_path,callback, **kwargs): + super().__init__(master, **kwargs) + system_code.load_json_file() + self.data_saver = SaveData() + self.my_font = Ctk.CTkFont(family=FONT, size=22) + self.output_path = output_path + self.callback = callback + self.error_txt = "" + + self.create_folder() + + def enable_keybinding(self): + self.master.bind("", self.on_a_press, add="+") + + def disable_keybinding(self): + self.master.unbind("") + + def on_a_press(self, event): + # Check if the frame is visible by querying its manager info + if self.winfo_manager(): + self.create_new_data_folder() + + def create_folder(self): + self.enable_keybinding() + self.create_folder_label = Ctk.CTkLabel(self, text="Type name for new Object:", width=100, font=self.my_font) + self.create_folder_entry = Ctk.CTkEntry(self, placeholder_text="New Data Object", width=100, font=self.my_font) + self.create_folder_name_btn = Ctk.CTkButton(self, text="Create", width=100, command=self.create_new_data_folder, font=self.my_font) + self.create_folder_error = Ctk.CTkLabel(self, text=self.error_txt, width=100, font=self.my_font) + self.place_create_folder() + + def create_new_data_folder(self): + """ + Create a new folder in the directory specified by self.output_path. + + The folder name will be 'data_folder'. If the folder already exists, a number will be appended + to create a unique folder name ('data_folder_1', 'data_folder_2', etc.). + """ + folder_name = self.create_folder_entry.get() + + # Construct the full path for the new data folder + full_path = os.path.join(self.output_path, folder_name) + if os.path.exists(full_path): + self.error_txt = "The folder exists already" + self.create_folder_error.configure(text=self.error_txt) + return + try: + os.makedirs(full_path) + print(f"Folder created at: {full_path}") + self.data_saver.create(full_path) + except OSError: + self.error_txt = "There occured an error creating the Folder" + self.create_folder_error.configure(text=self.error_txt) + self.callback(full_path) + + + def place_create_folder(self): + self.create_folder_label.place( + relx=0.5, + rely=0.425, + relwidth=0.3, + relheight=0.06, + anchor="center", + ) # Position the converter button to the left + self.create_folder_entry.place( + relx=0.3875, + rely=0.5, + relwidth=0.125, + relheight=0.06, + anchor="w", + ) # Position the converter button to the left + self.create_folder_name_btn.place( + relx=0.6125, + rely=0.5, + relwidth=0.08, + relheight=0.06, + anchor="e", + ) # Adjusted for .place + self.create_folder_error.place( + relx=0.5, + rely=0.575, + relwidth=0.3, + relheight=0.06, + anchor="center", + ) # Position the converter button to the left + diff --git a/scripts/folder_mangement/OpenFolder.py b/scripts/folder_mangement/OpenFolder.py new file mode 100644 index 0000000..d4b902a --- /dev/null +++ b/scripts/folder_mangement/OpenFolder.py @@ -0,0 +1,99 @@ +import customtkinter as Ctk +import os +from PIL import Image +from ..SaveData import SaveData +import scripts.get_sys_info as system_code + + +FONT = "Berlin Sans FB" + +class OpenFolder(Ctk.CTkScrollableFrame): + def __init__(self,master,output_path, callback, **kwargs, ): + super().__init__(master, **kwargs) + self.my_font = Ctk.CTkFont(family=FONT, size=16) + self.warning_font = Ctk.CTkFont(family=FONT, size=20) + # the variables needed to get from the upper class + self.button_image = Ctk.CTkImage(Image.open(r"./icons/folder.png"), size=(63, 63)) + self.output_path = output_path + self.callback = callback # Store the callback function + system_code.load_json_file() + self.data_saver = SaveData() + self.folders = self.get_all_folders() + self.button_size = (50, 50) # Size width and height + self.padding = 10 # Padding around each button + if len(self.folders) == 0: + self.folder_has_no_subs() + else: + self.make_buttons() + self.bind("", self.on_configure, '+') + + def on_configure(self, event=None): + self.rearrange_buttons() + + def get_button_widths(self): + """ + Estimates button widths based on button text size. + """ + average_char_width = 8 + width = max(len(button._text) * average_char_width for button in self.buttons) + return max(width, self.button_size[0]) + + def get_max_folders_per_row(self): + """ + Calculate the maximum number of folders that can fit in a row based on the container's width. + """ + container_width = self.winfo_width() + button_width = self.get_button_widths() + # Calculate the space required for one button including padding + total_button_width = button_width + 2 * self.padding + # Divide the available space in the container by the space required for one button + max_folders_per_row = max(1, container_width // total_button_width) + + return max_folders_per_row + + def get_all_folders(self): + folders = {f.name: f.path for f in os.scandir(self.output_path) if f.is_dir()} + return dict(sorted(folders.items())) + + def rearrange_buttons(self): + """ + Rearrange buttons based on the current window size and calculated folders per row. + If the window size changes, it recalculates the arrangement. + """ + max_folders_per_row = self.get_max_folders_per_row() + + for index, button in enumerate(self.buttons): + row = index // max_folders_per_row + col = index % max_folders_per_row + button.grid(row=row, column=col, padx=self.padding, pady=self.padding) + + def make_buttons(self): + """ + Generates buttons for each folder provided. + """ + self.buttons = [] + for key, value in self.folders.items(): + folder_btn = Ctk.CTkButton( + self, text=key, + width=self.button_size[0], height=self.button_size[1], + image=self.button_image, # Corrected: Use self.button_image for the image parameter + compound="top", # Position text below the image + command=lambda val=value: self.new_folder_chosen(val), + font=self.my_font + ) + folder_btn.grid_remove() + self.buttons.append(folder_btn) + self.rearrange_buttons() # Rearrange buttons after creation + + def new_folder_chosen(self, folder_path): + """ + Callback for when a new folder is chosen. + """ + self.data_saver.search_in_folder(folder_path) + + self.callback(folder_path) # Call the callback passing the current value + + def folder_has_no_subs(self): + self.place_forget() + self.label = Ctk.CTkLabel(self, text="No Folders were found", width=100, font=self.warning_font) + self.label.grid(row = 1, column = 1, padx= 50, pady = 50) \ No newline at end of file diff --git a/scripts/folder_mangement/SwitchFolder.py b/scripts/folder_mangement/SwitchFolder.py new file mode 100644 index 0000000..a38662f --- /dev/null +++ b/scripts/folder_mangement/SwitchFolder.py @@ -0,0 +1,117 @@ +import customtkinter as Ctk +import os +import scripts.get_sys_info as system_code +from ..SaveData import SaveData +from tkinter import filedialog + + +FONT = "Berlin Sans FB" + +class SwitchFolder(Ctk.CTkFrame): + def __init__(self,master, callback, **kwargs): + super().__init__(master, **kwargs) + system_code.load_json_file() + self.data_saver = SaveData() + self.my_font = Ctk.CTkFont(family=FONT, size=22) + self.callback = callback + self.error_txt = "" + self.input_path = None + self.output_path = None + self.img_paths = None + + self.create_selection() + # the selection part + def create_selection(self): + # input + self.input_entry = Ctk.CTkEntry(self, placeholder_text="Input folder path", width=100, font=self.my_font) + self.input_btn = Ctk.CTkButton(self, text="Browse", width=100, command=self.get_folder_path, font=self.my_font) + # output + self.output_entry = Ctk.CTkEntry(self, placeholder_text="Output folder path", width=100, font=self.my_font) + self.output_btn = Ctk.CTkButton(self, text="Browse", width=100, command=self.get_project_path, font=self.my_font) + # start + self.start_btn = Ctk.CTkButton(self, text="Start", width=100, command=self.open_labeling, font=self.my_font) + self.error_label = Ctk.CTkLabel(self, text=self.error_txt, width=100, font=self.my_font) + self.place_label_selection() + + def open_labeling(self): + source_path = self.input_entry.get() + self.output_path = self.output_entry.get() + if not os.path.exists(source_path): + self.error_txt = "Source Folder could not be found" + self.error_label.configure(text=self.error_txt) + elif not os.path.exists(self.output_path): + self.error_txt = "Output Folder could not be found" + self.error_label.configure(text=self.error_txt) + else: + self.data_saver.search_in_folder(self.output_path) + self.img_paths = self.load_images_into_array(source_path) + self.give_back() + + def load_images_into_array(self, folder_path): + image_paths = [] + for filename in os.listdir(folder_path): + if filename.endswith(system_code.img_format_options): + img_path = os.path.join(folder_path, filename) + image_paths.append(img_path) + return image_paths + + def get_folder_path(self): + file_path = filedialog.askdirectory() + self.input_entry.delete(0, Ctk.END) # Delete any existing text in the Entry widget + self.input_entry.insert(0, file_path) # Insert the new text + + def get_project_path(self): + video_path = filedialog.askdirectory() + self.output_entry.delete(0, Ctk.END) # Delete any existing text in the Entry widget + self.output_entry.insert(0, video_path) # Insert the new text + + def give_back(self): + self.callback(self.img_paths, self.output_path) + + def place_label_selection(self): + # output placing + self.input_entry.place( + relx=0.10, + rely=0.4, + anchor="w", + relwidth=0.5, + relheight=0.06 + ) # Position the converter button to the left + self.input_btn.place( + relx=0.90, + rely=0.4, + anchor="e", + relwidth=0.2, + relheight=0.06 + ) # Position the converter button to the left + + # output placing + self.output_entry.place( + relx=0.10, + rely=0.5, + anchor="w", + relwidth=0.5, + relheight=0.06 + ) # Position the converter button to the left + self.output_btn.place( + relx=0.90, + rely=0.5, + anchor="e", + relwidth=0.2, + relheight=0.06 + ) # Position the converter button to the left + # button row + self.start_btn.place( + relx=0.5, + rely=0.6, + anchor="center", + relwidth=0.8, + relheight=0.06 + ) # Position the converter button to the left + self.error_label.place( + relx=0.5, + rely=0.7, + anchor="center", + relwidth=0.8, + relheight=0.06 + ) # Position the converter button to the left \ No newline at end of file