A slew of tiny pager improvements
- stop displaying search bar widget on <ctrl-c> - if there's existing search bar content highlight it automatically to allow user to start typing new content right away - when activated allow search bar to insert its own set of keybinding controls; restore prior bindings on exitkivy_mainline_and_py3.8
parent
3bbb1db2b4
commit
884fcaa88e
|
@ -18,7 +18,7 @@ def get_brokermod(brokername: str) -> ModuleType:
|
||||||
"""Return the imported broker module by name.
|
"""Return the imported broker module by name.
|
||||||
"""
|
"""
|
||||||
module = import_module('.' + brokername, 'piker.brokers')
|
module = import_module('.' + brokername, 'piker.brokers')
|
||||||
# we only allows monkeys because it's for internal keying
|
# we only allow monkeying because it's for internal keying
|
||||||
module.name = module.__name__.split('.')[-1]
|
module.name = module.__name__.split('.')[-1]
|
||||||
return module
|
return module
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ Pager widget + kb controls
|
||||||
import inspect
|
import inspect
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from kivy.core.window import Window
|
from kivy.core.window import Window, Widget
|
||||||
from kivy.uix.textinput import TextInput
|
from kivy.uix.textinput import TextInput
|
||||||
from kivy.uix.scrollview import ScrollView
|
from kivy.uix.scrollview import ScrollView
|
||||||
|
|
||||||
|
@ -12,7 +12,12 @@ from ..log import get_logger
|
||||||
log = get_logger('keyboard')
|
log = get_logger('keyboard')
|
||||||
|
|
||||||
|
|
||||||
async def handle_input(nursery, widget, patts2funcs: dict, patt_len_limit=3):
|
async def handle_input(
|
||||||
|
nursery,
|
||||||
|
widget,
|
||||||
|
patts2funcs: dict,
|
||||||
|
patt_len_limit=3
|
||||||
|
) -> None:
|
||||||
"""Handle keyboard input.
|
"""Handle keyboard input.
|
||||||
|
|
||||||
For each character pattern-tuple in ``patts2funcs`` invoke the
|
For each character pattern-tuple in ``patts2funcs`` invoke the
|
||||||
|
@ -31,10 +36,13 @@ async def handle_input(nursery, widget, patts2funcs: dict, patt_len_limit=3):
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
async for kb, keycode, text, modifiers in keyq:
|
async for kb, keycode, text, modifiers in keyq:
|
||||||
log.debug(
|
log.debug(f"""
|
||||||
f"Keyboard input received:\n"
|
kb: {kb}
|
||||||
f"key {keycode}\ntext {text}\nmodifiers {modifiers}"
|
keycode: {keycode}
|
||||||
)
|
text: {text}
|
||||||
|
modifiers: {modifiers}
|
||||||
|
patts2funcs: {patts2funcs}
|
||||||
|
""")
|
||||||
code, key = keycode
|
code, key = keycode
|
||||||
if modifiers and key in modifiers:
|
if modifiers and key in modifiers:
|
||||||
continue
|
continue
|
||||||
|
@ -61,6 +69,7 @@ async def handle_input(nursery, widget, patts2funcs: dict, patt_len_limit=3):
|
||||||
log.debug(f'invoking kb func {func}')
|
log.debug(f'invoking kb func {func}')
|
||||||
func()
|
func()
|
||||||
last_patt = []
|
last_patt = []
|
||||||
|
break
|
||||||
|
|
||||||
if len(last_patt) > patt_len_limit:
|
if len(last_patt) > patt_len_limit:
|
||||||
last_patt = []
|
last_patt = []
|
||||||
|
@ -75,26 +84,41 @@ async def handle_input(nursery, widget, patts2funcs: dict, patt_len_limit=3):
|
||||||
|
|
||||||
|
|
||||||
class SearchBar(TextInput):
|
class SearchBar(TextInput):
|
||||||
def __init__(self, kbctls: dict, container: 'Widget', pager: 'PagerView',
|
def __init__(
|
||||||
searcher, **kwargs):
|
self,
|
||||||
|
container: Widget,
|
||||||
|
pager: 'PagerView',
|
||||||
|
searcher,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
super(SearchBar, self).__init__(
|
super(SearchBar, self).__init__(
|
||||||
multiline=False,
|
multiline=False,
|
||||||
hint_text='Ticker Search',
|
hint_text='Ticker Search',
|
||||||
cursor_blink=False,
|
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
self.cursor_blink = False
|
||||||
self.foreground_color = self.hint_text_color # actually readable
|
self.foreground_color = self.hint_text_color # actually readable
|
||||||
self.kbctls = kbctls
|
|
||||||
self._container = container
|
self._container = container
|
||||||
self._pager = pager
|
self._pager = pager
|
||||||
self._searcher = searcher
|
self._searcher = searcher
|
||||||
# indicate to ``handle_input`` that search is activated on '/'
|
# indicate to ``handle_input`` that search is activated on '/'
|
||||||
self.kbctls.update({
|
self._pager.kbctls.update({
|
||||||
('/',): self.handle_input
|
('/',): self.handle_input
|
||||||
})
|
})
|
||||||
|
|
||||||
|
self.kbctls = {
|
||||||
|
('ctrl-c',): self.undisplay,
|
||||||
|
}
|
||||||
|
|
||||||
self._sugg_template = ' '*4 + '{} matches: '
|
self._sugg_template = ' '*4 + '{} matches: '
|
||||||
self._matched = []
|
self._matched = []
|
||||||
|
|
||||||
|
def undisplay(self):
|
||||||
|
"Stop displaying this text widget"
|
||||||
|
self.dispatch('on_text_validate') # same as pressing <enter>
|
||||||
|
if self.text_validate_unfocus:
|
||||||
|
self.focus = False
|
||||||
|
|
||||||
def suggest(self, matches):
|
def suggest(self, matches):
|
||||||
self.suggestion_text = ''
|
self.suggestion_text = ''
|
||||||
suffix = self._sugg_template.format(len(matches) or "No")
|
suffix = self._sugg_template.format(len(matches) or "No")
|
||||||
|
@ -138,14 +162,31 @@ class SearchBar(TextInput):
|
||||||
self._pager.scroll_to(widget)
|
self._pager.scroll_to(widget)
|
||||||
|
|
||||||
async def handle_input(self):
|
async def handle_input(self):
|
||||||
|
# TODO: wrap this in a cntx mng
|
||||||
|
old_ctls = self._pager.kbctls.copy()
|
||||||
|
self._pager.kbctls.clear()
|
||||||
|
# makes a copy
|
||||||
|
self._pager.kbctls.update(self.kbctls)
|
||||||
|
|
||||||
self._container.add_widget(self) # display it
|
self._container.add_widget(self) # display it
|
||||||
self.focus = True # focus immediately (doesn't work from __init__)
|
self.focus = True # focus immediately (doesn't work from __init__)
|
||||||
|
|
||||||
|
# select any existing text making the widget ready
|
||||||
|
# to accept new input right away
|
||||||
|
if self.text:
|
||||||
|
self.select_all()
|
||||||
|
|
||||||
# wait for <enter> to close search bar
|
# wait for <enter> to close search bar
|
||||||
await self.async_bind('on_text_validate').__aiter__().__anext__()
|
await self.async_bind('on_text_validate').__aiter__().__anext__()
|
||||||
log.debug(f"Seach text is {self.text}")
|
log.debug(f"Seach text is {self.text}")
|
||||||
|
|
||||||
log.debug("Closing search bar")
|
log.debug("Closing search bar")
|
||||||
self._container.remove_widget(self) # stop displaying
|
self._container.remove_widget(self) # stop displaying
|
||||||
|
|
||||||
|
# restore old keyboard bindings
|
||||||
|
self._pager.kbctls.clear()
|
||||||
|
self._pager.kbctls.update(old_ctls)
|
||||||
|
|
||||||
return self.text
|
return self.text
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,8 +208,7 @@ class PagerView(ScrollView):
|
||||||
# add contained child widget (can only be one)
|
# add contained child widget (can only be one)
|
||||||
self._contained = contained
|
self._contained = contained
|
||||||
self.add_widget(contained)
|
self.add_widget(contained)
|
||||||
self.search = SearchBar(
|
self.search = SearchBar(container, self, searcher=contained)
|
||||||
self.kbctls, container, self, searcher=contained)
|
|
||||||
# spawn kb handler task
|
# spawn kb handler task
|
||||||
nursery.start_soon(handle_input, nursery, self, self.kbctls)
|
nursery.start_soon(handle_input, nursery, self, self.kbctls)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue