change focus when an element is clicked
This commit is contained in:
1 parent
23376fef8e
commit
9ed722ae45
4 files changed
+83
-38
No files matched your search
@@ -64,7 +64,9 @@ impl PersistantElementIter {
|
||||
}
|
||||
|
||||
/// remove stale element refreneces
|
||||
pub fn prune<S: State>(&mut self, mutations: &Mutations, rdom: &RealDom<S>) {
|
||||
/// returns true if the focused element is removed
|
||||
pub fn prune<S: State>(&mut self, mutations: &Mutations, rdom: &RealDom<S>) -> bool {
|
||||
let mut changed = false;
|
||||
let ids_removed: Vec<_> = mutations
|
||||
.edits
|
||||
.iter()
|
||||
@@ -82,6 +84,7 @@ impl PersistantElementIter {
|
||||
.position(|(el_id, _)| ids_removed.iter().any(|id| el_id.as_u64() == *id))
|
||||
{
|
||||
self.stack.truncate(r);
|
||||
changed = true;
|
||||
}
|
||||
// if a child is removed or inserted before or at the current element, update the child index
|
||||
for (el_id, child_idx) in self.stack.iter_mut() {
|
||||
@@ -122,6 +125,7 @@ impl PersistantElementIter {
|
||||
}
|
||||
}
|
||||
}
|
||||
changed
|
||||
}
|
||||
|
||||
/// get the next element
|
||||
|
||||
@@ -109,10 +109,11 @@ pub(crate) struct FocusState {
|
||||
pub(crate) focus_iter: PersistantElementIter,
|
||||
pub(crate) last_focused_id: Option<ElementId>,
|
||||
pub(crate) focus_level: FocusLevel,
|
||||
pub(crate) dirty: bool,
|
||||
}
|
||||
|
||||
impl FocusState {
|
||||
// returns true if the focus has changed
|
||||
/// Returns true if the focus has changed.
|
||||
pub fn progress(&mut self, rdom: &mut Dom, forward: bool) -> bool {
|
||||
if let Some(last) = self.last_focused_id {
|
||||
if !rdom[last].state.focus.pass_focus {
|
||||
@@ -227,6 +228,7 @@ impl FocusState {
|
||||
self.focus_iter.prev(&rdom).id()
|
||||
} != id
|
||||
{}
|
||||
self.dirty = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -253,6 +255,9 @@ impl FocusState {
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.focus_iter.prune(mutations, rdom) {
|
||||
self.dirty = true;
|
||||
}
|
||||
for m in &mutations.edits {
|
||||
match m {
|
||||
dioxus_core::DomEdit::ReplaceWith { root, .. } => remove_children(
|
||||
@@ -269,4 +274,22 @@ impl FocusState {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_focus(&mut self, rdom: &mut Dom, id: ElementId) {
|
||||
if let Some(old) = self.last_focused_id.replace(id) {
|
||||
rdom[old].state.focused = false;
|
||||
}
|
||||
let state = &mut rdom[id].state;
|
||||
state.focused = true;
|
||||
self.focus_level = state.focus.level;
|
||||
// reset the position to the currently focused element
|
||||
while self.focus_iter.next(&rdom).id() != id {}
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
pub(crate) fn clean(&mut self) -> bool {
|
||||
let old = self.dirty;
|
||||
self.dirty = false;
|
||||
old
|
||||
}
|
||||
}
|
||||
+50
-34
@@ -7,7 +7,7 @@ use fxhash::{FxHashMap, FxHashSet};
|
||||
use dioxus_html::{on::*, KeyCode};
|
||||
use std::{
|
||||
any::Any,
|
||||
cell::RefCell,
|
||||
cell::{RefCell, RefMut},
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
@@ -79,7 +79,7 @@ pub struct InnerInputState {
|
||||
wheel: Option<WheelData>,
|
||||
last_key_pressed: Option<(KeyboardData, Instant)>,
|
||||
screen: Option<(u16, u16)>,
|
||||
focus_state: FocusState,
|
||||
pub(crate) focus_state: FocusState,
|
||||
// subscribers: Vec<Rc<dyn Fn() + 'static>>,
|
||||
}
|
||||
|
||||
@@ -170,19 +170,14 @@ impl InnerInputState {
|
||||
resolved_events: &mut Vec<UserEvent>,
|
||||
layout: &Stretch,
|
||||
dom: &mut Dom,
|
||||
) -> bool {
|
||||
) {
|
||||
let previous_mouse = self.mouse.as_ref().map(|m| (m.0.clone(), m.1.clone()));
|
||||
|
||||
self.wheel = None;
|
||||
let mut force_redraw = false;
|
||||
|
||||
evts.retain(|e| match &e.1 {
|
||||
EventData::Keyboard(k) => match k.key_code {
|
||||
KeyCode::Tab => {
|
||||
let focus_event = self.focus_state.progress(dom, !k.shift_key);
|
||||
force_redraw |= focus_event;
|
||||
!focus_event
|
||||
}
|
||||
KeyCode::Tab => !self.focus_state.progress(dom, !k.shift_key),
|
||||
_ => true,
|
||||
},
|
||||
_ => true,
|
||||
@@ -197,11 +192,10 @@ impl InnerInputState {
|
||||
// for s in &self.subscribers {
|
||||
// s();
|
||||
// }
|
||||
force_redraw
|
||||
}
|
||||
|
||||
fn resolve_mouse_events(
|
||||
&self,
|
||||
&mut self,
|
||||
previous_mouse: Option<(MouseData, Vec<u16>)>,
|
||||
resolved_events: &mut Vec<UserEvent>,
|
||||
layout: &Stretch,
|
||||
@@ -343,14 +337,14 @@ impl InnerInputState {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// mousedown
|
||||
// mousedown
|
||||
if data.clicked {
|
||||
let mut will_bubble = FxHashSet::default();
|
||||
for node in dom.get_listening_sorted("mousedown") {
|
||||
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
|
||||
let currently_contains = layout_contains_point(node_layout, data.new_pos);
|
||||
|
||||
if currently_contains && data.clicked {
|
||||
if currently_contains {
|
||||
try_create_event(
|
||||
"mousedown",
|
||||
Arc::new(data.mouse_data.clone()),
|
||||
@@ -363,14 +357,14 @@ impl InnerInputState {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// mouseup
|
||||
// mouseup
|
||||
if data.released {
|
||||
let mut will_bubble = FxHashSet::default();
|
||||
for node in dom.get_listening_sorted("mouseup") {
|
||||
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
|
||||
let currently_contains = layout_contains_point(node_layout, data.new_pos);
|
||||
|
||||
if currently_contains && data.released {
|
||||
if currently_contains {
|
||||
try_create_event(
|
||||
"mouseup",
|
||||
Arc::new(data.mouse_data.clone()),
|
||||
@@ -383,14 +377,14 @@ impl InnerInputState {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// click
|
||||
// click
|
||||
if data.released && data.mouse_data.button == 0 {
|
||||
let mut will_bubble = FxHashSet::default();
|
||||
for node in dom.get_listening_sorted("click") {
|
||||
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
|
||||
let currently_contains = layout_contains_point(node_layout, data.new_pos);
|
||||
|
||||
if currently_contains && data.released && data.mouse_data.button == 0 {
|
||||
if currently_contains {
|
||||
try_create_event(
|
||||
"click",
|
||||
Arc::new(data.mouse_data.clone()),
|
||||
@@ -403,14 +397,14 @@ impl InnerInputState {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// contextmenu
|
||||
// contextmenu
|
||||
if data.released && data.mouse_data.button == 2 {
|
||||
let mut will_bubble = FxHashSet::default();
|
||||
for node in dom.get_listening_sorted("contextmenu") {
|
||||
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
|
||||
let currently_contains = layout_contains_point(node_layout, data.new_pos);
|
||||
|
||||
if currently_contains && data.released && data.mouse_data.button == 2 {
|
||||
if currently_contains {
|
||||
try_create_event(
|
||||
"contextmenu",
|
||||
Arc::new(data.mouse_data.clone()),
|
||||
@@ -423,15 +417,15 @@ impl InnerInputState {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// wheel
|
||||
let mut will_bubble = FxHashSet::default();
|
||||
for node in dom.get_listening_sorted("wheel") {
|
||||
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
|
||||
let currently_contains = layout_contains_point(node_layout, data.new_pos);
|
||||
// wheel
|
||||
if let Some(w) = data.wheel_data {
|
||||
if data.wheel_delta != 0.0 {
|
||||
let mut will_bubble = FxHashSet::default();
|
||||
for node in dom.get_listening_sorted("wheel") {
|
||||
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
|
||||
let currently_contains = layout_contains_point(node_layout, data.new_pos);
|
||||
|
||||
if let Some(w) = data.wheel_data {
|
||||
if currently_contains && data.wheel_delta != 0.0 {
|
||||
if currently_contains {
|
||||
try_create_event(
|
||||
"wheel",
|
||||
Arc::new(w.clone()),
|
||||
@@ -492,6 +486,24 @@ impl InnerInputState {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update focus
|
||||
if data.released {
|
||||
let mut focus_id = None;
|
||||
dom.traverse_depth_first(|node| {
|
||||
let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
|
||||
let currently_contains = layout_contains_point(node_layout, data.new_pos);
|
||||
|
||||
if currently_contains {
|
||||
if node.state.focus.level.focusable() {
|
||||
focus_id = Some(node.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
if let Some(id) = focus_id {
|
||||
self.focus_state.set_focus(dom, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,10 +553,10 @@ impl RinkInputHandler {
|
||||
}
|
||||
|
||||
// returns a list of events and if a event will force a rerender
|
||||
pub(crate) fn get_events(&self, layout: &Stretch, dom: &mut Dom) -> (Vec<UserEvent>, bool) {
|
||||
pub(crate) fn get_events(&self, layout: &Stretch, dom: &mut Dom) -> Vec<UserEvent> {
|
||||
let mut resolved_events = Vec::new();
|
||||
|
||||
let rerender = (*self.state).borrow_mut().update(
|
||||
(*self.state).borrow_mut().update(
|
||||
&mut (*self.queued_events).borrow_mut(),
|
||||
&mut resolved_events,
|
||||
layout,
|
||||
@@ -598,7 +610,11 @@ impl RinkInputHandler {
|
||||
}
|
||||
}
|
||||
|
||||
(resolved_events, rerender)
|
||||
resolved_events
|
||||
}
|
||||
|
||||
pub(crate) fn state(&self) -> RefMut<InnerInputState> {
|
||||
self.state.borrow_mut()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -223,8 +223,10 @@ fn render_vdom(
|
||||
}
|
||||
|
||||
{
|
||||
let (evts, rerender) = handler.get_events(&stretch.borrow(), &mut rdom);
|
||||
updated |= rerender;
|
||||
let evts = handler.get_events(&stretch.borrow(), &mut rdom);
|
||||
{
|
||||
updated |= handler.state().focus_state.clean();
|
||||
}
|
||||
for e in evts {
|
||||
vdom.handle_message(SchedulerMsg::Event(e));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user