system/ui: add password visibility toggle with eye icon to keyboard (#35246)

* add password visibility toggle with eye icon to keyboard

* added show_password_toggle
pull/35249/head
Dean Lee 3 months ago committed by GitHub
parent a6456503b0
commit dcfbb99b13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 7
      system/ui/lib/inputbox.py
  2. 51
      system/ui/widgets/keyboard.py
  3. 2
      system/ui/widgets/network.py

@ -62,13 +62,12 @@ class InputBox:
return True
return False
def render(self, rect, color=rl.LIGHTGRAY, border_color=rl.DARKGRAY, text_color=rl.BLACK, font_size=80):
def render(self, rect, color=rl.BLACK, border_color=rl.DARKGRAY, text_color=rl.WHITE, font_size=80):
# Handle mouse input
self._handle_mouse_input(rect, font_size)
# Draw input box
rl.draw_rectangle_rec(rect, color)
rl.draw_rectangle_lines_ex(rect, 1, border_color)
# Process keyboard input
self._handle_keyboard_input()
@ -81,7 +80,7 @@ class InputBox:
# Display text
font = gui_app.font()
display_text = "" * len(self._input_text) if self._password_mode else self._input_text
display_text = "*" * len(self._input_text) if self._password_mode else self._input_text
padding = 10
rl.draw_text_ex(
font,
@ -100,7 +99,7 @@ class InputBox:
cursor_height = font_size + 4
cursor_y = rect.y + rect.height / 2 - cursor_height / 2
rl.draw_line(int(cursor_x), int(cursor_y), int(cursor_x), int(cursor_y + cursor_height), rl.BLACK)
rl.draw_line(int(cursor_x), int(cursor_y), int(cursor_x), int(cursor_y + cursor_height), rl.LIGHTGRAY)
def _handle_mouse_input(self, rect, font_size):
"""Handle mouse clicks to position cursor."""

@ -1,5 +1,5 @@
import pyray as rl
from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.lib.application import gui_app, FontWeight
from openpilot.system.ui.lib.button import gui_button
from openpilot.system.ui.lib.inputbox import InputBox
from openpilot.system.ui.lib.label import gui_label
@ -45,11 +45,16 @@ keyboard_layouts = {
class Keyboard:
def __init__(self, max_text_size: int = 255, min_text_size: int = 0):
def __init__(self, max_text_size: int = 255, min_text_size: int = 0, password_mode: bool = False, show_password_toggle: bool = False):
self._layout = keyboard_layouts["lowercase"]
self._max_text_size = max_text_size
self._min_text_size = min_text_size
self._input_box = InputBox(max_text_size)
self._password_mode = password_mode
self._show_password_toggle = show_password_toggle
self._eye_open_texture = gui_app.texture("icons/eye_open.png", 81, 54)
self._eye_closed_texture = gui_app.texture("icons/eye_closed.png", 81, 54)
@property
def text(self):
@ -60,14 +65,17 @@ class Keyboard:
def render(self, title: str, sub_title: str):
rect = rl.Rectangle(CONTENT_MARGIN, CONTENT_MARGIN, gui_app.width - 2 * CONTENT_MARGIN, gui_app.height - 2 * CONTENT_MARGIN)
gui_label(rl.Rectangle(rect.x, rect.y, rect.width, 95), title, 90)
gui_label(rl.Rectangle(rect.x, rect.y + 95, rect.width, 60), sub_title, 55, rl.GRAY)
if gui_button(rl.Rectangle(rect.x + rect.width - 300, rect.y, 300, 100), "Cancel"):
gui_label(rl.Rectangle(rect.x, rect.y, rect.width, 95), title, 90, font_weight=FontWeight.BOLD)
gui_label(rl.Rectangle(rect.x, rect.y + 95, rect.width, 60), sub_title, 55, font_weight=FontWeight.NORMAL)
if gui_button(rl.Rectangle(rect.x + rect.width - 386, rect.y, 386, 125), "Cancel"):
self.clear()
return 0
# Text box for input
self._input_box.render(rl.Rectangle(rect.x, rect.y + 160, rect.width, 100))
# Draw input box and password toggle
input_margin = 25
input_box_rect = rl.Rectangle(rect.x + input_margin, rect.y + 160, rect.width - input_margin, 100)
self._render_input_area(input_box_rect)
h_space, v_space = 15, 15
row_y_start = rect.y + 300 # Starting Y position for the first row
key_height = (rect.height - 300 - 3 * v_space) / 4
@ -95,6 +103,35 @@ class Keyboard:
return -1
def _render_input_area(self, input_rect: rl.Rectangle):
if self._show_password_toggle:
self._input_box.set_password_mode(self._password_mode)
self._input_box.render(rl.Rectangle(input_rect.x, input_rect.y, input_rect.width - 100, input_rect.height))
# render eye icon
eye_texture = self._eye_closed_texture if self._password_mode else self._eye_open_texture
eye_rect = rl.Rectangle(input_rect.x + input_rect.width - 90, input_rect.y, 80, input_rect.height)
eye_x = eye_rect.x + (eye_rect.width - eye_texture.width) / 2
eye_y = eye_rect.y + (eye_rect.height - eye_texture.height) / 2
rl.draw_texture_v(eye_texture, rl.Vector2(eye_x, eye_y), rl.WHITE)
# Handle click on eye icon
if rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_LEFT) and rl.check_collision_point_rec(
rl.get_mouse_position(), eye_rect
):
self._password_mode = not self._password_mode
else:
self._input_box.render(input_rect)
rl.draw_line_ex(
rl.Vector2(input_rect.x, input_rect.y + input_rect.height - 2),
rl.Vector2(input_rect.x + input_rect.width, input_rect.y + input_rect.height - 2),
3.0, # 3 pixel thickness
rl.Color(189, 189, 189, 255),
)
def handle_key_press(self, key):
if key in (SHIFT_DOWN_KEY, ABC_KEY):
self._layout = keyboard_layouts["lowercase"]

@ -48,7 +48,7 @@ class WifiManagerUI:
self.state: UIState = StateIdle()
self.btn_width = 200
self.scroll_panel = GuiScrollPanel()
self.keyboard = Keyboard(max_text_size=MAX_PASSWORD_LENGTH, min_text_size=MIN_PASSWORD_LENGTH)
self.keyboard = Keyboard(max_text_size=MAX_PASSWORD_LENGTH, min_text_size=MIN_PASSWORD_LENGTH, show_password_toggle=True)
self._networks: list[NetworkInfo] = []

Loading…
Cancel
Save