Add animation playback toggle boundary

This commit is contained in:
2026-06-03 16:47:02 +02:00
parent 5752bc6ae9
commit 603bb0c4e7
7 changed files with 217 additions and 26 deletions

View File

@@ -21,6 +21,7 @@ enum class DocumentAnimationOperation {
goto_next,
goto_previous,
playback_step,
toggle_playback,
set_onion_size,
};
@@ -36,11 +37,15 @@ struct DocumentAnimationOperationPlan {
int onion_size = 1;
int layer_index = 0;
std::uint32_t layer_id = 0;
int playback_idle_ms = 100;
bool requires_selected_frame = false;
bool mutates_document = false;
bool reloads_animation_layers = false;
bool updates_canvas_animation = false;
bool marks_unsaved = false;
bool playback_was_active = false;
bool playback_active = false;
bool resets_playback_timer = false;
};
class DocumentAnimationServices {
@@ -57,6 +62,12 @@ public:
virtual void goto_frame(int target_frame) = 0;
virtual void set_timeline_frame(int target_frame) = 0;
virtual void set_onion_size(int onion_size) = 0;
virtual void capture_playback_restore_mode() = 0;
virtual void enter_playback_camera_mode() = 0;
virtual void restore_playback_canvas_mode() = 0;
virtual void set_playback_active(bool active) = 0;
virtual void reset_playback_timer() = 0;
virtual void set_playback_idle_ms(int idle_ms) = 0;
virtual void update_canvas_animation() = 0;
virtual void update_frame_status() = 0;
virtual void reload_animation_layers() = 0;
@@ -343,6 +354,18 @@ public:
return pp::foundation::Result<DocumentAnimationOperationPlan>::success(plan);
}
[[nodiscard]] inline pp::foundation::Result<DocumentAnimationOperationPlan> plan_animation_playback_toggle(
bool playback_active)
{
DocumentAnimationOperationPlan plan;
plan.operation = DocumentAnimationOperation::toggle_playback;
plan.playback_was_active = playback_active;
plan.playback_active = !playback_active;
plan.playback_idle_ms = playback_active ? 100 : 10;
plan.resets_playback_timer = !playback_active;
return pp::foundation::Result<DocumentAnimationOperationPlan>::success(plan);
}
[[nodiscard]] inline pp::foundation::Result<DocumentAnimationOperationPlan> plan_animation_onion_size(int onion_size)
{
if (onion_size < 0) {
@@ -419,6 +442,18 @@ public:
}
return validate_animation_frame_index(plan.frame_count, plan.target_frame);
case DocumentAnimationOperation::toggle_playback:
if (plan.playback_active == plan.playback_was_active) {
return pp::foundation::Status::invalid_argument("animation playback toggle must change state");
}
if (plan.playback_idle_ms <= 0) {
return pp::foundation::Status::invalid_argument("animation playback idle interval must be positive");
}
if (plan.playback_active && !plan.resets_playback_timer) {
return pp::foundation::Status::invalid_argument("animation playback start must reset timer");
}
return pp::foundation::Status::success();
case DocumentAnimationOperation::set_onion_size:
if (plan.onion_size < 0) {
return pp::foundation::Status::invalid_argument("animation onion size must not be negative");
@@ -517,6 +552,20 @@ public:
services.update_frame_status();
return pp::foundation::Status::success();
case DocumentAnimationOperation::toggle_playback:
if (plan.playback_active) {
services.capture_playback_restore_mode();
services.enter_playback_camera_mode();
if (plan.resets_playback_timer) {
services.reset_playback_timer();
}
} else {
services.restore_playback_canvas_mode();
}
services.set_playback_active(plan.playback_active);
services.set_playback_idle_ms(plan.playback_idle_ms);
return pp::foundation::Status::success();
case DocumentAnimationOperation::set_onion_size:
services.set_onion_size(plan.onion_size);
if (plan.updates_canvas_animation) {