original editor compliance and some fixes

This commit is contained in:
2025-11-14 14:08:41 -05:00
parent 911085ef47
commit 5470368b6a
22 changed files with 202 additions and 78 deletions

View File

@@ -295,4 +295,18 @@ namespace anm2ed::anm2
if (frame.atFrame == atFrame) return i; if (frame.atFrame == atFrame) return i;
return -1; 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;
}
} }

View File

@@ -26,5 +26,6 @@ namespace anm2ed::anm2
void frames_generate_from_grid(glm::ivec2, glm::ivec2, glm::ivec2, int, int, int); void frames_generate_from_grid(glm::ivec2, glm::ivec2, glm::ivec2, int, int, int);
void frames_sort_by_at_frame(); void frames_sort_by_at_frame();
int frame_index_from_at_frame_get(int); int frame_index_from_at_frame_get(int);
float frame_time_from_index_get(int);
}; };
} }

View File

@@ -228,6 +228,7 @@ namespace anm2ed
{ {
anm2::Spritesheet& spritesheet = anm2.content.spritesheets[id]; anm2::Spritesheet& spritesheet = anm2.content.spritesheets[id];
this->spritesheet.selection = {id}; this->spritesheet.selection = {id};
this->spritesheet.reference = id;
toasts.info(std::format("Initialized spritesheet #{}: {}", id, spritesheet.path.string())); toasts.info(std::format("Initialized spritesheet #{}: {}", id, spritesheet.path.string()));
} }
else else

View File

