#[widget]Expand description
Attribute to implement the kas::Widget family of traits
This may only be used within the impl_scope! macro.
Assists implementation of the Widget, Events and Layout traits.
Implementations of these traits are generated if missing or augmented with
missing method implementations.
This macro may inject methods into existing Layout / Events / Widget implementations.
This is used both to provide default implementations which could not be
written on the trait and to implement properties like navigable.
(In the case of multiple implementations of the same trait, as used for
specialization, only the first implementation of each trait is extended.)
Syntax
WidgetAttr :
#[widgetWidgetAttrArgs?]WidgetAttrArgs :
{(WidgetAttrArg;) *}
Supported arguments (WidgetAttrArg) are:
Data = Type: theWidget::Dataassociated typederive = self.fieldwherefieldis the name (or number) of a field: enables “derive mode” (see below) over the given fieldnavigable = bool— a quick implementation ofEvents::navigable: whether this widget supports keyboard focus via the Tab key (default isfalse)hover_highlight = bool— if true, generateEvents::handle_hoverto request a redraw on focus gained/lostcursor_icon = expr— if used, generateEvent::handle_hover, callingcx.set_cursor_icon(expr)layout = layout— defines widget layout via an expression; see below for documentation
The struct must contain a field of type widget_core!() (usually named
core). The macro widget_core!() is a placeholder, expanded by
#[widget] and used to identify the field used (any name may be used).
This field might have type CoreData or might use a special generated
type; either way it has fields id: WidgetId (assigned by during configure)
and rect: Rect (usually assigned by
Layout::set_rect). It may contain additional fields for layout data. The
type supports Default and Clone (although Clone actually
default-initializes all fields other than rect since clones of widgets
must themselves be configured).
Assuming the deriving type is a struct or tuple struct, fields support
the following attributes:
#[widget]: marks the field as aWidgetto be configured, enumerated byWidget::get_childand included by glob layouts#[widget(expr)]: the same, but maps the data reference type;expris an expression returning a reference to the child widget’s input data; available inputs areself,data(own input data) andindex(of the child).
Layout
Widget layout may be specified either by implementing the Layout trait or
via the layout property of #[widget]. The latter accepts the following
syntax, where Layout is any of the below.
Using the layout = ...; property will also generate a corresponding
implementation of Events::nav_next, with a couple of exceptions
(where macro-time analysis is insufficient to implement this method).
Column, Row, List, AlignedColumn, AlignedRow, Grid, Float, Align, Pack, Margins :
These stand-alone macros are explicitly supported in this position.
Optionally, a Storage specifier is supported immediately after the macro name, e.g.
column! 'storage_name ["one", "two"]
Single :
self.Member
A named child:self.foo(more precisely, this matches any expression startingself, and uses&mut (#expr))Slice :
slice!Storage?(Direction,self.Member)
A field with type[W]for someW: Layout. (Note: this does not automatically register the slice widgets as children for the purpose of configuration and event-handling. An explicit implementation ofWidget::get_childwill be required.)Frame :
frame!Storage?(Layout (,style=Expr )?)
Adds a frame of type Expr around content, defaulting toFrameStyle::Frame.Button :
button!Storage?(Layout (,color=Expr )?)
Adds a button frame (optionally with color Expr) around content.WidgetConstructor :
Expr
An expression yielding a widget, e.g.Label::new("Hello world"). The result must be an object of some typeW: Widget.LabelLit :
StrLit
A string literal generates a label widget, e.g. “Hello world”. This is an internal type without text wrapping.NonNavigable :
non_navigable!(Layout)
Does not affect layout. Specifies that the content is excluded from tab-navigation order.
Additional syntax rules (not layout items):
Member :
Ident | Index
The name of a struct field or an index into a tuple struct.Direction :
left|right|up|down| Expr:
Note that an Expr must start withselfStorage :
'Ident
Used to explicitly name the storage used by a generated widget or layout; for examplerow 'x: ["A", "B", "C"]will add a fieldx: RwhereR: RowStoragewithin the generatedwidget_core!(). If omitted, the field name will be anonymous (generated).
Examples
A simple example is the
Frame widget:
impl_scope! {
/// A frame around content
#[autoimpl(Deref, DerefMut using self.inner)]
#[autoimpl(class_traits using self.inner where W: trait)]
#[derive(Clone, Default)]
#[widget{
layout = frame!(self.inner, style = kas::theme::FrameStyle::Frame);
}]
pub struct Frame<W: Widget> {
core: widget_core!(),
#[widget]
pub inner: W,
}
impl Self {
/// Construct a frame
#[inline]
pub fn new(inner: W) -> Self {
Frame {
core: Default::default(),
inner,
}
}
}
}A simple row layout: layout = row! [self.a, self.b];
Derive
It is possible to derive from a field which is itself a widget, e.g.:
impl_scope! {
#[autoimpl(Deref, DerefMut using self.0)]
#[derive(Clone, Default)]
#[widget{ derive = self.0; }]
pub struct ScrollBarRegion<W: Widget>(ScrollBars<ScrollRegion<W>>);
}This is a special mode where most features of #[widget] are not
available. Only Layout methods may be specified (overriding those from
the derived widget); everything else is derived.
Debugging
To inspect the output of this macro, set the environment variable
KAS_DEBUG_WIDGET to the name of the widget concerned, dump the output to
a temporary file and format. For example:
KAS_DEBUG_WIDGET=Border cargo build > temp.rs
rustfmt temp.rs