0.5.0 — VIS Widgets, Help Button & Popup Polish#
Released — current version
Adds general-purpose widgets, a one-line Help-button hookup, standard confirmation dialogs, and a flicker-free popup centring helper. The project-upgrade-tool work originally planned for 0.5 has been deferred (see “Out of scope” below).
VIS Widgets#
General-purpose widgets that Tkinter does not provide natively. All
exported from VIStk.Widgets.
Tooltip— hover tooltip bound to any widget.textmay be astror a zero-arg callable for state-dependent tooltips. Cleans up itsaftercallback on widget destroy:from VIStk.Widgets import Tooltip Tooltip(my_button, text="Save the current document")
CollapsibleFrame— frame whose body is hidden under a header button. Pack children intocf.body;cf.expanded_varis aBooleanVarcallers can bind for shared state:cf = CollapsibleFrame(parent, text="Advanced", expanded=False) cf.pack(fill="x") ttk.Entry(cf.body).pack()
AutocompleteEntry—ttk.Entrywith a filtered dropdownListbox.valuesis either an iterable or a callable(text) -> iterable. Keyboard:Up/Downmove,Returnaccepts,Tabaccepts the first match,Escapecloses.match="prefix"(default) or"contains".DateEntry—ttk.Entry+ calendar-picker button. No third-party dependencies.get()returnsdate | None,set(date)sets programmatically, invalid manual input reverts to the last valid value on focus-out.
Confirmation Dialogs#
Drop-in helpers so screens stop reimplementing the
tkinter.messagebox dance:
from VIStk.Widgets import confirm, confirm_discard
if confirm(parent, title="Delete?", message="Really delete?"):
...
choice = confirm_discard(parent, name="Work Order #12345")
if choice == "cancel":
return False # veto on_quit
if choice == "save":
_save()
return True
confirm(...) -> bool— two-button Yes/No.confirm_discard(...) -> "save" | "discard" | "cancel"— three- button Save / Discard / Cancel. Closing the window or pressing Escape both return"cancel".
Both dialogs are modal, transient over their parent, centred via
WindowGeometry.center_on(), and never flash at the OS default
position before centring.
Help Button & Per-Screen docs URL#
Wiring a top-level Help button is a one-liner from .VIS/Host.py:
from VIStk.Widgets import HostMenu
from VIStk.Objects import open_active_screen_docs
host_menu.add_project_command("Help", open_active_screen_docs)
HostMenu.add_project_command(label, command)#
New companion to set_project_items. Adds a clickable leaf entry
directly on the menubar (not a cascade). Survives all tab changes;
removed only by clear_project_items.
Per-screen docs field#
Each entry under Screens.<name> in project.json may carry a
docs URL:
"Screens": {
"Home": {"...": "...", "docs": null},
"Settings": {"...": "...", "docs": "https://example.com/docs/settings"}
},
"defaults": {
"icon": "...",
"docs": "https://example.com/docs"
}
Screen.docs: str | None— per-screen URL.Nonemeans “fall through to project default”.Project.default_docs: str | None— project-level fallback.Project.resolve_docs_url(screen_name=None)— runs the fallback chain (screendocs->default_docs->None).Project.active_screen_name— property returning the active tab’sbase_name(resolved from the live tab ID introduced in 0.4.7).VIStk.Objects.open_active_screen_docs()— looks up the active screen’s URL viaProject().resolve_docs_url()and hands it towebbrowser.open(). ReturnsTrueon dispatch,Falseif no URL was configured.
URLs are passed verbatim to webbrowser.open(). No path
normalisation — authors write fully-qualified URLs (https://,
file:///, etc.).
VIS docs CLI#
VIS docs set <screen_name> <url> # set a per-screen URL
VIS docs set --default <url> # set the project default
VIS docs clear <screen_name> # clear a per-screen URL
VIS docs clear --default # clear the project default
VIS docs list # show all configured URLs
The scaffolder (VIS add screen) writes "docs": null into new
entries so the field is discoverable.
Popup Flicker Fix — WindowGeometry.center_on#
The canonical update + getGeometry + setGeometry pattern made every
centred popup flash at the OS default position before jumping to the
final centred coordinates. center_on does the same math inside a
withdraw() / deiconify() wrap and uses update_idletasks()
(layout-only) instead of update() (which also processes the map
request):
popup = Toplevel(root)
# ... build child widgets ...
WindowGeometry(popup)
popup.WindowGeometry.center_on(root)
Not intended for the root Tk() window — withdraw() on the
main application window hides it entirely. setGeometry itself is
unchanged.
Out of Scope (deferred)#
Project Upgrade Tool (
VIS upgrade) — the originally planned 0.5 epic is deferred to 0.7 (which is already titled “Defaults & Navigation, update tools” — a better fit).Color palette feature — deferred; tracked separately for a later 0.5.x or 0.6.x.
``is_dirty`` auto-generated ``on_quit`` — the
confirm_discardhelper covers the manual case; the auto-wrapper can land later without an API break.