Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

python ui: wifi manager #34594

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions system/ui/lib/keyboard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import pyray as rl
from openpilot.system.ui.lib.button import gui_button
from openpilot.system.ui.lib.label import gui_label

# Constants for special keys
BACKSPACE_KEY = "<-"
ENTER_KEY = "Enter"
SPACE_KEY = " "
SHIFT_KEY = "↑"
SHIFT_DOWN_KEY = "↓"
NUMERIC_KEY = "123"
SYMBOL_KEY = "#+="
ABC_KEY = "ABC"

# Define keyboard layouts as a dictionary for easier access
keyboard_layouts = {
"lowercase": [
["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"],
["a", "s", "d", "f", "g", "h", "j", "k", "l"],
[SHIFT_KEY, "z", "x", "c", "v", "b", "n", "m", BACKSPACE_KEY],
[NUMERIC_KEY, "/", "-", SPACE_KEY, ".", ENTER_KEY],
],
"uppercase": [
["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"],
["A", "S", "D", "F", "G", "H", "J", "K", "L"],
[SHIFT_DOWN_KEY, "Z", "X", "C", "V", "B", "N", "M", BACKSPACE_KEY],
[NUMERIC_KEY, "/", "-", SPACE_KEY, ".", ENTER_KEY],
],
"numbers": [
["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"],
["-", "/", ":", ";", "(", ")", "$", "&", "@", "\""],
[SYMBOL_KEY, ".", ",", "?", "!", "`", BACKSPACE_KEY],
[ABC_KEY, SPACE_KEY, ".", ENTER_KEY],
],
"specials": [
["[", "]", "{", "}", "#", "%", "^", "*", "+", "="],
["_", "\\", "|", "~", "<", ">", "€", "£", "¥", "•"],
[NUMERIC_KEY, ".", ",", "?", "!", "'", BACKSPACE_KEY],
[ABC_KEY, SPACE_KEY, ".", ENTER_KEY],
],
}


class Keyboard:
def __init__(self, max_text_size: int = 255):
self._layout = keyboard_layouts["lowercase"]
self._input_text = ""
self._max_text_size = max_text_size

@property
def text(self) -> str:
return self._input_text

def clear(self):
self._input_text = ""

def render(self, rect, title, sub_title):
gui_label((rect.x, rect.y, rect.width, 95), title, 90)
gui_label((rect.x, rect.y + 95, rect.width, 60), sub_title, 55, rl.GRAY)
gui_button((rect.x + rect.width - 300, rect.y, 300, 100), "Cancel")

# Text box for input
rl.gui_text_box(rl.Rectangle(rect.x, rect.y + 160, rect.width, 100), self._input_text, self._max_text_size, True)

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
key_max_width = (rect.width - (len(self._layout[2]) - 1) * h_space) / len(self._layout[2])

# Iterate over the rows of keys in the current layout
for row, keys in enumerate(self._layout):
key_width = min((rect.width - (180 if row == 1 else 0) - h_space * (len(keys) - 1)) / len(keys), key_max_width)
start_x = rect.x + (90 if row == 1 else 0)

for i, key in enumerate(keys):
if i > 0:
start_x += h_space

new_width = (key_width * 3 + h_space * 2) if key == SPACE_KEY else (key_width * 2 + h_space if key == ENTER_KEY else key_width)
key_rect = rl.Rectangle(start_x, row_y_start + row * (key_height + v_space), new_width, key_height)
start_x += new_width

if rl.gui_button(key_rect, key):
if key == ENTER_KEY:
return 1
else:
self.handle_key_press(key)

return 0

def handle_key_press(self, key):
if key in (SHIFT_DOWN_KEY, ABC_KEY):
self._layout = keyboard_layouts["lowercase"]
elif key == SHIFT_KEY:
self._layout = keyboard_layouts["uppercase"]
elif key == NUMERIC_KEY:
self._layout = keyboard_layouts["numbers"]
elif key == SYMBOL_KEY:
self._layout = keyboard_layouts["specials"]
elif key == BACKSPACE_KEY and len(self._input_text) > 0:
self._input_text = self._input_text[:-1]
elif key != BACKSPACE_KEY and len(self._input_text) < self._max_text_size:
self._input_text += key
10 changes: 7 additions & 3 deletions system/ui/lib/label.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import pyray as rl
from openpilot.system.ui.lib.utils import GuiStyleContext

