All docs
Contributing UI with @tool.view
Use @tool.view for editor tabs and sidebars, and declared viewer extensions for HUDs and overlays.
A tool can contribute a sidebar control form or an editor data view with
@tool.view. Its factory returns a View:
a class with param() fields, @action methods and optional data rendering.
location="sidebar"docks one surface in the shell.location="editor"declares an editor tab and is the default.- Content inside a viewer uses
tool.viewer_extension(...)withViewerExtensionSpec.surfaces.
The View interaction model is independent of GTK. A native drawing shell can use GTK behind the supported shell seam; ordinary form and data-view authors do not need to import it.
Usage#
A sidebar is a View subclass with fields and actions. The factory receives its host context:
from lsdtools import Tool, View, action, param
tool = Tool("mine")
class MineControls(View):
count = param(int, default=5, min=1, label="Count")
@action(label="Run", style="suggested")
def run(self):
self.ctx.ui.notify(f"running with {self.count}")
@tool.view("mine.controls", title="Mine controls", location="sidebar")
def controls(ctx):
return MineControls()
The mounted factory injects self.ctx. An action reads typed fields directly and
can use self.ctx.ui.notify(...) for notifications. Tests and other front ends invoke
the same action through view.invoke("run").
Sidebar (params + actions)#
A sidebar @tool.view is one docked surface. It uses the single-instance policy and
does not accept editor entity-binding options. For additional native sidebar layout or delivery
contracts, use the separately declared @tool.sidebar_view seam.
At mount time the sidebar becomes a SidebarViewContribution. This and the editor's
MainViewType are declared exports of
lsdtools.extend; the old ViewContribution type is removed.
See Params & actions for ordinary View controls.
Overlay (a HUD)#
The previous @tool.view(location="overlay", dock=..., view_kind=...)
API is removed. Tool.view rejects that location.
Declare viewer content with tool.viewer_extension(spec), where spec is a
ViewerExtensionSpec containing ViewerSurfaceSpec entries. These types,
ViewerSurfaceKind and package-qualified OwnedContributionId values come from
lsdtools.extend. A declaration identifies its target viewer_kinds, surface kind,
region and build factory. For example, a toolbar is a ViewerSurfaceKind.TOOLBAR
surface in an available viewer region such as viewer.tools.
Use the viewer extension's declared placement and lifecycle rather than mounting an extra editor View over the canvas. Its package ownership is validated when the Tool is mounted; declaring a factory does not run it during API inventory. See the extension reference for the complete surface contract.
Editor (a data view)#
An editor factory may receive (ctx, entity=None) and returns a View, such as one from
lsdtools.views. Declare how the tab accepts and binds entities explicitly:
from lsdtools import Entity, Tool, views
tool = Tool("mine")
@tool.view(
"mine.report",
title="Grade report",
location="editor",
instance_policy="per_entity",
binding_cardinality="one",
accepts_entity=lambda entity: isinstance(entity, Entity),
)
def report_view(ctx, entity=None):
return views.table(title="Grades").watch(entity)
This example accepts Entity objects; use a more selective predicate when a view requires one domain type or output contract. A second factory argument alone does not imply a per-entity view.
| Option | Meaning |
|---|---|
instance_policy |
single, reusable or per_entity declares instance reuse. |
accepts_entity |
Predicate deciding whether an entity is accepted by this view kind. |
binding_cardinality |
none, one or many declares entity-binding capacity. |
default_open |
Explicit activation-time opening signal; default false. |
Editor declarations use the same MainViewType contract as native main views. The
host assigns each live instance its exact ctx.view_id. A @tool.view factory must
return a View; returning an arbitrary GTK widget is a mount error.
Receiving an entity's output — watch#
watch(entity) connects the View's data to an entity and
refreshes it after runs. It returns the View, so views.table(...).watch(entity) can be the
factory's result. Watching an already-run entity pulls its output immediately.
Instance creation, entity acceptance and data observation are separate choices. The old
opens_for argument and opens_for_type helper are removed; migrate matching to
accepts_entity and declare the instance/binding policy. default_open=True is the
explicit way to request activation-time opening of an editor view.
Custom views#
For a representation the built-in kinds cannot express, subclass View
with its own kind, feed(data) and to_text() / to_image().
Register the native drawing shell through lsdtools.views.set_view_shell:
from lsdtools.views import set_view_shell
set_view_shell("sparkline", build_sparkline_shell) # build_sparkline_shell(view) -> Gtk.Widget
The complete View subclass and native shell belong together; see Custom views.
For native main-view factories, use @tool.main_view and its explicit host/view-id contract.
Related#
Learn — Commands & actions · UI overview · Naming: which is which
API — Tool · Context · Extension facade
Examples — A dockable panel · A complete package
Frequently asked questions
What location values does @tool.view accept?
editor and sidebar only. An overlay belongs to a declared viewer extension. Passing location=overlay raises an error.
Does an entity argument make a view per-entity automatically?
No. Declare instance_policy, accepts_entity and binding_cardinality explicitly. default_open controls activation-time opening for editor views.