Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4208f3e
add new card designs
VoidNoVerges Feb 5, 2026
276b849
implement new card designs to code currently used for hand
VoidNoVerges Feb 5, 2026
484aacf
add new mod structure for new ui elements
VoidNoVerges Feb 6, 2026
289e194
implement the card table
VoidNoVerges Feb 10, 2026
0cc818b
return Task<AppMessage> in update_with_msg
VoidNoVerges Feb 11, 2026
5f0c836
return Task<AppMessage> in update_animations
VoidNoVerges Feb 12, 2026
d3e51ec
remove AnimationEndSensor as it is now redundant
VoidNoVerges Feb 12, 2026
fd25619
rewrite AnimationStarter so it works with tasks
VoidNoVerges Feb 12, 2026
81d4a50
adjust the visability of fields in ViewableHandCard
VoidNoVerges Feb 12, 2026
44e0238
add TaskBatcher for batching iced tasks together
VoidNoVerges Feb 12, 2026
1888d74
fix bug in AnimationStarter where one animation is not started
VoidNoVerges Feb 12, 2026
e3d0d20
move convert functions from ui element traits to Message instead
VoidNoVerges Feb 12, 2026
82b3118
add ReplaceUsize trait for better integration of AnimationStarter
VoidNoVerges Feb 13, 2026
1375e0c
fix card positioning in table middle
VoidNoVerges Feb 13, 2026
e96392f
add trump card animation
VoidNoVerges Feb 13, 2026
c6f10cc
add remove animation for card deck
VoidNoVerges Feb 13, 2026
d94b0c2
add remove animation for card stack
VoidNoVerges Feb 13, 2026
b543156
add glow images
VoidNoVerges Feb 13, 2026
6f0c516
add glow animation to card deck
VoidNoVerges Feb 13, 2026
9c3a1a0
fix glow animation
VoidNoVerges Feb 13, 2026
e966b7c
fix potential usize smaller than 0
VoidNoVerges Feb 13, 2026
3a240e3
fix bug where glow is not faded in correctly
VoidNoVerges Feb 13, 2026
9f46a84
improve deck card animations
VoidNoVerges Feb 13, 2026
1ac11b2
update documentation
VoidNoVerges Feb 14, 2026
9787b23
Merge remote-tracking branch 'origin/main' into card-table-paul
VoidNoVerges Feb 14, 2026
8c2b989
small cleanup
VoidNoVerges Feb 14, 2026
9133e0e
fix clippy warnings
VoidNoVerges Feb 14, 2026
4a4d49d
Remove inconsistent card naming, everything uses colors now
end41r Feb 14, 2026
0098537
Fix wrong unwrap checks for clippy
end41r Feb 14, 2026
f358ea4
Fix ready button, and move unclear usize/u64 to use PlayerId for
end41r Feb 14, 2026
65771b8
fmt
end41r Feb 14, 2026
2e68c87
Remove unneccesary print
end41r Feb 14, 2026
985a0f2
Change all occurences of heigth to height
end41r Feb 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed assets/cards/club.png
Binary file not shown.
Binary file removed assets/cards/diamond.png
Binary file not shown.
Binary file added assets/cards/glow_blue.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/glow_green.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/glow_red.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/glow_yellow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/cards/heart.png
Binary file not shown.
Binary file removed assets/cards/spade.png
Binary file not shown.
Binary file added assets/cards/variations/blue_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/blue_10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/blue_11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/blue_12.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/blue_13.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/blue_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/blue_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/blue_4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/blue_5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/blue_6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/blue_7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/blue_8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/blue_9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/green_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/green_10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/green_11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/green_12.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/cards/variations/green_13.png
Binary file added assets/cards/variations/green_2.png
Binary file added assets/cards/variations/green_3.png
Binary file added assets/cards/variations/green_4.png
Binary file added assets/cards/variations/green_5.png
Binary file added assets/cards/variations/green_6.png
Binary file added assets/cards/variations/green_7.png
Binary file added assets/cards/variations/green_8.png
Binary file added assets/cards/variations/green_9.png
Binary file added assets/cards/variations/jester.png
Binary file added assets/cards/variations/red_1.png
Binary file added assets/cards/variations/red_10.png
Binary file added assets/cards/variations/red_11.png
Binary file added assets/cards/variations/red_12.png
Binary file added assets/cards/variations/red_13.png
Binary file added assets/cards/variations/red_2.png
Binary file added assets/cards/variations/red_3.png
Binary file added assets/cards/variations/red_4.png
Binary file added assets/cards/variations/red_5.png
Binary file added assets/cards/variations/red_6.png
Binary file added assets/cards/variations/red_7.png
Binary file added assets/cards/variations/red_8.png
Binary file added assets/cards/variations/red_9.png
Binary file added assets/cards/variations/wizard.png
Binary file added assets/cards/variations/yellow_1.png
Binary file added assets/cards/variations/yellow_10.png
Binary file added assets/cards/variations/yellow_11.png
Binary file added assets/cards/variations/yellow_12.png
Binary file added assets/cards/variations/yellow_13.png
Binary file added assets/cards/variations/yellow_2.png
Binary file added assets/cards/variations/yellow_3.png
Binary file added assets/cards/variations/yellow_4.png
Binary file added assets/cards/variations/yellow_5.png
Binary file added assets/cards/variations/yellow_6.png
Binary file added assets/cards/variations/yellow_7.png
Binary file added assets/cards/variations/yellow_8.png
Binary file added assets/cards/variations/yellow_9.png
193 changes: 151 additions & 42 deletions src/animation/mod.rs → src/animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,27 @@
/// via the new function.
/// Keep in mind that if you choose 0 for the animation duration the animation will always
/// count as finished (the progress function returns 1.0).
pub mod animation_end_sensor;
pub mod animation_starter;

