188 lines
6.4 KiB
Python
188 lines
6.4 KiB
Python
from datetime import datetime
|
|
import curses
|
|
from big_digits import BIG_DIGITS
|
|
|
|
def _draw_error(stdscr, error_message):
|
|
"""Draw error message if present"""
|
|
if error_message:
|
|
height, width = stdscr.getmaxyx()
|
|
# Truncate message if too long
|
|
error_message = error_message[:width-4]
|
|
|
|
error_x = max(0, width // 2 - len(error_message) // 2)
|
|
error_y = height - 4 # Show near bottom of screen
|
|
|
|
# Red color for errors
|
|
stdscr.attron(curses.color_pair(3) | curses.A_BOLD)
|
|
stdscr.addstr(error_y, error_x, error_message)
|
|
stdscr.attroff(curses.color_pair(3) | curses.A_BOLD)
|
|
|
|
def _draw_big_digit(stdscr, y, x, digit, big_digits):
|
|
"""
|
|
Draw a big digit using predefined patterns
|
|
"""
|
|
patterns = big_digits[digit]
|
|
for i, line in enumerate(patterns):
|
|
stdscr.addstr(y + i, x, line)
|
|
|
|
def _draw_big_time(stdscr, big_digits):
|
|
"""
|
|
Draw the time in big digits
|
|
"""
|
|
current_time = datetime.now()
|
|
time_str = current_time.strftime("%H:%M:%S")
|
|
|
|
# Get terminal dimensions
|
|
height, width = stdscr.getmaxyx()
|
|
|
|
# Calculate starting position to center the big clock
|
|
digit_width = 14 # Width of each digit pattern including spacing
|
|
total_width = digit_width * len(time_str)
|
|
start_x = (width - total_width) // 2
|
|
start_y = (height - 7) // 2 - 4 # Move up a bit to make room for date
|
|
|
|
# Color for the big time
|
|
stdscr.attron(curses.color_pair(1))
|
|
for i, digit in enumerate(time_str):
|
|
_draw_big_digit(stdscr, start_y, start_x + i * digit_width, digit, big_digits)
|
|
stdscr.attroff(curses.color_pair(1))
|
|
|
|
def _draw_main_clock(stdscr):
|
|
"""
|
|
Draw the main clock screen
|
|
"""
|
|
current_time = datetime.now()
|
|
time_str = current_time.strftime("%H:%M:%S")
|
|
date_str = current_time.strftime("%Y-%m-%d")
|
|
|
|
# Get terminal dimensions
|
|
height, width = stdscr.getmaxyx()
|
|
|
|
# Draw big time
|
|
# Note: You'll need to pass BIG_DIGITS from big_digits module when calling
|
|
_draw_big_time(stdscr, BIG_DIGITS)
|
|
|
|
# Draw date
|
|
date_x = width // 2 - len(date_str) // 2
|
|
date_y = height // 2 + 4 # Below the big clock
|
|
|
|
stdscr.attron(curses.color_pair(2))
|
|
stdscr.addstr(date_y, date_x, date_str)
|
|
stdscr.attroff(curses.color_pair(2))
|
|
|
|
# Draw menu options
|
|
menu_str = "A: Add Alarm L: List Alarms Q: Quit"
|
|
menu_x = width // 2 - len(menu_str) // 2
|
|
stdscr.addstr(height - 2, menu_x, menu_str)
|
|
|
|
def _draw_add_alarm(stdscr, context):
|
|
"""
|
|
Draw the add alarm screen
|
|
|
|
Args:
|
|
stdscr: The curses screen object
|
|
context: A dictionary containing UI state variables
|
|
"""
|
|
height, width = stdscr.getmaxyx()
|
|
|
|
form_y = height // 2 - 3
|
|
stdscr.addstr(form_y -1, width // 2 - 10, "Add New Alarm")
|
|
|
|
# Name input
|
|
if context['new_alarm_selected'] == 4:
|
|
stdscr.attron(curses.color_pair(2))
|
|
stdscr.addstr(form_y + 1, width // 2 - 10, f"Name: {context['new_alarm_name']}")
|
|
if context['new_alarm_selected'] == 4:
|
|
stdscr.attroff(curses.color_pair(2))
|
|
|
|
# Time selection
|
|
hour_str = f"{context['new_alarm_hour']:02d}"
|
|
minute_str = f"{context['new_alarm_minute']:02d}"
|
|
|
|
# Highlight selected field
|
|
if context['new_alarm_selected'] == 0:
|
|
stdscr.attron(curses.color_pair(2))
|
|
stdscr.addstr(form_y + 2, width // 2 - 2, hour_str)
|
|
if context['new_alarm_selected'] == 0:
|
|
stdscr.attroff(curses.color_pair(2))
|
|
|
|
stdscr.addstr(form_y + 2, width // 2, ":")
|
|
|
|
if context['new_alarm_selected'] == 1:
|
|
stdscr.attron(curses.color_pair(2))
|
|
stdscr.addstr(form_y + 2, width // 2 + 1, minute_str)
|
|
if context['new_alarm_selected'] == 1:
|
|
stdscr.attroff(curses.color_pair(2))
|
|
|
|
# Enabled/Disabled toggle
|
|
enabled_str = "Enabled" if context['new_alarm_enabled'] else "Disabled"
|
|
if context['new_alarm_selected'] == 5:
|
|
stdscr.attron(curses.color_pair(2))
|
|
stdscr.addstr(form_y + 4, width // 2 - len(enabled_str)//2, enabled_str)
|
|
if context['new_alarm_selected'] == 5:
|
|
stdscr.attroff(curses.color_pair(2))
|
|
|
|
# Date selection
|
|
date_str = "No specific date" if not context['new_alarm_date'] else context['new_alarm_date'].strftime("%Y-%m-%d")
|
|
if context['new_alarm_selected'] == 2:
|
|
stdscr.attron(curses.color_pair(2))
|
|
stdscr.addstr(form_y + 3, width // 2 - len(date_str) // 2, date_str)
|
|
if context['new_alarm_selected'] == 2:
|
|
stdscr.attroff(curses.color_pair(2))
|
|
|
|
# Weekday selection
|
|
weekday_str = "Repeat: " + " ".join(
|
|
context['weekday_names'][i] if i in context['new_alarm_weekdays'] else "___"
|
|
for i in range(7)
|
|
)
|
|
if context['new_alarm_selected'] == 3:
|
|
stdscr.attron(curses.color_pair(2))
|
|
stdscr.addstr(form_y + 5, width // 2 - len(weekday_str) // 2, weekday_str)
|
|
if context['new_alarm_selected'] == 3:
|
|
stdscr.attroff(curses.color_pair(2))
|
|
|
|
# Instructions
|
|
stdscr.addstr(height - 2, 2,
|
|
"↑↓: Change ←→: Switch Space: Toggle Enter: Save Esc: Cancel")
|
|
|
|
def _draw_list_alarms(stdscr, context):
|
|
"""
|
|
Draw the list of alarms screen
|
|
|
|
Args:
|
|
stdscr: The curses screen object
|
|
context: A dictionary containing UI state variables
|
|
"""
|
|
height, width = stdscr.getmaxyx()
|
|
|
|
# Header
|
|
stdscr.addstr(2, width // 2 - 5, "Alarms")
|
|
|
|
if not context['alarms']:
|
|
stdscr.addstr(4, width // 2 - 10, "No alarms set")
|
|
else:
|
|
for i, alarm in enumerate(context['alarms'][:height-6]):
|
|
# Format time and repeat information
|
|
time_str = alarm.get('time', 'Unknown')
|
|
|
|
# Format repeat info
|
|
repeat_info = ""
|
|
repeat_rule = alarm.get('repeat_rule', {})
|
|
if repeat_rule:
|
|
if repeat_rule.get('type') == 'weekly':
|
|
days = repeat_rule.get('days', [])
|
|
repeat_info = f" (Every {', '.join(context['weekday_names'][d] for d in days)})"
|
|
elif repeat_rule.get('type') == 'once' and repeat_rule.get('date'):
|
|
repeat_info = f" (On {repeat_rule['date']})"
|
|
|
|
# Status indicator
|
|
status = "✓" if alarm.get('enabled', True) else "✗"
|
|
display_str = f"{status} {time_str}{repeat_info}"
|
|
|
|
# Truncate if too long
|
|
display_str = display_str[:width-4]
|
|
|
|
stdscr.addstr(4 + i, 2, display_str)
|
|
|
|
stdscr.addstr(height - 2, 2, "D: Delete Enter: Edit Esc: Back")
|