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

Improved keyboard #113

Merged
merged 3 commits into from
Jun 9, 2024
Merged
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
153 changes: 124 additions & 29 deletions modules/app_components/dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,21 @@
from events.input import BUTTON_TYPES, ButtonDownEvent
from system.eventbus import eventbus

from .tokens import label_font_size, set_color
from .tokens import button_labels, label_font_size, set_color

SPECIAL_KEY_META = "..."
SPECIAL_KEY_DONE = "Done"
SPECIAL_KEY_BACK = "Back"
SPECIAL_KEY_CANCEL = "Cancel"
SPECIAL_KEY_BACKSPACE = "Bksp"
SPECIAL_KEY_SYMBOL = "Sym"
SPECIAL_KEY_SHIFT = "Shift"
SPECIAL_KEY_CAPS = "Caps Lock"
SPECIAL_KEY_SPACE = "Space"

LOWERCASE_ALPHABET = list("abcdefghijklmnopqrstuvwxyz")
UPPERCASE_ALPHABET = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890")
SYMBOL_ALPHABET = list("-=!\"£$%^&*()_+[];'#,./{}:@~<>?") + [SPECIAL_KEY_SPACE]


class YesNoDialog:
Expand Down Expand Up @@ -52,6 +66,7 @@ def draw(self, ctx):
display.hexagon(ctx, 0, 0, 120)

self.draw_message(ctx)
button_labels(ctx, confirm_label="Yes", cancel_label="No")
ctx.restore()

def _handle_buttondown(self, event: ButtonDownEvent):
Expand All @@ -69,8 +84,6 @@ def _handle_buttondown(self, event: ButtonDownEvent):


class TextDialog:
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890-=!\"£$%^&*()_+[];'#,./{}:@~<>?"

def __init__(self, message, app, masked=False, on_complete=None, on_cancel=None):
self.open = True
self.app = app
Expand All @@ -79,9 +92,45 @@ def __init__(self, message, app, masked=False, on_complete=None, on_cancel=None)
self.complete_handler = on_complete
self.masked = masked
self.text = ""
self.current = 0
self._current_alphabet = LOWERCASE_ALPHABET
self._keys = []
self._caps = False
self._layer = 0
self._result = None
eventbus.on(ButtonDownEvent, self._handle_buttondown, self.app)
self._update_keys()

def _update_keys(self):
if self._layer == -1:
self._keys = [
[SPECIAL_KEY_CANCEL],
[SPECIAL_KEY_SYMBOL],
[SPECIAL_KEY_SHIFT],
[SPECIAL_KEY_CAPS],
[SPECIAL_KEY_BACKSPACE],
[SPECIAL_KEY_BACK],
]
return

buttons = 4 if self._layer == 0 else 6
group_size = len(self._current_alphabet) // buttons

if group_size == 0:
group_size = 1

self._keys = []
for i in range(buttons):
start_index = group_size * i
end_index = (group_size * i) + group_size

if i + 1 == buttons:
end_index = len(self._current_alphabet)

self._keys.append(self._current_alphabet[start_index:end_index])

if self._layer == 0:
self._keys.insert(4, [SPECIAL_KEY_META])
self._keys.insert(2, [SPECIAL_KEY_DONE])

def _cleanup(self):
eventbus.remove(ButtonDownEvent, self._handle_buttondown, self.app)
Expand All @@ -107,10 +156,7 @@ def draw_message(self, ctx):

ctx.move_to(0, -15).text(self.message)
ctx.move_to(0, 15).text(
(self.text if not self.masked else ("*" * len(self.text)))
+ "["
+ self.alphabet[self.current]
+ "]"
self.text if not self.masked else ("*" * len(self.text))
)

def draw(self, ctx):
Expand All @@ -119,30 +165,79 @@ def draw(self, ctx):
display.hexagon(ctx, 0, 0, 120)

self.draw_message(ctx)
if len(self._keys) == 6:
button_labels(
ctx,
up_label="".join(self._keys[0]),
down_label="".join(self._keys[3]),
left_label="".join(self._keys[4]),
right_label="".join(self._keys[1]),
confirm_label="".join(self._keys[2]),
cancel_label="".join(self._keys[5]),
)

ctx.restore()

