Fix cursor position and live timer updates

- Track cursor position in UIManager.cursor_pos
- Restore cursor after print_message() and update_server_info()
- Sync cursor_pos between wait_stdin thread and manager
- Update server info panel every second for live timer display
- Timer now ticks continuously instead of only on game events
This commit is contained in:
pfl
2026-01-09 14:58:05 +01:00
parent a03b4b0b93
commit fbaa4564e4
2 changed files with 25 additions and 2 deletions

View File

@ -367,6 +367,9 @@ def main_loop(screen):
# Shutdown flag # Shutdown flag
shutdown = False shutdown = False
# Timer refresh tracking (update UI once per second)
last_ui_update = 0
# Setup JSON logging if requested # Setup JSON logging if requested
json_logger = None json_logger = None
if args.json_log: if args.json_log:
@ -525,6 +528,12 @@ def main_loop(screen):
formatted_msg, attributes = format_message(message) formatted_msg, attributes = format_message(message)
ui.print_message(formatted_msg) ui.print_message(formatted_msg)
# Update server info panel every second (for live timer display)
current_time = time.time()
if current_time - last_ui_update >= 1.0:
ui.update_server_info(game_state)
last_ui_update = current_time
finally: finally:
# Clean up resources # Clean up resources
logger.info("Shutting down...") logger.info("Shutting down...")

18
ui.py
View File

@ -200,6 +200,7 @@ class UIManager:
self.input_queue = None self.input_queue = None
self.command_history = [] self.command_history = []
self.history_index = -1 self.history_index = -1
self.cursor_pos = 0 # Track cursor position in input
self._init_curses() self._init_curses()
self._create_windows() self._create_windows()
@ -290,6 +291,7 @@ class UIManager:
def wait_stdin(q, window, manager): def wait_stdin(q, window, manager):
current_input = "" current_input = ""
cursor_pos = 0 cursor_pos = 0
manager.cursor_pos = 0 # Keep manager in sync
temp_history_index = -1 temp_history_index = -1
temp_input = "" # Temp storage when navigating history temp_input = "" # Temp storage when navigating history
quit_confirm = False quit_confirm = False
@ -325,6 +327,7 @@ class UIManager:
words[-1] = suggestions[suggestion_index] words[-1] = suggestions[suggestion_index]
current_input = ' '.join(words) current_input = ' '.join(words)
cursor_pos = len(current_input) cursor_pos = len(current_input)
manager.cursor_pos = cursor_pos
# Update display # Update display
window.erase() window.erase()
@ -387,6 +390,7 @@ class UIManager:
q.put(current_input) q.put(current_input)
current_input = "" current_input = ""
cursor_pos = 0 cursor_pos = 0
manager.cursor_pos = cursor_pos
temp_history_index = -1 temp_history_index = -1
temp_input = "" temp_input = ""
suggestions = [] suggestions = []
@ -407,6 +411,7 @@ class UIManager:
temp_history_index -= 1 temp_history_index -= 1
current_input = manager.command_history[temp_history_index] current_input = manager.command_history[temp_history_index]
cursor_pos = len(current_input) cursor_pos = len(current_input)
manager.cursor_pos = cursor_pos
suggestions = [] suggestions = []
suggestion_index = -1 suggestion_index = -1
original_word = "" original_word = ""
@ -427,6 +432,7 @@ class UIManager:
current_input = manager.command_history[temp_history_index] current_input = manager.command_history[temp_history_index]
cursor_pos = len(current_input) cursor_pos = len(current_input)
manager.cursor_pos = cursor_pos
suggestions = [] suggestions = []
suggestion_index = -1 suggestion_index = -1
original_word = "" original_word = ""
@ -438,6 +444,7 @@ class UIManager:
elif key == curses.KEY_LEFT: elif key == curses.KEY_LEFT:
if cursor_pos > 0: if cursor_pos > 0:
cursor_pos -= 1 cursor_pos -= 1
manager.cursor_pos = cursor_pos
window.move(0, cursor_pos) window.move(0, cursor_pos)
window.noutrefresh() window.noutrefresh()
@ -445,6 +452,7 @@ class UIManager:
elif key == curses.KEY_RIGHT: elif key == curses.KEY_RIGHT:
if cursor_pos < len(current_input): if cursor_pos < len(current_input):
cursor_pos += 1 cursor_pos += 1
manager.cursor_pos = cursor_pos
window.move(0, cursor_pos) window.move(0, cursor_pos)
window.noutrefresh() window.noutrefresh()
@ -453,6 +461,7 @@ class UIManager:
if cursor_pos > 0: if cursor_pos > 0:
current_input = current_input[:cursor_pos-1] + current_input[cursor_pos:] current_input = current_input[:cursor_pos-1] + current_input[cursor_pos:]
cursor_pos -= 1 cursor_pos -= 1
manager.cursor_pos = cursor_pos
temp_history_index = -1 # Exit history mode temp_history_index = -1 # Exit history mode
window.erase() window.erase()
@ -477,6 +486,7 @@ class UIManager:
char = chr(key) char = chr(key)
current_input = current_input[:cursor_pos] + char + current_input[cursor_pos:] current_input = current_input[:cursor_pos] + char + current_input[cursor_pos:]
cursor_pos += 1 cursor_pos += 1
manager.cursor_pos = cursor_pos
temp_history_index = -1 # Exit history mode temp_history_index = -1 # Exit history mode
window.erase() window.erase()
@ -521,7 +531,9 @@ class UIManager:
"""Print formatted message to output window""" """Print formatted message to output window"""
print_colored(self.output_window, message, attributes) print_colored(self.output_window, message, attributes)
self.output_window.noutrefresh() self.output_window.noutrefresh()
self.input_window.move(0, 0) # Restore cursor to input window at current position
self.input_window.move(0, self.cursor_pos)
self.input_window.noutrefresh()
curses.doupdate() curses.doupdate()
def update_server_info(self, game_state): def update_server_info(self, game_state):
@ -709,5 +721,7 @@ class UIManager:
print_colored(self.info_window, separator, 0) print_colored(self.info_window, separator, 0)
self.info_window.noutrefresh() self.info_window.noutrefresh()
# Restore cursor to input window at current position
self.input_window.move(0, self.cursor_pos)
self.input_window.noutrefresh()
curses.doupdate() curses.doupdate()