managed autosave deletion
This commit is contained in:
@@ -271,6 +271,8 @@ namespace anm2ed::imgui
|
|||||||
bool isValid = spritesheet->is_valid();
|
bool isValid = spritesheet->is_valid();
|
||||||
auto& texture = isValid ? spritesheet->texture : resources.icons[icon::NONE];
|
auto& texture = isValid ? spritesheet->texture : resources.icons[icon::NONE];
|
||||||
auto tintColor = !isValid ? ImVec4(1.0f, 0.25f, 0.25f, 1.0f) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
auto tintColor = !isValid ? ImVec4(1.0f, 0.25f, 0.25f, 1.0f) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
static std::vector<int> dragDropSelection{};
|
||||||
|
bool isRegionDragDropSourceSubmitted = false;
|
||||||
|
|
||||||
for (int i = 0; i < (int)spritesheet->regionOrder.size(); i++)
|
for (int i = 0; i < (int)spritesheet->regionOrder.size(); i++)
|
||||||
{
|
{
|
||||||
@@ -324,17 +326,19 @@ namespace anm2ed::imgui
|
|||||||
auto tooltipPadding = style.WindowPadding.x * 4.0f;
|
auto tooltipPadding = style.WindowPadding.x * 4.0f;
|
||||||
auto minWidth = previewSize.x + style.ItemSpacing.x + textWidth + tooltipPadding;
|
auto minWidth = previewSize.x + style.ItemSpacing.x + textWidth + tooltipPadding;
|
||||||
|
|
||||||
ImGui::SetNextWindowSize(ImVec2(minWidth, 0), ImGuiCond_Appearing);
|
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing);
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing);
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.WindowPadding);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.WindowPadding);
|
||||||
|
if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip) && !ImGui::IsMouseDragging(ImGuiMouseButton_Left))
|
||||||
|
{
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(minWidth, 0), ImGuiCond_Appearing);
|
||||||
if (ImGui::BeginItemTooltip())
|
if (ImGui::BeginItemTooltip())
|
||||||
{
|
{
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2());
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2());
|
||||||
auto childFlags = ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY;
|
auto childFlags = ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY;
|
||||||
auto noScrollFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
|
auto noScrollFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
|
||||||
|
|
||||||
if (ImGui::BeginChild("##Region Tooltip Image Child", to_imvec2(previewSize), childFlags, noScrollFlags))
|
if (ImGui::BeginChild("##Region Tooltip Image Child", to_imvec2(previewSize), childFlags,
|
||||||
|
noScrollFlags))
|
||||||
ImGui::ImageWithBg(texture.id, to_imvec2(previewSize), to_imvec2(uvMin), to_imvec2(uvMax), ImVec4(),
|
ImGui::ImageWithBg(texture.id, to_imvec2(previewSize), to_imvec2(uvMin), to_imvec2(uvMax), ImVec4(),
|
||||||
tintColor);
|
tintColor);
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
@@ -365,7 +369,8 @@ namespace anm2ed::imgui
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
StringType originString = LABEL_REGION_ORIGIN_CENTER;
|
StringType originString = LABEL_REGION_ORIGIN_CENTER;
|
||||||
if (region.origin == anm2::Spritesheet::Region::TOP_LEFT) originString = LABEL_REGION_ORIGIN_TOP_LEFT;
|
if (region.origin == anm2::Spritesheet::Region::TOP_LEFT)
|
||||||
|
originString = LABEL_REGION_ORIGIN_TOP_LEFT;
|
||||||
auto originLabel = localize.get(originString);
|
auto originLabel = localize.get(originString);
|
||||||
ImGui::TextUnformatted(
|
ImGui::TextUnformatted(
|
||||||
std::vformat(localize.get(FORMAT_ORIGIN), std::make_format_args(originLabel)).c_str());
|
std::vformat(localize.get(FORMAT_ORIGIN), std::make_format_args(originLabel)).c_str());
|
||||||
@@ -374,28 +379,22 @@ namespace anm2ed::imgui
|
|||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
ImGui::EndTooltip();
|
ImGui::EndTooltip();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ImGui::PopStyleVar(2);
|
ImGui::PopStyleVar(2);
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.WindowPadding);
|
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceNoPreviewTooltip))
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing);
|
|
||||||
if (ImGui::BeginDragDropSource())
|
|
||||||
{
|
{
|
||||||
static std::vector<int> dragDropSelection{};
|
isRegionDragDropSourceSubmitted = true;
|
||||||
|
if (selection.contains(id))
|
||||||
dragDropSelection.assign(selection.begin(), selection.end());
|
dragDropSelection.assign(selection.begin(), selection.end());
|
||||||
|
else
|
||||||
|
dragDropSelection = {id};
|
||||||
|
|
||||||
ImGui::SetDragDropPayload("Region Drag Drop", dragDropSelection.data(),
|
ImGui::SetDragDropPayload("Region Drag Drop", dragDropSelection.data(),
|
||||||
dragDropSelection.size() * sizeof(int));
|
dragDropSelection.size() * sizeof(int));
|
||||||
|
|
||||||
for (auto regionId : dragDropSelection)
|
|
||||||
{
|
|
||||||
auto dragIt = spritesheet->regions.find(regionId);
|
|
||||||
if (dragIt == spritesheet->regions.end()) continue;
|
|
||||||
ImGui::TextUnformatted(dragIt->second.name.c_str());
|
|
||||||
}
|
|
||||||
ImGui::EndDragDropSource();
|
ImGui::EndDragDropSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PopStyleVar(2);
|
|
||||||
|
|
||||||
if (ImGui::BeginDragDropTarget())
|
if (ImGui::BeginDragDropTarget())
|
||||||
{
|
{
|
||||||
if (auto payload = ImGui::AcceptDragDropPayload("Region Drag Drop"))
|
if (auto payload = ImGui::AcceptDragDropPayload("Region Drag Drop"))
|
||||||
@@ -450,6 +449,36 @@ namespace anm2ed::imgui
|
|||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto regionDragPayload = ImGui::GetDragDropPayload();
|
||||||
|
bool isRegionDragActive = regionDragPayload && regionDragPayload->IsDataType("Region Drag Drop");
|
||||||
|
if (isRegionDragActive && !isRegionDragDropSourceSubmitted && !dragDropSelection.empty() &&
|
||||||
|
ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceExtern | ImGuiDragDropFlags_SourceNoPreviewTooltip))
|
||||||
|
{
|
||||||
|
ImGui::SetDragDropPayload("Region Drag Drop", dragDropSelection.data(),
|
||||||
|
dragDropSelection.size() * sizeof(int));
|
||||||
|
ImGui::EndDragDropSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRegionDragActive && !dragDropSelection.empty())
|
||||||
|
{
|
||||||
|
auto mousePos = ImGui::GetIO().MousePos;
|
||||||
|
auto tooltipOffset = ImVec2(16.0f, 16.0f);
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(mousePos.x + tooltipOffset.x, mousePos.y + tooltipOffset.y));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.WindowPadding);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing);
|
||||||
|
if (ImGui::BeginTooltip())
|
||||||
|
{
|
||||||
|
for (auto regionId : dragDropSelection)
|
||||||
|
{
|
||||||
|
auto dragIt = spritesheet->regions.find(regionId);
|
||||||
|
if (dragIt == spritesheet->regions.end()) continue;
|
||||||
|
ImGui::TextUnformatted(dragIt->second.name.c_str());
|
||||||
|
}
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar(2);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
selection.finish();
|
selection.finish();
|
||||||
|
|
||||||
|
|||||||
@@ -1174,6 +1174,10 @@ namespace anm2ed::imgui
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
float playheadLineCenterX{};
|
||||||
|
float playheadLineTopY{};
|
||||||
|
bool isPlayheadLineSet{};
|
||||||
|
|
||||||
auto frame_child = [&](anm2::Type type, int id, int& index, float width)
|
auto frame_child = [&](anm2::Type type, int id, int& index, float width)
|
||||||
{
|
{
|
||||||
auto item = animation ? animation->item_get(type, id) : nullptr;
|
auto item = animation ? animation->item_get(type, id) : nullptr;
|
||||||
@@ -1307,6 +1311,11 @@ namespace anm2ed::imgui
|
|||||||
{
|
{
|
||||||
ImGui::SetCursorPos(ImVec2(cursorPos.x + frameSize.x * floorf(playback.time), cursorPos.y));
|
ImGui::SetCursorPos(ImVec2(cursorPos.x + frameSize.x * floorf(playback.time), cursorPos.y));
|
||||||
ImGui::Image(resources.icons[icon::PLAYHEAD].id, frameSize);
|
ImGui::Image(resources.icons[icon::PLAYHEAD].id, frameSize);
|
||||||
|
auto playheadMin = ImGui::GetItemRectMin();
|
||||||
|
auto playheadMax = ImGui::GetItemRectMax();
|
||||||
|
playheadLineCenterX = (playheadMin.x + playheadMax.x) * 0.5f;
|
||||||
|
playheadLineTopY = playheadMax.y;
|
||||||
|
isPlayheadLineSet = true;
|
||||||
overlay_icon(resources.icons[icon::PLAYHEAD].id, playheadIconTint, true);
|
overlay_icon(resources.icons[icon::PLAYHEAD].id, playheadIconTint, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1686,7 +1695,9 @@ namespace anm2ed::imgui
|
|||||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2());
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2());
|
||||||
if (ImGui::BeginChild("##Frames List Child", viewListChildSize, true, ImGuiWindowFlags_HorizontalScrollbar))
|
if (ImGui::BeginChild("##Frames List Child", viewListChildSize, true, ImGuiWindowFlags_HorizontalScrollbar))
|
||||||
{
|
{
|
||||||
auto cursorScreenPos = ImGui::GetCursorScreenPos();
|
playheadLineCenterX = 0.0f;
|
||||||
|
playheadLineTopY = 0.0f;
|
||||||
|
isPlayheadLineSet = false;
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2());
|
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2());
|
||||||
if (ImGui::BeginTable("##Frames List Table", 1,
|
if (ImGui::BeginTable("##Frames List Table", 1,
|
||||||
@@ -1757,20 +1768,17 @@ namespace anm2ed::imgui
|
|||||||
|
|
||||||
ImDrawList* windowDrawList = ImGui::GetWindowDrawList();
|
ImDrawList* windowDrawList = ImGui::GetWindowDrawList();
|
||||||
|
|
||||||
auto frameSize = ImVec2(ImGui::GetTextLineHeight(),
|
auto lineBottomY = ImGui::GetWindowPos().y + ImGui::GetWindowSize().y;
|
||||||
ImGui::GetTextLineHeightWithSpacing() + (ImGui::GetStyle().WindowPadding.y * 2));
|
if (isHorizontalScroll) lineBottomY -= ImGui::GetStyle().ScrollbarSize;
|
||||||
auto playheadIndex = std::floor(playback.time);
|
|
||||||
auto lineCenterX = cursorScreenPos.x + frameSize.x * (playheadIndex + 0.6f) - scroll.x;
|
|
||||||
auto linePos =
|
|
||||||
ImVec2(lineCenterX - (PLAYHEAD_LINE_THICKNESS * 0.5f), cursorScreenPos.y + (frameSize.y * 2.0f));
|
|
||||||
auto lineSize = ImVec2((PLAYHEAD_LINE_THICKNESS / 2.0f),
|
|
||||||
viewListChildSize.y - frameSize.y -
|
|
||||||
(isHorizontalScroll ? ImGui::GetStyle().ScrollbarSize * 2.0f : 0.0f));
|
|
||||||
|
|
||||||
auto rectMin = windowDrawList->GetClipRectMin();
|
auto rectMin = windowDrawList->GetClipRectMin();
|
||||||
auto rectMax = windowDrawList->GetClipRectMax();
|
auto rectMax = windowDrawList->GetClipRectMax();
|
||||||
if (pickerLineDrawList)
|
if (pickerLineDrawList && isPlayheadLineSet && lineBottomY > playheadLineTopY)
|
||||||
{
|
{
|
||||||
|
auto linePos =
|
||||||
|
ImVec2(playheadLineCenterX - (PLAYHEAD_LINE_THICKNESS * 0.5f), playheadLineTopY);
|
||||||
|
auto lineSize =
|
||||||
|
ImVec2((PLAYHEAD_LINE_THICKNESS / 2.0f), std::max(0.0f, lineBottomY - playheadLineTopY));
|
||||||
pickerLineDrawList->PushClipRect(rectMin, rectMax);
|
pickerLineDrawList->PushClipRect(rectMin, rectMax);
|
||||||
pickerLineDrawList->AddRectFilled(linePos, ImVec2(linePos.x + lineSize.x, linePos.y + lineSize.y),
|
pickerLineDrawList->AddRectFilled(linePos, ImVec2(linePos.x + lineSize.x, linePos.y + lineSize.y),
|
||||||
ImGui::GetColorU32(playheadLineColor));
|
ImGui::GetColorU32(playheadLineColor));
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ namespace anm2ed::imgui::wizard
|
|||||||
|
|
||||||
ImGui::BeginDisabled(!isRaw);
|
ImGui::BeginDisabled(!isRaw);
|
||||||
{
|
{
|
||||||
input_float_range(localize.get(BASIC_SCALE), scale, 0.1f, 100.0f, 0.1f, STEP_FAST, "%.1fx");
|
input_float_range(localize.get(BASIC_SCALE), scale, 0.1f, 100.0f, 1.0f, STEP_FAST, "%.1fx");
|
||||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SCALE_OUTPUT));
|
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SCALE_OUTPUT));
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
|||||||
+36
-19
@@ -30,6 +30,15 @@ namespace anm2ed
|
|||||||
std::filesystem::create_directories(parent, ec);
|
std::filesystem::create_directories(parent, ec);
|
||||||
if (ec) logger.warning(std::format("Could not create directory for {}: {}", path::to_utf8(path), ec.message()));
|
if (ec) logger.warning(std::format("Could not create directory for {}: {}", path::to_utf8(path), ec.message()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void autosave_file_remove(const std::filesystem::path& path)
|
||||||
|
{
|
||||||
|
if (path.empty()) return;
|
||||||
|
|
||||||
|
std::error_code ec{};
|
||||||
|
std::filesystem::remove(path, ec);
|
||||||
|
if (ec) logger.warning(std::format("Could not remove autosave file {}: {}", path::to_utf8(path), ec.message()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::selection_history_push(int index)
|
void Manager::selection_history_push(int index)
|
||||||
@@ -107,10 +116,22 @@ namespace anm2ed
|
|||||||
{
|
{
|
||||||
std::string errorString{};
|
std::string errorString{};
|
||||||
ensure_parent_directory_exists(path);
|
ensure_parent_directory_exists(path);
|
||||||
|
const auto previousAutosavePath = document->autosave_path_get();
|
||||||
document->path = !path.empty() ? path : document->path;
|
document->path = !path.empty() ? path : document->path;
|
||||||
document->path.replace_extension(".anm2");
|
document->path.replace_extension(".anm2");
|
||||||
document->save(document->path, &errorString, compatibility, isBakeSpecialInterpolatedFramesOnSave, isRoundScale,
|
const auto autosavePath = document->autosave_path_get();
|
||||||
isRoundRotation);
|
if (document->save(document->path, &errorString, compatibility, isBakeSpecialInterpolatedFramesOnSave,
|
||||||
|
isRoundScale, isRoundRotation))
|
||||||
|
{
|
||||||
|
autosaveFiles.erase(std::remove(autosaveFiles.begin(), autosaveFiles.end(), previousAutosavePath),
|
||||||
|
autosaveFiles.end());
|
||||||
|
if (autosavePath != previousAutosavePath)
|
||||||
|
autosaveFiles.erase(std::remove(autosaveFiles.begin(), autosaveFiles.end(), autosavePath),
|
||||||
|
autosaveFiles.end());
|
||||||
|
autosave_file_remove(previousAutosavePath);
|
||||||
|
autosave_file_remove(autosavePath);
|
||||||
|
autosave_files_write();
|
||||||
|
}
|
||||||
recent_file_add(document->path);
|
recent_file_add(document->path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,15 +163,6 @@ namespace anm2ed
|
|||||||
|
|
||||||
const auto autosavePath = documents[index].autosave_path_get();
|
const auto autosavePath = documents[index].autosave_path_get();
|
||||||
autosaveFiles.erase(std::remove(autosaveFiles.begin(), autosaveFiles.end(), autosavePath), autosaveFiles.end());
|
autosaveFiles.erase(std::remove(autosaveFiles.begin(), autosaveFiles.end(), autosavePath), autosaveFiles.end());
|
||||||
|
|
||||||
if (!autosavePath.empty())
|
|
||||||
{
|
|
||||||
std::error_code ec{};
|
|
||||||
std::filesystem::remove(autosavePath, ec);
|
|
||||||
if (ec)
|
|
||||||
logger.warning(std::format("Could not remove autosave file {}: {}", path::to_utf8(autosavePath), ec.message()));
|
|
||||||
}
|
|
||||||
|
|
||||||
autosave_files_write();
|
autosave_files_write();
|
||||||
|
|
||||||
documents.erase(documents.begin() + index);
|
documents.erase(documents.begin() + index);
|
||||||
@@ -351,6 +363,8 @@ namespace anm2ed
|
|||||||
|
|
||||||
void Manager::autosave_files_open()
|
void Manager::autosave_files_open()
|
||||||
{
|
{
|
||||||
|
std::vector<std::filesystem::path> restoredFiles{};
|
||||||
|
|
||||||
for (auto& path : autosaveFiles)
|
for (auto& path : autosaveFiles)
|
||||||
{
|
{
|
||||||
if (auto document = open(path, false, false))
|
if (auto document = open(path, false, false))
|
||||||
@@ -358,10 +372,16 @@ namespace anm2ed
|
|||||||
document->isForceDirty = true;
|
document->isForceDirty = true;
|
||||||
document->path = document->path_from_autosave_get(path);
|
document->path = document->path_from_autosave_get(path);
|
||||||
document->change(Document::ALL);
|
document->change(Document::ALL);
|
||||||
|
restoredFiles.emplace_back(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
autosave_files_clear();
|
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()
|
void Manager::autosave_files_load()
|
||||||
@@ -401,14 +421,11 @@ namespace anm2ed
|
|||||||
std::format("Could not write autosave files to: {}. Skipping...", path::to_utf8(autosave_path_get())));
|
std::format("Could not write autosave files to: {}. Skipping...", path::to_utf8(autosave_path_get())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::autosave_files_clear()
|
void Manager::autosave_files_clear(bool removeFiles)
|
||||||
{
|
{
|
||||||
|
if (removeFiles)
|
||||||
for (auto& path : autosaveFiles)
|
for (auto& path : autosaveFiles)
|
||||||
{
|
autosave_file_remove(path);
|
||||||
std::error_code ec{};
|
|
||||||
std::filesystem::remove(path, ec);
|
|
||||||
if (ec) logger.warning(std::format("Could not remove autosave file {}: {}", path::to_utf8(path), ec.message()));
|
|
||||||
}
|
|
||||||
|
|
||||||
autosaveFiles.clear();
|
autosaveFiles.clear();
|
||||||
autosave_files_write();
|
autosave_files_write();
|
||||||
@@ -420,5 +437,5 @@ namespace anm2ed
|
|||||||
chords[i] = imgui::string_to_chord(settings.*SHORTCUT_MEMBERS[i]);
|
chords[i] = imgui::string_to_chord(settings.*SHORTCUT_MEMBERS[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager::~Manager() { autosave_files_clear(); }
|
Manager::~Manager() = default;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -95,7 +95,7 @@ namespace anm2ed
|
|||||||
void autosave_files_load();
|
void autosave_files_load();
|
||||||
void autosave_files_open();
|
void autosave_files_open();
|
||||||
void autosave_files_write();
|
void autosave_files_write();
|
||||||
void autosave_files_clear();
|
void autosave_files_clear(bool removeFiles = false);
|
||||||
|
|
||||||
void chords_set(Settings&);
|
void chords_set(Settings&);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user