def gui_label(rect, text, font_size):

def gui_label(rect, text, font_size, color: rl.Color = None, alignment: rl.GuiTextAlignment = rl.GuiTextAlignment.TEXT_ALIGN_LEFT):
styles = [
(rl.GuiControl.DEFAULT, rl.GuiDefaultProperty.TEXT_SIZE, font_size),
(rl.GuiControl.DEFAULT, rl.GuiDefaultProperty.TEXT_LINE_SPACING, font_size),
(rl.GuiControl.DEFAULT, rl.GuiDefaultProperty.TEXT_ALIGNMENT_VERTICAL, rl.GuiTextAlignmentVertical.TEXT_ALIGN_TOP),
(rl.GuiControl.DEFAULT, rl.GuiDefaultProperty.TEXT_WRAP_MODE, rl.GuiTextWrapMode.TEXT_WRAP_WORD)
(rl.GuiControl.DEFAULT, rl.GuiDefaultProperty.TEXT_ALIGNMENT_VERTICAL, rl.GuiTextAlignmentVertical.TEXT_ALIGN_MIDDLE),
(rl.GuiControl.DEFAULT, rl.GuiDefaultProperty.TEXT_WRAP_MODE, rl.GuiTextWrapMode.TEXT_WRAP_WORD),
(rl.GuiControl.DEFAULT, rl.GuiControlProperty.TEXT_ALIGNMENT, alignment)
]
if color:
styles.append((rl.GuiControl.LABEL, rl.GuiControlProperty.TEXT_COLOR_NORMAL, rl.color_to_int(color)))

with GuiStyleContext(styles):
rl.gui_label(rect, text)
18 changes: 8 additions & 10 deletions system/ui/lib/scroll_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,17 @@

MOUSE_WHEEL_SCROLL_SPEED = 30


class GuiScrollPanel:
def __init__(self, bounds: rl.Rectangle, content: rl.Rectangle, show_vertical_scroll_bar: bool = False):
def __init__(self):
self._dragging: bool = False
self._last_mouse_y: float = 0.0
self._bounds = bounds
self._content = content
self._scroll = rl.Vector2(0, 0)
self._scroll: rl.Vector2 = rl.Vector2(0, 0)
self._view = rl.Rectangle(0, 0, 0, 0)
self._show_vertical_scroll_bar: bool = show_vertical_scroll_bar

def handle_scroll(self)-> rl.Vector2:
def handle_scroll(self, bounds: rl.Rectangle, content: rl.Rectangle, show_vertical_scroll_bar: bool = False) -> rl.Vector2:
mouse_pos = rl.get_mouse_position()
if rl.check_collision_point_rec(mouse_pos, self._bounds) and rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_LEFT):
if rl.check_collision_point_rec(mouse_pos, bounds) and rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_LEFT):
if not self._dragging:
self._dragging = True
self._last_mouse_y = mouse_pos.y
Expand All @@ -29,12 +27,12 @@ def handle_scroll(self)-> rl.Vector2:
self._dragging = False

wheel_move = rl.get_mouse_wheel_move()
if self._show_vertical_scroll_bar:
if show_vertical_scroll_bar:
self._scroll.y += wheel_move * (MOUSE_WHEEL_SCROLL_SPEED - 20)
rl.gui_scroll_panel(self._bounds, FFI().NULL, self._content, self._scroll, self._view)
rl.gui_scroll_panel(bounds, FFI().NULL, content, self._scroll, self._view)
else:
self._scroll.y += wheel_move * MOUSE_WHEEL_SCROLL_SPEED
max_scroll_y = self._content.height - self._bounds.height
max_scroll_y = max(content.height - bounds.height, 0)
self._scroll.y = max(min(self._scroll.y, 0), -max_scroll_y)

return self._scroll
Loading
Loading