mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 04:01:32 -06:00
Launcher: Add search box (#4863)
* Add fuzzy search box to Launcher. * move func bind to the kv and prefer substring matching (#79) * move the func bind to the kv * prefer substr matching * Remove fuzzy results, rely on substring only. * Use early return instead of else. * Add type hint to filter_clients_by_type. * Activate search on keyboard input. * Clear search box when filtering by type. * Update Launcher.py Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com> --------- Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com> Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
This commit is contained in:

committed by
GitHub

parent
efe2b7c539
commit
f857933748
31
Launcher.py
31
Launcher.py
@@ -230,10 +230,11 @@ def run_gui(path: str, args: Any) -> None:
|
|||||||
from kivy.properties import ObjectProperty
|
from kivy.properties import ObjectProperty
|
||||||
from kivy.core.window import Window
|
from kivy.core.window import Window
|
||||||
from kivy.metrics import dp
|
from kivy.metrics import dp
|
||||||
from kivymd.uix.button import MDIconButton
|
from kivymd.uix.button import MDIconButton, MDButton
|
||||||
from kivymd.uix.card import MDCard
|
from kivymd.uix.card import MDCard
|
||||||
from kivymd.uix.menu import MDDropdownMenu
|
from kivymd.uix.menu import MDDropdownMenu
|
||||||
from kivymd.uix.snackbar import MDSnackbar, MDSnackbarText
|
from kivymd.uix.snackbar import MDSnackbar, MDSnackbarText
|
||||||
|
from kivymd.uix.textfield import MDTextField
|
||||||
|
|
||||||
from kivy.lang.builder import Builder
|
from kivy.lang.builder import Builder
|
||||||
|
|
||||||
@@ -253,6 +254,7 @@ def run_gui(path: str, args: Any) -> None:
|
|||||||
navigation: MDGridLayout = ObjectProperty(None)
|
navigation: MDGridLayout = ObjectProperty(None)
|
||||||
grid: MDGridLayout = ObjectProperty(None)
|
grid: MDGridLayout = ObjectProperty(None)
|
||||||
button_layout: ScrollBox = ObjectProperty(None)
|
button_layout: ScrollBox = ObjectProperty(None)
|
||||||
|
search_box: MDTextField = ObjectProperty(None)
|
||||||
cards: list[LauncherCard]
|
cards: list[LauncherCard]
|
||||||
current_filter: Sequence[str | Type] | None
|
current_filter: Sequence[str | Type] | None
|
||||||
|
|
||||||
@@ -338,14 +340,29 @@ def run_gui(path: str, args: Any) -> None:
|
|||||||
scroll_percent = self.button_layout.convert_distance_to_scroll(0, top)
|
scroll_percent = self.button_layout.convert_distance_to_scroll(0, top)
|
||||||
self.button_layout.scroll_y = max(0, min(1, scroll_percent[1]))
|
self.button_layout.scroll_y = max(0, min(1, scroll_percent[1]))
|
||||||
|
|
||||||
def filter_clients(self, caller):
|
def filter_clients_by_type(self, caller: MDButton):
|
||||||
self._refresh_components(caller.type)
|
self._refresh_components(caller.type)
|
||||||
|
self.search_box.text = ""
|
||||||
|
|
||||||
|
def filter_clients_by_name(self, caller: MDTextField, name: str) -> None:
|
||||||
|
if len(name) == 0:
|
||||||
|
self._refresh_components(self.current_filter)
|
||||||
|
return
|
||||||
|
|
||||||
|
sub_matches = [
|
||||||
|
card for card in self.cards
|
||||||
|
if name.lower() in card.component.display_name.lower() and card.component.type != Type.HIDDEN
|
||||||
|
]
|
||||||
|
self.button_layout.layout.clear_widgets()
|
||||||
|
for card in sub_matches:
|
||||||
|
self.button_layout.layout.add_widget(card)
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
self.top_screen = Builder.load_file(Utils.local_path("data/launcher.kv"))
|
self.top_screen = Builder.load_file(Utils.local_path("data/launcher.kv"))
|
||||||
self.grid = self.top_screen.ids.grid
|
self.grid = self.top_screen.ids.grid
|
||||||
self.navigation = self.top_screen.ids.navigation
|
self.navigation = self.top_screen.ids.navigation
|
||||||
self.button_layout = self.top_screen.ids.button_layout
|
self.button_layout = self.top_screen.ids.button_layout
|
||||||
|
self.search_box = self.top_screen.ids.search_box
|
||||||
self.set_colors()
|
self.set_colors()
|
||||||
self.top_screen.md_bg_color = self.theme_cls.backgroundColor
|
self.top_screen.md_bg_color = self.theme_cls.backgroundColor
|
||||||
|
|
||||||
@@ -353,6 +370,7 @@ def run_gui(path: str, args: Any) -> None:
|
|||||||
refresh_components = self._refresh_components
|
refresh_components = self._refresh_components
|
||||||
|
|
||||||
Window.bind(on_drop_file=self._on_drop_file)
|
Window.bind(on_drop_file=self._on_drop_file)
|
||||||
|
Window.bind(on_keyboard=self._on_keyboard)
|
||||||
|
|
||||||
for component in components:
|
for component in components:
|
||||||
self.cards.append(self.build_card(component))
|
self.cards.append(self.build_card(component))
|
||||||
@@ -389,6 +407,15 @@ def run_gui(path: str, args: Any) -> None:
|
|||||||
else:
|
else:
|
||||||
logging.warning(f"unable to identify component for {file}")
|
logging.warning(f"unable to identify component for {file}")
|
||||||
|
|
||||||
|
def _on_keyboard(self, window: Window, key: int, scancode: int, codepoint: str, modifier: list[str]):
|
||||||
|
# Activate search as soon as we start typing, no matter if we are focused on the search box or not.
|
||||||
|
# Focus first, then capture the first character we type, otherwise it gets swallowed and lost.
|
||||||
|
# Limit text input to ASCII non-control characters (space bar to tilde).
|
||||||
|
if not self.search_box.focus:
|
||||||
|
self.search_box.focus = True
|
||||||
|
if key in range(32, 126):
|
||||||
|
self.search_box.text += codepoint
|
||||||
|
|
||||||
def _stop(self, *largs):
|
def _stop(self, *largs):
|
||||||
# ran into what appears to be https://groups.google.com/g/kivy-users/c/saWDLoYCSZ4 with PyCharm.
|
# ran into what appears to be https://groups.google.com/g/kivy-users/c/saWDLoYCSZ4 with PyCharm.
|
||||||
# Closing the window explicitly cleans it up.
|
# Closing the window explicitly cleans it up.
|
||||||
|
@@ -80,7 +80,7 @@ MDFloatLayout:
|
|||||||
id: all
|
id: all
|
||||||
style: "text"
|
style: "text"
|
||||||
type: (Type.CLIENT, Type.TOOL, Type.ADJUSTER, Type.MISC)
|
type: (Type.CLIENT, Type.TOOL, Type.ADJUSTER, Type.MISC)
|
||||||
on_release: app.filter_clients(self)
|
on_release: app.filter_clients_by_type(self)
|
||||||
|
|
||||||
MDButtonIcon:
|
MDButtonIcon:
|
||||||
icon: "asterisk"
|
icon: "asterisk"
|
||||||
@@ -90,7 +90,7 @@ MDFloatLayout:
|
|||||||
id: client
|
id: client
|
||||||
style: "text"
|
style: "text"
|
||||||
type: (Type.CLIENT, )
|
type: (Type.CLIENT, )
|
||||||
on_release: app.filter_clients(self)
|
on_release: app.filter_clients_by_type(self)
|
||||||
|
|
||||||
MDButtonIcon:
|
MDButtonIcon:
|
||||||
icon: "controller"
|
icon: "controller"
|
||||||
@@ -100,7 +100,7 @@ MDFloatLayout:
|
|||||||
id: Tool
|
id: Tool
|
||||||
style: "text"
|
style: "text"
|
||||||
type: (Type.TOOL, )
|
type: (Type.TOOL, )
|
||||||
on_release: app.filter_clients(self)
|
on_release: app.filter_clients_by_type(self)
|
||||||
|
|
||||||
MDButtonIcon:
|
MDButtonIcon:
|
||||||
icon: "desktop-classic"
|
icon: "desktop-classic"
|
||||||
@@ -110,7 +110,7 @@ MDFloatLayout:
|
|||||||
id: adjuster
|
id: adjuster
|
||||||
style: "text"
|
style: "text"
|
||||||
type: (Type.ADJUSTER, )
|
type: (Type.ADJUSTER, )
|
||||||
on_release: app.filter_clients(self)
|
on_release: app.filter_clients_by_type(self)
|
||||||
|
|
||||||
MDButtonIcon:
|
MDButtonIcon:
|
||||||
icon: "wrench"
|
icon: "wrench"
|
||||||
@@ -120,7 +120,7 @@ MDFloatLayout:
|
|||||||
id: misc
|
id: misc
|
||||||
style: "text"
|
style: "text"
|
||||||
type: (Type.MISC, )
|
type: (Type.MISC, )
|
||||||
on_release: app.filter_clients(self)
|
on_release: app.filter_clients_by_type(self)
|
||||||
|
|
||||||
MDButtonIcon:
|
MDButtonIcon:
|
||||||
icon: "dots-horizontal-circle-outline"
|
icon: "dots-horizontal-circle-outline"
|
||||||
@@ -131,7 +131,7 @@ MDFloatLayout:
|
|||||||
id: favorites
|
id: favorites
|
||||||
style: "text"
|
style: "text"
|
||||||
type: ("favorites", )
|
type: ("favorites", )
|
||||||
on_release: app.filter_clients(self)
|
on_release: app.filter_clients_by_type(self)
|
||||||
|
|
||||||
MDButtonIcon:
|
MDButtonIcon:
|
||||||
icon: "star"
|
icon: "star"
|
||||||
@@ -141,5 +141,21 @@ MDFloatLayout:
|
|||||||
MDNavigationDrawerDivider:
|
MDNavigationDrawerDivider:
|
||||||
|
|
||||||
|
|
||||||
ScrollBox:
|
MDGridLayout:
|
||||||
id: button_layout
|
id: main_layout
|
||||||
|
cols: 1
|
||||||
|
spacing: "10dp"
|
||||||
|
|
||||||
|
MDTextField:
|
||||||
|
id: search_box
|
||||||
|
mode: "outlined"
|
||||||
|
set_text: app.filter_clients_by_name
|
||||||
|
|
||||||
|
MDTextFieldLeadingIcon:
|
||||||
|
icon: "magnify"
|
||||||
|
|
||||||
|
MDTextFieldHintText:
|
||||||
|
text: "Search"
|
||||||
|
|
||||||
|
ScrollBox:
|
||||||
|
id: button_layout
|
||||||
|
Reference in New Issue
Block a user