pub trait Widget: WidgetChildren + Layout {
fn pre_configure(&mut self, mgr: &mut ConfigMgr<'_>, id: WidgetId);
fn configure(&mut self, mgr: &mut ConfigMgr<'_>) { ... }
fn navigable(&self) -> bool { ... }
fn translation(&self) -> Offset { ... }
fn nav_next(
&mut self,
mgr: &mut ConfigMgr<'_>,
reverse: bool,
from: Option<usize>
) -> Option<usize> { ... }
fn handle_event(&mut self, mgr: &mut EventMgr<'_>, event: Event) -> Response { ... }
fn steal_event(
&mut self,
mgr: &mut EventMgr<'_>,
id: &WidgetId,
event: &Event
) -> Response { ... }
fn handle_unused(
&mut self,
mgr: &mut EventMgr<'_>,
index: usize,
event: Event
) -> Response { ... }
fn handle_message(&mut self, mgr: &mut EventMgr<'_>, index: usize) { ... }
fn handle_scroll(&mut self, mgr: &mut EventMgr<'_>, scroll: Scroll) { ... }
}Expand description
The Widget trait
Widgets implement a family of traits, of which this trait is the final member:
WidgetCore— base functionalityWidgetChildren— enumerates childrenLayout— handles sizing and positioning for self and childrenWidget— configuration, some aspects of layout, event handling
Implementing Widget
To implement a widget, use the macros::widget macro. This is the
only supported method of implementing Widget.
The macros::widget macro only works within macros::impl_scope.
Other trait implementations can be detected within this scope:
WidgetCoreis always generatedWidgetChildrenis generated if no direct implementation is presentLayoutis generated if thelayoutattribute property is set, and no direct implementation is found. In other cases where a direct implementation of the trait is found, (default) method implementations may be injected where not already present.Widgetis generated if no direct implementation is present, otherwise some (default) method implementations are injected where these methods are not directly implemented.
Some simple examples follow. See also
examples apps
and kas_widgets code.
use kas::prelude::*;
use kas::event;
use kas::theme::TextClass;
use std::fmt::Debug;
impl_scope! {
/// A text label
#[derive(Clone, Debug)]
#[widget]
pub struct AccelLabel {
core: widget_core!(),
class: TextClass,
label: Text<AccelString>,
}
impl Self {
/// Construct from `label`
pub fn new(label: impl Into<AccelString>) -> Self {
AccelLabel {
core: Default::default(),
class: TextClass::AccelLabel(true),
label: Text::new(label.into()),
}
}
/// Set text class (inline)
pub fn with_class(mut self, class: TextClass) -> Self {
self.class = class;
self
}
/// Get the accelerator keys
pub fn keys(&self) -> &[event::VirtualKeyCode] {
self.label.text().keys()
}
}
impl Layout for Self {
fn size_rules(&mut self, size_mgr: SizeMgr, mut axis: AxisInfo) -> SizeRules {
axis.set_default_align_hv(Align::Default, Align::Center);
size_mgr.text_rules(&mut self.label, self.class, axis)
}
fn set_rect(&mut self, mgr: &mut ConfigMgr, rect: Rect) {
self.core.rect = rect;
mgr.text_set_size(&mut self.label, self.class, rect.size, None);
}
fn draw(&mut self, mut draw: DrawMgr) {
draw.text_effects(self.rect(), &self.label, self.class);
}
}
}
impl_scope! {
/// A push-button with a text label
#[derive(Debug)]
#[widget {
layout = button: self.label;
navigable = true;
hover_highlight = true;
}]
pub struct TextButton<M: Clone + Debug + 'static> {
core: widget_core!(),
#[widget]
label: AccelLabel,
message: M,
}
impl Self {
/// Construct a button with given `label`
pub fn new(label: impl Into<AccelString>, message: M) -> Self {
TextButton {
core: Default::default(),
label: AccelLabel::new(label).with_class(TextClass::Button),
message,
}
}
}
impl Widget for Self {
fn configure(&mut self, mgr: &mut ConfigMgr) {
mgr.add_accel_keys(self.id_ref(), self.label.keys());
}
fn handle_event(&mut self, mgr: &mut EventMgr, event: Event) -> Response {
event.on_activate(mgr, self.id(), |mgr| {
mgr.push_msg(self.message.clone());
Response::Used
})
}
}
}Required Methods
sourcefn pre_configure(&mut self, mgr: &mut ConfigMgr<'_>, id: WidgetId)
fn pre_configure(&mut self, mgr: &mut ConfigMgr<'_>, id: WidgetId)
Pre-configuration
This method is called before children are configured to assign a
WidgetId. Usually it does nothing else, but a custom implementation
may be used to affect child configuration, e.g. via
EventState::new_accel_layer.
Default impl: assign id to self
Provided Methods
Configure widget
Widgets are configured on window creation or dynamically via the
parent calling ConfigMgr::configure. Parent widgets are responsible
for ensuring that children are configured before calling
Layout::size_rules or Layout::set_rect. Configuration may be
repeated and may be used as a mechanism to change a child’s WidgetId,
but this may be expensive.
This method may be used to configure event handling and to load
resources, including resources affecting Layout::size_rules.
The window’s scale factor (and thus any sizes available through
ConfigMgr::size_mgr) may not be correct initially (some platforms
construct all windows using scale factor 1) and/or may change in the
future. Changes to the scale factor result in recalculation of
Layout::size_rules but not repeated configuration.
Is this widget navigable via Tab key?
Defaults to false.
sourcefn translation(&self) -> Offset
fn translation(&self) -> Offset
Get translation of children relative to this widget
Usually this is zero; only widgets with scrollable or offset content
and child widgets need to implement this.
Such widgets must also implement Widget::handle_scroll.
Affects event handling via Layout::find_id and affects the positioning
of pop-up menus. Layout::draw must be implemented directly using
DrawMgr::with_clip_region to offset contents.
Navigation in spatial order
Controls Tab navigation order of children. This method should:
- Return
Noneif there is no next child - Determine the next child after
from(if provided) or the whole range, optionally inreverseorder - Ensure that the selected widget is addressable through
WidgetChildren::get_child
Both from and the return value use the widget index, as used by
WidgetChildren::get_child.
Default implementation:
- Generated from
#[widget]’s layout property, if used - Otherwise, iterate through children in order of definition
sourcefn handle_event(&mut self, mgr: &mut EventMgr<'_>, event: Event) -> Response
fn handle_event(&mut self, mgr: &mut EventMgr<'_>, event: Event) -> Response
Handle an event sent to this widget
An Event is some form of user input, timer or notification.
This is the primary event handler for a widget. Secondary handlers are:
- If this method returns
Response::Unused, thenWidget::handle_unusedis called on each parent until the event is used (or the root widget is reached) - If a message is left on the stack by
EventMgr::push_msg, thenWidget::handle_messageis called on each parent until the stack is empty (failing to empty the stack results in a warning in the log). - If any scroll state is set by
EventMgr::set_scroll, thenWidget::handle_scrollis called for each parent
Default implementation: do nothing; return Response::Unused.
Calling handle_event
It is not recommended to call handle_event directly except on self.
Doing so would miss related event handling code such as cursor-hover
effects and calling other event-handling methods on parents.
Instead, one should call EventMgr::send with the target’s id.
Potentially steal an event before it reaches a child
This is called on each widget while sending an event, including when the
target is self.
If this returns Response::Used, the event is not sent further.
Default implementation: return Response::Unused.
Handle an event sent to child index but left unhandled
Default implementation: call Self::handle_event with event.
sourcefn handle_message(&mut self, mgr: &mut EventMgr<'_>, index: usize)
fn handle_message(&mut self, mgr: &mut EventMgr<'_>, index: usize)
Handler for messages from children/descendants
This method is called when a child leaves a message on the stack. Some parent or ancestor widget should read this message.
The default implementation does nothing.
sourcefn handle_scroll(&mut self, mgr: &mut EventMgr<'_>, scroll: Scroll)
fn handle_scroll(&mut self, mgr: &mut EventMgr<'_>, scroll: Scroll)
Handler for scrolling
When a child calls EventMgr::set_scroll with a value other than
Scroll::None, this method is called. (This method is not called
after Self::handle_event or other handlers called on self.)
Note that Scroll::Rect values are in the child’s coordinate space,
and must be translated to the widget’s own coordinate space by this
method (this is not done by the default implementation since any widget
with non-zero translation very likely wants to implement this method
anyway).
If the child is in an independent coordinate space, then this method
should call mgr.set_scroll(Scroll::None) to avoid any reactions to
child’s scroll requests.
The default implementation does nothing.