Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI Improvements #390

Merged
merged 1 commit into from
Jan 9, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 141 additions & 52 deletions EclipsingBinaries/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,27 +181,53 @@ def __init__(self):
# Bind quit to autosave settings
self.protocol("WM_DELETE_WINDOW", self.quit_program)

# ---------- Undo/Redo Support ----------
def create_input_field(self, parent, label_text, placeholder_text, row, variable=None):
"""Create a labeled input field with placeholder functionality and custom undo/redo."""
def create_input_field(
self, parent, label_text, placeholder_text, row, variable=None, validation_func=None, error_message=""
):
"""
Create a labeled input field with placeholder functionality, validation, and inline error message.
"""
# Create a label for the input field
tk.Label(parent, text=label_text, font=self.label_font, bg="#ffffff").grid(
row=row, column=0, padx=10, pady=5, sticky="e"
)

entry = tk.Entry(parent, width=40, font=self.label_font)
# Create the entry widget
entry = tk.Entry(parent, width=30, font=self.label_font) # Reduced width
entry.grid(row=row, column=1, padx=10, pady=5, sticky="w")

# Error message label (initially empty)
error_label = tk.Label(
parent, text="", font=("Helvetica", 9), fg="red", bg="#ffffff" # Smaller font size
)
error_label.place(in_=entry, relx=1.05, rely=0.5, anchor="w") # Positioned to the right of the entry

# Placeholder functionality
def on_focus_in(event):
if entry.get() == placeholder_text:
if entry.get() == placeholder_text and entry["fg"] == "gray":
entry.delete(0, "end")
entry.config(fg="black")

def on_focus_out(event):
if not entry.get():
if not entry.get().strip(): # If entry is empty
entry.insert(0, placeholder_text)
entry.config(fg="gray")

validate_input() # Validate on focus out

# Validation function
def validate_input():
value = entry.get().strip()
if value == placeholder_text or not value: # Input is empty
error_label.config(text=error_message or "This field is required.")
entry.config(bg="#ffe6e6") # Highlight entry with a light red background
elif validation_func and not validation_func(value): # Validation fails
error_label.config(text=error_message)
entry.config(bg="#ffe6e6")
else: # Valid input
error_label.config(text="")
entry.config(bg="white")

# Bind events
entry.insert(0, placeholder_text)
entry.config(fg="gray")
entry.bind("<FocusIn>", on_focus_in)
Expand Down Expand Up @@ -402,21 +428,34 @@ def show_iraf_reduction(self):

# Input fields with placeholders
raw_images_path = self.create_input_field(self.right_frame, "Raw Images Path:",
"C:\\folder1\\raw_images", row=1)
"C:\\folder1\\raw_images", row=1,
validation_func=lambda x: len(x.strip()) > 0, # Empty string
error_message="File path cannot be empty.")

calibrated_images_path = self.create_input_field(self.right_frame, "Calibrated Images Path:",
"C:\\folder1\\calibrated_images", row=2)
"C:\\folder1\\calibrated_images", row=2,
validation_func=lambda x: len(x.strip()) > 0, # Empty string
error_message="File path cannot be empty.")

location = self.create_input_field(self.right_frame, "Location:",
"e.g., BSUO, CTIO, etc.", row=3)
"e.g., BSUO, CTIO, etc.", row=3,
validation_func=lambda x: isinstance(x, str) and x.isalpha(), # String
error_message="Value must be a string.")

# Checkbox for dark frames
dark_bool_var = tk.BooleanVar(value=True)
self.create_checkbox(self.right_frame, "Use Dark Frames", dark_bool_var, row=4)

# Overscan and Trim region inputs
overscan = self.create_input_field(self.right_frame, "Overscan Region:",
"[2073:2115, :]", row=5)
"[2073:2115, :]", row=5,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter at least [:,:].")

trim = self.create_input_field(self.right_frame, "Trim Region:",
"[20:2060, 12:2057]", row=6)
"[20:2060, 12:2057]", row=6,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter at least [:,:].")

