change focus when an element is clicked

This commit is contained in:
Evan Almloff committed 2022-05-03 17:19:16 -05:00
1 parent 23376fef8e
commit 9ed722ae45
4 files changed
+83 -38

No files matched your search

+5 -1
View File
@@ -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
+24 -1
View File
@@ -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
View File
@@ -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()
}
}
+4 -2
View File
@@ -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));
}