Add animation panel action planner

This commit is contained in:
2026-06-03 16:57:56 +02:00
parent 603bb0c4e7
commit cee5f141a3
8 changed files with 335 additions and 10 deletions

View File

@@ -25,6 +25,20 @@ enum class DocumentAnimationOperation {
set_onion_size,
};
enum class DocumentAnimationPanelAction {
goto_frame,
next_frame,
previous_frame,
playback_step,
toggle_playback,
};
struct DocumentAnimationPanelState {
int total_duration = 1;
int current_frame = 0;
bool playback_active = false;
};
struct DocumentAnimationOperationPlan {
DocumentAnimationOperation operation = DocumentAnimationOperation::goto_frame;
int frame_count = 1;
@@ -380,6 +394,32 @@ public:
return pp::foundation::Result<DocumentAnimationOperationPlan>::success(plan);
}
[[nodiscard]] inline pp::foundation::Result<DocumentAnimationOperationPlan> plan_animation_panel_action(
DocumentAnimationPanelAction action,
const DocumentAnimationPanelState& state,
int target_frame = 0)
{
switch (action) {
case DocumentAnimationPanelAction::goto_frame:
return plan_animation_goto_frame(state.total_duration, target_frame);
case DocumentAnimationPanelAction::next_frame:
return plan_animation_step_frame(state.total_duration, state.current_frame, 1);
case DocumentAnimationPanelAction::previous_frame:
return plan_animation_step_frame(state.total_duration, state.current_frame, -1);
case DocumentAnimationPanelAction::playback_step:
return plan_animation_playback_step(state.total_duration, state.current_frame, 1);
case DocumentAnimationPanelAction::toggle_playback:
return plan_animation_playback_toggle(state.playback_active);
}
return pp::foundation::Result<DocumentAnimationOperationPlan>::failure(
pp::foundation::Status::invalid_argument("unknown animation panel action"));
}
[[nodiscard]] inline pp::foundation::Status validate_animation_operation_plan(
const DocumentAnimationOperationPlan& plan) noexcept
{

View File

@@ -163,6 +163,15 @@ void NodePanelAnimation::execute_animation_plan(const pp::app::DocumentAnimation
LOG("Animation panel action failed: %s", status.message);
}
pp::app::DocumentAnimationPanelState NodePanelAnimation::animation_panel_state() const
{
return pp::app::DocumentAnimationPanelState {
.total_duration = Canvas::I->anim_duration(),
.current_frame = Canvas::I->m_anim_frame,
.playback_active = btn_play->is_active(),
};
}
void NodePanelAnimation::init_controls()
{
m_layers_container = find<NodeScroll>("layers");
@@ -275,7 +284,10 @@ void NodePanelAnimation::init_controls()
};
m_timeline->on_frame_changed = [this] (NodeAnimationTimeline* target, int frame) {
const auto plan = pp::app::plan_animation_goto_frame(Canvas::I->anim_duration(), frame);
const auto plan = pp::app::plan_animation_panel_action(
pp::app::DocumentAnimationPanelAction::goto_frame,
animation_panel_state(),
frame);
if (!plan)
return;
LOG("goto frame %d", plan.value().target_frame);
@@ -283,19 +295,25 @@ void NodePanelAnimation::init_controls()
};
btn_next->on_click = [this] (Node* target) {
const auto plan = pp::app::plan_animation_step_frame(Canvas::I->anim_duration(), Canvas::I->m_anim_frame, 1);
const auto plan = pp::app::plan_animation_panel_action(
pp::app::DocumentAnimationPanelAction::next_frame,
animation_panel_state());
if (!plan)
return;
execute_animation_plan(plan.value());
};
btn_prev->on_click = [this](Node* target) {
const auto plan = pp::app::plan_animation_step_frame(Canvas::I->anim_duration(), Canvas::I->m_anim_frame, -1);
const auto plan = pp::app::plan_animation_panel_action(
pp::app::DocumentAnimationPanelAction::previous_frame,
animation_panel_state());
if (!plan)
return;
execute_animation_plan(plan.value());
};
btn_play->on_click = [this] (Node*) {
const auto plan = pp::app::plan_animation_playback_toggle(btn_play->is_active());
const auto plan = pp::app::plan_animation_panel_action(
pp::app::DocumentAnimationPanelAction::toggle_playback,
animation_panel_state());
if (plan)
execute_animation_plan(plan.value());
};
@@ -364,10 +382,9 @@ void NodePanelAnimation::on_tick(float dt)
if (m_playback_timer > (1.f / m_fps->get_float()))
{
m_playback_timer = 0;
const auto plan = pp::app::plan_animation_playback_step(
Canvas::I->anim_duration(),
Canvas::I->m_anim_frame,
1);
const auto plan = pp::app::plan_animation_panel_action(
pp::app::DocumentAnimationPanelAction::playback_step,
animation_panel_state());
if (plan)
execute_animation_plan(plan.value());
}

View File

@@ -10,6 +10,7 @@
class Layer;
namespace pp::app {
struct DocumentAnimationPanelState;
struct DocumentAnimationOperationPlan;
}
@@ -73,6 +74,7 @@ class NodePanelAnimation : public Node
float m_playback_timer = 0;
void execute_animation_plan(const pp::app::DocumentAnimationOperationPlan& plan, Layer* layer = nullptr);
[[nodiscard]] pp::app::DocumentAnimationPanelState animation_panel_state() const;
public:
using this_class = NodePanelAnimation;
using parent = Node;