# Button to open and plot bias image
tk.Button(self.right_frame, text="Open Bias Image", font=self.button_font, bg="#003366", fg="white",
Expand Down Expand Up @@ -484,9 +523,13 @@ def show_tess_search(self):

# Input fields
system_name = self.create_input_field(self.right_frame, "System Name:",
"NSVS 896797", row=1)
"NSVS 896797", row=1,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter a system name.")
download_path = self.create_input_field(self.right_frame, "Download Path:",
"C:\\folder1\\download", row=2)
"C:\\folder1\\download", row=2,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter a file pathway.")

# Checkbox for download specific sector
download_all_var = tk.BooleanVar(value=False) # Default to unchecked
Expand Down Expand Up @@ -595,15 +638,29 @@ def show_aij_comparison_selector(self):

# Input fields
ra = self.create_input_field(self.right_frame, "Right Ascension (RA):",
"HH:MM:SS.SSSS", row=1)
"HH:MM:SS.SSSS", row=1,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter a RA.")

dec = self.create_input_field(self.right_frame, "Declination (DEC):",
"DD:MM:SS.SSSS or -DD:MM:SS.SSSS", row=2)
"DD:MM:SS.SSSS or -DD:MM:SS.SSSS", row=2,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter a DEC.")

folder_path = self.create_input_field(self.right_frame, "Data Save Folder Path:",
"C:\\folder1\\download", row=3)
"C:\\folder1\\download", row=3,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter a file pathway.")

obj_name = self.create_input_field(self.right_frame, "Object Name:",
"NSVS 896797", row=4)
"NSVS 896797", row=4,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter the object name.")

science_image = self.create_input_field(self.right_frame, "Science Image Folder Path:",
"C:\\folder1\\calibrated_images", row=5)
"C:\\folder1\\calibrated_images", row=5,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter a file pathway.")

# Buttons for comparison selector
tk.Button(self.right_frame, text="Run Comparison Selector", font=self.button_font, bg="#003366", fg="white",
Expand Down Expand Up @@ -634,15 +691,29 @@ def show_multi_aperture_photometry(self):

# Input fields
obj_name = self.create_input_field(self.right_frame, "Object Name:",
"NSVS 896797", row=1)
"NSVS 896797", row=1,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter an object name.")

reduced_images_path = self.create_input_field(self.right_frame, "Reduced Images Path:",
"C:\\folder1\\reduced_images", row=2)
"C:\\folder1\\reduced_images", row=2,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter a file pathway.")

radec_b_file = self.create_input_field(self.right_frame, "RADEC File (B Filter):",
"C:\\folder1\\B.radec", row=3)
"C:\\folder1\\B.radec", row=3,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter a file pathway with file name")

radec_v_file = self.create_input_field(self.right_frame, "RADEC File (V Filter):",
"C:\\folder1\\V.radec", row=4)
"C:\\folder1\\V.radec", row=4,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter a file pathway with file name.")

radec_r_file = self.create_input_field(self.right_frame, "RADEC File (R Filter):",
"C:\\folder1\\R.radec", row=5)
"C:\\folder1\\R.radec", row=5,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter a file pathway with file name.")

# Run button
self.create_run_button(self.right_frame, self.run_multi_aperture_photometry, row=6,
Expand Down Expand Up @@ -675,11 +746,19 @@ def show_gaia_query(self):

# Input fields
ra = self.create_input_field(self.right_frame, "Right Ascension (RA):",
"HH:MM:SS.SSSS", row=1)
"HH:MM:SS.SSSS", row=1,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter a RA.")

dec = self.create_input_field(self.right_frame, "Declination (DEC):",
"DD:MM:SS.SSSS or -DD:MM:SS.SSSS", row=2)
"DD:MM:SS.SSSS or -DD:MM:SS.SSSS", row=2,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter a DEC.")

output_file = self.create_input_field(self.right_frame, "Output File Path:",
"C:\\folder1\\Gaia_[star name].txt", row=3)
"C:\\folder1\\Gaia_[star name].txt", row=3,
validation_func=lambda x: len(x.strip()) > 0, # Empty
error_message="Please enter a file pathway.")

# Run button
self.create_run_button(self.right_frame, self.run_gaia_query, row=4,
Expand Down Expand Up @@ -764,18 +843,28 @@ def update_file_path_fields():
label_text="HJD:",
placeholder_text="2458403.58763",
row=6,
validation_func=lambda x: x.replace(".", "", 1).isdigit(), # Is a float
error_message="Please enter a valid HJD."
)

# Period input
period_var = self.create_input_field(self.right_frame, "Period:",
"0.3175", row=7)
"0.3175", row=7,
validation_func=lambda x: x.replace(".", "", 1).isdigit(), # Is a float
error_message="Please enter a valid Period.")

obj_name_var = self.create_input_field(self.right_frame, "System Name:",
"NSVS_896797", row=8)
"NSVS_896797", row=8,
validation_func=lambda x: len(x.strip()) > 0, # Empty, # Is a float
error_message="Please enter a System Name."
)

# Output file path
output_var = self.create_input_field(self.right_frame, "Output File Path:",
"C:/folder1/folder2", row=9)
"C:/folder1/folder2", row=9,
validation_func=lambda x: len(x.strip()) > 0, # Empty, # Is a float
error_message="Please enter a file pathway."
)

# Button to run O'Connell Effect calculation
tk.Button(
Expand Down Expand Up @@ -1119,28 +1208,28 @@ def quit_program(self):
if messagebox.askyesno("Exit", "Are you sure you want to exit?"):
self.destroy()

class PlaceholderEntry(tk.Entry):
def __init__(self, master=None, placeholder="Enter text...", placeholder_color="grey", *args, **kwargs):
super().__init__(master, *args, **kwargs)

self.placeholder = placeholder
self.placeholder_color = placeholder_color
self.default_fg_color = self["fg"]

self.bind("<FocusIn>", self._clear_placeholder)
self.bind("<FocusOut>", self._add_placeholder)

self._add_placeholder()

def _clear_placeholder(self, event=None):
if self["fg"] == self.placeholder_color:
self.delete(0, tk.END)
self["fg"] = self.default_fg_color

def _add_placeholder(self, event=None):
if not self.get():
self.insert(0, self.placeholder)
self["fg"] = self.placeholder_color
# class PlaceholderEntry(tk.Entry):
# def __init__(self, master=None, placeholder="Enter text...", placeholder_color="grey", *args, **kwargs):
# super().__init__(master, *args, **kwargs)
#
# self.placeholder = placeholder
# self.placeholder_color = placeholder_color
# self.default_fg_color = self["fg"]
#
# self.bind("<FocusIn>", self._clear_placeholder)
# self.bind("<FocusOut>", self._add_placeholder)
#
# self._add_placeholder()
#
# def _clear_placeholder(self, event=None):
# if self["fg"] == self.placeholder_color:
# self.delete(0, tk.END)
# self["fg"] = self.default_fg_color
#
# def _add_placeholder(self, event=None):
# if not self.get():
# self.insert(0, self.placeholder)
# self["fg"] = self.placeholder_color


def launch_main_gui():
Expand Down
Loading