#include "documents.hpp" #include #include #include "path_.hpp" #include "strings.hpp" #include "time_.hpp" #include "toast.hpp" #include "log.hpp" using namespace anm2ed::resource; using namespace anm2ed::types; using namespace anm2ed::util; namespace anm2ed::imgui { void Documents::update(Taskbar& taskbar, Manager& manager, Settings& settings, Resources& resources, bool& isQuitting) { auto viewport = ImGui::GetMainViewport(); auto windowHeight = ImGui::GetFrameHeightWithSpacing(); bool isLightTheme = settings.theme == theme::LIGHT; bool pushedStyle = false; ImGui::SetNextWindowViewport(viewport->ID); ImGui::SetNextWindowPos(ImVec2(viewport->Pos.x, viewport->Pos.y + taskbar.height)); ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, windowHeight)); if (isLightTheme) { ImGui::PushStyleColor(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_TitleBgActive)); pushedStyle = true; } for (auto& document : manager.documents) { auto isDirty = document.is_dirty() && document.is_autosave_dirty(); if (isDirty) { document.lastAutosaveTime += ImGui::GetIO().DeltaTime; if (document.lastAutosaveTime > time::SECOND_M) manager.autosave(document, (anm2::Compatibility)settings.fileCompatibility, settings.fileBakeSpecialInterpolatedFramesOnSave, settings.bakeIsRoundScale, settings.bakeIsRoundRotation); } } if (ImGui::Begin("##Documents", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) { height = ImGui::GetWindowSize().y; if (ImGui::BeginTabBar("##Documents Bar", ImGuiTabBarFlags_Reorderable)) { auto documentsCount = (int)manager.documents.size(); bool isCloseShortcut = shortcut(manager.chords[SHORTCUT_CLOSE], shortcut::GLOBAL) && !closePopup.is_open(); int closeShortcutIndex = isCloseShortcut && manager.selected >= 0 && manager.selected < documentsCount ? manager.selected : -1; std::vector closeIndices{}; closeIndices.reserve(documentsCount); for (int i = 0; i < documentsCount; ++i) { auto& document = manager.documents[i]; auto isDocumentDirty = document.is_dirty() || document.isForceDirty; auto isSpritesheetDirty = document.spritesheet_any_dirty(); auto isDirty = isDocumentDirty || isSpritesheetDirty; if (!closePopup.is_open()) { if (isQuitting) document.isOpen = false; else if (i == closeShortcutIndex) document.isOpen = false; } if (!closePopup.is_open() && !document.isOpen) { if (isDirty) { closePopup.open(); closeDocumentIndex = i; document.isOpen = true; } else { closeIndices.push_back(i); continue; } } auto isRequested = i == manager.pendingSelected; auto font = isDocumentDirty ? font::ITALICS : font::REGULAR; auto filename = path::to_utf8(document.filename_get()); auto string = isDocumentDirty ? std::vformat(localize.get(FORMAT_NOT_SAVED), std::make_format_args(filename)) : filename; auto label = std::format("{}###Document{}", string, i); auto flags = isDocumentDirty ? ImGuiTabItemFlags_UnsavedDocument : 0; if (isRequested) flags |= ImGuiTabItemFlags_SetSelected; ImGui::PushFont(resources.fonts[font].get(), font::SIZE); if (ImGui::BeginTabItem(label.c_str(), &document.isOpen, flags)) { if (manager.selected != i) manager.set(i); if (isRequested) manager.pendingSelected = -1; ImGui::EndTabItem(); } auto pathUtf8 = path::to_utf8(document.path); ImGui::SetItemTooltip("%s", pathUtf8.c_str()); ImGui::PopFont(); } for (auto it = closeIndices.rbegin(); it != closeIndices.rend(); ++it) { if (closePopup.is_open() && closeDocumentIndex > *it) --closeDocumentIndex; manager.close(*it); } ImGui::EndTabBar(); } closePopup.trigger(); if (ImGui::BeginPopupModal(closePopup.label(), &closePopup.isOpen, ImGuiWindowFlags_NoResize)) { if (closeDocumentIndex >= 0 && closeDocumentIndex < (int)manager.documents.size()) { auto& closeDocument = manager.documents[closeDocumentIndex]; auto filename = path::to_utf8(closeDocument.filename_get()); auto isDocumentDirty = closeDocument.is_dirty() || closeDocument.isForceDirty; auto isSpritesheetDirty = closeDocument.spritesheet_any_dirty(); auto promptLabel = isDocumentDirty && isSpritesheetDirty ? LABEL_DOCUMENT_AND_SPRITESHEETS_MODIFIED_PROMPT : (isDocumentDirty ? LABEL_DOCUMENT_MODIFIED_PROMPT : LABEL_SPRITESHEETS_MODIFIED_PROMPT); auto prompt = std::vformat(localize.get(promptLabel), std::make_format_args(filename)); ImGui::TextUnformatted(prompt.c_str()); auto widgetSize = imgui::widget_size_with_row_get(3); auto close = [&]() { closeDocumentIndex = -1; closePopup.close(); }; shortcut(manager.chords[SHORTCUT_CONFIRM]); if (ImGui::Button(localize.get(BASIC_YES), widgetSize)) { if (isDocumentDirty) manager.save(closeDocumentIndex, {}, (anm2::Compatibility)settings.fileCompatibility, settings.fileBakeSpecialInterpolatedFramesOnSave, settings.bakeIsRoundScale, settings.bakeIsRoundRotation); if (isSpritesheetDirty) { for (auto& [id, spritesheet] : closeDocument.anm2.content.spritesheets) { if (!closeDocument.spritesheet_is_dirty(id)) continue; auto pathString = path::to_utf8(spritesheet.path); if (spritesheet.save(closeDocument.directory_get())) { closeDocument.spritesheet_hash_set_saved(id); toasts.push(std::vformat(localize.get(TOAST_SAVE_SPRITESHEET), std::make_format_args(id, pathString))); logger.info(std::vformat(localize.get(TOAST_SAVE_SPRITESHEET, anm2ed::ENGLISH), std::make_format_args(id, pathString))); } else { toasts.push( std::vformat(localize.get(TOAST_SAVE_SPRITESHEET_FAILED), std::make_format_args(id, pathString))); logger.error(std::vformat(localize.get(TOAST_SAVE_SPRITESHEET_FAILED, anm2ed::ENGLISH), std::make_format_args(id, pathString))); } } } manager.close(closeDocumentIndex); close(); } ImGui::SameLine(); if (ImGui::Button(localize.get(BASIC_NO), widgetSize)) { manager.close(closeDocumentIndex); close(); } ImGui::SameLine(); shortcut(manager.chords[SHORTCUT_CANCEL]); if (ImGui::Button(localize.get(BASIC_CANCEL), widgetSize)) { isQuitting = false; close(); } } else { closeDocumentIndex = -1; closePopup.close(); } ImGui::EndPopup(); } } ImGui::End(); if (pushedStyle) ImGui::PopStyleColor(); if (manager.isAnm2DragDrop) { auto drag_drop_reset = [&]() { manager.isAnm2DragDrop = false; manager.anm2DragDropPaths.clear(); manager.anm2DragDropPopup.close(); }; if (manager.anm2DragDropPaths.empty()) drag_drop_reset(); else { if (!manager.anm2DragDropPopup.is_open()) manager.anm2DragDropPopup.open(); manager.anm2DragDropPopup.trigger(); if (ImGui::BeginPopupContextWindow(manager.anm2DragDropPopup.label(), ImGuiPopupFlags_None)) { auto document = manager.get(); if (ImGui::MenuItem(manager.anm2DragDropPaths.size() > 1 ? localize.get(LABEL_DOCUMENTS_OPEN_MANY) : localize.get(LABEL_DOCUMENTS_OPEN_NEW))) { for (auto& path : manager.anm2DragDropPaths) manager.open(path); drag_drop_reset(); } if (ImGui::MenuItem(localize.get(LABEL_DOCUMENTS_MERGE_INTO_CURRENT), nullptr, false, document && !manager.anm2DragDropPaths.empty())) { if (document) { auto merge_anm2s = [&]() { for (auto& path : manager.anm2DragDropPaths) { anm2::Anm2 source(path); document->anm2.merge(source, document->directory_get(), path.parent_path()); } }; DOCUMENT_EDIT_PTR(document, localize.get(EDIT_MERGE_ANM2), Document::ALL, merge_anm2s()); drag_drop_reset(); } } ImGui::Separator(); if (ImGui::MenuItem(localize.get(BASIC_CANCEL))) drag_drop_reset(); manager.anm2DragDropPopup.end(); ImGui::EndPopup(); } else if (!ImGui::IsPopupOpen(manager.anm2DragDropPopup.label())) drag_drop_reset(); } } } }