From 5470368b6a38d9278b336211963bf6e7d7c58613 Mon Sep 17 00:00:00 2001 From: shweet Date: Fri, 14 Nov 2025 14:08:41 -0500 Subject: [PATCH] original editor compliance and some fixes --- src/anm2/item.cpp | 14 ++++ src/anm2/item.h | 1 + src/document.cpp | 1 + src/imgui/imgui_.cpp | 5 +- src/imgui/imgui_.h | 4 +- src/imgui/window/animation_preview.cpp | 16 +++-- src/imgui/window/animations.cpp | 20 ++++-- src/imgui/window/animations.h | 1 + src/imgui/window/events.cpp | 9 ++- src/imgui/window/events.h | 2 + src/imgui/window/layers.cpp | 34 +++++---- src/imgui/window/layers.h | 2 + src/imgui/window/nulls.cpp | 36 ++++++---- src/imgui/window/nulls.h | 4 +- src/imgui/window/sounds.cpp | 6 ++ src/imgui/window/sounds.h | 2 + src/imgui/window/spritesheets.cpp | 6 ++ src/imgui/window/spritesheets.h | 2 + src/imgui/window/timeline.cpp | 96 ++++++++++++++++++-------- src/imgui/window/timeline.h | 9 +-- src/settings.h | 8 ++- src/tool.h | 2 +- 22 files changed, 202 insertions(+), 78 deletions(-) diff --git a/src/anm2/item.cpp b/src/anm2/item.cpp index cf8b202..079c0ee 100644 --- a/src/anm2/item.cpp +++ b/src/anm2/item.cpp @@ -295,4 +295,18 @@ namespace anm2ed::anm2 if (frame.atFrame == atFrame) return i; return -1; } + + float Item::frame_time_from_index_get(int index) + { + if (!vector::in_bounds(frames, index)) return 0.0f; + + float time{}; + for (auto [i, frame] : std::views::enumerate(frames)) + { + if (i == index) return time; + time += frame.duration; + } + + return time; + } } diff --git a/src/anm2/item.h b/src/anm2/item.h index 4f4e7e8..7855d5b 100644 --- a/src/anm2/item.h +++ b/src/anm2/item.h @@ -26,5 +26,6 @@ namespace anm2ed::anm2 void frames_generate_from_grid(glm::ivec2, glm::ivec2, glm::ivec2, int, int, int); void frames_sort_by_at_frame(); int frame_index_from_at_frame_get(int); + float frame_time_from_index_get(int); }; } \ No newline at end of file diff --git a/src/document.cpp b/src/document.cpp index 0cc0c38..1940a6e 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -228,6 +228,7 @@ namespace anm2ed { anm2::Spritesheet& spritesheet = anm2.content.spritesheets[id]; this->spritesheet.selection = {id}; + this->spritesheet.reference = id; toasts.info(std::format("Initialized spritesheet #{}: {}", id, spritesheet.path.string())); } else diff --git a/src/imgui/imgui_.cpp b/src/imgui/imgui_.cpp index 1ebd66c..d751163 100644 --- a/src/imgui/imgui_.cpp +++ b/src/imgui/imgui_.cpp @@ -62,7 +62,7 @@ namespace anm2ed::imgui } bool selectable_input_text(const std::string& label, const std::string& id, std::string& text, bool isSelected, - ImGuiSelectableFlags flags, bool* isRenamed) + ImGuiSelectableFlags flags, bool* isRenamed, bool isBeginEditing) { static std::string editID{}; static bool isJustEdit{}; @@ -90,7 +90,8 @@ namespace anm2ed::imgui { if (ImGui::Selectable(label.c_str(), isSelected, flags)) isActivated = true; - if ((ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_F2) && isSelected) || + if (isBeginEditing || + (ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_F2) && isSelected) || (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))) { editID = id; diff --git a/src/imgui/imgui_.h b/src/imgui/imgui_.h index 1277b72..70eccf3 100644 --- a/src/imgui/imgui_.h +++ b/src/imgui/imgui_.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include #include #include @@ -170,7 +170,7 @@ namespace anm2ed::imgui ImGuiInputTextFlags = 0); bool combo_negative_one_indexed(const std::string&, int*, std::vector&); bool selectable_input_text(const std::string&, const std::string&, std::string&, bool = false, - ImGuiSelectableFlags = 0, bool* = nullptr); + ImGuiSelectableFlags = 0, bool* = nullptr, bool = false); void set_item_tooltip_shortcut(const char*, const std::string& = {}); void external_storage_set(ImGuiSelectionExternalStorage*, int, bool); void render_checker_background(ImDrawList*, ImVec2, ImVec2, glm::vec2, float); diff --git a/src/imgui/window/animation_preview.cpp b/src/imgui/window/animation_preview.cpp index e5f899a..79d16cf 100644 --- a/src/imgui/window/animation_preview.cpp +++ b/src/imgui/window/animation_preview.cpp @@ -354,7 +354,8 @@ namespace anm2ed::imgui auto render = [&](anm2::Animation* animation, float time, vec3 colorOffset = {}, float alphaOffset = {}, bool isOnionskin = false) { - auto transform = transform_get(zoom, pan); + auto baseTransform = transform_get(zoom, pan); + auto transform = baseTransform; auto root = animation->rootAnimation.frame_generate(time, anm2::ROOT); if (isRootTransform) @@ -362,8 +363,8 @@ namespace anm2ed::imgui if (!isOnlyShowLayers && root.isVisible && animation->rootAnimation.isVisible) { - auto rootTransform = transform * math::quad_model_get(TARGET_SIZE, root.position, TARGET_SIZE * 0.5f, - math::percent_to_unit(root.scale), root.rotation); + auto rootTransform = baseTransform * math::quad_model_get(TARGET_SIZE, root.position, TARGET_SIZE * 0.5f, + math::percent_to_unit(root.scale), root.rotation); vec4 color = isOnionskin ? vec4(colorOffset, alphaOffset) : color::GREEN; @@ -511,9 +512,10 @@ namespace anm2ed::imgui { auto isMouseClicked = ImGui::IsMouseClicked(ImGuiMouseButton_Left); auto isMouseReleased = ImGui::IsMouseReleased(ImGuiMouseButton_Left); - auto isMouseDown = ImGui::IsMouseDown(ImGuiMouseButton_Left); + auto isMouseLeftDown = ImGui::IsMouseDown(ImGuiMouseButton_Left); auto isMouseMiddleDown = ImGui::IsMouseDown(ImGuiMouseButton_Middle); auto isMouseRightDown = ImGui::IsMouseDown(ImGuiMouseButton_Right); + auto isMouseDown = isMouseLeftDown || isMouseMiddleDown || isMouseRightDown; auto mouseDelta = to_ivec2(ImGui::GetIO().MouseDelta); auto mouseWheel = ImGui::GetIO().MouseWheel; @@ -589,7 +591,11 @@ namespace anm2ed::imgui case tool::SCALE: if (!frame) break; if (isBegin) document.snapshot("Frame Scale"); - if (isMouseDown) frame->scale += mouseDelta; + if (isMouseDown) + { + frame->scale += mouseDelta; + if (isMod) frame->scale = {frame->scale.x, frame->scale.x}; + } if (isLeftPressed) frame->scale.x -= step; if (isRightPressed) frame->scale.x += step; if (isUpPressed) frame->scale.y -= step; diff --git a/src/imgui/window/animations.cpp b/src/imgui/window/animations.cpp index 675a9d8..b5b5b30 100644 --- a/src/imgui/window/animations.cpp +++ b/src/imgui/window/animations.cpp @@ -54,6 +54,7 @@ namespace anm2ed::imgui auto isDefault = anm2.animations.defaultAnimation == animation.name; auto isReferenced = reference.animationIndex == (int)i; + auto isNewSelection = newAnimationSelectedIndex == (int)i; auto font = isDefault && isReferenced ? font::BOLD_ITALICS : isDefault ? font::BOLD @@ -62,13 +63,20 @@ namespace anm2ed::imgui ImGui::PushFont(resources.fonts[font].get(), font::SIZE); ImGui::SetNextItemSelectionUserData((int)i); + if (selectable_input_text(animation.name, std::format("###Document #{} Animation #{}", manager.selected, i), - animation.name, selection.contains((int)i))) + animation.name, selection.contains((int)i), ImGuiSelectableFlags_None, nullptr, + isNewSelection)) { reference = {(int)i}; document.frames.clear(); } if (ImGui::IsItemHovered()) hovered = (int)i; + if (isNewSelection) + { + ImGui::SetScrollHereY(0.5f); + newAnimationSelectedIndex = -1; + } ImGui::PopFont(); if (ImGui::BeginItemTooltip()) @@ -190,13 +198,17 @@ namespace anm2ed::imgui } animation.rootAnimation.frames.emplace_back(anm2::Frame()); - auto index = 0; - if (!anm2.animations.items.empty()) - index = selection.empty() ? (int)anm2.animations.items.size() - 1 : *selection.rbegin() + 1; + auto index = (int)anm2.animations.items.size(); + if (!selection.empty()) + { + index = *selection.rbegin() + 1; + index = std::min(index, (int)anm2.animations.items.size()); + } anm2.animations.items.insert(anm2.animations.items.begin() + index, animation); selection = {index}; reference = {index}; + newAnimationSelectedIndex = index; }; DOCUMENT_EDIT(document, "Add Animation", Document::ANIMATIONS, add()); diff --git a/src/imgui/window/animations.h b/src/imgui/window/animations.h index 6257a29..2e373c0 100644 --- a/src/imgui/window/animations.h +++ b/src/imgui/window/animations.h @@ -10,6 +10,7 @@ namespace anm2ed::imgui class Animations { PopupHelper mergePopup{PopupHelper("Merge Animations")}; + int newAnimationSelectedIndex{-1}; public: void update(Manager&, Settings&, Resources&, Clipboard&); diff --git a/src/imgui/window/events.cpp b/src/imgui/window/events.cpp index f9c652b..e32a0f2 100644 --- a/src/imgui/window/events.cpp +++ b/src/imgui/window/events.cpp @@ -34,9 +34,15 @@ namespace anm2ed::imgui { ImGui::PushID(id); ImGui::SetNextItemSelectionUserData(id); + const bool isNewEvent = (newEventId == id); if (selectable_input_text(event.name, std::format("###Document #{} Event #{}", manager.selected, id), - event.name, selection.contains(id))) + event.name, selection.contains(id), ImGuiSelectableFlags_None, nullptr, isNewEvent)) if (ImGui::IsItemHovered()) hovered = id; + if (isNewEvent) + { + ImGui::SetScrollHereY(0.5f); + newEventId = -1; + } if (ImGui::BeginItemTooltip()) { @@ -105,6 +111,7 @@ namespace anm2ed::imgui anm2.content.events[id] = anm2::Event(); selection = {id}; reference = {id}; + newEventId = id; }; DOCUMENT_EDIT(document, "Add Event", Document::EVENTS, add()); diff --git a/src/imgui/window/events.h b/src/imgui/window/events.h index 7d01fce..4cdca79 100644 --- a/src/imgui/window/events.h +++ b/src/imgui/window/events.h @@ -9,6 +9,8 @@ namespace anm2ed::imgui { class Events { + int newEventId{-1}; + public: void update(Manager&, Settings&, Resources&, Clipboard&); }; diff --git a/src/imgui/window/layers.cpp b/src/imgui/window/layers.cpp index 90200cb..2d57aaf 100644 --- a/src/imgui/window/layers.cpp +++ b/src/imgui/window/layers.cpp @@ -39,6 +39,11 @@ namespace anm2ed::imgui ImGui::SetNextItemSelectionUserData(id); ImGui::Selectable(std::format(anm2::LAYER_FORMAT, id, layer.name, layer.spritesheetID).c_str(), isSelected); + if (newLayerId == id) + { + ImGui::SetScrollHereY(0.5f); + newLayerId = -1; + } if (ImGui::IsItemHovered()) { hovered = id; @@ -152,25 +157,28 @@ namespace anm2ed::imgui if (ImGui::Button(reference == -1 ? "Add" : "Confirm", widgetSize)) { - auto add = [&]() - { - auto id = map::next_id_get(anm2.content.layers); - anm2.content.layers[id] = layer; - selection = {id}; - }; - - auto set = [&]() - { - anm2.content.layers[reference] = layer; - selection = {reference}; - }; - if (reference == -1) { + auto add = [&]() + { + auto id = map::next_id_get(anm2.content.layers); + anm2.content.layers[id] = layer; + selection = {id}; + newLayerId = id; + }; + DOCUMENT_EDIT(document, "Add Layer", Document::LAYERS, add()); } else + { + auto set = [&]() + { + anm2.content.layers[reference] = layer; + selection = {reference}; + }; + DOCUMENT_EDIT(document, "Set Layer Properties", Document::LAYERS, set()); + } manager.layer_properties_close(); } diff --git a/src/imgui/window/layers.h b/src/imgui/window/layers.h index 2431571..f977fb9 100644 --- a/src/imgui/window/layers.h +++ b/src/imgui/window/layers.h @@ -9,6 +9,8 @@ namespace anm2ed::imgui { class Layers { + int newLayerId{-1}; + public: void update(Manager&, Settings&, Resources&, Clipboard&); }; diff --git a/src/imgui/window/nulls.cpp b/src/imgui/window/nulls.cpp index 641f398..fd59153 100644 --- a/src/imgui/window/nulls.cpp +++ b/src/imgui/window/nulls.cpp @@ -40,6 +40,11 @@ namespace anm2ed::imgui ImGui::SetNextItemSelectionUserData(id); if (isReferenced) ImGui::PushFont(resources.fonts[font::ITALICS].get(), font::SIZE); ImGui::Selectable(std::format(anm2::NULL_FORMAT, id, null.name).c_str(), isSelected); + if (newNullId == id) + { + ImGui::SetScrollHereY(0.5f); + newNullId = -1; + } if (ImGui::IsItemHovered()) { hovered = id; @@ -152,25 +157,28 @@ namespace anm2ed::imgui if (ImGui::Button(reference == -1 ? "Add" : "Confirm", widgetSize)) { - auto add = [&]() - { - auto id = map::next_id_get(anm2.content.nulls); - anm2.content.nulls[id] = null; - selection = {id}; - }; - - auto set = [&]() - { - anm2.content.nulls[reference] = null; - selection = {reference}; - }; - if (reference == -1) { + auto add = [&]() + { + auto id = map::next_id_get(anm2.content.nulls); + anm2.content.nulls[id] = null; + selection = {id}; + newNullId = id; + }; + DOCUMENT_EDIT(document, "Add Null", Document::NULLS, add()); } else + { + auto set = [&]() + { + anm2.content.nulls[reference] = null; + selection = {reference}; + }; + DOCUMENT_EDIT(document, "Set Null Properties", Document::NULLS, set()); + } manager.null_properties_close(); } @@ -184,4 +192,4 @@ namespace anm2ed::imgui manager.null_properties_end(); } -} \ No newline at end of file +} diff --git a/src/imgui/window/nulls.h b/src/imgui/window/nulls.h index 7ffd1fd..de0c547 100644 --- a/src/imgui/window/nulls.h +++ b/src/imgui/window/nulls.h @@ -9,7 +9,9 @@ namespace anm2ed::imgui { class Nulls { + int newNullId{-1}; + public: void update(Manager&, Settings&, Resources&, Clipboard&); }; -} \ No newline at end of file +} diff --git a/src/imgui/window/sounds.cpp b/src/imgui/window/sounds.cpp index 2f4f6a2..39fb0c6 100644 --- a/src/imgui/window/sounds.cpp +++ b/src/imgui/window/sounds.cpp @@ -42,6 +42,11 @@ namespace anm2ed::imgui if (isReferenced) ImGui::PushFont(resources.fonts[font::ITALICS].get(), font::SIZE); if (ImGui::Selectable(pathLabel, isSelected)) sound.play(); if (ImGui::IsItemHovered()) hovered = id; + if (newSoundId == id) + { + ImGui::SetScrollHereY(0.5f); + newSoundId = -1; + } if (isReferenced) ImGui::PopFont(); @@ -137,6 +142,7 @@ namespace anm2ed::imgui if (anm2.sound_add(document.directory_get().string(), dialog.path, id)) { selection = {id}; + newSoundId = id; toasts.info(std::format("Initialized sound #{}: {}", id, dialog.path)); } else diff --git a/src/imgui/window/sounds.h b/src/imgui/window/sounds.h index c39efa6..6f61b7e 100644 --- a/src/imgui/window/sounds.h +++ b/src/imgui/window/sounds.h @@ -10,6 +10,8 @@ namespace anm2ed::imgui { class Sounds { + int newSoundId{-1}; + public: void update(Manager&, Settings&, Resources&, Dialog&, Clipboard&); }; diff --git a/src/imgui/window/spritesheets.cpp b/src/imgui/window/spritesheets.cpp index c57c7af..5e09e60 100644 --- a/src/imgui/window/spritesheets.cpp +++ b/src/imgui/window/spritesheets.cpp @@ -104,6 +104,11 @@ namespace anm2ed::imgui ImGui::SetNextItemStorageID(id); if (ImGui::Selectable("##Spritesheet Selectable", isSelected, 0, spritesheetChildSize)) reference = id; if (ImGui::IsItemHovered()) hovered = id; + if (newSpritesheetId == id) + { + ImGui::SetScrollHereY(0.5f); + newSpritesheetId = -1; + } auto viewport = ImGui::GetMainViewport(); auto textureSize = texture.size.x * texture.size.y > (viewport->Size.x * viewport->Size.y) * 0.5f @@ -192,6 +197,7 @@ namespace anm2ed::imgui if (dialog.is_selected(dialog::SPRITESHEET_OPEN)) { document.spritesheet_add(dialog.path); + newSpritesheetId = document.spritesheet.reference; dialog.reset(); } diff --git a/src/imgui/window/spritesheets.h b/src/imgui/window/spritesheets.h index f012e8b..c35e88d 100644 --- a/src/imgui/window/spritesheets.h +++ b/src/imgui/window/spritesheets.h @@ -10,6 +10,8 @@ namespace anm2ed::imgui { class Spritesheets { + int newSpritesheetId{-1}; + public: void update(Manager&, Settings&, Resources&, Dialog&, Clipboard& clipboard); }; diff --git a/src/imgui/window/timeline.cpp b/src/imgui/window/timeline.cpp index e9c895d..47638c7 100644 --- a/src/imgui/window/timeline.cpp +++ b/src/imgui/window/timeline.cpp @@ -36,6 +36,10 @@ namespace anm2ed::imgui - Press {} to increment time. - Press {} to shorten the selected frame, by one frame. - Press {} to extend the selected frame, by one frame. +- Press {} to go to the previous frame. +- Press {} to go to the next frame. +- Click and hold on a frame while holding CTRL to change its duration. +- Click and hold on a trigger to change its At Frame. - Hold Alt while clicking a non-trigger frame to toggle interpolation.)"; void Timeline::update(Manager& manager, Settings& settings, Resources& resources, Clipboard& clipboard) @@ -313,10 +317,11 @@ namespace anm2ed::imgui ImGui::BeginDisabled(); ImGui::Text("(?)"); - ImGui::SetItemTooltip("%s", - std::format(HELP_FORMAT, settings.shortcutNextFrame, settings.shortcutPreviousFrame, - settings.shortcutShortenFrame, settings.shortcutExtendFrame) - .c_str()); + ImGui::SetItemTooltip("%s", std::format(HELP_FORMAT, settings.shortcutMovePlayheadBack, + settings.shortcutMovePlayheadForward, settings.shortcutShortenFrame, + settings.shortcutExtendFrame, settings.shortcutPreviousFrame, + settings.shortcutNextFrame) + .c_str()); ImGui::EndDisabled(); } } @@ -600,12 +605,15 @@ namespace anm2ed::imgui reference = frameReference; } - if (type == anm2::TRIGGER && ImGui::IsItemHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Left) && - !draggedTrigger) + if (ImGui::IsItemHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Left)) { - draggedTrigger = &frame; - draggedTriggerIndex = (int)i; - draggedTriggerAtFrameStart = hoveredTime; + if (type == anm2::TRIGGER || ImGui::IsKeyDown(ImGuiMod_Ctrl)) + { + draggedFrame = &frame; + draggedFrameIndex = (int)i; + draggedFrameStart = hoveredTime; + if (type != anm2::TRIGGER) draggedFrameStartDuration = draggedFrame->duration; + } } ImGui::PopStyleColor(3); @@ -781,33 +789,42 @@ namespace anm2ed::imgui frameSelectionSnapshotReference = reference; } - if (draggedTrigger) + if (draggedFrame) { ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); - if (!isDraggedTriggerSnapshot && hoveredTime != draggedTriggerAtFrameStart) + if (!isDraggedFrameSnapshot && hoveredTime != draggedFrameStart) { - isDraggedTriggerSnapshot = true; - document.snapshot("Trigger At Frame"); + isDraggedFrameSnapshot = true; + document.snapshot(type == anm2::TRIGGER ? "Trigger At Frame" : "Frame Duration"); } - draggedTrigger->atFrame = glm::clamp( - hoveredTime, 0, settings.playbackIsClamp ? animation->frameNum - 1 : anm2::FRAME_NUM_MAX - 1); - - for (std::size_t triggerIndex = 0; triggerIndex < animation->triggers.frames.size(); ++triggerIndex) + if (type == anm2::TRIGGER) { - if ((int)triggerIndex == draggedTriggerIndex) continue; - auto& trigger = animation->triggers.frames[triggerIndex]; - if (trigger.atFrame == draggedTrigger->atFrame) draggedTrigger->atFrame--; + draggedFrame->atFrame = glm::clamp( + hoveredTime, 0, settings.playbackIsClamp ? animation->frameNum - 1 : anm2::FRAME_NUM_MAX - 1); + + for (auto [i, trigger] : std::views::enumerate(animation->triggers.frames)) + { + if ((int)i == draggedFrameIndex) continue; + if (trigger.atFrame == draggedFrame->atFrame) draggedFrame->atFrame--; + } } + else + { + draggedFrame->duration = glm::clamp(draggedFrameStartDuration + (hoveredTime - draggedFrameStart), + anm2::FRAME_DURATION_MIN, anm2::FRAME_DURATION_MAX); + } + if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { document.change(Document::FRAMES); - draggedTrigger = nullptr; - draggedTriggerIndex = -1; - draggedTriggerAtFrameStart = -1; - isDraggedTriggerSnapshot = false; - item->frames_sort_by_at_frame(); + draggedFrame = nullptr; + draggedFrameIndex = -1; + draggedFrameStart = -1; + draggedFrameStartDuration = -1; + isDraggedFrameSnapshot = false; + if (type == anm2::TRIGGER) item->frames_sort_by_at_frame(); } } } @@ -958,6 +975,7 @@ namespace anm2ed::imgui ImGui::BeginDisabled(!item); { shortcut(manager.chords[SHORTCUT_ADD]); + shortcut(manager.chords[SHORTCUT_INSERT_FRAME]); if (ImGui::Button("Insert", widgetSize)) { auto insert_frame = [&]() @@ -1000,7 +1018,7 @@ namespace anm2ed::imgui DOCUMENT_EDIT(document, "Insert Frame", Document::FRAMES, insert_frame()); } - set_item_tooltip_shortcut("Insert a frame, based on the current selection.", settings.shortcutAdd); + set_item_tooltip_shortcut("Insert a frame, based on the current selection.", settings.shortcutInsertFrame); ImGui::SameLine(); @@ -1292,13 +1310,13 @@ namespace anm2ed::imgui { if (shortcut(manager.chords[SHORTCUT_PLAY_PAUSE], shortcut::GLOBAL)) playback.toggle(); - if (shortcut(manager.chords[SHORTCUT_PREVIOUS_FRAME], shortcut::GLOBAL, true)) + if (shortcut(manager.chords[SHORTCUT_MOVE_PLAYHEAD_BACK], shortcut::GLOBAL, true)) { playback.decrement(settings.playbackIsClamp ? animation->frameNum : anm2::FRAME_NUM_MAX); document.frameTime = playback.time; } - if (shortcut(manager.chords[SHORTCUT_NEXT_FRAME], shortcut::GLOBAL, true)) + if (shortcut(manager.chords[SHORTCUT_MOVE_PLAYHEAD_FORWARD], shortcut::GLOBAL, true)) { playback.increment(settings.playbackIsClamp ? animation->frameNum : anm2::FRAME_NUM_MAX); document.frameTime = playback.time; @@ -1325,6 +1343,28 @@ namespace anm2ed::imgui document.change(Document::FRAMES); } } + + if (shortcut(manager.chords[SHORTCUT_PREVIOUS_FRAME], shortcut::GLOBAL, true)) + { + if (auto item = document.item_get()) + { + reference.frameIndex--; + reference.frameIndex = glm::clamp(reference.frameIndex--, -1, (int)item->frames.size() - 1); + frames.selection = {reference.frameIndex}; + document.frameTime = item->frame_time_from_index_get(reference.frameIndex); + } + } + + if (shortcut(manager.chords[SHORTCUT_NEXT_FRAME], shortcut::GLOBAL, true)) + { + if (auto item = document.item_get()) + { + reference.frameIndex++; + reference.frameIndex = glm::clamp(reference.frameIndex, -1, (int)item->frames.size() - 1); + frames.selection = {reference.frameIndex}; + document.frameTime = item->frame_time_from_index_get(reference.frameIndex); + } + } } } } diff --git a/src/imgui/window/timeline.h b/src/imgui/window/timeline.h index 474e3da..ed35730 100644 --- a/src/imgui/window/timeline.h +++ b/src/imgui/window/timeline.h @@ -30,10 +30,11 @@ namespace anm2ed::imgui int addItemID{-1}; int addItemSpritesheetID{-1}; int hoveredTime{}; - anm2::Frame* draggedTrigger{}; - int draggedTriggerIndex{-1}; - int draggedTriggerAtFrameStart{-1}; - bool isDraggedTriggerSnapshot{}; + anm2::Frame* draggedFrame{}; + int draggedFrameIndex{-1}; + int draggedFrameStart{-1}; + int draggedFrameStartDuration{-1}; + bool isDraggedFrameSnapshot{}; FrameDragDrop frameDragDrop{}; std::vector frameSelectionSnapshot{}; std::vector frameSelectionLocked{}; diff --git a/src/settings.h b/src/settings.h index 6d0d22d..1699705 100644 --- a/src/settings.h +++ b/src/settings.h @@ -190,11 +190,13 @@ namespace anm2ed X(SHORTCUT_ZOOM_OUT, shortcutZoomOut, "Zoom Out", STRING, "Ctrl+Minus") \ /* Timeline / Playback */ \ X(SHORTCUT_PLAY_PAUSE, shortcutPlayPause, "Play/Pause", STRING, "Space") \ - X(SHORTCUT_PREVIOUS_FRAME, shortcutPreviousFrame, "Previous Frame", STRING, "Comma") \ - X(SHORTCUT_NEXT_FRAME, shortcutNextFrame, "Next Frame", STRING, "Period") \ - X(SHORTCUT_INSERT_FRAME, shortcutInsertFrame, "Insert Frame", STRING, "F6") \ + X(SHORTCUT_MOVE_PLAYHEAD_BACK, shortcutMovePlayheadBack, "Playhead Back", STRING, "Comma") \ + X(SHORTCUT_MOVE_PLAYHEAD_FORWARD, shortcutMovePlayheadForward, "Playhead Forward", STRING, "Period") \ X(SHORTCUT_SHORTEN_FRAME, shortcutShortenFrame, "Shorten Frame", STRING, "F4") \ X(SHORTCUT_EXTEND_FRAME, shortcutExtendFrame, "Extend Frame", STRING, "F5") \ + X(SHORTCUT_INSERT_FRAME, shortcutInsertFrame, "Insert Frame", STRING, "F6") \ + X(SHORTCUT_PREVIOUS_FRAME, shortcutPreviousFrame, "Previous Frame", STRING, "F7") \ + X(SHORTCUT_NEXT_FRAME, shortcutNextFrame, "Next Frame", STRING, "F8") \ /* Toggles */ \ X(SHORTCUT_ONIONSKIN, shortcutOnionskin, "Onionskin", STRING, "O") diff --git a/src/tool.h b/src/tool.h index 109630e..2b16b4e 100644 --- a/src/tool.h +++ b/src/tool.h @@ -54,7 +54,7 @@ namespace anm2ed::tool {ImGuiMouseCursor_ResizeNESW, resource::icon::SCALE, SHORTCUT_SCALE, ANIMATION_PREVIEW, "##Scale", "Use the scale tool.\nWill scale the selected item as the cursor is dragged, or directional keys are " - "pressed.\n(Animation Preview only.)"}, + "pressed.\nHold SHIFT to lock scaling to one dimension.\n(Animation Preview only.)"}, {ImGuiMouseCursor_Arrow, resource::icon::CROP, SHORTCUT_CROP, SPRITESHEET_EDITOR, "##Crop", "Use the crop tool.\nWill produce a crop rectangle based on how the cursor is dragged, or directional keys are "