fix: render more of launchers
This commit is contained in:
@@ -90,6 +90,7 @@ class FuzzyMenu(Window):
|
|||||||
self._items: list[Any] = []
|
self._items: list[Any] = []
|
||||||
self._filtered: list[Any] = []
|
self._filtered: list[Any] = []
|
||||||
self._selected_index: int = 0
|
self._selected_index: int = 0
|
||||||
|
self._scroll_offset: int = 0
|
||||||
|
|
||||||
self.viewport = Box(name="viewport", spacing=4, orientation="v")
|
self.viewport = Box(name="viewport", spacing=4, orientation="v")
|
||||||
|
|
||||||
@@ -115,12 +116,14 @@ class FuzzyMenu(Window):
|
|||||||
self._items = self._provider.items()
|
self._items = self._provider.items()
|
||||||
self.search_entry.set_text("")
|
self.search_entry.set_text("")
|
||||||
self._selected_index = 0
|
self._selected_index = 0
|
||||||
|
self._scroll_offset = 0
|
||||||
self._refresh_viewport("")
|
self._refresh_viewport("")
|
||||||
super().show()
|
super().show()
|
||||||
self.search_entry.grab_focus()
|
self.search_entry.grab_focus()
|
||||||
|
|
||||||
def _on_text_changed(self, entry, *_):
|
def _on_text_changed(self, entry, *_):
|
||||||
self._selected_index = 0
|
self._selected_index = 0
|
||||||
|
self._scroll_offset = 0
|
||||||
self._refresh_viewport(entry.get_text())
|
self._refresh_viewport(entry.get_text())
|
||||||
|
|
||||||
def _on_key_press(self, _widget, event):
|
def _on_key_press(self, _widget, event):
|
||||||
@@ -130,6 +133,9 @@ class FuzzyMenu(Window):
|
|||||||
if keyval == Gdk.KEY_Escape:
|
if keyval == Gdk.KEY_Escape:
|
||||||
self.hide()
|
self.hide()
|
||||||
return True
|
return True
|
||||||
|
if ctrl and keyval in (Gdk.KEY_g, Gdk.KEY_G):
|
||||||
|
self.hide()
|
||||||
|
return True
|
||||||
if keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter):
|
if keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter):
|
||||||
self._activate_selected()
|
self._activate_selected()
|
||||||
return True
|
return True
|
||||||
@@ -141,27 +147,51 @@ class FuzzyMenu(Window):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _window_size(self) -> int:
|
||||||
|
return self._max_results if self._max_results is not None else len(self._filtered)
|
||||||
|
|
||||||
def _move_selection(self, delta: int):
|
def _move_selection(self, delta: int):
|
||||||
if not self._filtered:
|
if not self._filtered:
|
||||||
return
|
return
|
||||||
self._selected_index = (self._selected_index + delta) % len(self._filtered)
|
new_index = self._selected_index + delta
|
||||||
self._update_selection_highlight()
|
new_index = max(0, min(new_index, len(self._filtered) - 1))
|
||||||
|
if new_index == self._selected_index:
|
||||||
|
return
|
||||||
|
self._selected_index = new_index
|
||||||
|
window = self._window_size()
|
||||||
|
if window <= 0:
|
||||||
|
self._scroll_offset = 0
|
||||||
|
elif self._selected_index < self._scroll_offset:
|
||||||
|
self._scroll_offset = self._selected_index
|
||||||
|
elif self._selected_index >= self._scroll_offset + window:
|
||||||
|
self._scroll_offset = self._selected_index - window + 1
|
||||||
|
self._render_visible()
|
||||||
|
|
||||||
def _refresh_viewport(self, query: str):
|
def _refresh_viewport(self, query: str):
|
||||||
self._filtered = self._provider.filter(self._items, query)
|
self._filtered = self._provider.filter(self._items, query)
|
||||||
if self._max_results is not None:
|
|
||||||
self._filtered = self._filtered[: self._max_results]
|
|
||||||
if self._selected_index >= len(self._filtered):
|
if self._selected_index >= len(self._filtered):
|
||||||
self._selected_index = 0
|
self._selected_index = 0
|
||||||
|
self._scroll_offset = 0
|
||||||
|
self._render_visible()
|
||||||
|
|
||||||
|
def _render_visible(self):
|
||||||
|
window = self._window_size()
|
||||||
|
if window <= 0:
|
||||||
|
visible: list[Any] = []
|
||||||
|
else:
|
||||||
|
max_offset = max(0, len(self._filtered) - window)
|
||||||
|
self._scroll_offset = min(self._scroll_offset, max_offset)
|
||||||
|
visible = self._filtered[self._scroll_offset : self._scroll_offset + window]
|
||||||
self.viewport.children = []
|
self.viewport.children = []
|
||||||
for item in self._filtered:
|
for item in visible:
|
||||||
self.viewport.add(self._provider.render(item))
|
self.viewport.add(self._provider.render(item))
|
||||||
self._update_selection_highlight()
|
self._update_selection_highlight()
|
||||||
|
|
||||||
def _update_selection_highlight(self):
|
def _update_selection_highlight(self):
|
||||||
|
visible_index = self._selected_index - self._scroll_offset
|
||||||
for i, child in enumerate(self.viewport.get_children()):
|
for i, child in enumerate(self.viewport.get_children()):
|
||||||
ctx = child.get_style_context()
|
ctx = child.get_style_context()
|
||||||
if i == self._selected_index:
|
if i == visible_index:
|
||||||
ctx.add_class("selected")
|
ctx.add_class("selected")
|
||||||
else:
|
else:
|
||||||
ctx.remove_class("selected")
|
ctx.remove_class("selected")
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ class ClipboardProvider:
|
|||||||
label=item.preview,
|
label=item.preview,
|
||||||
h_align="start",
|
h_align="start",
|
||||||
ellipsization="end",
|
ellipsization="end",
|
||||||
|
max_chars_width=120,
|
||||||
name="clip-preview",
|
name="clip-preview",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: white;
|
color: white;
|
||||||
|
min-width: 720px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#viewport {
|
#viewport {
|
||||||
@@ -53,3 +54,4 @@
|
|||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user