|
8 | 8 | #include "command/CommandHandle.h" |
9 | 9 | #include "command/type/PropertyCmd.h" |
10 | 10 | #include "command/type/MultiPropertyCmd.h" |
| 11 | +#include "command/type/CreateEntityCmd.h" |
11 | 12 |
|
12 | 13 | #include "component/ActionComponent.h" |
13 | 14 | #include "component/AnimationComponent.h" |
|
20 | 21 | #include "component/TranslateTracksComponent.h" |
21 | 22 | #include "component/SpriteAnimationComponent.h" |
22 | 23 | #include "component/TimedActionComponent.h" |
| 24 | +#include "component/PositionActionComponent.h" |
| 25 | +#include "component/RotationActionComponent.h" |
| 26 | +#include "component/ScaleActionComponent.h" |
| 27 | +#include "component/ColorActionComponent.h" |
| 28 | +#include "component/AlphaActionComponent.h" |
23 | 29 | #include "subsystem/ActionSystem.h" |
24 | 30 | #include "subsystem/MeshSystem.h" |
25 | 31 |
|
@@ -112,6 +118,16 @@ std::string editor::AnimationWindow::getActionLabel(Entity actionEntity, Scene* |
112 | 118 | } |
113 | 119 |
|
114 | 120 | if (sig.test(scene->getComponentId<TimedActionComponent>())) { |
| 121 | + if (sig.test(scene->getComponentId<PositionActionComponent>())) |
| 122 | + return "PositionAction"; |
| 123 | + if (sig.test(scene->getComponentId<RotationActionComponent>())) |
| 124 | + return "RotationAction"; |
| 125 | + if (sig.test(scene->getComponentId<ScaleActionComponent>())) |
| 126 | + return "ScaleAction"; |
| 127 | + if (sig.test(scene->getComponentId<ColorActionComponent>())) |
| 128 | + return "ColorAction"; |
| 129 | + if (sig.test(scene->getComponentId<AlphaActionComponent>())) |
| 130 | + return "AlphaAction"; |
115 | 131 | return "TimedAction"; |
116 | 132 | } |
117 | 133 |
|
@@ -379,36 +395,96 @@ void editor::AnimationWindow::drawToolbar(float width, AnimationComponent& anim, |
379 | 395 | // Add Action |
380 | 396 | ImGui::BeginDisabled(isPreviewing); |
381 | 397 | if (ImGui::Button(ICON_FA_PLUS " Add Action")) { |
382 | | - // If a frame is selected, add to the same track, otherwise track 0 |
383 | | - uint32_t targetTrack = 0; |
384 | | - if (selectedFrameIndex >= 0 && selectedFrameIndex < (int)anim.actions.size()) { |
385 | | - targetTrack = anim.actions[selectedFrameIndex].track; |
| 398 | + ImGui::OpenPopup("##add_action_popup"); |
| 399 | + } |
| 400 | + if (ImGui::BeginPopup("##add_action_popup")) { |
| 401 | + EntityCreationType selectedType = EntityCreationType::EMPTY; |
| 402 | + std::string entityName; |
| 403 | + bool selected = false; |
| 404 | + |
| 405 | + if (ImGui::MenuItem(ICON_FA_PLUS " Empty Action")) { |
| 406 | + selected = true; |
| 407 | + } |
| 408 | + ImGui::Separator(); |
| 409 | + if (ImGui::MenuItem(ICON_FA_FILM " Animation")) { |
| 410 | + selectedType = EntityCreationType::ANIMATION; |
| 411 | + entityName = "Animation"; |
| 412 | + selected = true; |
| 413 | + } |
| 414 | + if (ImGui::MenuItem(ICON_FA_PLAY " Sprite Animation")) { |
| 415 | + selectedType = EntityCreationType::SPRITE_ANIMATION; |
| 416 | + entityName = "SpriteAnimation"; |
| 417 | + selected = true; |
| 418 | + } |
| 419 | + if (ImGui::MenuItem(ICON_FA_ARROWS_UP_DOWN_LEFT_RIGHT " Position Action")) { |
| 420 | + selectedType = EntityCreationType::POSITION_ACTION; |
| 421 | + entityName = "PositionAction"; |
| 422 | + selected = true; |
| 423 | + } |
| 424 | + if (ImGui::MenuItem(ICON_FA_ROTATE " Rotation Action")) { |
| 425 | + selectedType = EntityCreationType::ROTATION_ACTION; |
| 426 | + entityName = "RotationAction"; |
| 427 | + selected = true; |
| 428 | + } |
| 429 | + if (ImGui::MenuItem(ICON_FA_UP_RIGHT_AND_DOWN_LEFT_FROM_CENTER " Scale Action")) { |
| 430 | + selectedType = EntityCreationType::SCALE_ACTION; |
| 431 | + entityName = "ScaleAction"; |
| 432 | + selected = true; |
| 433 | + } |
| 434 | + if (ImGui::MenuItem(ICON_FA_PALETTE " Color Action")) { |
| 435 | + selectedType = EntityCreationType::COLOR_ACTION; |
| 436 | + entityName = "ColorAction"; |
| 437 | + selected = true; |
| 438 | + } |
| 439 | + if (ImGui::MenuItem(ICON_FA_EYE " Alpha Action")) { |
| 440 | + selectedType = EntityCreationType::ALPHA_ACTION; |
| 441 | + entityName = "AlphaAction"; |
| 442 | + selected = true; |
386 | 443 | } |
387 | 444 |
|
388 | | - ActionFrame newFrame = {0.0f, 1.0f, NULL_ENTITY, targetTrack}; |
389 | | - |
390 | | - // Find non-overlapping track |
391 | | - bool overlap; |
392 | | - do { |
393 | | - overlap = false; |
394 | | - for (const auto& a : anim.actions) { |
395 | | - if (a.track == newFrame.track) { |
396 | | - float startA = a.startTime; |
397 | | - float endA = a.startTime + a.duration; |
398 | | - float startB = newFrame.startTime; |
399 | | - float endB = newFrame.startTime + newFrame.duration; |
400 | | - // Strict less-than for overlap means adjoining frames (e.g. 0-1 and 1-2) are OK |
401 | | - if (std::max(startA, startB) < std::min(endA, endB)) { |
402 | | - overlap = true; |
403 | | - newFrame.track++; |
404 | | - break; |
| 445 | + if (selected) { |
| 446 | + // If a frame is selected, add to the same track, otherwise track 0 |
| 447 | + uint32_t targetTrack = 0; |
| 448 | + if (selectedFrameIndex >= 0 && selectedFrameIndex < (int)anim.actions.size()) { |
| 449 | + targetTrack = anim.actions[selectedFrameIndex].track; |
| 450 | + } |
| 451 | + |
| 452 | + Entity actionEntity = NULL_ENTITY; |
| 453 | + if (selectedType != EntityCreationType::EMPTY) { |
| 454 | + Entity target = scene->findComponent<ActionComponent>(selectedEntity) |
| 455 | + ? scene->getComponent<ActionComponent>(selectedEntity).target |
| 456 | + : NULL_ENTITY; |
| 457 | + auto* cmd = new CreateEntityCmd(project, selectedSceneId, entityName, selectedType, target); |
| 458 | + CommandHandle::get(selectedSceneId)->addCommandNoMerge(cmd); |
| 459 | + actionEntity = cmd->getEntity(); |
| 460 | + } |
| 461 | + |
| 462 | + ActionFrame newFrame = {0.0f, 1.0f, actionEntity, targetTrack}; |
| 463 | + |
| 464 | + // Find non-overlapping track |
| 465 | + bool overlap; |
| 466 | + do { |
| 467 | + overlap = false; |
| 468 | + for (const auto& a : anim.actions) { |
| 469 | + if (a.track == newFrame.track) { |
| 470 | + float startA = a.startTime; |
| 471 | + float endA = a.startTime + a.duration; |
| 472 | + float startB = newFrame.startTime; |
| 473 | + float endB = newFrame.startTime + newFrame.duration; |
| 474 | + if (std::max(startA, startB) < std::min(endA, endB)) { |
| 475 | + overlap = true; |
| 476 | + newFrame.track++; |
| 477 | + break; |
| 478 | + } |
405 | 479 | } |
406 | 480 | } |
407 | | - } |
408 | | - } while (overlap); |
| 481 | + } while (overlap); |
| 482 | + |
| 483 | + anim.actions.push_back(newFrame); |
| 484 | + selectedFrameIndex = anim.actions.size() - 1; |
| 485 | + } |
409 | 486 |
|
410 | | - anim.actions.push_back(newFrame); |
411 | | - selectedFrameIndex = anim.actions.size() - 1; |
| 487 | + ImGui::EndPopup(); |
412 | 488 | } |
413 | 489 | ImGui::EndDisabled(); |
414 | 490 | ImGui::SameLine(); |
@@ -602,8 +678,19 @@ bool editor::AnimationWindow::drawTracks(ImVec2 canvasPos, ImVec2 canvasSize, fl |
602 | 678 | return IM_COL32(80, 190, 190, 200); // Teal: MorphTracks |
603 | 679 | if (sig.test(scene->getComponentId<KeyframeTracksComponent>())) |
604 | 680 | return IM_COL32(70, 130, 180, 200); // Steel blue: KeyframeTracks |
605 | | - if (sig.test(scene->getComponentId<TimedActionComponent>())) |
606 | | - return IM_COL32(180, 100, 70, 200); // Warm red: TimedAction |
| 681 | + if (sig.test(scene->getComponentId<TimedActionComponent>())) { |
| 682 | + if (sig.test(scene->getComponentId<PositionActionComponent>())) |
| 683 | + return IM_COL32(100, 180, 220, 200); // Light blue: PositionAction |
| 684 | + if (sig.test(scene->getComponentId<RotationActionComponent>())) |
| 685 | + return IM_COL32(220, 160, 70, 200); // Amber: RotationAction |
| 686 | + if (sig.test(scene->getComponentId<ScaleActionComponent>())) |
| 687 | + return IM_COL32(180, 100, 200, 200); // Violet: ScaleAction |
| 688 | + if (sig.test(scene->getComponentId<ColorActionComponent>())) |
| 689 | + return IM_COL32(220, 120, 160, 200); // Pink: ColorAction |
| 690 | + if (sig.test(scene->getComponentId<AlphaActionComponent>())) |
| 691 | + return IM_COL32(160, 200, 120, 200); // Lime: AlphaAction |
| 692 | + return IM_COL32(180, 100, 70, 200); // Warm red: generic TimedAction |
| 693 | + } |
607 | 694 | if (sig.test(scene->getComponentId<AnimationComponent>())) |
608 | 695 | return IM_COL32(180, 170, 70, 200); // Gold: Animation |
609 | 696 |
|
@@ -745,6 +832,12 @@ bool editor::AnimationWindow::drawTracks(ImVec2 canvasPos, ImVec2 canvasSize, fl |
745 | 832 | } |
746 | 833 | } |
747 | 834 | } |
| 835 | + |
| 836 | + if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && hovered) { |
| 837 | + if (frame.action != NULL_ENTITY && scene->isEntityCreated(frame.action)) { |
| 838 | + project->setSelectedEntity(selectedSceneId, frame.action); |
| 839 | + } |
| 840 | + } |
748 | 841 | } |
749 | 842 | } |
750 | 843 |
|
|
0 commit comments