def _handle_buttondown(self, event: ButtonDownEvent):
if BUTTON_TYPES["CANCEL"] in event.button:
self._cleanup()
self._result = False
if self.cancel_handler is not None:
self.cancel_handler()

if BUTTON_TYPES["CONFIRM"] in event.button:
self._cleanup()
self._result = self.text
if self.complete_handler is not None:
self.complete_handler()
key = -1

if BUTTON_TYPES["UP"] in event.button:
self.current = (self.current - 1) % len(self.alphabet)

if BUTTON_TYPES["DOWN"] in event.button:
self.current = (self.current + 1) % len(self.alphabet)

if BUTTON_TYPES["RIGHT"] in event.button:
self.text += self.alphabet[self.current]

if BUTTON_TYPES["LEFT"] in event.button:
if len(self.text) > 0:
key = 0
elif BUTTON_TYPES["RIGHT"] in event.button:
key = 1
elif BUTTON_TYPES["DOWN"] in event.button:
key = 3
elif BUTTON_TYPES["LEFT"] in event.button:
key = 4
elif BUTTON_TYPES["CANCEL"] in event.button:
key = 5
elif BUTTON_TYPES["CONFIRM"] in event.button:
key = 2

if key == -1:
return

selected = self._keys[key]
if len(selected) == 1:
selected = self._keys[key][0]

if selected == SPECIAL_KEY_SPACE:
selected = " "

if selected == SPECIAL_KEY_DONE:
self._cleanup()
self._result = self.text
if self.complete_handler is not None:
self.complete_handler()
elif selected == SPECIAL_KEY_CANCEL:
self._cleanup()
self._result = False
if self.cancel_handler is not None:
self.cancel_handler()
elif selected == SPECIAL_KEY_BACKSPACE:
self.text = self.text[:-1]
elif selected == SPECIAL_KEY_BACK:
self._layer = 0
elif selected == SPECIAL_KEY_META:
self._layer = -1
elif selected == SPECIAL_KEY_SYMBOL:
self._layer = 0
self._current_alphabet = SYMBOL_ALPHABET
elif selected == SPECIAL_KEY_SHIFT or selected == SPECIAL_KEY_CAPS:
self._layer = 0
self._current_alphabet = UPPERCASE_ALPHABET
if selected == SPECIAL_KEY_CAPS:
self._caps = True
else:
self.text += selected
self._layer = 0

if self._caps:
self._current_alphabet = UPPERCASE_ALPHABET
else:
self._current_alphabet = LOWERCASE_ALPHABET
elif len(selected) > 0:
self._current_alphabet = selected
self._layer = 1

self._update_keys()
34 changes: 34 additions & 0 deletions modules/app_components/tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@

# Font size
one_pt = ppi / 72
seven_pt = 7 * one_pt
ten_pt = 10 * one_pt
twelve_pt = 12 * one_pt
fourteen_pt = 14 * one_pt
sixteen_pt = 16 * one_pt
eighteen_pt = 18 * one_pt
twentyfour_pt = 24 * one_pt
small_font_size = seven_pt
label_font_size = ten_pt
heading_font_size = eighteen_pt

Expand Down Expand Up @@ -52,3 +54,35 @@ def clear_background(ctx):

def set_color(ctx, color):
ctx.rgb(*ui_colors.get(color, colors.get(color, color)))


def button_labels(
ctx,
up_label=None,
down_label=None,
left_label=None,
right_label=None,
cancel_label=None,
confirm_label=None,
):
set_color(ctx, "label")

ctx.font_size = small_font_size
ctx.text_align = ctx.CENTER
ctx.text_baseline = ctx.MIDDLE
if up_label is not None:
ctx.move_to(0, -100).text(up_label)
if down_label is not None:
ctx.move_to(0, 100).text(down_label)

ctx.text_align = ctx.RIGHT
if right_label is not None:
ctx.move_to(75, -75).text(right_label)
if confirm_label is not None:
ctx.move_to(75, 75).text(confirm_label)

ctx.text_align = ctx.LEFT
if cancel_label is not None:
ctx.move_to(-75, -75).text(cancel_label)
if left_label is not None:
ctx.move_to(-75, 75).text(left_label)
Loading