///
/// You can also set a Message to be sent when the animation reaches the highest frame number
/// via on_end or returns(!) to the first frame number 0 via on start.
/// Check the source of your animation type for the specific implementation of this.
///
/// If you want to start multiple animations with a set delay you need to use AnimationStarter.
/// You give it a message with an usize 0 at its end that will start an animation.
/// The message needs to implement ReplaceUsize + Message for this.
/// You can also give it a message to send when all animations have ended via on_all_ended.
/// Now to use it you call start and update it every animation tick via next_frame
use derive_more::{Deref, DerefMut};
use iced::Task;
use std::f32::consts::PI;

use crate::{
client::AppMessage,
ui_element_traits::{Message, ReplaceUsize},
};

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum AnimationState {
enum AnimationState {
NotMoving,
MovingForward,
Reversing,
Expand Down Expand Up @@ -123,11 +136,13 @@ pub fn ease_out_bounce(v: f32) -> f32 {
// AI-Usage: Claude.ai for learning how to make a trait require another trait.
// (Now this is not the case here anymore but it used to be).

#[derive(Debug, Clone)]
#[derive(Clone, Debug)]
pub struct AnimationCore {
max_frame_number: usize,
current_frame_number: usize,
animation_state: AnimationState,
on_start: Option<AppMessage>,
on_end: Option<AppMessage>,
}

impl AnimationCore {
Expand All @@ -136,12 +151,16 @@ impl AnimationCore {
max_frame_number: duration,
current_frame_number: 0,
animation_state: AnimationState::NotMoving,
on_start: None,
on_end: None,
}
}
pub fn start(&mut self) {
if self.not_moving() || self.animation_state == AnimationState::Ended {
self.animation_state = AnimationState::MovingForward;
}
self.animation_state = AnimationState::MovingForward;
}
pub fn start_force(&mut self) {
self.current_frame_number = 0;
self.animation_state = AnimationState::MovingForward;
}
#[allow(dead_code)]
pub fn interrupt(&mut self) {
Expand Down Expand Up @@ -175,11 +194,27 @@ impl AnimationCore {
pub fn current_frame_number(&self) -> usize {
self.current_frame_number
}
pub fn not_moving(&self) -> bool {
self.animation_state == AnimationState::NotMoving
/// Message sent when an animation reaches an end point
pub fn on_end(&mut self, msg: AppMessage) {
self.on_end = Some(msg)
}
pub fn moving_forward(&self) -> bool {
self.animation_state == AnimationState::MovingForward
pub fn on_start(&mut self, msg: AppMessage) {
self.on_start = Some(msg)
}
/// Send a message when an animation reaches a reverse point or end if not reversing.
fn end_task(&self) -> Task<AppMessage> {
match &self.on_end {
Some(msg) => Task::done(msg.clone()),
None => Task::none(),
}
}
/// Send a message everytime when an animation returns to start.
/// This won't trigger when the animation is started.
fn start_task(&self) -> Task<AppMessage> {
match &self.on_start {
Some(msg) => Task::done(msg.clone()),
None => Task::none(),
}
}
}

Expand All @@ -203,125 +238,199 @@ new_core!(ReversableBasicAnimation);
new_core!(AutoReversingAnimation);
new_core!(CircularAutoReversingAnimation);

#[derive(Debug, Clone, Deref, DerefMut)]
#[derive(Clone, Debug, Deref, DerefMut)]
pub struct BasicAnimation(AnimationCore);
impl BasicAnimation {
pub fn next_frame(&mut self) {
pub fn next_frame(&mut self) -> Task<AppMessage> {
if self.animation_state == AnimationState::MovingForward {
if self.current_frame_number < self.max_frame_number {
self.current_frame_number += 1;
} else {
self.animation_state = AnimationState::Ended;
return self.end_task();
}
}
}
#[allow(dead_code)]
pub fn ended(&self) -> bool {
self.animation_state == AnimationState::Ended
Task::none()
}
}

#[allow(dead_code)]
#[derive(Debug, Clone, Deref, DerefMut)]
#[derive(Clone, Debug, Deref, DerefMut)]
pub struct CircularAnimation(AnimationCore);
impl CircularAnimation {
#[allow(dead_code)]
pub fn next_frame(&mut self) {
pub fn next_frame(&mut self) -> Task<AppMessage> {
if self.animation_state == AnimationState::MovingForward && self.max_frame_number != 0 {
self.current_frame_number =
// The 1 is there for going to the next frame number.
(self.current_frame_number + 1) % self.max_frame_number;
let frame_number_before = self.current_frame_number;
self.current_frame_number = (self.current_frame_number + 1) % self.max_frame_number;
let frame_number_after = self.current_frame_number;
if frame_number_before >= frame_number_after {
return self.end_task();
}
}
Task::none()
}
}

#[derive(Debug, Clone, Deref, DerefMut)]
#[derive(Clone, Debug, Deref, DerefMut)]
pub struct ReversableBasicAnimation(AnimationCore);
impl ReversableBasicAnimation {
pub fn reverse(&mut self) {
self.animation_state = AnimationState::Reversing;
}
pub fn start_from_reverse(&mut self) {
#[allow(dead_code)]
pub fn reverse_force(&mut self) {
self.current_frame_number = self.max_frame_number;
self.animation_state = AnimationState::Reversing;
self.current_frame_number = self.max_frame_number
}
pub fn next_frame(&mut self) {
pub fn next_frame(&mut self) -> Task<AppMessage> {
match self.animation_state {
AnimationState::MovingForward => {
if self.current_frame_number < self.max_frame_number {
self.current_frame_number += 1;
} else {
self.animation_state = AnimationState::NotMoving;
return self.end_task();
}
}
AnimationState::Reversing => {
if self.current_frame_number > 0 {
self.current_frame_number -= 1;
} else {
self.animation_state = AnimationState::Ended;
return self.start_task();
}
}
_ => {}
}
}
#[allow(dead_code)]
pub fn reversing(&self) -> bool {
self.animation_state == AnimationState::Reversing
Task::none()
}
}

#[derive(Debug, Clone, Deref, DerefMut)]
#[derive(Clone, Debug, Deref, DerefMut)]
pub struct AutoReversingAnimation(AnimationCore);
impl AutoReversingAnimation {
pub fn next_frame(&mut self) {
pub fn next_frame(&mut self) -> Task<AppMessage> {
match self.animation_state {
AnimationState::MovingForward => {
if self.current_frame_number < self.max_frame_number {
self.current_frame_number += 1;
} else {
self.animation_state = AnimationState::Reversing;
return self.end_task();
}
}
AnimationState::Reversing => {
if self.current_frame_number > 0 {
self.current_frame_number -= 1;
} else {
self.reset();
return self.start_task();
}
}
_ => {}
}
}
#[allow(dead_code)]
pub fn reversing(&self) -> bool {
self.animation_state == AnimationState::Reversing
Task::none()
}
}

#[derive(Debug, Clone, Deref, DerefMut)]
#[derive(Clone, Debug, Deref, DerefMut)]
pub struct CircularAutoReversingAnimation(AnimationCore);
impl CircularAutoReversingAnimation {
pub fn next_frame(&mut self) {
pub fn next_frame(&mut self) -> Task<AppMessage> {
match self.animation_state {
AnimationState::MovingForward => {
if self.current_frame_number < self.max_frame_number {
self.current_frame_number += 1;
} else {
self.animation_state = AnimationState::Reversing;
return self.end_task();
}
}
AnimationState::Reversing => {
if self.current_frame_number > 0 {
self.current_frame_number -= 1;
} else {
self.animation_state = AnimationState::MovingForward;
return self.start_task();
}
}
_ => {}
}
Task::none()
}
#[allow(dead_code)]
pub fn reversing(&self) -> bool {
self.animation_state == AnimationState::Reversing
}

#[derive(Clone, Debug)]
pub struct AnimationStarter<MStart: Message + ReplaceUsize, MEnd: Message> {
state: AnimationState,
times: usize,
animation_delay: usize,
animation_length: usize,
tick: usize,
started: usize,
on_start_single: MStart,
on_all_ended: Option<MEnd>,
}

impl<MStart: Message + ReplaceUsize, MEnd: Message> AnimationStarter<MStart, MEnd> {
/// Check AppMessage::replace_usize
pub fn new(animation_delay: usize, animation_duration: usize, first_start_msg: MStart) -> Self {
Self {
times: 0,
state: AnimationState::NotMoving,
animation_delay,
animation_length: animation_duration,
tick: 0,
started: 0,
on_start_single: first_start_msg,
on_all_ended: None,
}
}
pub fn start(&mut self, times: usize) {
self.times = times;
self.state = AnimationState::MovingForward;
}
pub fn next_frame(&mut self) -> Task<AppMessage> {
if self.state == AnimationState::MovingForward {
self.tick += 1;
if self.check_all_ended() {
return self.all_ended();
} else if self.check_tick() {
return self.start_single();
}
}
Task::none()
}
pub fn on_all_ended(&mut self, msg: MEnd) {
self.on_all_ended = Some(msg)
}
pub fn times(&self) -> usize {
self.times
}
fn check_tick(&self) -> bool {
self.tick.is_multiple_of(self.animation_delay)
}
fn check_all_ended(&self) -> bool {
(self.tick == self.animation_delay * self.times + self.animation_length)
|| (self.times == 0)
}
fn all_ended(&mut self) -> Task<AppMessage> {
let task: Task<AppMessage> = match &self.on_all_ended {
Some(msg) => Task::done(msg.convert_msg()),
None => Task::none(),
};
self.state = AnimationState::NotMoving;
self.tick = 0;
self.started = 0;
task
}
fn start_single(&mut self) -> Task<AppMessage> {
self.started += 1;
Task::done(
self.on_start_single
.replace_usize(self.started - 1)
.convert_msg(),
)
}
}
Loading