added char attribute to Text event

This commit is contained in:
Will McGugan
2022-09-04 11:02:24 +01:00
parent 1cc52bc913
commit b271ca7c2f
10 changed files with 72 additions and 29 deletions

View File

@@ -62,7 +62,7 @@ class FileSearchApp(App):
self.file_table.filter = event.value
app = FileSearchApp(log_path="textual.log", css_path="file_search.scss", watch_css=True)
app = FileSearchApp(css_path="file_search.scss", watch_css=True)
if __name__ == "__main__":
result = app.run()

View File

@@ -1,6 +1,6 @@
Screen {
layout: dock;
docks: top=top bottom=bottom;
}
#file_table_wrapper {

17
sandbox/will/input.py Normal file
View File

@@ -0,0 +1,17 @@
from textual.app import App
from textual.widgets import TextInput
class InputApp(App):
CSS = """
TextInput {
}
"""
def compose(self):
yield TextInput(initial="foo")
app = InputApp()

View File

@@ -101,7 +101,7 @@ class XTermParser(Parser[events.Event]):
key_events = sequence_to_key_events(character)
for event in key_events:
if event.key == "escape":
event = events.Key(event.sender, key="^")
event = events.Key(event.sender, "^", None)
on_token(event)
while not self.is_eof:
@@ -229,7 +229,21 @@ class XTermParser(Parser[events.Event]):
on_token(event)
def _sequence_to_key_events(self, sequence: str) -> Iterable[events.Key]:
default = (sequence,) if len(sequence) == 1 else ()
keys = ANSI_SEQUENCES_KEYS.get(sequence, default)
for key in keys:
yield events.Key(self.sender, key)
"""Map a sequence of code points on to a sequence of keys.
Args:
sequence (str): Sequence of code points.
Returns:
Iterable[events.Key]: keys
"""
keys = ANSI_SEQUENCES_KEYS.get(sequence)
if keys is not None:
for key in keys:
yield events.Key(
self.sender, key.value, sequence if len(sequence) == 1 else None
)
elif len(sequence) == 1:
yield events.Key(self.sender, sequence, sequence)

View File

@@ -656,7 +656,9 @@ class App(Generic[ReturnType], DOMNode):
await asyncio.sleep(0.05)
else:
print(f"press {key!r}")
driver.send_event(events.Key(self, key))
driver.send_event(
events.Key(self, key, key if len(key) == 1 else None)
)
await asyncio.sleep(0.01)
if screenshot:
self._screenshot = self.export_screenshot(

View File

@@ -188,18 +188,26 @@ class Key(InputEvent):
"""Sent when the user hits a key on the keyboard.
Args:
sender (MessageTarget): The sender of the event (the App)
key (str): The pressed key if a single character (or a longer string for special characters)
sender (MessageTarget): The sender of the event (the App).
key (str): A key name (textual.keys.Keys).
char (str | None, optional): A printable character or None if it is not printable.
"""
__slots__ = ["key"]
__slots__ = ["key", "char"]
def __init__(self, sender: MessageTarget, key: str) -> None:
def __init__(self, sender: MessageTarget, key: str, char: str | None) -> None:
super().__init__(sender)
self.key = key.value if isinstance(key, Keys) else key
self.key = key
self.char = (key if len(key) == 1 else None) if char is None else char
def __rich_repr__(self) -> rich.repr.Result:
yield "key", self.key
yield "char", self.char, None
@property
def key_name(self) -> str | None:
"""Name of a key suitable for use as a Python identifier."""
return self.key.replace("+", "_")
@property
def is_printable(self) -> bool:
@@ -209,7 +217,7 @@ class Key(InputEvent):
Returns:
bool: True if the key is printable.
"""
return self.key == Keys.Space or self.key not in KEY_VALUES
return False if self.char is None else self.char.isprintable()
@rich.repr.auto

View File

@@ -517,7 +517,7 @@ class MessagePump(metaclass=MessagePumpMeta):
Args:
event (events.Key): A key event.
"""
key_method = getattr(self, f"key_{event.key}", None)
key_method = getattr(self, f"key_{event.key_name}", None)
if key_method is not None:
if await invoke(key_method, event):
event.prevent_default()

View File

@@ -19,6 +19,7 @@ __all__ = [
"Placeholder",
"Pretty",
"Static",
"TextInput",
"TreeControl",
]

View File

@@ -1,10 +1,11 @@
# This stub file must re-export every classes exposed in the __init__.py's `__all__` list:
from ._button import Button as Button
from ._data_table import DataTable
from ._data_table import DataTable as DataTable
from ._directory_tree import DirectoryTree as DirectoryTree
from ._footer import Footer as Footer
from ._header import Header as Header
from ._placeholder import Placeholder as Placeholder
from ._pretty import Pretty as Pretty
from ._static import Static as Static
from ._text_input import TextInput as TextInput
from ._tree_control import TreeControl as TreeControl

View File

@@ -40,12 +40,9 @@ class TextWidgetBase(Widget):
key = event.key
if key == "escape":
return
elif key == "space":
key = " "
changed = False
if event.is_printable:
changed = self._editor.insert(key)
if event.char is not None and event.is_printable:
changed = self._editor.insert(event.char)
elif key == "ctrl+h":
changed = self._editor.delete_back()
elif key == "ctrl+d":
@@ -59,11 +56,11 @@ class TextWidgetBase(Widget):
elif key == "end" or key == "ctrl+e":
self._editor.cursor_text_end()
self.refresh(layout=True)
if changed:
self.post_message_no_wait(self.Changed(self, value=self._editor.content))
self.refresh(layout=True)
def _apply_cursor_to_text(self, display_text: Text, index: int) -> Text:
if index < 0:
return display_text
@@ -115,10 +112,9 @@ class TextInput(TextWidgetBase, can_focus=True):
DEFAULT_CSS = """
TextInput {
width: auto;
background: $surface;
height: 3;
padding: 0 1;
content-align: left middle;
padding: 1;
background: $surface;
}
"""
@@ -165,11 +161,15 @@ class TextInput(TextWidgetBase, can_focus=True):
self._editor.cursor_text_end()
self.refresh()
def on_resize(self, event: events.Resize) -> None:
def get_content_width(self, container: Size, viewport: Size) -> int:
# TODO: Why does this need +2 ?
return min(cell_len(self._editor.content) + 2, container.width)
def _on_resize(self, event: events.Resize) -> None:
# Ensure the cursor remains visible when the widget is resized
self._reset_visible_range()
def on_click(self, event: events.Click) -> None:
def _on_click(self, event: events.Click) -> None:
"""When the user clicks on the text input, the cursor moves to the
character that was clicked on. Double-width characters makes this more
difficult."""