diff --git a/mininterface/tk_interface/date_entry.py b/mininterface/tk_interface/date_entry.py new file mode 100644 index 0000000..e642d72 --- /dev/null +++ b/mininterface/tk_interface/date_entry.py @@ -0,0 +1,237 @@ +import tkinter as tk +import re +from datetime import datetime + +try: + from tkcalendar import Calendar +except ImportError: + Calendar = None + +class DateEntry(tk.Frame): + def __init__(self, master=None, **kwargs): + super().__init__(master, **kwargs) + self.create_widgets() + self.pack(expand=True, fill=tk.BOTH) + self.bind_all_events() + + def create_widgets(self): + self.spinbox = tk.Spinbox(self, font=("Arial", 16), width=30, wrap=True) + self.spinbox.pack(padx=20, pady=20) + self.spinbox.insert(0, datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-4]) + self.spinbox.focus_set() + self.spinbox.icursor(8) + + # Bind up/down arrow keys + self.spinbox.bind("", self.increment_value) + self.spinbox.bind("", self.decrement_value) + + # Bind mouse click on spinbox arrows + self.spinbox.bind("", self.on_spinbox_click) + + # Bind key release event to update calendar when user changes the input field + self.spinbox.bind("", self.on_spinbox_change) + + # Toggle calendar button + self.toggle_button = tk.Button(self, text="Show/Hide Calendar", command=self.toggle_calendar) + self.toggle_button.pack(pady=10) + + if Calendar: + self.create_calendar() + + def bind_all_events(self): + # Copy to clipboard with ctrl+c + self.bind_all("", self.copy_to_clipboard) + + # Select all in the spinbox with ctrl+a + self.bind_all("", lambda event: self.select_all()) + + # Paste from clipboard with ctrl+v + self.bind_all("", lambda event: self.paste_from_clipboard()) + + # Toggle calendar widget with ctrl+shift+c + self.bind_all("", lambda event: self.toggle_calendar()) + + def create_calendar(self): + # Create a frame to hold the calendar + self.frame = tk.Frame(self) + self.frame.pack(padx=20, pady=20, expand=True, fill=tk.BOTH) + + # Add a calendar widget + self.calendar = Calendar(self.frame, selectmode='day', date_pattern='yyyy-mm-dd') + self.calendar.place(relwidth=0.7, relheight=0.8, anchor='n', relx=0.5) + + # Bind date selection event + self.calendar.bind("<>", self.on_date_select) + + # Initialize calendar with the current date + self.update_calendar(self.spinbox.get(), '%Y-%m-%d %H:%M:%S.%f') + + def toggle_calendar(self, event=None): + if Calendar: + if hasattr(self, 'frame') and self.frame.winfo_ismapped(): + self.frame.pack_forget() + else: + self.frame.pack(padx=20, pady=20, expand=True, fill=tk.BOTH) + + def increment_value(self, event=None): + self.change_date(1) + + def decrement_value(self, event=None): + self.change_date(-1) + + def find_valid_date(self): + input = self.spinbox.get() + # use regex to find the date part + date_part = re.search(r'\d{4}-\d{2}-\d{2}', input) + if date_part: + return date_part.group() + return False + + def find_valid_time(self): + input = self.spinbox.get() + # use regex to find the time part + time_part = re.search(r'\d{2}:\d{2}:\d{2}', input) + if time_part: + return time_part.group() + return False + + def change_date(self, delta): + date_str = self.spinbox.get() + caret_pos = self.spinbox.index(tk.INSERT) + + date = self.find_valid_date() + time = self.find_valid_time() + + if date: + split_input = re.split(r'[- :.]', date_str) + part_index = self.get_part_index(caret_pos, len(split_input)) + + # Increment or decrement the relevant part + number = int(split_input[part_index]) + new_number = number + delta + split_input[part_index] = str(new_number).zfill(len(split_input[part_index])) + + if time: + new_value_str = f"{split_input[0]}-{split_input[1]}-{split_input[2]} {split_input[3]}:{split_input[4]}:{split_input[5]}.{split_input[6][:2]}" + string_format = '%Y-%m-%d %H:%M:%S.%f' + else: + new_value_str = f"{split_input[0]}-{split_input[1]}-{split_input[2]}" + string_format = '%Y-%m-%d' + + # Validate the new date + try: + datetime.strptime(new_value_str, string_format) + self.spinbox.delete(0, tk.END) + self.spinbox.insert(0, new_value_str) + self.spinbox.icursor(caret_pos) + if Calendar: + self.update_calendar(new_value_str, string_format) + except ValueError: + pass + + def get_part_index(self, caret_pos, split_length): + if caret_pos < 5: # year + return 0 + elif caret_pos < 8: # month + return 1 + elif caret_pos < 11: # day + return 2 + elif split_length > 3: + if caret_pos < 14: # hour + return 3 + elif caret_pos < 17: # minute + return 4 + elif caret_pos < 20: # second + return 5 + else: # millisecond + return 6 + return 2 + + def on_spinbox_click(self, event): + # Check if the click was on the spinbox arrows + if self.spinbox.identify(event.x, event.y) == "buttonup": + self.increment_value() + elif self.spinbox.identify(event.x, event.y) == "buttondown": + self.decrement_value() + + def on_date_select(self, event): + selected_date = self.calendar.selection_get() + self.spinbox.delete(0, tk.END) + self.spinbox.insert(0, selected_date.strftime('%Y-%m-%d')) + self.spinbox.icursor(len(self.spinbox.get())) + + def on_spinbox_change(self, event): + if Calendar: + self.update_calendar(self.spinbox.get()) + + def update_calendar(self, date_str, string_format='%Y-%m-%d'): + try: + date = datetime.strptime(date_str, string_format) + self.calendar.selection_set(date) + except ValueError: + pass + + def copy_to_clipboard(self, event=None): + self.clipboard_clear() + self.clipboard_append(self.spinbox.get()) + self.update() # now it stays on the clipboard after the window is closed + self.show_popup("Copied to clipboard") + + def show_popup(self, message): + popup = tk.Toplevel(self) + popup.wm_title("") + + label = tk.Label(popup, text=message, font=("Arial", 12)) + label.pack(side="top", fill="x", pady=10, padx=10) + + # Position the popup window in the top-left corner of the widget + x = self.winfo_rootx() + y = self.winfo_rooty() + + # Position of the popup window has to be "inside" the main window or it will be focused on popup + popup.geometry(f"400x100+{x+200}+{y-150}") + + # Close the popup after 2 seconds + self.after(1000, popup.destroy) + + # Keep focus on the spinbox + self.spinbox.focus_force() + + + def select_all(self, event=None): + self.spinbox.selection_range(0, tk.END) + self.spinbox.focus_set() + self.spinbox.icursor(0) + return 'break' + + def paste_from_clipboard(self, event=None): + self.spinbox.delete(0, tk.END) + self.spinbox.insert(0, self.clipboard_get()) + +if __name__ == "__main__": + root = tk.Tk() + # Get the screen width and height + # This is calculating the position of the TOTAL dimentions of all screens combined + # How to calculate the position of the window on the current screen? + screen_width = root.winfo_screenwidth() + screen_height = root.winfo_screenheight() + + print(screen_width, screen_height) + + # Calculate the position to center the window + x = (screen_width // 2) - 400 + y = (screen_height // 2) - 600 + + print(x, y) + + # Set the position of the window + root.geometry(f"800x600+{x}+{y}") + # keep the main widget on top all the time + root.wm_attributes("-topmost", False) + root.wm_attributes("-topmost", True) + root.title("Date Editor") + + date_entry = DateEntry(root) + date_entry.pack(expand=True, fill=tk.BOTH) + root.mainloop() + diff --git a/mininterface/tk_interface/dategui.py b/mininterface/tk_interface/dategui.py deleted file mode 100644 index b6b7561..0000000 --- a/mininterface/tk_interface/dategui.py +++ /dev/null @@ -1,127 +0,0 @@ -import tkinter as tk -from tkcalendar import Calendar -import re -from datetime import datetime - -def increment_date(event=None): - change_date(1) - -def decrement_date(event=None): - change_date(-1) - -def change_date(delta): - date_str = spinbox.get() - caret_pos = spinbox.index(tk.INSERT) - - # Split the date string by multiple delimiters - split_input = re.split(r'[- :.]', date_str) - - # Determine which part of the date the caret is on - # 0 -> day - # 1 -> month - # 2 -> year - # 3 -> hour - # 4 -> minute - # 5 -> second - # 6 -> microsecond - if caret_pos < 3: - part_index = 0 - elif caret_pos < 6: - part_index = 1 - elif caret_pos < 11: - part_index = 2 - elif caret_pos < 14: - part_index = 3 - elif caret_pos < 17: - part_index = 4 - elif caret_pos < 20: - part_index = 5 - else: - part_index = 6 - - # Increment or decrement the relevant part - number = int(split_input[part_index]) - new_number = number + delta - split_input[part_index] = str(new_number).zfill(len(split_input[part_index])) - - # Reconstruct the date string - new_date_str = f"{split_input[0]}-{split_input[1]}-{split_input[2]} {split_input[3]}:{split_input[4]}:{split_input[5]}.{split_input[6][:2]}" - - # Validate the new date - try: - datetime.strptime(new_date_str, '%d-%m-%Y %H:%M:%S.%f') - spinbox.delete(0, tk.END) - spinbox.insert(0, new_date_str) - spinbox.icursor(caret_pos) - update_calendar(new_date_str) - except ValueError: - pass - -def on_spinbox_click(event): - # Check if the click was on the spinbox arrows - if spinbox.identify(event.x, event.y) == "buttonup": - increment_date() - elif spinbox.identify(event.x, event.y) == "buttondown": - decrement_date() - -def on_date_select(event): - selected_date = calendar.selection_get() - current_time = datetime.now().strftime("%H:%M:%S.%f")[:-4] - new_date_str = f"{selected_date.strftime('%d-%m-%Y')} {current_time}" - spinbox.delete(0, tk.END) - spinbox.insert(0, new_date_str) - update_calendar(new_date_str) - -def update_calendar(date_str): - try: - date_obj = datetime.strptime(date_str, '%d-%m-%Y %H:%M:%S.%f') - calendar.selection_set(date_obj) - except ValueError: - pass - -def on_spinbox_change(event): - update_calendar(spinbox.get()) - -def copy_to_clipboard(): - root.clipboard_clear() - root.clipboard_append(spinbox.get()) - root.update() # now it stays on the clipboard after the window is closed - -root = tk.Tk() -root.geometry("800x600") -root.title("Date Editor") - -spinbox = tk.Spinbox(root, font=("Arial", 16), width=30, wrap=True) -spinbox.pack(padx=20, pady=20) -spinbox.insert(0, datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f")[:-4]) - -# Bind up/down arrow keys -spinbox.bind("", increment_date) -spinbox.bind("", decrement_date) - -# Bind mouse click on spinbox arrows -spinbox.bind("", on_spinbox_click) - -# Bind key release event to update calendar when user changes the input field -spinbox.bind("", on_spinbox_change) - -# Create a frame to hold the calendar and copy button -frame = tk.Frame(root) -frame.pack(padx=20, pady=20, expand=True, fill=tk.BOTH) - -# Add a calendar widget -calendar = Calendar(frame, selectmode='day', date_pattern='dd-mm-yyyy') -calendar.place(relwidth=0.7, relheight=0.8, anchor='n', relx=0.5) - -# Bind date selection event -calendar.bind("<>", on_date_select) - -# Add a copy-to-clipboard button -copy_button = tk.Button(frame, text="Copy to Clipboard", command=copy_to_clipboard, height=1) -copy_button.place(relwidth=0.2, relheight=0.1, anchor='n', relx=0.5, rely=0.85) - -# Initialize calendar with the current date -update_calendar(spinbox.get()) - -root.mainloop() -