@@ -62,7 +62,7 @@ namespace anm2ed::imgui
} }
bool selectable_input_text(const std::string& label, const std::string& id, std::string& text, bool isSelected, 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 std::string editID{};
static bool isJustEdit{}; static bool isJustEdit{};
@@ -90,7 +90,8 @@ namespace anm2ed::imgui
{ {
if (ImGui::Selectable(label.c_str(), isSelected, flags)) isActivated = true; 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))) (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)))
{ {
editID = id; editID = id;

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <imgui/imgui.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <imgui/imgui.h>
#include <set> #include <set>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
@@ -170,7 +170,7 @@ namespace anm2ed::imgui
ImGuiInputTextFlags = 0); ImGuiInputTextFlags = 0);
bool combo_negative_one_indexed(const std::string&, int*, std::vector<const char*>&); bool combo_negative_one_indexed(const std::string&, int*, std::vector<const char*>&);
bool selectable_input_text(const std::string&, const std::string&, std::string&, bool = false, 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 set_item_tooltip_shortcut(const char*, const std::string& = {});
void external_storage_set(ImGuiSelectionExternalStorage*, int, bool); void external_storage_set(ImGuiSelectionExternalStorage*, int, bool);
void render_checker_background(ImDrawList*, ImVec2, ImVec2, glm::vec2, float); void render_checker_background(ImDrawList*, ImVec2, ImVec2, glm::vec2, float);

View File

@@ -354,7 +354,8 @@ namespace anm2ed::imgui
auto render = [&](anm2::Animation* animation, float time, vec3 colorOffset = {}, float alphaOffset = {}, auto render = [&](anm2::Animation* animation, float time, vec3 colorOffset = {}, float alphaOffset = {},
bool isOnionskin = false) 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); auto root = animation->rootAnimation.frame_generate(time, anm2::ROOT);
if (isRootTransform) if (isRootTransform)
@@ -362,8 +363,8 @@ namespace anm2ed::imgui
if (!isOnlyShowLayers && root.isVisible && animation->rootAnimation.isVisible) if (!isOnlyShowLayers && root.isVisible && animation->rootAnimation.isVisible)
{ {
auto rootTransform = transform * math::quad_model_get(TARGET_SIZE, root.position, TARGET_SIZE * 0.5f, auto rootTransform = baseTransform * math::quad_model_get(TARGET_SIZE, root.position, TARGET_SIZE * 0.5f,
math::percent_to_unit(root.scale), root.rotation); math::percent_to_unit(root.scale), root.rotation);
vec4 color = isOnionskin ? vec4(colorOffset, alphaOffset) : color::GREEN; vec4 color = isOnionskin ? vec4(colorOffset, alphaOffset) : color::GREEN;
@@ -511,9 +512,10 @@ namespace anm2ed::imgui
{ {
auto isMouseClicked = ImGui::IsMouseClicked(ImGuiMouseButton_Left); auto isMouseClicked = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
auto isMouseReleased = ImGui::IsMouseReleased(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 isMouseMiddleDown = ImGui::IsMouseDown(ImGuiMouseButton_Middle);
auto isMouseRightDown = ImGui::IsMouseDown(ImGuiMouseButton_Right); auto isMouseRightDown = ImGui::IsMouseDown(ImGuiMouseButton_Right);
auto isMouseDown = isMouseLeftDown || isMouseMiddleDown || isMouseRightDown;
auto mouseDelta = to_ivec2(ImGui::GetIO().MouseDelta); auto mouseDelta = to_ivec2(ImGui::GetIO().MouseDelta);
auto mouseWheel = ImGui::GetIO().MouseWheel; auto mouseWheel = ImGui::GetIO().MouseWheel;
@@ -589,7 +591,11 @@ namespace anm2ed::imgui
case tool::SCALE: case tool::SCALE:
if (!frame) break; if (!frame) break;
if (isBegin) document.snapshot("Frame Scale"); 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 (isLeftPressed) frame->scale.x -= step;
if (isRightPressed) frame->scale.x += step; if (isRightPressed) frame->scale.x += step;
if (isUpPressed) frame->scale.y -= step; if (isUpPressed) frame->scale.y -= step;

View File

@@ -54,6 +54,7 @@ namespace anm2ed::imgui
auto isDefault = anm2.animations.defaultAnimation == animation.name; auto isDefault = anm2.animations.defaultAnimation == animation.name;
auto isReferenced = reference.animationIndex == (int)i; auto isReferenced = reference.animationIndex == (int)i;
auto isNewSelection = newAnimationSelectedIndex == (int)i;
auto font = isDefault && isReferenced ? font::BOLD_ITALICS auto font = isDefault && isReferenced ? font::BOLD_ITALICS
: isDefault ? font::BOLD : isDefault ? font::BOLD
@@ -62,13 +63,20 @@ namespace anm2ed::imgui
ImGui::PushFont(resources.fonts[font].get(), font::SIZE); ImGui::PushFont(resources.fonts[font].get(), font::SIZE);
ImGui::SetNextItemSelectionUserData((int)i); ImGui::SetNextItemSelectionUserData((int)i);
if (selectable_input_text(animation.name, std::format("###Document #{} Animation #{}", manager.selected, 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}; reference = {(int)i};
document.frames.clear(); document.frames.clear();
} }
if (ImGui::IsItemHovered()) hovered = (int)i; if (ImGui::IsItemHovered()) hovered = (int)i;
if (isNewSelection)
{
ImGui::SetScrollHereY(0.5f);
newAnimationSelectedIndex = -1;
}
ImGui::PopFont(); ImGui::PopFont();
if (ImGui::BeginItemTooltip()) if (ImGui::BeginItemTooltip())
@@ -190,13 +198,17 @@ namespace anm2ed::imgui
} }
animation.rootAnimation.frames.emplace_back(anm2::Frame()); animation.rootAnimation.frames.emplace_back(anm2::Frame());
auto index = 0; auto index = (int)anm2.animations.items.size();
if (!anm2.animations.items.empty()) if (!selection.empty())
index = selection.empty() ? (int)anm2.animations.items.size() - 1 : *selection.rbegin() + 1; {
index = *selection.rbegin() + 1;
index = std::min(index, (int)anm2.animations.items.size());
}
anm2.animations.items.insert(anm2.animations.items.begin() + index, animation); anm2.animations.items.insert(anm2.animations.items.begin() + index, animation);
selection = {index}; selection = {index};
reference = {index}; reference = {index};
newAnimationSelectedIndex = index;
}; };
DOCUMENT_EDIT(document, "Add Animation", Document::ANIMATIONS, add()); DOCUMENT_EDIT(document, "Add Animation", Document::ANIMATIONS, add());

View File

@@ -10,6 +10,7 @@ namespace anm2ed::imgui
class Animations class Animations
{ {
PopupHelper mergePopup{PopupHelper("Merge Animations")}; PopupHelper mergePopup{PopupHelper("Merge Animations")};
int newAnimationSelectedIndex{-1};
public: public:
void update(Manager&, Settings&, Resources&, Clipboard&); void update(Manager&, Settings&, Resources&, Clipboard&);

View File

@@ -34,9 +34,15 @@ namespace anm2ed::imgui
{ {
ImGui::PushID(id); ImGui::PushID(id);
ImGui::SetNextItemSelectionUserData(id); ImGui::SetNextItemSelectionUserData(id);
const bool isNewEvent = (newEventId == id);
if (selectable_input_text(event.name, std::format("###Document #{} Event #{}", manager.selected, 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 (ImGui::IsItemHovered()) hovered = id;
if (isNewEvent)
{
ImGui::SetScrollHereY(0.5f);
newEventId = -1;
}
if (ImGui::BeginItemTooltip()) if (ImGui::BeginItemTooltip())
{ {
@@ -105,6 +111,7 @@ namespace anm2ed::imgui
anm2.content.events[id] = anm2::Event(); anm2.content.events[id] = anm2::Event();
selection = {id}; selection = {id};
reference = {id}; reference = {id};
newEventId = id;
}; };
DOCUMENT_EDIT(document, "Add Event", Document::EVENTS, add()); DOCUMENT_EDIT(document, "Add Event", Document::EVENTS, add());

View File

@@ -9,6 +9,8 @@ namespace anm2ed::imgui
{ {
class Events class Events
{ {
int newEventId{-1};
public: public:
void update(Manager&, Settings&, Resources&, Clipboard&); void update(Manager&, Settings&, Resources&, Clipboard&);
}; };

View File

@@ -39,6 +39,11 @@ namespace anm2ed::imgui
ImGui::SetNextItemSelectionUserData(id); ImGui::SetNextItemSelectionUserData(id);
ImGui::Selectable(std::format(anm2::LAYER_FORMAT, id, layer.name, layer.spritesheetID).c_str(), isSelected); 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()) if (ImGui::IsItemHovered())
{ {
hovered = id; hovered = id;
@@ -152,25 +157,28 @@ namespace anm2ed::imgui
if (ImGui::Button(reference == -1 ? "Add" : "Confirm", widgetSize)) 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) 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()); DOCUMENT_EDIT(document, "Add Layer", Document::LAYERS, add());
} }
else else
{
auto set = [&]()
{
anm2.content.layers[reference] = layer;
selection = {reference};
};
DOCUMENT_EDIT(document, "Set Layer Properties", Document::LAYERS, set()); DOCUMENT_EDIT(document, "Set Layer Properties", Document::LAYERS, set());
}
manager.layer_properties_close(); manager.layer_properties_close();
} }

View File

@@ -9,6 +9,8 @@ namespace anm2ed::imgui
{ {
class Layers class Layers
{ {
int newLayerId{-1};
public: public:
void update(Manager&, Settings&, Resources&, Clipboard&); void update(Manager&, Settings&, Resources&, Clipboard&);
}; };

View File

@@ -40,6 +40,11 @@ namespace anm2ed::imgui
ImGui::SetNextItemSelectionUserData(id); ImGui::SetNextItemSelectionUserData(id);
if (isReferenced) ImGui::PushFont(resources.fonts[font::ITALICS].get(), font::SIZE); if (isReferenced) ImGui::PushFont(resources.fonts[font::ITALICS].get(), font::SIZE);
ImGui::Selectable(std::format(anm2::NULL_FORMAT, id, null.name).c_str(), isSelected); 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()) if (ImGui::IsItemHovered())
{ {
hovered = id; hovered = id;
@@ -152,25 +157,28 @@ namespace anm2ed::imgui
if (ImGui::Button(reference == -1 ? "Add" : "Confirm", widgetSize)) 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) 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()); DOCUMENT_EDIT(document, "Add Null", Document::NULLS, add());
} }
else else
{
auto set = [&]()
{
anm2.content.nulls[reference] = null;
selection = {reference};
};
DOCUMENT_EDIT(document, "Set Null Properties", Document::NULLS, set()); DOCUMENT_EDIT(document, "Set Null Properties", Document::NULLS, set());
}
manager.null_properties_close(); manager.null_properties_close();
} }

View File

@@ -9,6 +9,8 @@ namespace anm2ed::imgui
{ {
class Nulls class Nulls
{ {
int newNullId{-1};
public: public:
void update(Manager&, Settings&, Resources&, Clipboard&); void update(Manager&, Settings&, Resources&, Clipboard&);
}; };

View File

@@ -42,6 +42,11 @@ namespace anm2ed::imgui
if (isReferenced) ImGui::PushFont(resources.fonts[font::ITALICS].get(), font::SIZE); if (isReferenced) ImGui::PushFont(resources.fonts[font::ITALICS].get(), font::SIZE);
if (ImGui::Selectable(pathLabel, isSelected)) sound.play(); if (ImGui::Selectable(pathLabel, isSelected)) sound.play();
if (ImGui::IsItemHovered()) hovered = id; if (ImGui::IsItemHovered()) hovered = id;
if (newSoundId == id)
{
ImGui::SetScrollHereY(0.5f);
newSoundId = -1;
}
if (isReferenced) ImGui::PopFont(); if (isReferenced) ImGui::PopFont();
@@ -137,6 +142,7 @@ namespace anm2ed::imgui
if (anm2.sound_add(document.directory_get().string(), dialog.path, id)) if (anm2.sound_add(document.directory_get().string(), dialog.path, id))
{ {
selection = {id}; selection = {id};
newSoundId = id;
toasts.info(std::format("Initialized sound #{}: {}", id, dialog.path)); toasts.info(std::format("Initialized sound #{}: {}", id, dialog.path));
} }
else else

View File

@@ -10,6 +10,8 @@ namespace anm2ed::imgui
{ {
class Sounds class Sounds
{ {
int newSoundId{-1};
public: public:
void update(Manager&, Settings&, Resources&, Dialog&, Clipboard&); void update(Manager&, Settings&, Resources&, Dialog&, Clipboard&);
}; };

View File

@@ -104,6 +104,11 @@ namespace anm2ed::imgui
ImGui::SetNextItemStorageID(id); ImGui::SetNextItemStorageID(id);
if (ImGui::Selectable("##Spritesheet Selectable", isSelected, 0, spritesheetChildSize)) reference = id; if (ImGui::Selectable("##Spritesheet Selectable", isSelected, 0, spritesheetChildSize)) reference = id;
if (ImGui::IsItemHovered()) hovered = id; if (ImGui::IsItemHovered()) hovered = id;
if (newSpritesheetId == id)
{
ImGui::SetScrollHereY(0.5f);
newSpritesheetId = -1;
}
auto viewport = ImGui::GetMainViewport(); auto viewport = ImGui::GetMainViewport();
auto textureSize = texture.size.x * texture.size.y > (viewport->Size.x * viewport->Size.y) * 0.5f 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)) if (dialog.is_selected(dialog::SPRITESHEET_OPEN))
{ {
document.spritesheet_add(dialog.path); document.spritesheet_add(dialog.path);
newSpritesheetId = document.spritesheet.reference;
dialog.reset(); dialog.reset();
} }

View File

@@ -10,6 +10,8 @@ namespace anm2ed::imgui
{ {
class Spritesheets class Spritesheets
{ {
int newSpritesheetId{-1};
public: public:
void update(Manager&, Settings&, Resources&, Dialog&, Clipboard& clipboard); void update(Manager&, Settings&, Resources&, Dialog&, Clipboard& clipboard);
}; };

View File

@@ -36,6 +36,10 @@ namespace anm2ed::imgui
- Press {} to increment time. - Press {} to increment time.
- Press {} to shorten the selected frame, by one frame. - Press {} to shorten the selected frame, by one frame.
- Press {} to extend 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.)"; - Hold Alt while clicking a non-trigger frame to toggle interpolation.)";
void Timeline::update(Manager& manager, Settings& settings, Resources& resources, Clipboard& clipboard) void Timeline::update(Manager& manager, Settings& settings, Resources& resources, Clipboard& clipboard)
@@ -313,10 +317,11 @@ namespace anm2ed::imgui
ImGui::BeginDisabled(); ImGui::BeginDisabled();
ImGui::Text("(?)"); ImGui::Text("(?)");
ImGui::SetItemTooltip("%s", ImGui::SetItemTooltip("%s", std::format(HELP_FORMAT, settings.shortcutMovePlayheadBack,
std::format(HELP_FORMAT, settings.shortcutNextFrame, settings.shortcutPreviousFrame, settings.shortcutMovePlayheadForward, settings.shortcutShortenFrame,
settings.shortcutShortenFrame, settings.shortcutExtendFrame) settings.shortcutExtendFrame, settings.shortcutPreviousFrame,
.c_str()); settings.shortcutNextFrame)
.c_str());
ImGui::EndDisabled(); ImGui::EndDisabled();
} }
} }
@@ -600,12 +605,15 @@ namespace anm2ed::imgui
reference = frameReference; reference = frameReference;
} }
if (type == anm2::TRIGGER && ImGui::IsItemHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Left) && if (ImGui::IsItemHovered() && ImGui::IsMouseDown(ImGuiMouseButton_Left))
!draggedTrigger)
{ {
draggedTrigger = &frame; if (type == anm2::TRIGGER || ImGui::IsKeyDown(ImGuiMod_Ctrl))
draggedTriggerIndex = (int)i; {
draggedTriggerAtFrameStart = hoveredTime; draggedFrame = &frame;
draggedFrameIndex = (int)i;
draggedFrameStart = hoveredTime;
if (type != anm2::TRIGGER) draggedFrameStartDuration = draggedFrame->duration;
}
} }
ImGui::PopStyleColor(3); ImGui::PopStyleColor(3);
@@ -781,33 +789,42 @@ namespace anm2ed::imgui
frameSelectionSnapshotReference = reference; frameSelectionSnapshotReference = reference;
} }
if (draggedTrigger) if (draggedFrame)
{ {
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
if (!isDraggedTriggerSnapshot && hoveredTime != draggedTriggerAtFrameStart) if (!isDraggedFrameSnapshot && hoveredTime != draggedFrameStart)
{ {
isDraggedTriggerSnapshot = true; isDraggedFrameSnapshot = true;
document.snapshot("Trigger At Frame"); document.snapshot(type == anm2::TRIGGER ? "Trigger At Frame" : "Frame Duration");
} }
draggedTrigger->atFrame = glm::clamp( if (type == anm2::TRIGGER)
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 ((int)triggerIndex == draggedTriggerIndex) continue; draggedFrame->atFrame = glm::clamp(
auto& trigger = animation->triggers.frames[triggerIndex]; hoveredTime, 0, settings.playbackIsClamp ? animation->frameNum - 1 : anm2::FRAME_NUM_MAX - 1);
if (trigger.atFrame == draggedTrigger->atFrame) draggedTrigger->atFrame--;
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)) if (ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{ {
document.change(Document::FRAMES); document.change(Document::FRAMES);
draggedTrigger = nullptr; draggedFrame = nullptr;
draggedTriggerIndex = -1; draggedFrameIndex = -1;
draggedTriggerAtFrameStart = -1; draggedFrameStart = -1;
isDraggedTriggerSnapshot = false; draggedFrameStartDuration = -1;
item->frames_sort_by_at_frame(); isDraggedFrameSnapshot = false;
if (type == anm2::TRIGGER) item->frames_sort_by_at_frame();
} }
} }
} }
@@ -958,6 +975,7 @@ namespace anm2ed::imgui
ImGui::BeginDisabled(!item); ImGui::BeginDisabled(!item);
{ {
shortcut(manager.chords[SHORTCUT_ADD]); shortcut(manager.chords[SHORTCUT_ADD]);
shortcut(manager.chords[SHORTCUT_INSERT_FRAME]);
if (ImGui::Button("Insert", widgetSize)) if (ImGui::Button("Insert", widgetSize))
{ {
auto insert_frame = [&]() auto insert_frame = [&]()
@@ -1000,7 +1018,7 @@ namespace anm2ed::imgui
DOCUMENT_EDIT(document, "Insert Frame", Document::FRAMES, insert_frame()); 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(); 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_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); playback.decrement(settings.playbackIsClamp ? animation->frameNum : anm2::FRAME_NUM_MAX);
document.frameTime = playback.time; 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); playback.increment(settings.playbackIsClamp ? animation->frameNum : anm2::FRAME_NUM_MAX);
document.frameTime = playback.time; document.frameTime = playback.time;
@@ -1325,6 +1343,28 @@ namespace anm2ed::imgui
document.change(Document::FRAMES); 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);
}
}
} }
} }
} }

