Route animation panel view through app core

This commit is contained in:
2026-06-05 00:37:11 +02:00
parent a9e12f2219
commit bd6cdc20c5
8 changed files with 469 additions and 28 deletions

View File

@@ -3,6 +3,7 @@
#include <limits>
#include <string>
#include <vector>
#define PP_REQUIRE(harness, expression) \
do { \
@@ -426,6 +427,114 @@ void onion_size_updates_canvas_without_document_mutation(pp::tests::Harness& har
PP_EXPECT(harness, !pp::app::plan_animation_onion_size(-1));
}
void panel_view_projects_layers_frames_and_timeline_state(pp::tests::Harness& harness)
{
std::vector<pp::app::DocumentAnimationLayerInput> layers;
layers.push_back(pp::app::DocumentAnimationLayerInput {
.layer_index = 0,
.layer_id = 10,
.name = "Base",
.visible = true,
.frame_durations = { 1, 2 },
});
layers.push_back(pp::app::DocumentAnimationLayerInput {
.layer_index = 1,
.layer_id = 20,
.name = "Ink",
.visible = false,
.frame_durations = { 3 },
});
const auto view = pp::app::plan_animation_panel_view(
layers,
4,
1,
2,
10,
1,
3);
PP_REQUIRE(harness, view);
PP_EXPECT(harness, view.value().total_duration == 4);
PP_EXPECT(harness, view.value().current_frame == 2);
PP_EXPECT(harness, view.value().onion_size == 3);
PP_EXPECT(harness, view.value().has_selected_frame);
PP_EXPECT(harness, view.value().layers.size() == 2);
PP_EXPECT(harness, !view.value().layers[0].current);
PP_EXPECT(harness, view.value().layers[1].current);
PP_EXPECT(harness, view.value().layers[0].name == "Base");
PP_EXPECT(harness, !view.value().layers[1].visible);
PP_EXPECT(harness, view.value().layers[0].frames.size() == 2);
PP_EXPECT(harness, view.value().layers[0].frames[0].duration == 1);
PP_EXPECT(harness, view.value().layers[0].frames[1].duration == 2);
PP_EXPECT(harness, !view.value().layers[0].frames[0].selected);
PP_EXPECT(harness, view.value().layers[0].frames[1].selected);
PP_EXPECT(harness, !view.value().layers[1].frames[0].selected);
}
void panel_view_preserves_stale_selection_as_no_active_frame(pp::tests::Harness& harness)
{
const std::vector<pp::app::DocumentAnimationLayerInput> layers {
pp::app::DocumentAnimationLayerInput {
.layer_index = 0,
.layer_id = 10,
.name = "Base",
.visible = true,
.frame_durations = { 1 },
},
};
const auto view = pp::app::plan_animation_panel_view(
layers,
1,
0,
0,
999,
42,
0);
PP_REQUIRE(harness, view);
PP_EXPECT(harness, !view.value().has_selected_frame);
PP_EXPECT(harness, !view.value().layers[0].frames[0].selected);
}
void panel_view_rejects_invalid_document_state(pp::tests::Harness& harness)
{
const std::vector<pp::app::DocumentAnimationLayerInput> valid_layers {
pp::app::DocumentAnimationLayerInput {
.layer_index = 0,
.layer_id = 10,
.name = "Base",
.visible = true,
.frame_durations = { 1 },
},
};
const std::vector<pp::app::DocumentAnimationLayerInput> empty_frames {
pp::app::DocumentAnimationLayerInput {
.layer_index = 0,
.layer_id = 10,
.name = "Base",
.visible = true,
.frame_durations = {},
},
};
const std::vector<pp::app::DocumentAnimationLayerInput> bad_duration {
pp::app::DocumentAnimationLayerInput {
.layer_index = 0,
.layer_id = 10,
.name = "Base",
.visible = true,
.frame_durations = { 0 },
},
};
PP_EXPECT(harness, !pp::app::plan_animation_panel_view({}, 1, 0, 0, 0, -1, 0));
PP_EXPECT(harness, !pp::app::plan_animation_panel_view(valid_layers, 0, 0, 0, 0, -1, 0));
PP_EXPECT(harness, !pp::app::plan_animation_panel_view(valid_layers, 1, 1, 0, 0, -1, 0));
PP_EXPECT(harness, !pp::app::plan_animation_panel_view(valid_layers, 1, 0, 1, 0, -1, 0));
PP_EXPECT(harness, !pp::app::plan_animation_panel_view(valid_layers, 1, 0, 0, 0, -1, -1));
PP_EXPECT(harness, !pp::app::plan_animation_panel_view(empty_frames, 1, 0, 0, 0, -1, 0));
PP_EXPECT(harness, !pp::app::plan_animation_panel_view(bad_duration, 1, 0, 0, 0, -1, 0));
}
void onion_frame_ranges_clamp_edges_and_alpha(pp::tests::Harness& harness)
{
const auto center = pp::app::plan_animation_onion_frame_range(5, 2, 1);
@@ -666,6 +775,9 @@ int main()
harness.run("panel actions plan timeline and playback intent", panel_actions_plan_timeline_and_playback_intent);
harness.run("panel actions reject invalid timeline state", panel_actions_reject_invalid_timeline_state);
harness.run("onion size updates canvas without document mutation", onion_size_updates_canvas_without_document_mutation);
harness.run("panel view projects layers frames and timeline state", panel_view_projects_layers_frames_and_timeline_state);
harness.run("panel view preserves stale selection as no active frame", panel_view_preserves_stale_selection_as_no_active_frame);
harness.run("panel view rejects invalid document state", panel_view_rejects_invalid_document_state);
harness.run("onion frame ranges clamp edges and alpha", onion_frame_ranges_clamp_edges_and_alpha);
harness.run("onion frame ranges reject invalid inputs", onion_frame_ranges_reject_invalid_inputs);
harness.run("timeline scrub clamps cursor to document frame", timeline_scrub_clamps_cursor_to_document_frame);