Skip to content

Commit

Permalink
fix transition layout (lapce#570)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrmoulton committed Sep 25, 2024
1 parent 232ac31 commit 1b3194d
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 68 deletions.
93 changes: 30 additions & 63 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::{
rc::Rc,
sync::Arc,
};
use taffy::Display;

#[cfg(not(target_arch = "wasm32"))]
use std::time::{Duration, Instant};
Expand Down Expand Up @@ -742,70 +741,38 @@ impl<'a> ComputeLayoutCx<'a> {
pub fn compute_view_layout(&mut self, id: ViewId) -> Option<Rect> {
let view_state = id.state();

{
let mut view_state_ref = view_state.borrow_mut();
let is_hidden_state = view_state_ref.is_hidden_state;
let style_has_hidden = view_state_ref.combined_style.get(DisplayProp) == Display::None;

match is_hidden_state {
IsHiddenState::Visble(dis) if style_has_hidden => {
// view state isn't yet marked as hidden but the style is, meaning that this is the first time that this view is hidden,
// need to check for animations
drop(view_state_ref);
let count = animations_recursive_on_remove(id, Scope::current());
let mut view_state_ref = view_state.borrow_mut();
view_state_ref.num_waiting_animations = count;

if count > 0 {
// set the combined style to display
view_state_ref
.combined_style
.apply_mut(Style::new().display(dis));
view_state_ref.is_hidden_state = IsHiddenState::AnimatingOut(dis);
} else {
// hidden and no animations active
view_state_ref.layout_rect = Rect::ZERO;
view_state_ref.is_hidden_state = IsHiddenState::Hidden;
return None;
}
}
IsHiddenState::AnimatingOut(dis) => {
if !style_has_hidden {
// finished hiding before animations finished
let display = view_state_ref.combined_style.get(DisplayProp);
view_state_ref.is_hidden_state = IsHiddenState::Visble(display);
} else if view_state_ref.num_waiting_animations == 0 {
// animations finished, set state to hidden
view_state_ref.is_hidden_state = IsHiddenState::Hidden;
view_state_ref.layout_rect = Rect::ZERO;
drop(view_state_ref);
id.request_layout();
return None;
} else {
// while still animating, keep the same display mode
view_state_ref
.combined_style
.apply_mut(Style::new().display(dis));
}
}
IsHiddenState::Hidden => {
drop(view_state_ref);
if !id.style_has_hidden() {
// view state was marked as hidden but style is now not, transition to visible
animations_recursive_on_create(id);
let mut view_state_ref = view_state.borrow_mut();
let display = view_state_ref.combined_style.get(DisplayProp);
view_state_ref.is_hidden_state = IsHiddenState::Visble(display);
} else {
// style is hidden, view state has hidden
view_state.borrow_mut().layout_rect = Rect::ZERO;
return None;
}
}
_ => {}
};
let mut is_hidden_state = view_state.borrow().is_hidden_state;
let display = view_state.borrow().combined_style.get(DisplayProp);
let request_layout = is_hidden_state.transition(
display,
|| {
let count = animations_recursive_on_remove(id, Scope::current());
view_state.borrow_mut().num_waiting_animations = count;
count > 0
},
|| {
animations_recursive_on_create(id);
},
|| view_state.borrow().num_waiting_animations,
);
if request_layout {
id.request_layout();
}

view_state.borrow_mut().is_hidden_state = is_hidden_state;
if is_hidden_state == IsHiddenState::Hidden {
view_state.borrow_mut().layout_rect = Rect::ZERO;
return None;
}

let modified = view_state
.borrow()
.combined_style
.clone()
.apply_opt(is_hidden_state.get_display(), Style::display);

view_state.borrow_mut().combined_style = modified;

self.save();

let layout = id.get_layout().unwrap_or_default();
Expand Down
53 changes: 48 additions & 5 deletions src/view_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,62 @@ bitflags! {
}
}

#[derive(Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IsHiddenState {
Visble(taffy::style::Display),
Visible(taffy::style::Display),
AnimatingOut(taffy::style::Display),
Hidden,
None,
}
impl IsHiddenState {
pub(crate) fn get_display(&self) -> Option<taffy::style::Display> {
match self {
IsHiddenState::Visble(dis) | IsHiddenState::AnimatingOut(dis) => Some(*dis),
IsHiddenState::Hidden => None,
IsHiddenState::AnimatingOut(dis) => Some(*dis),
_ => None,
}
}

// returns true if the view should request layout
pub(crate) fn transition(
&mut self,
display: taffy::Display,
remove_animations: impl FnOnce() -> bool,
add_animations: impl FnOnce(),
num_waiting_anim: impl FnOnce() -> u16,
) -> bool {
let hide = display == taffy::Display::None;
let mut request_layout = false;
*self = match self {
Self::None if hide => Self::Hidden,
Self::None if !hide => Self::Visible(display),
Self::Visible(dis) if !hide => Self::Visible(*dis),
Self::Visible(dis) if hide => {
let active_animations = remove_animations();
if active_animations {
// request_layout = true;
Self::AnimatingOut(*dis)
} else {
Self::Hidden
}
}
Self::AnimatingOut(_) if !hide => Self::Visible(display),
Self::AnimatingOut(dis) if hide => {
if num_waiting_anim() == 0 {
request_layout = true;
Self::Hidden
} else {
Self::AnimatingOut(*dis)
}
}
Self::Hidden if hide => Self::Hidden,
Self::Hidden if !hide => {
add_animations();
Self::Visible(display)
}
_ => unreachable!(),
};
request_layout
}
}

/// View state stores internal state associated with a view which is owned and managed by Floem.
Expand Down Expand Up @@ -154,7 +197,7 @@ impl ViewState {
cleanup_listener: None,
last_pointer_down: None,
window_origin: Point::ZERO,
is_hidden_state: IsHiddenState::Visble(taffy::Display::Flex),
is_hidden_state: IsHiddenState::None,
num_waiting_animations: 0,
debug_name: Default::default(),
}
Expand Down

0 comments on commit 1b3194d

Please sign in to comment.