#include "manager.h" #include #include "filesystem_.h" #include "log.h" #include "toast.h" #include "vector_.h" using namespace anm2ed::types; using namespace anm2ed::util; namespace anm2ed { constexpr std::size_t RECENT_LIMIT = 10; std::filesystem::path Manager::recent_files_path_get() { return filesystem::path_preferences_get() + "recent.txt"; } std::filesystem::path Manager::autosave_path_get() { return filesystem::path_preferences_get() + "autosave.txt"; } std::filesystem::path Manager::autosave_directory_get() { return filesystem::path_preferences_get() + "autosave"; } Manager::Manager() { recent_files_load(); autosave_files_load(); } Document* Manager::get(int index) { return vector::find(documents, index > -1 ? index : selected); } void Manager::open(const std::string& path, bool isNew, bool isRecent) { std::string errorString{}; documents.emplace_back(path, isNew, &errorString); auto& document = documents.back(); if (!document.is_valid()) { documents.pop_back(); toasts.error(std::format("Failed to open document: {} ({})", path, errorString)); return; } if (isRecent) recent_file_add(path); selected = (int)documents.size() - 1; pendingSelected = selected; toasts.info(std::format("Opened document: {}", path)); } void Manager::new_(const std::string& path) { open(path, true); } void Manager::save(int index, const std::string& path) { if (auto document = get(index); document) { std::string errorString{}; document->path = !path.empty() ? path : document->path.string(); document->save(document->path, &errorString); recent_file_add(document->path); } } void Manager::save(const std::string& path) { save(selected, path); } void Manager::autosave(Document& document) { std::string errorString{}; auto autosavePath = document.autosave_path_get(); document.autosave(&errorString); autosaveFiles.erase(std::remove(autosaveFiles.begin(), autosaveFiles.end(), autosavePath), autosaveFiles.end()); autosaveFiles.insert(autosaveFiles.begin(), autosavePath); autosave_files_write(); } void Manager::close(int index) { if (!vector::in_bounds(documents, index)) return; autosaveFiles.erase(std::remove(autosaveFiles.begin(), autosaveFiles.end(), get()->autosave_path_get()), autosaveFiles.end()); autosave_files_write(); documents.erase(documents.begin() + index); if (documents.empty()) { selected = -1; pendingSelected = -1; return; } if (selected >= index) selected = std::max(0, selected - 1); selected = std::clamp(selected, 0, (int)documents.size() - 1); pendingSelected = selected; if (selected >= 0 && selected < (int)documents.size()) documents[selected].change(Document::ALL); } void Manager::set(int index) { if (documents.empty()) { selected = -1; pendingSelected = -1; return; } index = std::clamp(index, 0, (int)documents.size() - 1); selected = index; if (auto document = get()) document->change(Document::ALL); } void Manager::layer_properties_open(int id) { if (auto document = get(); document) { if (id == -1) editLayer = anm2::Layer(); else editLayer = document->anm2.content.layers.at(id); document->layer.reference = id; layerPropertiesPopup.open(); } } void Manager::layer_properties_trigger() { layerPropertiesPopup.trigger(); } void Manager::layer_properties_end() { layerPropertiesPopup.end(); } void Manager::layer_properties_close() { editLayer = anm2::Layer(); layerPropertiesPopup.close(); } void Manager::null_properties_open(int id) { if (auto document = get(); document) { if (id == -1) editNull = anm2::Null(); else editNull = document->anm2.content.nulls.at(id); document->null.reference = id; nullPropertiesPopup.open(); } } void Manager::null_properties_trigger() { nullPropertiesPopup.trigger(); } void Manager::null_properties_end() { nullPropertiesPopup.end(); } void Manager::null_properties_close() { editNull = anm2::Null(); nullPropertiesPopup.close(); } void Manager::recent_file_add(const std::string& path) { if (path.empty()) return; std::error_code ec{}; if (!std::filesystem::exists(path, ec)) { logger.warning(std::format("Skipping missing recent file: {}", path)); return; } recentFiles.erase(std::remove(recentFiles.begin(), recentFiles.end(), path), recentFiles.end()); recentFiles.insert(recentFiles.begin(), path); if (recentFiles.size() > RECENT_LIMIT) recentFiles.resize(RECENT_LIMIT); recent_files_write(); } void Manager::recent_files_load() { auto path = recent_files_path_get(); std::ifstream file(path); if (!file) { logger.warning(std::format("Could not load recent files from: {}. Skipping...", path.string())); return; } logger.info(std::format("Loading recent files from: {}", path.string())); std::string line{}; while (std::getline(file, line)) { if (line.empty()) continue; if (std::find(recentFiles.begin(), recentFiles.end(), line) != recentFiles.end()) continue; std::error_code ec{}; if (!std::filesystem::exists(line, ec)) { logger.warning(std::format("Skipping missing recent file: {}", line)); continue; } recentFiles.emplace_back(line); } } void Manager::recent_files_write() { auto path = recent_files_path_get(); std::ofstream file; file.open(path, std::ofstream::out | std::ofstream::trunc); if (!file.is_open()) { logger.warning(std::format("Could not write recent files to: {}. Skipping...", path.string())); return; } for (auto& path : recentFiles) file << path.string() << '\n'; } void Manager::recent_files_clear() { recentFiles.clear(); recent_files_write(); } void Manager::autosave_files_open() { for (auto& path : autosaveFiles) { auto fileName = path.filename().string(); if (!fileName.empty() && fileName.front() == '.') fileName.erase(fileName.begin()); auto restorePath = path.parent_path() / fileName; restorePath.replace_extension(""); open(path.string(), false, false); if (auto document = get()) { document->isForceDirty = true; document->path = restorePath; document->change(Document::ALL); } } autosave_files_clear(); } void Manager::autosave_files_load() { auto path = autosave_path_get(); std::ifstream file(path); if (!file) { logger.warning(std::format("Could not load autosave files from: {}. Skipping...", path.string())); return; } logger.info(std::format("Loading autosave files from: {}", path.string())); std::string line{}; while (std::getline(file, line)) { if (line.empty()) continue; if (std::find(autosaveFiles.begin(), autosaveFiles.end(), line) != autosaveFiles.end()) continue; autosaveFiles.emplace_back(line); } } void Manager::autosave_files_write() { std::ofstream autosaveWriteFile; autosaveWriteFile.open(autosave_path_get(), std::ofstream::out | std::ofstream::trunc); for (auto& path : autosaveFiles) autosaveWriteFile << path.string() << "\n"; autosaveWriteFile.close(); } void Manager::autosave_files_clear() { for (auto& path : autosaveFiles) std::filesystem::remove(path); autosaveFiles.clear(); autosave_files_write(); } void Manager::chords_set(Settings& settings) { for (int i = 0; i < SHORTCUT_COUNT; i++) chords[i] = imgui::string_to_chord(settings.*SHORTCUT_MEMBERS[i]); } Manager::~Manager() { autosave_files_clear(); } }