#include "document.h" #include #include "log.h" #include "toast.h" using namespace anm2ed::anm2; using namespace anm2ed::imgui; using namespace anm2ed::types; using namespace glm; namespace anm2ed { Document::Document(Anm2& anm2, const std::string& path) { this->anm2 = std::move(anm2); this->path = path; clean(); change(Document::ALL); } Document::Document(const std::string& path, bool isNew, std::string* errorString) { if (isNew) { anm2 = anm2::Anm2(); if (!save(path)) return; } else { anm2 = Anm2(path, errorString); if (errorString && !errorString->empty()) return; } this->path = path; clean(); change(Document::ALL); } Document::Document(Document&& other) noexcept : path(std::move(other.path)), snapshots(std::move(other.snapshots)), current(snapshots.current), anm2(current.anm2), reference(current.reference), playback(current.playback), animation(current.animation), merge(current.merge), event(current.event), layer(current.layer), null(current.null), sound(current.sound), spritesheet(current.spritesheet), frames(current.frames), message(current.message), previewZoom(other.previewZoom), previewPan(other.previewPan), editorPan(other.editorPan), editorZoom(other.editorZoom), overlayIndex(other.overlayIndex), hash(other.hash), saveHash(other.saveHash), autosaveHash(other.autosaveHash), lastAutosaveTime(other.lastAutosaveTime), isOpen(other.isOpen), isForceDirty(other.isForceDirty), isAnimationPreviewSet(other.isAnimationPreviewSet), isSpritesheetEditorSet(other.isSpritesheetEditorSet) { } Document& Document::operator=(Document&& other) noexcept { if (this != &other) { path = std::move(other.path); snapshots = std::move(other.snapshots); previewZoom = other.previewZoom; previewPan = other.previewPan; editorPan = other.editorPan; editorZoom = other.editorZoom; overlayIndex = other.overlayIndex; hash = other.hash; saveHash = other.saveHash; autosaveHash = other.autosaveHash; lastAutosaveTime = other.lastAutosaveTime; isOpen = other.isOpen; isForceDirty = other.isForceDirty; isAnimationPreviewSet = other.isAnimationPreviewSet; isSpritesheetEditorSet = other.isSpritesheetEditorSet; } return *this; } bool Document::save(const std::string& path, std::string* errorString) { this->path = !path.empty() ? path : this->path.string(); if (anm2.serialize(this->path.string(), errorString)) { toasts.info(std::format("Saved document to: {}", this->path.string())); clean(); return true; } else if (errorString) toasts.warning(std::format("Could not save document to: {} ({})", this->path.string(), *errorString)); return false; } std::filesystem::path Document::autosave_path_get() { return directory_get() / std::string("." + filename_get().string() + ".autosave"); } std::filesystem::path Document::path_from_autosave_get(std::filesystem::path& path) { auto fileName = path.filename().string(); if (!fileName.empty() && fileName.front() == '.') fileName.erase(fileName.begin()); auto restorePath = path.parent_path() / fileName; restorePath.replace_extension(""); return path; } bool Document::autosave(std::string* errorString) { auto autosavePath = autosave_path_get(); if (anm2.serialize(autosavePath.string(), errorString)) { autosaveHash = hash; lastAutosaveTime = 0.0f; toasts.info("Autosaving..."); logger.info(std::format("Autosaved document to: {}", autosavePath.string())); return true; } else if (errorString) toasts.warning(std::format("Could not autosave document to: {} ({})", autosavePath.string(), *errorString)); return false; } void Document::hash_set() { hash = anm2.hash(); } void Document::clean() { saveHash = anm2.hash(); hash = saveHash; lastAutosaveTime = 0.0f; isForceDirty = false; } void Document::change(ChangeType type) { hash_set(); auto layers_set = [&]() { layer.unused = anm2.layers_unused(); }; auto nulls_set = [&]() { null.unused = anm2.nulls_unused(); }; auto events_set = [&]() { event.unused = anm2.events_unused(); event.labels_set(anm2.event_labels_get()); }; auto animations_set = [&]() { animation.labels_set(anm2.animation_labels_get()); }; auto spritesheets_set = [&]() { spritesheet.unused = anm2.spritesheets_unused(); spritesheet.labels_set(anm2.spritesheet_labels_get()); }; auto sounds_set = [&]() { sound.unused = anm2.sounds_unused(); sound.labels_set(anm2.sound_labels_get()); for (auto& animation : anm2.animations.items) for (auto& trigger : animation.triggers.frames) if (!anm2.content.sounds.contains(trigger.soundID)) trigger.soundID = -1; }; switch (type) { case LAYERS: layers_set(); break; case NULLS: nulls_set(); break; case EVENTS: events_set(); break; case SPRITESHEETS: spritesheets_set(); break; case SOUNDS: sounds_set(); break; case ANIMATIONS: animations_set(); break; case FRAMES: events_set(); sounds_set(); break; case ALL: layers_set(); nulls_set(); events_set(); spritesheets_set(); animations_set(); sounds_set(); break; default: break; } } bool Document::is_dirty() const { return hash != saveHash; } bool Document::is_autosave_dirty() const { return hash != autosaveHash; } std::filesystem::path Document::directory_get() const { return path.parent_path(); } std::filesystem::path Document::filename_get() const { return path.filename(); } bool Document::is_valid() const { return !path.empty(); } anm2::Frame* Document::frame_get() { return anm2.frame_get(reference.animationIndex, reference.itemType, reference.frameIndex, reference.itemID); } anm2::Item* Document::item_get() { return anm2.item_get(reference.animationIndex, reference.itemType, reference.itemID); } anm2::Animation* Document::animation_get() { return anm2.animation_get(reference.animationIndex); } anm2::Spritesheet* Document::spritesheet_get() { return anm2.spritesheet_get(spritesheet.reference); } void Document::spritesheet_add(const std::string& path) { auto add = [&]() { int id{}; if (anm2.spritesheet_add(directory_get().string(), path, id)) { 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 toasts.error(std::format("Failed to initialize spritesheet: {}", path)); }; DOCUMENT_EDIT_PTR(this, "Add Spritesheet", Document::SPRITESHEETS, add()); } void Document::snapshot(const std::string& message) { this->message = message; snapshots.push(current); } void Document::undo() { snapshots.undo(); toasts.info(std::format("Undo: {}", message)); change(Document::ALL); } void Document::redo() { snapshots.redo(); toasts.info(std::format("Redo: {}", message)); change(Document::ALL); } bool Document::is_able_to_undo() { return !snapshots.undoStack.is_empty(); } bool Document::is_able_to_redo() { return !snapshots.redoStack.is_empty(); } }