"""Filters tab: desert filter + an editable EXTRA_FILTERS table."""
from __future__ import annotations
import tkinter as tk
from typing import Any, Dict, List
from spino import config_io
from spino.gui_toolkit.widget.MyLabel import MyLabel
from spino.gui_toolkit.widget.MyEntry import MyEntry
from spino.gui_toolkit.widget.MyDropDown import MyDropdown
from spino.gui_toolkit.widget.MyButton import MyButton
from spino.gui_toolkit.widget.MyTable import MyTable
from spino.gui_toolkit.widget.HelpButton import HelpButton
from spino.panels.base import opt_float
_COLUMNS = ["column", "min", "max", "contains"]
_WIDTHS = [150, 100, 100, 160]
[docs]
class FiltersPanel:
KEYS = ["DESERT_FILTER", "EXTRA_FILTERS"]
def __init__(self, tab, bg: str, defaults: Dict[str, Any]):
frame = tk.Frame(tab, bg=bg)
frame.grid(row=0, column=0, columnspan=101, sticky="nsew", padx=8, pady=8)
tab.grid_rowconfigure(0, weight=1)
tab.grid_columnconfigure(0, weight=1)
tab.grid_columnconfigure(100, weight=0)
frame.grid_columnconfigure(0, weight=1)
header = MyLabel(frame, 0, 0, color=bg, label_text="Filters")
try:
header.label.config(font=("Sans", 20, "bold"))
except Exception:
pass
HelpButton(frame, 0, 1, "Filters", config_io.HELP["Filters"])
self._desert = MyDropdown(frame, 1, 0, config_io.DESERT_FILTERS,
label_text="DESERT_FILTER", color=bg,
initial_value=config_io.DESERT_FILTERS.index(
defaults["DESERT_FILTER"]))
MyLabel(frame, 2, 0, color=bg,
label_text="EXTRA_FILTERS (applied sequentially, AND):")
# Table in its own frame (MyTable .pack()s itself).
table_frame = tk.Frame(frame, bg=bg)
table_frame.grid(row=3, column=0, columnspan=2, sticky="nsew", pady=4)
frame.grid_rowconfigure(3, weight=1)
self._table = MyTable(table_frame, _COLUMNS, _WIDTHS, height=8)
# Row editor
editor = tk.Frame(frame, bg=bg)
editor.grid(row=4, column=0, columnspan=2, sticky="ew", pady=4)
# Each labelled widget spans 2 parent columns (label + field), so place
# them 2 columns apart to avoid overlap.
self._col = MyDropdown(editor, 0, 0, config_io.FILTER_COLUMNS,
label_text="column", color=bg)
self._min = MyEntry(editor, 0, 2, text="", label_text="min", color=bg,
entry_width=8)
self._max = MyEntry(editor, 0, 4, text="", label_text="max", color=bg,
entry_width=8)
self._contains = MyEntry(editor, 0, 6, text="", label_text="contains",
color=bg, entry_width=12)
MyButton(editor, 0, 8, "Add row", "#A3BE8C", self._add_row, color_panel=bg)
MyButton(frame, 5, 0, "Remove selected", "#BF616A", self._remove_selected,
color_panel=bg)
self.set_values(defaults)
# -- table helpers ----------------------------------------------------- #
def _add_row(self):
col = self._col.get_value()
self._table.insert("", "end", values=(
col, self._min.get_value().strip(),
self._max.get_value().strip(), self._contains.get_value().strip()))
self._min.set_value(""); self._max.set_value(""); self._contains.set_value("")
def _remove_selected(self):
for iid in self._table.selection():
self._table.delete(iid)
def _clear(self):
for iid in self._table.get_children():
self._table.delete(iid)
# -- collect / load ---------------------------------------------------- #
[docs]
def collect(self) -> Dict[str, Any]:
filters: List[Dict[str, Any]] = []
for iid in self._table.get_children():
col, vmin, vmax, contains = self._table.item(iid)["values"]
col = str(col).strip()
if not col:
continue
row: Dict[str, Any] = {"column": col}
contains = str(contains).strip()
if contains:
row["contains"] = contains
else:
fmin = opt_float(vmin)
fmax = opt_float(vmax)
if fmin is not None:
row["min"] = fmin
if fmax is not None:
row["max"] = fmax
filters.append(row)
return {"DESERT_FILTER": self._desert.get_value(),
"EXTRA_FILTERS": filters}
[docs]
def set_values(self, v: Dict[str, Any]) -> None:
self._desert.set_value(v["DESERT_FILTER"])
self._clear()
for f in v.get("EXTRA_FILTERS", []):
self._table.insert("", "end", values=(
f.get("column", ""),
f.get("min", ""),
f.get("max", ""),
f.get("contains", "")))