Attribute Macro kas_macros::widget
source · #[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 :
#
[
widget
WidgetAttrArgs?]
WidgetAttrArgs :
{
(WidgetAttrArg;
) *}
Supported arguments (WidgetAttrArg) are:
Data = Type
: theWidget::Data
associated typederive = self.field
wherefield
is 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_hover
to request a redraw on focus gained/lostcursor_icon = expr
— if used, generateEvent::handle_hover
, callingcx.set_hover_cursor(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: Id
(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 aWidget
to be configured, enumerated byWidget::get_child
and included by glob layouts#[widget(expr)]
: the same, but maps the data reference type;expr
is 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_child
will 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 withself
Storage :
'
Ident
Used to explicitly name the storage used by a generated widget or layout; for examplerow 'x: ["A", "B", "C"]
will add a fieldx: R
whereR: RowStorage
within 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