ribir_core 0.4.0-alpha.2

A non-intrusive declarative GUI framework, to build modern native/wasm cross-platform applications.
Documentation
use crate::{events::focus_mgr::FocusHandle, prelude::*};

#[derive(Default)]
pub struct RequestFocus {
  handle: Option<FocusHandle>,
}

impl Declare for RequestFocus {
  type Builder = FatObj<()>;
  #[inline]
  fn declarer() -> Self::Builder { FatObj::new(()) }
}

impl ComposeChild for RequestFocus {
  type Child = Widget;
  fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> impl WidgetBuilder {
    fn_widget! {
      @$child {
        on_mounted: move |e| {
          let handle = e.window().focus_mgr.borrow().focus_handle(e.id);
          $this.silent().handle = Some(handle);
        }
      }
      .build(ctx!())
      .try_unwrap_state_and_attach(this, ctx!())
    }
  }
}
impl RequestFocus {
  pub fn request_focus(&self) {
    if let Some(h) = self.handle.as_ref() {
      h.request_focus();
    }
  }

  pub fn unfocus(&self) {
    if let Some(h) = self.handle.as_ref() {
      h.unfocus();
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use crate::{reset_test_env, test_helper::*};

  #[test]
  fn dynamic_focus_node() {
    reset_test_env!();

    let widget = fn_widget! {
      @MixBuiltin {
        tab_index: 0i16, auto_focus: false,
        @MixBuiltin {
          tab_index: 0i16, auto_focus: false,
          @MixBuiltin {
            tab_index: 0i16, auto_focus: false,
            @MockBox {
              size: Size::default(),
            }
          }
        }
      }
    };

    let wnd = TestWindow::new(widget);
    let tree = wnd.widget_tree.borrow();
    let id = tree.content_root();
    let node = id.get(&tree.arena).unwrap();
    let mut cnt = 0;
    node.query_all_iter::<MixBuiltin>().for_each(|b| {
      if b.contain_flag(BuiltinFlags::Focus) {
        cnt += 1;
      }
    });
    assert_eq!(cnt, 1);
  }
}