From 8c421595c420ca06fdc9146d09a66a744287f872 Mon Sep 17 00:00:00 2001 From: shweet Date: Fri, 22 May 2026 11:13:39 -0400 Subject: [PATCH] more tweaks --- src/document.cpp | 22 +++++++- src/document.hpp | 1 + src/imgui/documents.cpp | 2 +- src/imgui/popup/autosave_restore.cpp | 2 +- src/imgui/window/timeline.cpp | 82 ++++++++++++++++++---------- src/imgui/window/timeline.hpp | 11 ---- src/imgui/window/window.cpp | 1 - src/manager.cpp | 14 ----- src/snapshots.cpp | 2 + src/snapshots.hpp | 2 + 10 files changed, 80 insertions(+), 59 deletions(-) diff --git a/src/document.cpp b/src/document.cpp index 4f0d8f7..6941696 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -159,6 +159,7 @@ namespace anm2ed::document auto& selection = document.frames.selection; auto& frameReferences = document.frames.references; auto& itemReferences = document.items.references; + auto& groupReferences = document.groupReferences; auto animationCount = animation_count_get(document.anm2); if (animationCount <= 0) @@ -167,6 +168,7 @@ namespace anm2ed::document selection.clear(); frameReferences.clear(); itemReferences.clear(); + groupReferences.clear(); document.frameTime = 0.0f; return; } @@ -188,6 +190,7 @@ namespace anm2ed::document reference.frameIndex = -1; selection.clear(); frameReferences.clear(); + groupReferences.clear(); document.frameTime = 0.0f; return; } @@ -201,6 +204,21 @@ namespace anm2ed::document ++it; } + for (auto it = groupReferences.begin(); it != groupReferences.end();) + { + auto animation = document.anm2.element_get(ElementType::ANIMATION, it->animationIndex); + Element* container{}; + if (animation && it->itemType == LAYER) + container = element_child_first_get(*animation, ElementType::LAYER_ANIMATIONS); + else if (animation && it->itemType == NULL_) + container = element_child_first_get(*animation, ElementType::NULL_ANIMATIONS); + auto group = container ? element_child_id_get(*container, ElementType::GROUP, it->itemID) : nullptr; + if (!group) + it = groupReferences.erase(it); + else + ++it; + } + for (auto it = frameReferences.begin(); it != frameReferences.end();) { auto item = document.anm2.element_get(it->animationIndex, item_type_get(it->itemType), it->itemID); @@ -282,8 +300,8 @@ namespace anm2ed playback(current.playback), animation(current.animation), event(current.event), frames(current.frames), items(current.items), layer(current.layer), merge(current.merge), null(current.null), region(current.region), sound(current.sound), spritesheet(current.spritesheet), textures(current.textures), sounds(current.sounds), - anm2(current.anm2), reference(current.reference), frameTime(current.frameTime), message(current.message), - regionBySpritesheet(std::move(other.regionBySpritesheet)), + anm2(current.anm2), reference(current.reference), groupReferences(current.groupReferences), + frameTime(current.frameTime), message(current.message), regionBySpritesheet(std::move(other.regionBySpritesheet)), changeAllFramePropertiesRegionId(other.changeAllFramePropertiesRegionId), previewZoom(other.previewZoom), previewPan(other.previewPan), editorPan(other.editorPan), editorZoom(other.editorZoom), overlayIndex(other.overlayIndex), hash(other.hash), saveHash(other.saveHash), autosaveHash(other.autosaveHash), diff --git a/src/document.hpp b/src/document.hpp index 075fba2..4115824 100644 --- a/src/document.hpp +++ b/src/document.hpp @@ -57,6 +57,7 @@ namespace anm2ed std::map& sounds = current.sounds; Anm2& anm2 = current.anm2; Reference& reference = current.reference; + std::set& groupReferences = current.groupReferences; float& frameTime = current.frameTime; std::string& message = current.message; std::map regionBySpritesheet{}; diff --git a/src/imgui/documents.cpp b/src/imgui/documents.cpp index 1719dc1..f095e8a 100644 --- a/src/imgui/documents.cpp +++ b/src/imgui/documents.cpp @@ -36,7 +36,7 @@ namespace anm2ed::imgui for (auto i = 0; i < (int)manager.documents.size(); ++i) { auto& document = manager.documents[i]; - auto isDirty = document.is_dirty() && document.is_autosave_dirty(); + auto isDirty = (document.is_dirty() || document.isForceDirty) && document.is_autosave_dirty(); if (isDirty) { document.lastAutosaveTime += ImGui::GetIO().DeltaTime; diff --git a/src/imgui/popup/autosave_restore.cpp b/src/imgui/popup/autosave_restore.cpp index f45bb35..8b1cd64 100644 --- a/src/imgui/popup/autosave_restore.cpp +++ b/src/imgui/popup/autosave_restore.cpp @@ -51,7 +51,7 @@ namespace anm2ed::imgui if (ImGui::Button(localize.get(BASIC_NO), widgetSize)) { - manager.autosave_files_clear(); + manager.autosave_files_clear(true); isRestoreAvailable = false; popup.close(); } diff --git a/src/imgui/window/timeline.cpp b/src/imgui/window/timeline.cpp index f5a82d0..0338999 100644 --- a/src/imgui/window/timeline.cpp +++ b/src/imgui/window/timeline.cpp @@ -57,6 +57,13 @@ namespace anm2ed::imgui constexpr auto TIMELINE_CHILD_BG_COLOR_LIGHT = ImVec4(0.5490f, 0.5490f, 0.5882f, 1.0f); constexpr auto TIMELINE_TEXT_COLOR_LIGHT = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); + enum class DropZone + { + BEFORE, + INSIDE, + AFTER + }; + constexpr glm::vec4 FRAME_COLOR_LIGHT_BASE[] = {{0.80f, 0.80f, 0.80f, 1.0f}, {0.5216f, 0.7333f, 1.0f, 1.0f}, {1.0f, 0.9961f, 0.5882f, 1.0f}, @@ -220,9 +227,9 @@ namespace anm2ed::imgui return left.animationIndex == right.animationIndex && left.itemType == right.itemType && left.itemID == right.itemID; }; - auto group_selection_reset = [this]() + auto group_selection_reset_for = [this](Document& targetDocument) { - groupReferences.clear(); + targetDocument.groupReferences.clear(); isRowSelectionAnchorSet = false; }; auto frame_references_for_current_get = [&]() @@ -256,7 +263,7 @@ namespace anm2ed::imgui }; auto frame_selection_set_for = [&](Document& targetDocument, Reference frameReference) { - group_selection_reset(); + group_selection_reset_for(targetDocument); targetDocument.frames.references = {frameReference}; targetDocument.reference = frameReference; item_selection_set_for(targetDocument, item_reference_from_frame_get(frameReference)); @@ -264,7 +271,7 @@ namespace anm2ed::imgui }; auto frame_selection_toggle_for = [&](Document& targetDocument, Reference frameReference) { - group_selection_reset(); + group_selection_reset_for(targetDocument); auto& selection = targetDocument.frames.references; auto itemReference = item_reference_from_frame_get(frameReference); if (selection.contains(frameReference)) @@ -287,7 +294,7 @@ namespace anm2ed::imgui auto frame_selection_range_set_for = [&](Document& targetDocument, Reference firstReference, Reference lastReference, bool isAdditive) -> bool { - group_selection_reset(); + group_selection_reset_for(targetDocument); if (!is_same_item(firstReference, lastReference) || firstReference.frameIndex < 0 || lastReference.frameIndex < 0) return false; @@ -714,13 +721,13 @@ namespace anm2ed::imgui auto reference_clear = [&]() { - group_selection_reset(); + group_selection_reset_for(document); reference_clear_for(document); }; auto reference_set_timeline_item = [&](int type, int id) { - group_selection_reset(); + group_selection_reset_for(document); reference_set_timeline_item_for(document, type, id); }; @@ -821,7 +828,7 @@ namespace anm2ed::imgui }; auto group_reference_get = [&](const TimelineItemRow& row) - { return TimelineGroupReference{manager.selected, reference.animationIndex, row.type, row.id}; }; + { return Reference{reference.animationIndex, row.type, row.id}; }; auto row_reference_get = [&](const TimelineItemRow& row) { @@ -844,7 +851,7 @@ namespace anm2ed::imgui auto is_group_selected = [&](const TimelineItemRow& row) { - return groupReferences.contains(group_reference_get(row)); + return document.groupReferences.contains(group_reference_get(row)); }; auto is_row_selected = [&](const TimelineItemRow& row) @@ -853,19 +860,19 @@ namespace anm2ed::imgui auto itemReference = item_reference_get(row.type, row.id); auto isReferenced = reference.itemType == row.type && reference.itemID == row.id; return document.items.references.contains(itemReference) || - (document.items.references.empty() && groupReferences.empty() && isReferenced); + (document.items.references.empty() && document.groupReferences.empty() && isReferenced); }; auto row_selection_clear = [&]() { document.items.references.clear(); - groupReferences.clear(); + document.groupReferences.clear(); }; auto row_selection_insert = [&](const TimelineRowReference& row) { if (row.isGroup) - groupReferences.insert({row.documentIndex, row.animationIndex, row.type, row.id}); + document.groupReferences.insert({row.animationIndex, row.type, row.id}); else document.items.references.insert(row_item_reference_get(row)); }; @@ -873,18 +880,18 @@ namespace anm2ed::imgui auto row_selection_erase = [&](const TimelineRowReference& row) { if (row.isGroup) - groupReferences.erase({row.documentIndex, row.animationIndex, row.type, row.id}); + document.groupReferences.erase({row.animationIndex, row.type, row.id}); else document.items.references.erase(row_item_reference_get(row)); }; auto is_row_reference_selected = [&](const TimelineRowReference& row) { - if (row.isGroup) return groupReferences.contains({row.documentIndex, row.animationIndex, row.type, row.id}); + if (row.isGroup) return document.groupReferences.contains({row.animationIndex, row.type, row.id}); return document.items.references.contains(row_item_reference_get(row)); }; - auto row_selection_count_get = [&]() { return document.items.references.size() + groupReferences.size(); }; + auto row_selection_count_get = [&]() { return document.items.references.size() + document.groupReferences.size(); }; auto row_selection_set = [&](const TimelineItemRow& row) { @@ -1060,13 +1067,13 @@ namespace anm2ed::imgui } } reference_clear_for(document); - group_selection_reset(); + group_selection_reset_for(document); }); }; auto item_references_groupable_get = [&]() { - if (!groupReferences.empty()) return std::vector{}; + if (!document.groupReferences.empty()) return std::vector{}; auto selectedItems = item_references_for_current_get(); std::erase_if(selectedItems, [](const Reference& itemReference) { return itemReference.itemType != LAYER && itemReference.itemType != NULL_; }); @@ -1139,7 +1146,7 @@ namespace anm2ed::imgui }; auto rows_move_to_row = [&](std::vector draggedRows, TimelineItemRow targetRow, - bool isDropAfter) + bool isDropAfter, bool isDropIntoGroup = false) { if (draggedRows.empty()) return; auto targetType = draggedRows.front().type; @@ -1224,7 +1231,7 @@ namespace anm2ed::imgui } auto targetGroupId = -1; - if (targetRow.isGroup && isDropAfter) + if (targetRow.isGroup && isDropIntoGroup) targetGroupId = targetRow.id; else if (targetRow.type == targetType) targetGroupId = targetRow.groupId; @@ -1239,12 +1246,12 @@ namespace anm2ed::imgui movedItems.end()); document.items.references.clear(); - groupReferences.clear(); + document.groupReferences.clear(); for (const auto& draggedRow : draggedRows) { if (draggedRow.isGroup) - groupReferences.insert({draggedRow.documentIndex, draggedRow.animationIndex, - draggedRow.type, draggedRow.id}); + document.groupReferences.insert( + {draggedRow.animationIndex, draggedRow.type, draggedRow.id}); else document.items.references.insert(row_item_reference_get(draggedRow)); } @@ -1334,7 +1341,18 @@ namespace anm2ed::imgui auto start = targetReference.itemType == TRIGGER ? targetHoveredTime : insertIndex; if (frames_deserialize(*item, clipboardString, start, indices, &errorString)) { - if (targetReference.itemType == LAYER && targetReference.itemID != -1) + if (targetReference.itemType != LAYER) + { + for (auto i : indices) + if (auto frame = track_frame_get(*item, i); frame) + { + frame->regionId = -1; + frame->crop = {}; + frame->size = {}; + frame->pivot = {}; + } + } + else if (targetReference.itemID != -1) { auto layer = command_layer_get(document, targetReference.itemID); auto spritesheet = @@ -1693,11 +1711,17 @@ namespace anm2ed::imgui "Timeline Row Drag Drop", ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect)) { - auto isDropAfter = is_drop_after(groupButtonMin, groupButtonMax); + auto groupDropThird = (groupButtonMax.y - groupButtonMin.y) / 3.0f; + auto dropZone = DropZone::BEFORE; + if (mousePos.y >= groupButtonMax.y - groupDropThird) + dropZone = DropZone::AFTER; + else if (mousePos.y >= groupButtonMin.y + groupDropThird) + dropZone = DropZone::INSIDE; + auto isDropAfter = dropZone != DropZone::BEFORE; auto payloadRows = (TimelineRowReference*)payload->Data; auto payloadCount = payload->DataSize / sizeof(TimelineRowReference); std::vector draggedRows(payloadRows, payloadRows + payloadCount); - auto isDropIntoGroup = isDropAfter && (row.type == LAYER || row.type == NULL_); + auto isDropIntoGroup = dropZone == DropZone::INSIDE && (row.type == LAYER || row.type == NULL_); for (auto draggedRow : draggedRows) if (draggedRow.isGroup || draggedRow.type != row.type) isDropIntoGroup = false; @@ -1706,7 +1730,7 @@ namespace anm2ed::imgui else drop_line_draw(ImGui::GetWindowDrawList(), groupChildMin, groupChildMax, isDropAfter); - if (payload->IsDelivery()) rows_move_to_row(draggedRows, row, isDropAfter); + if (payload->IsDelivery()) rows_move_to_row(draggedRows, row, isDropAfter, isDropIntoGroup); } ImGui::EndDragDropTarget(); } @@ -2985,7 +3009,7 @@ namespace anm2ed::imgui isFrameBoxClipSet = false; if (animation && ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_A, ImGuiInputFlags_RouteFocused)) { - group_selection_reset(); + group_selection_reset_for(document); document.frames.references = all_frame_references_for_items_get(); if (!document.frames.references.empty()) { @@ -3099,7 +3123,7 @@ namespace anm2ed::imgui { if (isFrameBoxSelecting) { - group_selection_reset(); + group_selection_reset_for(document); if (isFrameBoxAdditive) document.frames.references.insert(frameBoxSelection.begin(), frameBoxSelection.end()); else @@ -3288,7 +3312,7 @@ namespace anm2ed::imgui ImGui::PopStyleVar(); ImGui::End(); - if (itemProperties.update(manager, settings, document, reference)) group_selection_reset(); + if (itemProperties.update(manager, settings, document, reference)) group_selection_reset_for(document); group_properties_update(); bakePopup.trigger(); diff --git a/src/imgui/window/timeline.hpp b/src/imgui/window/timeline.hpp index 2a55539..d817349 100644 --- a/src/imgui/window/timeline.hpp +++ b/src/imgui/window/timeline.hpp @@ -14,16 +14,6 @@ namespace anm2ed::imgui { - struct TimelineGroupReference - { - int documentIndex{-1}; - int animationIndex{-1}; - int type{NONE}; - int id{-1}; - - auto operator<=>(const TimelineGroupReference&) const = default; - }; - struct TimelineRowReference { int documentIndex{-1}; @@ -62,7 +52,6 @@ namespace anm2ed::imgui ImVec2 frameBoxStart{}; ImVec2 frameBoxEnd{}; std::set frameBoxSelection{}; - std::set groupReferences{}; TimelineRowReference rowSelectionAnchor{}; bool isRowSelectionAnchorSet{}; PopupHelper groupPropertiesPopup{PopupHelper(LABEL_GROUP_PROPERTIES, POPUP_SMALL_NO_HEIGHT)}; diff --git a/src/imgui/window/window.cpp b/src/imgui/window/window.cpp index e91f518..10a77bf 100644 --- a/src/imgui/window/window.cpp +++ b/src/imgui/window/window.cpp @@ -2721,7 +2721,6 @@ namespace anm2ed::imgui } else { - ImGui::Text("%s", localize.get(TEXT_SOUND_PLAY)); ImGui::Text("%s", localize.get(TEXT_OPEN_DIRECTORY)); } ImGui::EndTooltip(); diff --git a/src/manager.cpp b/src/manager.cpp index 0456a10..142b94b 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -187,10 +187,6 @@ namespace anm2ed { if (!vector::in_bounds(documents, index)) return; - const auto autosavePath = documents[index].autosave_path_get(); - autosaveFiles.erase(std::remove(autosaveFiles.begin(), autosaveFiles.end(), autosavePath), autosaveFiles.end()); - autosave_files_write(); - documents.erase(documents.begin() + index); selection_history_cleanup(index); @@ -390,8 +386,6 @@ namespace anm2ed void Manager::autosave_files_open() { - std::vector restoredFiles{}; - for (auto& path : autosaveFiles) { if (auto document = open(path, false, false)) @@ -399,16 +393,8 @@ namespace anm2ed document->isForceDirty = true; document->path = document->path_from_autosave_get(path); document->change(Document::ALL); - restoredFiles.emplace_back(path); } } - - for (auto& path : restoredFiles) - { - autosaveFiles.erase(std::remove(autosaveFiles.begin(), autosaveFiles.end(), path), autosaveFiles.end()); - autosave_file_remove(path); - } - autosave_files_write(); } void Manager::autosave_files_load() diff --git a/src/snapshots.cpp b/src/snapshots.cpp index c8e0fb7..3c4e483 100644 --- a/src/snapshots.cpp +++ b/src/snapshots.cpp @@ -23,8 +23,10 @@ namespace anm2ed out.sound = sound; out.spritesheet = spritesheet; out.textures = textures; + out.sounds = sounds; out.anm2 = anm2; out.reference = reference; + out.groupReferences = groupReferences; out.frameTime = frameTime; out.message = message; return out; diff --git a/src/snapshots.hpp b/src/snapshots.hpp index 3f4f2df..5b9202c 100644 --- a/src/snapshots.hpp +++ b/src/snapshots.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "anm2/anm2.hpp" #include "audio.hpp" @@ -36,6 +37,7 @@ namespace anm2ed std::map sounds{}; Anm2 anm2{}; Reference reference{}; + std::set groupReferences{}; float frameTime{}; std::string message = snapshots::ACTION;