mirror of
https://github.com/pdxlocations/contact.git
synced 2026-08-07 09:22:51 +02:00
redraw other input types
This commit is contained in:
@@ -247,6 +247,7 @@ def get_admin_key_input(current_value: List[bytes]) -> Optional[List[str]]:
|
||||
start_x = (curses.COLS - width) // 2
|
||||
|
||||
repeated_win = curses.newwin(height, width, start_y, start_x)
|
||||
repeated_win.timeout(200)
|
||||
repeated_win.bkgd(get_color("background"))
|
||||
repeated_win.attrset(get_color("window_frame"))
|
||||
repeated_win.keypad(True) # Enable keypad for special keys
|
||||
@@ -288,12 +289,14 @@ def get_admin_key_input(current_value: List[bytes]) -> Optional[List[str]]:
|
||||
repeated_win.refresh()
|
||||
curses.noecho()
|
||||
curses.curs_set(0)
|
||||
menu_state.need_redraw = True
|
||||
return None
|
||||
|
||||
elif key == ord("\n"): # Enter key to save and return
|
||||
if all(is_valid_base64(val) for val in user_values): # Ensure all values are valid Base64 and 32 bytes
|
||||
curses.noecho()
|
||||
curses.curs_set(0)
|
||||
menu_state.need_redraw = True
|
||||
return user_values # Return the edited Base64 values
|
||||
else:
|
||||
invalid_input = "Error: Each key must be valid Base64 and 32 bytes long!"
|
||||
@@ -312,6 +315,9 @@ def get_admin_key_input(current_value: List[bytes]) -> Optional[List[str]]:
|
||||
pass # Ignore invalid character inputs
|
||||
|
||||
|
||||
from contact.utilities.singleton import menu_state # Required if not already imported
|
||||
|
||||
|
||||
def get_repeated_input(current_value: List[str]) -> Optional[str]:
|
||||
height = 9
|
||||
width = 80
|
||||
@@ -319,71 +325,82 @@ def get_repeated_input(current_value: List[str]) -> Optional[str]:
|
||||
start_x = (curses.COLS - width) // 2
|
||||
|
||||
repeated_win = curses.newwin(height, width, start_y, start_x)
|
||||
repeated_win.timeout(200)
|
||||
repeated_win.bkgd(get_color("background"))
|
||||
repeated_win.attrset(get_color("window_frame"))
|
||||
repeated_win.keypad(True) # Enable keypad for special keys
|
||||
repeated_win.keypad(True)
|
||||
|
||||
curses.echo()
|
||||
curses.curs_set(1) # Show the cursor
|
||||
curses.curs_set(1)
|
||||
|
||||
# Editable list of values (max 3 values)
|
||||
user_values = current_value[:3]
|
||||
cursor_pos = 0 # Track which value is being edited
|
||||
user_values = current_value[:3] + [""] * (3 - len(current_value)) # Always 3 fields
|
||||
cursor_pos = 0
|
||||
invalid_input = ""
|
||||
|
||||
while True:
|
||||
def redraw():
|
||||
repeated_win.erase()
|
||||
repeated_win.border()
|
||||
repeated_win.addstr(1, 2, "Edit up to 3 Values:", get_color("settings_default", bold=True))
|
||||
|
||||
# Display current values, allowing editing
|
||||
for i, line in enumerate(user_values):
|
||||
prefix = "→ " if i == cursor_pos else " " # Highlight the current line
|
||||
prefix = "→ " if i == cursor_pos else " "
|
||||
repeated_win.addstr(
|
||||
3 + i, 2, f"{prefix}Value{i + 1}: ", get_color("settings_default", bold=(i == cursor_pos))
|
||||
)
|
||||
repeated_win.addstr(3 + i, 18, line)
|
||||
repeated_win.addstr(3 + i, 18, line[: width - 20]) # Prevent overflow
|
||||
|
||||
# Move cursor to the correct position inside the field
|
||||
curses.curs_set(1)
|
||||
repeated_win.move(3 + cursor_pos, 18 + len(user_values[cursor_pos])) # Position cursor at end of text
|
||||
|
||||
# Show error message if needed
|
||||
if invalid_input:
|
||||
repeated_win.addstr(7, 2, invalid_input, get_color("settings_default", bold=True))
|
||||
repeated_win.addstr(7, 2, invalid_input[: width - 4], get_color("settings_default", bold=True))
|
||||
|
||||
repeated_win.move(3 + cursor_pos, 18 + len(user_values[cursor_pos]))
|
||||
repeated_win.refresh()
|
||||
key = repeated_win.getch()
|
||||
|
||||
if key == 27 or key == curses.KEY_LEFT: # Escape or Left Arrow -> Cancel and return original
|
||||
while True:
|
||||
if menu_state.need_redraw:
|
||||
menu_state.need_redraw = False
|
||||
redraw()
|
||||
|
||||
redraw()
|
||||
|
||||
try:
|
||||
key = repeated_win.get_wch()
|
||||
except curses.error:
|
||||
continue # ignore timeout or input issues
|
||||
|
||||
if key in (27, curses.KEY_LEFT): # ESC or Left Arrow
|
||||
repeated_win.erase()
|
||||
repeated_win.refresh()
|
||||
curses.noecho()
|
||||
curses.curs_set(0)
|
||||
menu_state.need_redraw = True
|
||||
return None
|
||||
|
||||
elif key == ord("\n"): # Enter key to save and return
|
||||
elif key in ("\n", curses.KEY_ENTER):
|
||||
curses.noecho()
|
||||
curses.curs_set(0)
|
||||
return ", ".join(user_values)
|
||||
elif key == curses.KEY_UP: # Move cursor up
|
||||
cursor_pos = (cursor_pos - 1) % len(user_values)
|
||||
elif key == curses.KEY_DOWN: # Move cursor down
|
||||
cursor_pos = (cursor_pos + 1) % len(user_values)
|
||||
elif key == curses.KEY_BACKSPACE or key == 127: # Backspace key
|
||||
if len(user_values[cursor_pos]) > 0:
|
||||
user_values[cursor_pos] = user_values[cursor_pos][:-1] # Remove last character
|
||||
menu_state.need_redraw = True
|
||||
return ", ".join(user_values).strip()
|
||||
elif key == curses.KEY_UP:
|
||||
cursor_pos = (cursor_pos - 1) % 3
|
||||
elif key == curses.KEY_DOWN:
|
||||
cursor_pos = (cursor_pos + 1) % 3
|
||||
elif key in (curses.KEY_BACKSPACE, 127):
|
||||
user_values[cursor_pos] = user_values[cursor_pos][:-1]
|
||||
else:
|
||||
try:
|
||||
user_values[cursor_pos] += chr(key) # Append valid character input to the selected field
|
||||
invalid_input = "" # Clear error if user starts fixing input
|
||||
except ValueError:
|
||||
pass # Ignore invalid character inputs
|
||||
ch = chr(key) if isinstance(key, int) else key
|
||||
if ch.isprintable():
|
||||
user_values[cursor_pos] += ch
|
||||
invalid_input = ""
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
from contact.utilities.singleton import menu_state # Ensure this is imported
|
||||
|
||||
|
||||
def get_fixed32_input(current_value: int) -> int:
|
||||
cvalue = current_value
|
||||
current_value = str(ipaddress.IPv4Address(current_value))
|
||||
original_value = current_value
|
||||
ip_string = str(ipaddress.IPv4Address(current_value))
|
||||
height = 10
|
||||
width = 80
|
||||
start_y = (curses.LINES - height) // 2
|
||||
@@ -393,55 +410,67 @@ def get_fixed32_input(current_value: int) -> int:
|
||||
fixed32_win.bkgd(get_color("background"))
|
||||
fixed32_win.attrset(get_color("window_frame"))
|
||||
fixed32_win.keypad(True)
|
||||
fixed32_win.timeout(200)
|
||||
|
||||
curses.echo()
|
||||
curses.curs_set(1)
|
||||
user_input = ""
|
||||
|
||||
while True:
|
||||
def redraw():
|
||||
fixed32_win.erase()
|
||||
fixed32_win.border()
|
||||
fixed32_win.addstr(1, 2, "Enter an IP address (xxx.xxx.xxx.xxx):", curses.A_BOLD)
|
||||
fixed32_win.addstr(3, 2, f"Current: {current_value}")
|
||||
fixed32_win.addstr(5, 2, f"New value: {user_input}")
|
||||
fixed32_win.addstr(1, 2, "Enter an IP address (xxx.xxx.xxx.xxx):", get_color("settings_default", bold=True))
|
||||
fixed32_win.addstr(3, 2, f"Current: {ip_string}", get_color("settings_default"))
|
||||
fixed32_win.addstr(5, 2, f"New value: {user_input}", get_color("settings_default"))
|
||||
fixed32_win.refresh()
|
||||
|
||||
key = fixed32_win.getch()
|
||||
while True:
|
||||
if menu_state.need_redraw:
|
||||
menu_state.need_redraw = False
|
||||
redraw()
|
||||
|
||||
if key == 27 or key == curses.KEY_LEFT: # Escape or Left Arrow to cancel
|
||||
redraw()
|
||||
|
||||
try:
|
||||
key = fixed32_win.get_wch()
|
||||
except curses.error:
|
||||
continue # ignore timeout
|
||||
|
||||
if key in (27, curses.KEY_LEFT): # ESC or Left Arrow to cancel
|
||||
fixed32_win.erase()
|
||||
fixed32_win.refresh()
|
||||
curses.noecho()
|
||||
curses.curs_set(0)
|
||||
return cvalue # Return the current value unchanged
|
||||
elif key == ord("\n"): # Enter key to validate and save
|
||||
# Validate IP address
|
||||
menu_state.need_redraw = True
|
||||
return original_value
|
||||
|
||||
elif key in ("\n", curses.KEY_ENTER):
|
||||
octets = user_input.split(".")
|
||||
if len(octets) == 4 and all(octet.isdigit() and 0 <= int(octet) <= 255 for octet in octets):
|
||||
curses.noecho()
|
||||
curses.curs_set(0)
|
||||
fixed32_address = ipaddress.ip_address(user_input)
|
||||
return int(fixed32_address) # Return the valid IP address
|
||||
menu_state.need_redraw = True
|
||||
return int(ipaddress.ip_address(user_input))
|
||||
else:
|
||||
fixed32_win.addstr(7, 2, "Invalid IP address. Try again.", curses.A_BOLD | curses.color_pair(5))
|
||||
fixed32_win.addstr(7, 2, "Invalid IP address. Try again.", get_color("settings_default", bold=True))
|
||||
fixed32_win.refresh()
|
||||
curses.napms(1500) # Wait for 1.5 seconds before refreshing
|
||||
user_input = "" # Clear invalid input
|
||||
elif key == curses.KEY_BACKSPACE or key == 127: # Backspace key
|
||||
curses.napms(1500)
|
||||
menu_state.need_redraw = True
|
||||
user_input = ""
|
||||
|
||||
elif key in (curses.KEY_BACKSPACE, 127):
|
||||
user_input = user_input[:-1]
|
||||
|
||||
else:
|
||||
try:
|
||||
char = chr(key)
|
||||
if char.isdigit() or char == ".":
|
||||
user_input += char # Append only valid characters (digits or dots)
|
||||
except ValueError:
|
||||
pass # Ignore invalid inputs
|
||||
ch = chr(key) if isinstance(key, int) else key
|
||||
if ch.isdigit() or ch == ".":
|
||||
user_input += ch
|
||||
except Exception:
|
||||
pass # Ignore unprintable inputs
|
||||
|
||||
|
||||
def get_list_input(prompt: str, current_option: Optional[str], list_options: List[str]) -> Optional[str]:
|
||||
"""
|
||||
Displays a scrollable list of list_options for the user to choose from.
|
||||
"""
|
||||
selected_index = list_options.index(current_option) if current_option in list_options else 0
|
||||
|
||||
height = min(len(list_options) + 5, curses.LINES)
|
||||
@@ -450,6 +479,7 @@ def get_list_input(prompt: str, current_option: Optional[str], list_options: Lis
|
||||
start_x = (curses.COLS - width) // 2
|
||||
|
||||
list_win = curses.newwin(height, width, start_y, start_x)
|
||||
list_win.timeout(200)
|
||||
list_win.bkgd(get_color("background"))
|
||||
list_win.attrset(get_color("window_frame"))
|
||||
list_win.keypad(True)
|
||||
@@ -457,36 +487,44 @@ def get_list_input(prompt: str, current_option: Optional[str], list_options: Lis
|
||||
list_pad = curses.newpad(len(list_options) + 1, width - 8)
|
||||
list_pad.bkgd(get_color("background"))
|
||||
|
||||
# Render header
|
||||
list_win.erase()
|
||||
list_win.border()
|
||||
list_win.addstr(1, 2, prompt, get_color("settings_default", bold=True))
|
||||
|
||||
# Render options on the pad
|
||||
for idx, color in enumerate(list_options):
|
||||
if idx == selected_index:
|
||||
list_pad.addstr(idx, 0, color.ljust(width - 8), get_color("settings_default", reverse=True))
|
||||
else:
|
||||
list_pad.addstr(idx, 0, color.ljust(width - 8), get_color("settings_default"))
|
||||
|
||||
# Initial refresh
|
||||
list_win.refresh()
|
||||
list_pad.refresh(
|
||||
0,
|
||||
0,
|
||||
list_win.getbegyx()[0] + 3,
|
||||
list_win.getbegyx()[1] + 4,
|
||||
list_win.getbegyx()[0] + list_win.getmaxyx()[0] - 2,
|
||||
list_win.getbegyx()[1] + list_win.getmaxyx()[1] - 4,
|
||||
)
|
||||
|
||||
max_index = len(list_options) - 1
|
||||
visible_height = list_win.getmaxyx()[0] - 5
|
||||
|
||||
draw_arrows(list_win, visible_height, max_index, [0], show_save_option=False) # Initial call to draw arrows
|
||||
def redraw_list_ui():
|
||||
list_win.erase()
|
||||
list_win.border()
|
||||
list_win.addstr(1, 2, prompt, get_color("settings_default", bold=True))
|
||||
|
||||
for idx, color in enumerate(list_options):
|
||||
if idx == selected_index:
|
||||
list_pad.addstr(idx, 0, color.ljust(width - 8), get_color("settings_default", reverse=True))
|
||||
else:
|
||||
list_pad.addstr(idx, 0, color.ljust(width - 8), get_color("settings_default"))
|
||||
|
||||
list_win.refresh()
|
||||
list_pad.refresh(
|
||||
0,
|
||||
0,
|
||||
list_win.getbegyx()[0] + 3,
|
||||
list_win.getbegyx()[1] + 4,
|
||||
list_win.getbegyx()[0] + list_win.getmaxyx()[0] - 2,
|
||||
list_win.getbegyx()[1] + list_win.getmaxyx()[1] - 4,
|
||||
)
|
||||
|
||||
draw_arrows(list_win, visible_height, max_index, [0], show_save_option=False)
|
||||
|
||||
# Initial draw
|
||||
redraw_list_ui()
|
||||
|
||||
while True:
|
||||
key = list_win.getch()
|
||||
if menu_state.need_redraw:
|
||||
menu_state.need_redraw = False
|
||||
redraw_list_ui()
|
||||
|
||||
try:
|
||||
key = list_win.getch()
|
||||
except curses.error:
|
||||
continue # Graceful timeout handling
|
||||
|
||||
if key == curses.KEY_UP:
|
||||
old_selected_index = selected_index
|
||||
@@ -499,8 +537,10 @@ def get_list_input(prompt: str, current_option: Optional[str], list_options: Lis
|
||||
elif key == ord("\n"): # Enter key
|
||||
list_win.clear()
|
||||
list_win.refresh()
|
||||
menu_state.need_redraw = True
|
||||
return list_options[selected_index]
|
||||
elif key == 27 or key == curses.KEY_LEFT: # ESC or Left Arrow
|
||||
list_win.clear()
|
||||
list_win.refresh()
|
||||
menu_state.need_redraw = True
|
||||
return current_option
|
||||
|
||||
Reference in New Issue
Block a user