SlidingView: Fix animation for deleting images

This commit is contained in:
Sophie Herold 2024-01-28 15:41:00 +01:00
parent 67513dc3f5
commit f1f8ba9a88
2 changed files with 79 additions and 52 deletions

View file

@ -115,7 +115,8 @@ const MAX_ZOOM_LEVEL: f64 = 20.0;
/// The thumbnail is currently used for drag and drop.
const THUMBNAIL_SIZE: f32 = 128.;
/// For large enough monitors occupy 40% of the screen area when opening window with image
/// For large enough monitors occupy 40% of the screen area when opening window
/// with image
const DEFAULT_OCCUPY_SCREEN: f64 = 0.4;
/// Screens with this resolution or smaller are handles as small

View file

@ -56,6 +56,7 @@ const PAGE_SPACING_PERCENT: f32 = 0.02;
#[derive(Debug)]
enum PositionTracking {
/// Animatable position, 0.0 first image, 1.0 second image etc
Position(f64),
StackedCards(StackedCards),
}
@ -67,14 +68,6 @@ impl Default for PositionTracking {
}
impl PositionTracking {
fn position(&self) -> f64 {
match self {
Self::Position(position) => *position,
// TODO: This could return something useful
Self::StackedCards(_) => 0.,
}
}
fn set_position(&mut self, position: f64) {
*self = Self::Position(position);
}
@ -93,13 +86,15 @@ impl PositionTracking {
struct StackedCards {
prev_image: LpImagePage,
progress: f64,
backward: bool,
}
impl StackedCards {
fn new(prev_image: LpImagePage) -> Self {
fn new(prev_image: LpImagePage, backward: bool) -> Self {
Self {
prev_image,
progress: 0.,
backward,
}
}
}
@ -228,13 +223,38 @@ mod imp {
impl WidgetImpl for LpSlidingView {
fn size_allocate(&self, width: i32, height: i32, _baseline: i32) {
let obj = self.obj();
// Unparent deleted children if not in animation that might contain them
if matches!(
*self.position_tracking.borrow(),
PositionTracking::Position(_)
) {
if let Some(mut child) = obj.first_child() {
let mut children = vec![child.clone()];
while let Some(new_child) = child.next_sibling() {
child = new_child;
children.push(child.clone());
}
for child in children {
if let Ok(page) = child.downcast::<LpImagePage>() {
if obj.index_of(&page).is_none() {
page.unparent();
}
}
}
}
}
for (page_index, page) in self.pages.borrow().iter().enumerate() {
match *self.position_tracking.borrow() {
PositionTracking::Position(_) => {
self.size_allocate_position(page_index, page, width, height)
}
PositionTracking::StackedCards(ref stacked_cards) => {
self.size_allocate_stacked_cards(page, stacked_cards, width, height)
PositionTracking::StackedCards(_) => {
// Hide all and show to relevant widgets later
page.set_child_visible(false);
}
}
@ -243,6 +263,11 @@ mod imp {
page.scrolled_window().allocate(width, height, 0, None);
}
}
if let PositionTracking::StackedCards(stacked_cards) = &*self.position_tracking.borrow()
{
self.size_allocate_stacked_cards(stacked_cards, width, height);
}
}
fn measure(&self, orientation: gtk::Orientation, for_size: i32) -> (i32, i32, i32, i32) {
@ -338,53 +363,42 @@ mod imp {
/// Allocate during stacked card animation
fn size_allocate_stacked_cards(
&self,
page: &LpImagePage,
stacked_cards: &StackedCards,
width: i32,
height: i32,
) {
let obj = self.obj().to_owned();
if let Some(new_page) = obj.current_page() {
let old_page = &stacked_cards.prev_image;
let prev_page = &stacked_cards.prev_image;
let Some(old_index) = obj.index_of(old_page) else {
return;
};
let Some(new_index) = obj.index_of(&new_page) else {
return;
};
let mut direction_sign = if new_index > old_index { 1. } else { -1. };
let mut direction_sign = if stacked_cards.backward { -1. } else { 1. };
if self.is_rtl() {
direction_sign *= -1.;
}
let progress = stacked_cards.progress;
// Only show visible images
if page == &new_page {
page.set_child_visible(true);
//New Page
new_page.set_child_visible(true);
// Ensure that new image is on top
page.unparent();
page.insert_after(&obj, Some(old_page));
// Ensure that new image is on top
new_page.unparent();
new_page.insert_after(&obj, Some(prev_page));
let x = direction_sign * STEP_PIXEL_SHIFT * (1. - progress as f32);
let transform = gsk::Transform::new().translate(&graphene::Point::new(x, 0.));
page.allocate(width, height, 0, Some(transform));
page.set_opacity(progress);
} else if page == old_page {
page.set_child_visible(true);
let x = -direction_sign
* f32::max(
0.,
(progress as f32 - STEP_MOVE_OUT_DELAY) * STEP_PIXEL_SHIFT,
);
let transform = gsk::Transform::new().translate(&graphene::Point::new(x, 0.));
page.allocate(width, height, 0, Some(transform));
} else {
page.set_child_visible(false);
}
let x = direction_sign * STEP_PIXEL_SHIFT * (1. - progress as f32);
let transform = gsk::Transform::new().translate(&graphene::Point::new(x, 0.));
new_page.allocate(width, height, 0, Some(transform));
new_page.set_opacity(progress);
// Prev Page
prev_page.set_child_visible(true);
let x = -direction_sign
* f32::max(
0.,
(progress as f32 - STEP_MOVE_OUT_DELAY) * STEP_PIXEL_SHIFT,
);
let transform = gsk::Transform::new().translate(&graphene::Point::new(x, 0.));
prev_page.allocate(width, height, 0, Some(transform));
}
}
@ -464,8 +478,8 @@ impl LpSlidingView {
let current_index = self.current_index();
if let Some(index) = self.index_of(page) {
// Don't unparent here since page might still be needed in delete animation.
self.imp().pages.borrow_mut().remove(index);
page.unparent();
self.queue_allocate();
@ -545,10 +559,16 @@ impl LpSlidingView {
/// Move to image with cards animation
fn step_to(&self, page: &LpImagePage) {
let animation = self.step_animation();
if let Some(prev_image) = self.current_page() {
*self.imp().position_tracking.borrow_mut() =
PositionTracking::StackedCards(StackedCards::new(prev_image));
animation.play();
if let Some(prev_page) = self.current_page() {
if let (Some(prev_index), Some(new_index)) =
(self.index_of(&prev_page), self.index_of(page))
{
let backward = new_index < prev_index;
*self.imp().position_tracking.borrow_mut() =
PositionTracking::StackedCards(StackedCards::new(prev_page, backward));
animation.play();
}
}
self.set_current_page(Some(page));
}
@ -574,9 +594,9 @@ impl LpSlidingView {
/// the current page if last remaining.
pub fn scroll_to_neighbor(&self) {
if let Some(next_page) = self.next_page() {
self.animate_to(&next_page);
self.step_to(&next_page);
} else if let Some(prev_page) = self.prev_page() {
self.animate_to(&prev_page);
self.step_to(&prev_page);
} else if let Some(current_page) = self.current_page() {
self.remove(&current_page, false);
}
@ -612,7 +632,13 @@ impl LpSlidingView {
}
fn position(&self) -> f64 {
self.imp().position_tracking.borrow().position()
match &*self.imp().position_tracking.borrow() {
PositionTracking::Position(position) => *position,
PositionTracking::StackedCards(_) => {
log::error!("Using SlidindView position while in StackedCards animation");
0.
}
}
}
fn position_shift(&self) -> f64 {