View File

@@ -30,10 +30,11 @@ namespace anm2ed::imgui
int addItemID{-1}; int addItemID{-1};
int addItemSpritesheetID{-1}; int addItemSpritesheetID{-1};
int hoveredTime{}; int hoveredTime{};
anm2::Frame* draggedTrigger{}; anm2::Frame* draggedFrame{};
int draggedTriggerIndex{-1}; int draggedFrameIndex{-1};
int draggedTriggerAtFrameStart{-1}; int draggedFrameStart{-1};
bool isDraggedTriggerSnapshot{}; int draggedFrameStartDuration{-1};
bool isDraggedFrameSnapshot{};
FrameDragDrop frameDragDrop{}; FrameDragDrop frameDragDrop{};
std::vector<int> frameSelectionSnapshot{}; std::vector<int> frameSelectionSnapshot{};
std::vector<int> frameSelectionLocked{}; std::vector<int> frameSelectionLocked{};

View File

@@ -190,11 +190,13 @@ namespace anm2ed
X(SHORTCUT_ZOOM_OUT, shortcutZoomOut, "Zoom Out", STRING, "Ctrl+Minus") \ X(SHORTCUT_ZOOM_OUT, shortcutZoomOut, "Zoom Out", STRING, "Ctrl+Minus") \
/* Timeline / Playback */ \ /* Timeline / Playback */ \
X(SHORTCUT_PLAY_PAUSE, shortcutPlayPause, "Play/Pause", STRING, "Space") \ X(SHORTCUT_PLAY_PAUSE, shortcutPlayPause, "Play/Pause", STRING, "Space") \
X(SHORTCUT_PREVIOUS_FRAME, shortcutPreviousFrame, "Previous Frame", STRING, "Comma") \ X(SHORTCUT_MOVE_PLAYHEAD_BACK, shortcutMovePlayheadBack, "Playhead Back", STRING, "Comma") \
X(SHORTCUT_NEXT_FRAME, shortcutNextFrame, "Next Frame", STRING, "Period") \ X(SHORTCUT_MOVE_PLAYHEAD_FORWARD, shortcutMovePlayheadForward, "Playhead Forward", STRING, "Period") \
X(SHORTCUT_INSERT_FRAME, shortcutInsertFrame, "Insert Frame", STRING, "F6") \
X(SHORTCUT_SHORTEN_FRAME, shortcutShortenFrame, "Shorten Frame", STRING, "F4") \ X(SHORTCUT_SHORTEN_FRAME, shortcutShortenFrame, "Shorten Frame", STRING, "F4") \
X(SHORTCUT_EXTEND_FRAME, shortcutExtendFrame, "Extend Frame", STRING, "F5") \ 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 */ \ /* Toggles */ \
X(SHORTCUT_ONIONSKIN, shortcutOnionskin, "Onionskin", STRING, "O") X(SHORTCUT_ONIONSKIN, shortcutOnionskin, "Onionskin", STRING, "O")

View File

@@ -54,7 +54,7 @@ namespace anm2ed::tool
{ImGuiMouseCursor_ResizeNESW, resource::icon::SCALE, SHORTCUT_SCALE, ANIMATION_PREVIEW, "##Scale", {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 " "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", {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 " "Use the crop tool.\nWill produce a crop rectangle based on how the cursor is dragged, or directional keys are "