From e632dbee8fbc39a8cc90a2644893442e7e4c7fa6 Mon Sep 17 00:00:00 2001 From: SpaceNerd0717 Date: Tue, 14 Oct 2025 00:48:56 -0400 Subject: [PATCH] Initial --- countdown.html | 41 ++++++++ main.py | 268 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 309 insertions(+) create mode 100644 countdown.html create mode 100644 main.py diff --git a/countdown.html b/countdown.html new file mode 100644 index 0000000..180745d --- /dev/null +++ b/countdown.html @@ -0,0 +1,41 @@ + + + + + + + + +
Mission
+
T-00:00:00
+ + \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..a7df624 --- /dev/null +++ b/main.py @@ -0,0 +1,268 @@ +import tkinter as tk +import time +from datetime import datetime + +HTML_FILE = "countdown.html" + +def write_html(mission_name, timer_text): + html = f""" + + + + + + + +
{mission_name}
+
{timer_text}
+ +""" + with open(HTML_FILE, "w", encoding="utf-8") as f: + f.write(html) + + +class CountdownApp: + def __init__(self, root): + self.root = root + self.root.title("RocketLaunchCountdown") + self.root.config(bg="black") + self.root.attributes("-topmost", True) + + # State + self.running = False + self.on_hold = False + self.scrubbed = False + self.counting_up = False + self.target_time = None + self.hold_start_time = None + self.remaining_time = 0 + self.mission_name = "Mission" + + # Display + self.text = tk.Label( + root, + text="T-00:00:00", + font=("Consolas", 80, "bold"), + fg="white", + bg="black" + ) + self.text.pack(padx=50, pady=20) + + # Mission name input + frame_top = tk.Frame(root, bg="black") + frame_top.pack(pady=5) + tk.Label(frame_top, text="Mission Name:", fg="white", bg="black").pack(side="left") + self.mission_entry = tk.Entry(frame_top, width=20, font=("Arial", 18)) + self.mission_entry.insert(0, self.mission_name) + self.mission_entry.pack(side="left") + + # Mode toggle + frame_mode = tk.Frame(root, bg="black") + frame_mode.pack(pady=5) + self.mode_var = tk.StringVar(value="duration") + tk.Radiobutton(frame_mode, text="Duration", variable=self.mode_var, value="duration", + fg="white", bg="black", command=self.update_inputs).pack(side="left", padx=5) + tk.Radiobutton(frame_mode, text="Clock Time", variable=self.mode_var, value="clock", + fg="white", bg="black", command=self.update_inputs).pack(side="left", padx=5) + + # Duration inputs + frame_duration = tk.Frame(root, bg="black") + frame_duration.pack(pady=5) + tk.Label(frame_duration, text="H", fg="white", bg="black").pack(side="left") + self.hours_entry = tk.Entry(frame_duration, width=3, font=("Arial", 18)) + self.hours_entry.insert(0, "0") + self.hours_entry.pack(side="left", padx=2) + tk.Label(frame_duration, text="M", fg="white", bg="black").pack(side="left") + self.minutes_entry = tk.Entry(frame_duration, width=3, font=("Arial", 18)) + self.minutes_entry.insert(0, "5") + self.minutes_entry.pack(side="left", padx=2) + tk.Label(frame_duration, text="S", fg="white", bg="black").pack(side="left") + self.seconds_entry = tk.Entry(frame_duration, width=3, font=("Arial", 18)) + self.seconds_entry.insert(0, "0") + self.seconds_entry.pack(side="left", padx=2) + + # Clock time input + frame_clock = tk.Frame(root, bg="black") + frame_clock.pack(pady=5) + tk.Label(frame_clock, text="HH:MM", fg="white", bg="black").pack(side="left") + self.clock_entry = tk.Entry(frame_clock, width=7, font=("Arial", 18)) + self.clock_entry.insert(0, "14:00") + self.clock_entry.pack(side="left", padx=5) + + # Control buttons + frame_buttons = tk.Frame(root, bg="black") + frame_buttons.pack(pady=10) + self.start_btn = tk.Button(frame_buttons, text="▶ Start", command=self.start, font=("Arial", 14)) + self.start_btn.pack(side="left", padx=5) + + self.hold_btn = tk.Button(frame_buttons, text="⏸ Hold", command=self.hold, font=("Arial", 14)) + self.hold_btn.pack(side="left", padx=5) + + self.resume_btn = tk.Button(frame_buttons, text="⏵ Resume", command=self.resume, font=("Arial", 14)) + # Hidden initially + self.resume_btn.pack_forget() + + self.scrub_btn = tk.Button(frame_buttons, text="🚫 Scrub", command=self.scrub, font=("Arial", 14), fg="red") + self.scrub_btn.pack(side="left", padx=5) + + self.reset_btn = tk.Button(frame_buttons, text="⟳ Reset", command=self.reset, font=("Arial", 14)) + self.reset_btn.pack(side="left", padx=5) + + self.update_inputs() + self.update_clock() + + # ---------------------------- + # Update input visibility based on mode + # ---------------------------- + def update_inputs(self): + if self.mode_var.get() == "duration": + self.hours_entry.config(state="normal") + self.minutes_entry.config(state="normal") + self.seconds_entry.config(state="normal") + self.clock_entry.config(state="disabled") + else: + self.hours_entry.config(state="disabled") + self.minutes_entry.config(state="disabled") + self.seconds_entry.config(state="disabled") + self.clock_entry.config(state="normal") + + # ---------------------------- + # Control logic + # ---------------------------- + def start(self): + self.mission_name = self.mission_entry.get().strip() or "Mission" + self.running = True + self.on_hold = False + self.scrubbed = False + self.counting_up = False + self.show_hold_button() + + try: + if self.mode_var.get() == "duration": + h = int(self.hours_entry.get()) + m = int(self.minutes_entry.get()) + s = int(self.seconds_entry.get()) + total_seconds = h * 3600 + m * 60 + s + else: + now = datetime.now() + parts = [int(p) for p in self.clock_entry.get().split(":")] + h, m = parts[0], parts[1] + s = parts[2] if len(parts) == 3 else 0 + target_today = now.replace(hour=h, minute=m, second=s, microsecond=0) + if target_today < now: + target_today = target_today.replace(day=now.day + 1) + total_seconds = (target_today - now).total_seconds() + except Exception: + self.text.config(text="Invalid time") + write_html(self.mission_name, "Invalid time") + return + + self.target_time = time.time() + total_seconds + self.remaining_time = total_seconds + + def hold(self): + if self.running and not self.on_hold and not self.scrubbed: + self.on_hold = True + self.hold_start_time = time.time() + self.remaining_time = max(0, self.target_time - self.hold_start_time) + self.show_resume_button() + + def resume(self): + if self.running and self.on_hold and not self.scrubbed: + self.on_hold = False + self.target_time = time.time() + self.remaining_time + self.show_hold_button() + + def show_hold_button(self): + self.resume_btn.pack_forget() + self.hold_btn.pack(side="left", padx=5) + + def show_resume_button(self): + self.hold_btn.pack_forget() + self.resume_btn.pack(side="left", padx=5) + + def scrub(self): + self.scrubbed = True + self.running = False + write_html(self.mission_name, "SCRUB") + self.text.config(text="SCRUB") + + def reset(self): + self.running = False + self.on_hold = False + self.scrubbed = False + self.counting_up = False + self.text.config(text="T-00:00:00") + write_html(self.mission_name, "T-00:00:00") + self.show_hold_button() + + # ---------------------------- + # Clock updating + # ---------------------------- + def format_time(self, seconds, prefix="T-"): + h = int(seconds // 3600) + m = int((seconds % 3600) // 60) + s = int(seconds % 60) + return f"{prefix}{h:02}:{m:02}:{s:02}" + + def update_clock(self): + if self.running and not self.scrubbed: + now = time.time() + if self.on_hold: + elapsed = int(now - self.hold_start_time) + timer_text = self.format_time(elapsed, "H+") + elif self.target_time: + diff = int(self.target_time - now) + if diff <= 0 and not self.counting_up: + self.counting_up = True + self.target_time = now + diff = 0 + if self.counting_up: + elapsed = int(now - self.target_time) + timer_text = self.format_time(elapsed, "T+") + else: + timer_text = self.format_time(diff, "T-") + else: + timer_text = "T-00:00:00" + else: + timer_text = self.text.cget("text") + + self.text.config(text=timer_text) + write_html(self.mission_name, timer_text) + self.root.after(200, self.update_clock) + + +if __name__ == "__main__": + root = tk.Tk() + app = CountdownApp(root) + write_html("Mission", "T-00:00:00") + root.mainloop()