Skip to content
Open
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
97 changes: 75 additions & 22 deletions python/libstored/gui/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,10 @@ def __init__(
super().__init__(app=app, master=parent, *args, **kwargs)
self._obj = obj

self._visible = False
self._grid_row: int | None = None
self._style_name: str | None = None

self.columnconfigure(0, weight=1)

self._label = ttk.Label(self, text=obj.name)
Expand Down Expand Up @@ -568,6 +572,7 @@ def obj(self) -> laio_zmq.Object:
return self._obj

def style(self, style: str):
self._style_name = style
if style != "":
style += "."

Expand All @@ -580,6 +585,25 @@ def style(self, style: str):
self._poll["style"] = f"{style}TCheckbutton"
self._refresh["style"] = f"{style}TButton"

def show(self, row: int):
if not self._visible:
self.grid(column=0, row=row, sticky="nsew")
self._visible = True
self._grid_row = row
return

if self._grid_row != row:
self.grid_configure(row=row)
self._grid_row = row

def hide(self):
if not self._visible:
return

self.grid_forget()
self._visible = False
self._grid_row = None

@laio_tk.AsyncApp.tk_func
def _on_poll_obj_change(self, x):
if x is not None:
Expand Down Expand Up @@ -692,18 +716,32 @@ def filter(self, f: typing.Callable[[laio_zmq.Object], bool] | None | bool = Tru
# No filter
f = lambda o: True

row = 0
self._filtered_objects = []
for o in self._objects:
if f(o.obj):
o.grid(column=0, row=row, sticky="nsew")
o.style("Even" if row % 2 == 0 else "Odd")
row += 1
self._filtered_objects.append(o)
else:
o.grid_forget()
new_filtered: list[ObjectRow] = []
for row in self._objects:
if f(row.obj):
new_filtered.append(row)

# nothing changed, so avoid expensive Tk updates.
if new_filtered == self._filtered_objects:
return

if row == 0:
new_set = set(new_filtered)
old_set = set(self._filtered_objects)

# Hide rows that are no longer visible.
for row in old_set - new_set:
row.hide()

# Show and (re)position rows that are visible.
for i, row in enumerate(new_filtered):
row.show(i)
style = "Even" if i % 2 == 0 else "Odd"
if row._style_name != style:
row.style(style)

self._filtered_objects = new_filtered

if len(new_filtered) == 0:
self.configure(height=1)

self.filtered.trigger()
Expand Down Expand Up @@ -780,28 +818,43 @@ class FilterEntry(ltk.Entry):
Regex filter on a given ObjectList.
"""

FILTER_DEBOUNCE_MS = 150

def __init__(self, parent: ttk.Widget, object_list: ObjectList, *args, **kwargs):
super().__init__(parent, hint="enter regex filter", *args, **kwargs)
self._object_list = object_list
self._filter_job: str | None = None
self._var.trace_add("write", self._on_change)

def _on_change(self, *args):
text = self.text

if text == "":
self._object_list.filter(None)
else:
if self._filter_job is not None:
try:
regex = re.compile(text, re.IGNORECASE)
self["foreground"] = "black"
except re.error:
self["foreground"] = "red"
return
self.after_cancel(self._filter_job)
except BaseException:
pass
self._filter_job = None

def f(o: laio_zmq.Object) -> bool:
return regex.search(o.name) is not None
try:
regex = re.compile(text, re.IGNORECASE)
self["foreground"] = "black"
except re.error:
self["foreground"] = "red"
return

def f(o: laio_zmq.Object, _regex=regex) -> bool:
return _regex.search(o.name) is not None

self._object_list.filter(f)
self._filter_job = self.after(self.FILTER_DEBOUNCE_MS, lambda: self._object_list.filter(f))

def destroy(self):
if self._filter_job is not None:
try:
self.after_cancel(self._filter_job)
except BaseException:
pass
self._filter_job = None


class Tools(laio_tk.Work, ttk.Frame):
Expand Down
Loading