|
|
|
@ -1,8 +1,10 @@ |
|
|
|
|
import pyray as rl |
|
|
|
|
import time |
|
|
|
|
from openpilot.system.ui.lib.application import gui_app |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PASSWORD_MASK_CHAR = "•" |
|
|
|
|
PASSWORD_MASK_DELAY = 1.5 # Seconds to show character before masking |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InputBox: |
|
|
|
@ -19,6 +21,8 @@ class InputBox: |
|
|
|
|
self._repeat_rate = 4 |
|
|
|
|
self._text_offset = 0 |
|
|
|
|
self._visible_width = 0 |
|
|
|
|
self._last_char_time = 0 # Track when last character was added |
|
|
|
|
self._masked_length = 0 # How many characters are currently masked |
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
def text(self): |
|
|
|
@ -52,7 +56,7 @@ class InputBox: |
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
font = gui_app.font() |
|
|
|
|
display_text = PASSWORD_MASK_CHAR * len(self._input_text) if self._password_mode else self._input_text |
|
|
|
|
display_text = self._get_display_text() |
|
|
|
|
padding = 10 |
|
|
|
|
|
|
|
|
|
if self._cursor_position > 0: |
|
|
|
@ -73,6 +77,10 @@ class InputBox: |
|
|
|
|
if len(self._input_text) < self._max_text_size: |
|
|
|
|
self._input_text = self._input_text[: self._cursor_position] + char + self._input_text[self._cursor_position :] |
|
|
|
|
self.set_cursor_position(self._cursor_position + 1) |
|
|
|
|
|
|
|
|
|
if self._password_mode: |
|
|
|
|
self._last_char_time = time.time() |
|
|
|
|
|
|
|
|
|
return True |
|
|
|
|
return False |
|
|
|
|
|
|
|
|
@ -114,7 +122,7 @@ class InputBox: |
|
|
|
|
|
|
|
|
|
# Display text |
|
|
|
|
font = gui_app.font() |
|
|
|
|
display_text = PASSWORD_MASK_CHAR * len(self._input_text) if self._password_mode else self._input_text |
|
|
|
|
display_text = self._get_display_text() |
|
|
|
|
padding = 10 |
|
|
|
|
|
|
|
|
|
# Clip text within input box bounds |
|
|
|
@ -144,6 +152,21 @@ class InputBox: |
|
|
|
|
|
|
|
|
|
rl.end_scissor_mode() |
|
|
|
|
|
|
|
|
|
def _get_display_text(self): |
|
|
|
|
"""Get text to display, applying password masking with delay if needed.""" |
|
|
|
|
if not self._password_mode: |
|
|
|
|
return self._input_text |
|
|
|
|
|
|
|
|
|
# Show character at last edited position if within delay window |
|
|
|
|
masked_text = PASSWORD_MASK_CHAR * len(self._input_text) |
|
|
|
|
recent_edit = time.time() - self._last_char_time < PASSWORD_MASK_DELAY |
|
|
|
|
if recent_edit and self._input_text: |
|
|
|
|
last_pos = max(0, self._cursor_position - 1) |
|
|
|
|
if last_pos < len(self._input_text): |
|
|
|
|
return masked_text[:last_pos] + self._input_text[last_pos] + masked_text[last_pos + 1 :] |
|
|
|
|
|
|
|
|
|
return masked_text |
|
|
|
|
|
|
|
|
|
def _handle_mouse_input(self, rect, font_size): |
|
|
|
|
"""Handle mouse clicks to position cursor.""" |
|
|
|
|
mouse_pos = rl.get_mouse_position() |
|
|
|
@ -151,7 +174,7 @@ class InputBox: |
|
|
|
|
# Calculate cursor position from click |
|
|
|
|
if len(self._input_text) > 0: |
|
|
|
|
font = gui_app.font() |
|
|
|
|
display_text = PASSWORD_MASK_CHAR * len(self._input_text) if self._password_mode else self._input_text |
|
|
|
|
display_text = self._get_display_text() |
|
|
|
|
|
|
|
|
|
# Find the closest character position to the click |
|
|
|
|
relative_x = mouse_pos.x - (rect.x + 10) + self._text_offset |
|
|
|
|