Skip to content

Commit

Permalink
refactor(core): 💡 consolidated all listener and FocusNode into a `Mix…
Browse files Browse the repository at this point in the history
…Builtin` widget
  • Loading branch information
M-Adoo committed Feb 23, 2024
1 parent 9597272 commit 133854e
Show file tree
Hide file tree
Showing 23 changed files with 1,071 additions and 1,008 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he

## [@Unreleased] - @ReleaseDate

### Changed

- **core**: Consolidated all listener and `FocusNode` into a `MixBuiltin` widget (#534 @M-Adoo)
- The `MixBuiltin` widget reduces memory usage and allows users to utilize all `on_xxx` event handlers, not only during the build declaration but also after the widget has been built.


## [0.2.0-alpha.3] - 2024-02-20

## [0.2.0-alpha.2] - 2024-02-13
Expand Down
2 changes: 1 addition & 1 deletion core/src/animation/transition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub trait TransitionState: Sized + 'static {
Self: AnimateState,
{
let state = self.clone_setter();
let animate: State<Animate<Self>> = Animate::declare_builder()
let animate = Animate::declare_builder()
.transition(transition)
.from(self.get())
.state(self)
Expand Down
14 changes: 3 additions & 11 deletions core/src/builtin_widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ mod void;
pub use void::Void;
mod unconstrained_box;
pub use unconstrained_box::*;
mod lifecycle;
pub use lifecycle::*;
mod opacity;
pub use opacity::*;
mod anchor;
Expand All @@ -63,6 +61,8 @@ pub mod focus_scope;
pub use focus_scope::*;
pub mod global_anchor;
pub use global_anchor::*;
mod mix_builtin;
pub use mix_builtin::*;

use crate::{
prelude::*,
Expand Down Expand Up @@ -148,16 +148,9 @@ macro_rules! impl_builtin_obj {
}

impl_builtin_obj!(
PointerListener,
FocusNode,
MixBuiltin,
RequestFocus,
FocusListener,
FocusBubbleListener,
HasFocus,
KeyboardListener,
CharsListener,
ImePreEditListener,
WheelListener,
MouseHover,
PointerPressed,
FittedBox,
Expand All @@ -174,7 +167,6 @@ impl_builtin_obj!(
GlobalAnchor,
Visibility,
Opacity,
LifecycleListener,
DelayDrop
);

Expand Down
95 changes: 9 additions & 86 deletions core/src/builtin_widgets/focus_node.rs
Original file line number Diff line number Diff line change
@@ -1,83 +1,4 @@
use crate::{
events::focus_mgr::{FocusHandle, FocusType},
prelude::*,
};

#[derive(Default, Query, Declare)]
pub struct FocusNode {
/// Indicates that `widget` can be focused, and where it participates in
/// sequential keyboard navigation (usually with the Tab key, hence the name.
///
/// It accepts an integer as a value, with different results depending on the
/// integer's value:
/// - A negative value (usually -1) means that the widget is not reachable via
/// sequential keyboard navigation, but could be focused with API or
/// visually by clicking with the mouse.
/// - Zero means that the element should be focusable in sequential keyboard
/// navigation, after any positive tab_index values and its order is defined
/// by the tree's source order.
/// - A positive value means the element should be focusable in sequential
/// keyboard navigation, with its order defined by the value of the number.
/// That is, tab_index=4 is focused before tab_index=5 and tab_index=0, but
/// after tab_index=3. If multiple elements share the same positive
/// tab_index value, their order relative to each other follows their
/// position in the tree source. The maximum value for tab_index is 32767.
/// If not specified, it takes the default value 0.
#[declare(default, builtin)]
pub tab_index: i16,
/// Indicates whether the `widget` should automatically get focus when the
/// window loads.
///
/// Only one widget should have this attribute specified. If there are
/// several, the widget nearest the root, get the initial
/// focus.
#[declare(default, builtin)]
pub auto_focus: bool,
}

impl ComposeChild for FocusNode {
type Child = Widget;
fn compose_child(
this: impl StateWriter<Value = Self>,
mut child: Self::Child,
) -> impl WidgetBuilder {
fn_widget! {
let tree = ctx!().tree.borrow();
let node = child.id().assert_get(&tree.arena);
let has_focus_node = node.contain_type::<FocusNode>();
if !has_focus_node {
let subject = node.query_most_outside(|l: &LifecycleListener| l.lifecycle_stream());
drop(tree);
let subject = if let Some(subject) = subject {
subject
} else {
let listener = LifecycleListener::default();
let subject = listener.lifecycle_stream();
child = child.attach_data(listener, ctx!());
subject
};

fn subscribe_fn(this: impl StateReader<Value = FocusNode>)
-> impl FnMut(&'_ mut AllLifecycle) + 'static
{
move |e| match e {
AllLifecycle::Mounted(e) => {
let auto_focus = this.read().auto_focus;
e.window().add_focus_node(e.id, auto_focus, FocusType::Node)
}
AllLifecycle::PerformedLayout(_) => {}
AllLifecycle::Disposed(e) => e.window().remove_focus_node(e.id, FocusType::Node),
}
}
let h = subject
.subscribe(subscribe_fn(this.clone_reader()))
.unsubscribe_when_dropped();
child = child.attach_state_data(this, ctx!()).attach_anonymous_data(h, ctx!());
}
child
}
}
}
use crate::{events::focus_mgr::FocusHandle, prelude::*};

#[derive(Declare, Query)]
pub struct RequestFocus {
Expand Down Expand Up @@ -124,11 +45,11 @@ mod tests {
reset_test_env!();

let widget = fn_widget! {
@FocusNode {
@MixBuiltin {
tab_index: 0i16, auto_focus: false,
@FocusNode {
@MixBuiltin {
tab_index: 0i16, auto_focus: false,
@FocusNode {
@MixBuiltin {
tab_index: 0i16, auto_focus: false,
@MockBox {
size: Size::default(),
Expand All @@ -143,11 +64,13 @@ mod tests {
let id = tree.root();
let node = id.get(&tree.arena).unwrap();
let mut cnt = 0;
node.query_type_inside_first(|_: &FocusNode| {
cnt += 1;
node.query_type_inside_first(|b: &MixBuiltin| {
if b.contain_flag(BuiltinFlags::Focus) {
cnt += 1;
}
true
});

assert!(cnt == 1);
assert_eq!(cnt, 1);
}
}
Loading

0 comments on commit 133854e

Please sign in to comment.