Sound drag/drop

This commit is contained in:
2025-11-30 22:25:57 -05:00
parent d0221928aa
commit 300e322b9d
49 changed files with 1280230 additions and 210091 deletions
+22 -16
View File
@@ -1,7 +1,9 @@
#include "documents.h"
#include <format>
#include <vector>
#include "strings.h"
#include "time_.h"
using namespace anm2ed::resource;
@@ -44,7 +46,7 @@ namespace anm2ed::imgui
{
height = ImGui::GetWindowSize().y;
if (ImGui::BeginTabBar("Documents Bar", ImGuiTabBarFlags_Reorderable))
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();
@@ -84,8 +86,9 @@ namespace anm2ed::imgui
auto isRequested = i == manager.pendingSelected;
auto font = isDirty ? font::ITALICS : font::REGULAR;
auto string = isDirty ? std::format("[Not Saved] {}", document.filename_get().string())
: document.filename_get().string();
auto filename = document.filename_get().string();
auto string =
isDirty ? std::vformat(localize.get(FORMAT_NOT_SAVED), std::make_format_args(filename)) : filename;
auto label = std::format("{}###Document{}", string, i);
auto flags = isDirty ? ImGuiTabItemFlags_UnsavedDocument : 0;
@@ -116,15 +119,15 @@ namespace anm2ed::imgui
closePopup.trigger();
if (ImGui::BeginPopupModal(closePopup.label, &closePopup.isOpen, ImGuiWindowFlags_NoResize))
if (ImGui::BeginPopupModal(closePopup.label(), &closePopup.isOpen, ImGuiWindowFlags_NoResize))
{
if (closeDocumentIndex >= 0 && closeDocumentIndex < (int)manager.documents.size())
{
auto& closeDocument = manager.documents[closeDocumentIndex];
ImGui::TextUnformatted(std::format("The document \"{}\" has been modified.\nDo you want to save it?",
closeDocument.filename_get().string())
.c_str());
auto filename = closeDocument.filename_get().string();
auto prompt = std::vformat(localize.get(LABEL_DOCUMENT_MODIFIED_PROMPT), std::make_format_args(filename));
ImGui::TextUnformatted(prompt.c_str());
auto widgetSize = imgui::widget_size_with_row_get(3);
@@ -134,7 +137,7 @@ namespace anm2ed::imgui
closePopup.close();
};
if (ImGui::Button("Yes", widgetSize))
if (ImGui::Button(localize.get(BASIC_YES), widgetSize))
{
manager.save(closeDocumentIndex);
manager.close(closeDocumentIndex);
@@ -143,7 +146,7 @@ namespace anm2ed::imgui
ImGui::SameLine();
if (ImGui::Button("No", widgetSize))
if (ImGui::Button(localize.get(BASIC_NO), widgetSize))
{
manager.close(closeDocumentIndex);
close();
@@ -151,7 +154,7 @@ namespace anm2ed::imgui
ImGui::SameLine();
if (ImGui::Button("Cancel", widgetSize))
if (ImGui::Button(localize.get(BASIC_CANCEL), widgetSize))
{
isQuitting = false;
close();
@@ -187,17 +190,18 @@ namespace anm2ed::imgui
manager.anm2DragDropPopup.trigger();
if (ImGui::BeginPopupContextWindow(manager.anm2DragDropPopup.label, ImGuiPopupFlags_None))
if (ImGui::BeginPopupContextWindow(manager.anm2DragDropPopup.label(), ImGuiPopupFlags_None))
{
auto document = manager.get();
if (ImGui::MenuItem(manager.anm2DragDropPaths.size() > 1 ? "Open Many Documents" : "Open New Document"))
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("Merge into Current Document", nullptr, false,
if (ImGui::MenuItem(localize.get(LABEL_DOCUMENTS_MERGE_INTO_CURRENT), nullptr, false,
document && !manager.anm2DragDropPaths.empty()))
{
if (document)
@@ -211,17 +215,19 @@ namespace anm2ed::imgui
}
};
DOCUMENT_EDIT_PTR(document, "Merge Anm2", Document::ALL, merge_anm2s());
DOCUMENT_EDIT_PTR(document, localize.get(EDIT_MERGE_ANM2), Document::ALL, merge_anm2s());
drag_drop_reset();
}
}
if (ImGui::MenuItem("Cancel")) 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))
else if (!ImGui::IsPopupOpen(manager.anm2DragDropPopup.label()))
drag_drop_reset();
}
}
+2 -1
View File
@@ -3,6 +3,7 @@
#include "manager.h"
#include "resources.h"
#include "settings.h"
#include "strings.h"
#include "taskbar.h"
namespace anm2ed::imgui
@@ -10,7 +11,7 @@ namespace anm2ed::imgui
class Documents
{
int closeDocumentIndex{-1};
imgui::PopupHelper closePopup{imgui::PopupHelper("Close Document", imgui::POPUP_TO_CONTENT)};
imgui::PopupHelper closePopup{imgui::PopupHelper(LABEL_DOCUMENT_CLOSE, imgui::POPUP_TO_CONTENT)};
public:
float height{};
+6 -4
View File
@@ -1,4 +1,5 @@
#include "imgui_.h"
#include "strings.h"
#include <imgui/imgui_internal.h>
@@ -161,7 +162,8 @@ namespace anm2ed::imgui
void set_item_tooltip_shortcut(const char* tooltip, const std::string& shortcut)
{
ImGui::SetItemTooltip("%s\n(Shortcut: %s)", tooltip, shortcut.c_str());
ImGui::SetItemTooltip(
"%s", std::vformat(localize.get(FORMAT_TOOLTIP_SHORTCUT), std::make_format_args(tooltip, shortcut)).c_str());
}
namespace
@@ -343,9 +345,9 @@ namespace anm2ed::imgui
return (*indexMap)[index];
}
PopupHelper::PopupHelper(const char* label, PopupType type, PopupPosition position)
PopupHelper::PopupHelper(StringType labelId, PopupType type, PopupPosition position)
{
this->label = label;
this->labelId = labelId;
this->type = type;
this->position = position;
}
@@ -361,7 +363,7 @@ namespace anm2ed::imgui
void PopupHelper::trigger()
{
if (isTriggered) ImGui::OpenPopup(label);
if (isTriggered) ImGui::OpenPopup(localize.get(labelId));
isTriggered = false;
auto viewport = ImGui::GetMainViewport();
+4 -2
View File
@@ -7,6 +7,7 @@
#include <unordered_map>
#include <vector>
#include "strings.h"
#include "types.h"
namespace anm2ed::imgui
@@ -216,14 +217,15 @@ namespace anm2ed::imgui
class PopupHelper
{
public:
const char* label{};
StringType labelId{};
PopupType type{};
PopupPosition position{};
bool isOpen{};
bool isTriggered{};
bool isJustOpened{};
PopupHelper(const char*, PopupType = POPUP_NORMAL, PopupPosition = POPUP_CENTER);
PopupHelper(StringType, PopupType = POPUP_NORMAL, PopupPosition = POPUP_CENTER);
const char* label() const { return localize.get(labelId); }
bool is_open();
void open();
void trigger();
+234 -197
View File
@@ -13,6 +13,7 @@
#include <imgui/imgui.h>
#include "log.h"
#include "math_.h"
#include "render.h"
#include "shader.h"
@@ -22,6 +23,8 @@
#include "icon.h"
#include "toast.h"
#include "strings.h"
using namespace anm2ed::resource;
using namespace anm2ed::types;
using namespace anm2ed::canvas;
@@ -30,8 +33,76 @@ using namespace glm;
namespace anm2ed::imgui
{
static constexpr auto ANM2ED_LABEL = "Anm2Ed";
static constexpr auto VERSION_LABEL = "Version 2.0";
namespace
{
#ifndef _WIN32
constexpr auto EXEC_PERMS =
std::filesystem::perms::owner_exec | std::filesystem::perms::group_exec | std::filesystem::perms::others_exec;
#endif
bool ffmpeg_is_executable(const std::string& pathString)
{
if (pathString.empty()) return false;
std::error_code ec{};
auto status = std::filesystem::status(pathString, ec);
if (ec || !std::filesystem::is_regular_file(status)) return false;
#ifndef _WIN32
if ((status.permissions() & EXEC_PERMS) == std::filesystem::perms::none) return false;
#endif
return true;
}
bool png_directory_ensure(const std::string& directory)
{
if (directory.empty())
{
toasts.push(localize.get(TOAST_PNG_DIRECTORY_NOT_SET));
logger.warning(localize.get(TOAST_PNG_DIRECTORY_NOT_SET, anm2ed::ENGLISH));
return false;
}
std::error_code ec{};
auto pathValue = std::filesystem::path(directory);
auto exists = std::filesystem::exists(pathValue, ec);
if (ec)
{
auto errorMessage = ec.message();
toasts.push(std::vformat(localize.get(TOAST_PNG_DIRECTORY_ACCESS_ERROR),
std::make_format_args(directory, errorMessage)));
logger.error(std::vformat(localize.get(TOAST_PNG_DIRECTORY_ACCESS_ERROR, anm2ed::ENGLISH),
std::make_format_args(directory, errorMessage)));
return false;
}
if (exists)
{
if (!std::filesystem::is_directory(pathValue, ec) || ec)
{
toasts.push(std::vformat(localize.get(TOAST_PNG_DIRECTORY_NOT_DIRECTORY), std::make_format_args(directory)));
logger.warning(std::vformat(localize.get(TOAST_PNG_DIRECTORY_NOT_DIRECTORY, anm2ed::ENGLISH),
std::make_format_args(directory)));
return false;
}
return true;
}
if (!std::filesystem::create_directories(pathValue, ec) || ec)
{
auto errorMessage = ec.message();
toasts.push(std::vformat(localize.get(TOAST_PNG_DIRECTORY_CREATE_ERROR),
std::make_format_args(directory, errorMessage)));
logger.error(std::vformat(localize.get(TOAST_PNG_DIRECTORY_CREATE_ERROR, anm2ed::ENGLISH),
std::make_format_args(directory, errorMessage)));
return false;
}
return true;
}
}
static constexpr auto CREDIT_DELAY = 1.0f;
static constexpr auto CREDIT_SCROLL_SPEED = 25.0f;
@@ -64,6 +135,10 @@ namespace anm2ed::imgui
{"Additional Help", font::BOLD},
{"im-tem"},
{""},
{"Localization", font::BOLD},
{"ExtremeThreat (Russian)"},
{"sawalk/사왈이 (Korean)"},
{""},
{"Based on the work of:", font::BOLD},
{"Adrian Gavrilita"},
{"Simon Parzer"},
@@ -122,12 +197,21 @@ namespace anm2ed::imgui
{""},
{""},
{""},
{""},
{""},
{""},
{""},
{"enjoy the jams :)"},
{""},
{""},
{""},
{""},
{""},
{""},
{""},
{""},
{""},
{""},
};
static constexpr auto CREDIT_COUNT = (int)(sizeof(CREDITS) / sizeof(Credit));
@@ -143,13 +227,14 @@ namespace anm2ed::imgui
{
height = ImGui::GetWindowSize().y;
if (ImGui::BeginMenu("File"))
if (ImGui::BeginMenu(localize.get(LABEL_FILE_MENU)))
{
if (ImGui::MenuItem("New", settings.shortcutNew.c_str())) dialog.file_save(dialog::ANM2_NEW);
if (ImGui::MenuItem("Open", settings.shortcutOpen.c_str())) dialog.file_open(dialog::ANM2_OPEN);
if (ImGui::MenuItem(localize.get(BASIC_NEW), settings.shortcutNew.c_str())) dialog.file_save(dialog::ANM2_NEW);
if (ImGui::MenuItem(localize.get(BASIC_OPEN), settings.shortcutOpen.c_str()))
dialog.file_open(dialog::ANM2_OPEN);
auto recentFiles = manager.recent_files_ordered();
if (ImGui::BeginMenu("Open Recent", !recentFiles.empty()))
if (ImGui::BeginMenu(localize.get(LABEL_OPEN_RECENT), !recentFiles.empty()))
{
for (std::size_t index = 0; index < recentFiles.size(); ++index)
{
@@ -162,21 +247,26 @@ namespace anm2ed::imgui
}
if (!recentFiles.empty())
if (ImGui::MenuItem("Clear List")) manager.recent_files_clear();
if (ImGui::MenuItem(localize.get(LABEL_CLEAR_LIST))) manager.recent_files_clear();
ImGui::EndMenu();
}
if (ImGui::MenuItem("Save", settings.shortcutSave.c_str(), false, document))
if (settings.fileIsWarnOverwrite) overwritePopup.open();
if (ImGui::MenuItem(localize.get(BASIC_SAVE), settings.shortcutSave.c_str(), false, document))
{
if (settings.fileIsWarnOverwrite)
overwritePopup.open();
else
manager.save(document->path);
}
if (ImGui::MenuItem("Save As", settings.shortcutSaveAs.c_str(), false, document))
if (ImGui::MenuItem(localize.get(LABEL_SAVE_AS), settings.shortcutSaveAs.c_str(), false, document))
dialog.file_save(dialog::ANM2_SAVE);
if (ImGui::MenuItem("Explore XML Location", nullptr, false, document))
if (ImGui::MenuItem(localize.get(LABEL_EXPLORE_XML_LOCATION), nullptr, false, document))
dialog.file_explorer_open(document->directory_get().string());
ImGui::Separator();
if (ImGui::MenuItem("Exit", settings.shortcutExit.c_str())) isQuitting = true;
if (ImGui::MenuItem(localize.get(LABEL_EXIT), settings.shortcutExit.c_str())) isQuitting = true;
ImGui::EndMenu();
}
if (dialog.is_selected(dialog::ANM2_NEW))
@@ -197,43 +287,43 @@ namespace anm2ed::imgui
dialog.reset();
}
if (ImGui::BeginMenu("Wizard"))
if (ImGui::BeginMenu(localize.get(LABEL_WIZARD_MENU)))
{
if (ImGui::MenuItem("Generate Animation From Grid", nullptr, false,
if (ImGui::MenuItem(localize.get(LABEL_TASKBAR_GENERATE_ANIMATION_FROM_GRID), nullptr, false,
item && document->reference.itemType == anm2::LAYER))
generatePopup.open();
ImGui::Separator();
if (ImGui::MenuItem("Render Animation", nullptr, false, animation)) renderPopup.open();
if (ImGui::MenuItem(localize.get(LABEL_TASKBAR_RENDER_ANIMATION), nullptr, false, animation))
renderPopup.open();
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Playback"))
if (ImGui::BeginMenu(localize.get(LABEL_PLAYBACK_MENU)))
{
ImGui::MenuItem("Always Loop", nullptr, &settings.playbackIsLoop);
ImGui::SetItemTooltip("%s", "Animations will always loop during playback, even if looping isn't set.");
ImGui::MenuItem(localize.get(LABEL_PLAYBACK_ALWAYS_LOOP), nullptr, &settings.playbackIsLoop);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_PLAYBACK_ALWAYS_LOOP));
ImGui::MenuItem("Clamp", nullptr, &settings.playbackIsClamp);
ImGui::SetItemTooltip("%s", "Operations will always be clamped to within the animation's bounds.\nFor example, "
"dragging the playhead, or triggers.");
ImGui::MenuItem(localize.get(LABEL_CLAMP), nullptr, &settings.playbackIsClamp);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_PLAYBACK_CLAMP));
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Window"))
if (ImGui::BeginMenu(localize.get(LABEL_WINDOW_MENU)))
{
for (std::size_t index = 0; index < WINDOW_COUNT; ++index)
{
auto member = WINDOW_MEMBERS[index];
ImGui::MenuItem(WINDOW_STRINGS[index], nullptr, &(settings.*member));
ImGui::MenuItem(localize.get(::anm2ed::WINDOW_STRING_TYPES[index]), nullptr, &(settings.*member));
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Settings"))
if (ImGui::BeginMenu(localize.get(LABEL_SETTINGS_MENU)))
{
if (ImGui::MenuItem("Configure"))
if (ImGui::MenuItem(localize.get(LABEL_TASKBAR_CONFIGURE)))
{
editSettings = settings;
configurePopup.open();
@@ -242,10 +332,10 @@ namespace anm2ed::imgui
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Help"))
if (ImGui::BeginMenu(localize.get(LABEL_HELP_MENU)))
{
if (ImGui::MenuItem("About")) aboutPopup.open();
if (ImGui::MenuItem(localize.get(LABEL_TASKBAR_ABOUT))) aboutPopup.open();
ImGui::EndMenu();
}
@@ -254,7 +344,7 @@ namespace anm2ed::imgui
generatePopup.trigger();
if (ImGui::BeginPopupModal(generatePopup.label, &generatePopup.isOpen, ImGuiWindowFlags_NoResize))
if (ImGui::BeginPopupModal(generatePopup.label(), &generatePopup.isOpen, ImGuiWindowFlags_NoResize))
{
auto& startPosition = settings.generateStartPosition;
auto& size = settings.generateSize;
@@ -270,15 +360,15 @@ namespace anm2ed::imgui
if (ImGui::BeginChild("##Options Child", childSize, ImGuiChildFlags_Borders))
{
ImGui::InputInt2("Start Position", value_ptr(startPosition));
ImGui::InputInt2("Frame Size", value_ptr(size));
ImGui::InputInt2("Pivot", value_ptr(pivot));
ImGui::InputInt("Rows", &rows, STEP, STEP_FAST);
ImGui::InputInt("Columns", &columns, STEP, STEP_FAST);
ImGui::InputInt2(localize.get(LABEL_GENERATE_START_POSITION), value_ptr(startPosition));
ImGui::InputInt2(localize.get(LABEL_GENERATE_FRAME_SIZE), value_ptr(size));
ImGui::InputInt2(localize.get(BASIC_PIVOT), value_ptr(pivot));
ImGui::InputInt(localize.get(LABEL_GENERATE_ROWS), &rows, STEP, STEP_FAST);
ImGui::InputInt(localize.get(LABEL_GENERATE_COLUMNS), &columns, STEP, STEP_FAST);
input_int_range("Count", count, anm2::FRAME_NUM_MIN, rows * columns);
input_int_range(localize.get(LABEL_GENERATE_COUNT), count, anm2::FRAME_NUM_MIN, rows * columns);
ImGui::InputInt("Duration", &delay, STEP, STEP_FAST);
ImGui::InputInt(localize.get(BASIC_DURATION), &delay, STEP, STEP_FAST);
}
ImGui::EndChild();
@@ -331,7 +421,7 @@ namespace anm2ed::imgui
auto widgetSize = widget_size_with_row_get(2);
if (ImGui::Button("Generate", widgetSize))
if (ImGui::Button(localize.get(LABEL_GENERATE), widgetSize))
{
auto generate_from_grid = [&]()
{
@@ -339,41 +429,46 @@ namespace anm2ed::imgui
animation->frameNum = animation->length();
};
DOCUMENT_EDIT_PTR(document, "Generate Animation from Grid", Document::FRAMES, generate_from_grid());
DOCUMENT_EDIT_PTR(document, localize.get(EDIT_GENERATE_ANIMATION_FROM_GRID), Document::FRAMES,
generate_from_grid());
generatePopup.close();
}
ImGui::SameLine();
if (ImGui::Button("Cancel", widgetSize)) generatePopup.close();
if (ImGui::Button(localize.get(BASIC_CANCEL), widgetSize)) generatePopup.close();
ImGui::EndPopup();
}
configurePopup.trigger();
if (ImGui::BeginPopupModal(configurePopup.label, &configurePopup.isOpen, ImGuiWindowFlags_NoResize))
if (ImGui::BeginPopupModal(configurePopup.label(), &configurePopup.isOpen, ImGuiWindowFlags_NoResize))
{
auto childSize = size_without_footer_get(2);
if (ImGui::BeginTabBar("##Configure Tabs"))
{
if (ImGui::BeginTabItem("Display"))
if (ImGui::BeginTabItem(localize.get(LABEL_DISPLAY)))
{
if (ImGui::BeginChild("##Tab Child", childSize, true))
{
input_float_range("UI Scale", editSettings.uiScale, 0.5f, 2.0f, 0.25f, 0.25f, "%.2f");
ImGui::SetItemTooltip("Change the scale of the UI.");
ImGui::SeparatorText(localize.get(LABEL_WINDOW_MENU));
input_float_range(localize.get(LABEL_UI_SCALE), editSettings.uiScale, 0.5f, 2.0f, 0.25f, 0.25f, "%.2f");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_UI_SCALE));
ImGui::Checkbox(localize.get(LABEL_VSYNC), &editSettings.isVsync);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_VSYNC));
ImGui::Checkbox("Vsync", &editSettings.isVsync);
ImGui::SetItemTooltip("Toggle vertical sync; synchronizes program update rate with monitor refresh rate.");
ImGui::SeparatorText(localize.get(LABEL_LOCALIZATION));
ImGui::Combo(localize.get(LABEL_LANGUAGE), &editSettings.language, LANGUAGE_STRINGS, LANGUAGE_COUNT);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_LANGUAGE));
ImGui::SeparatorText("Theme");
ImGui::SeparatorText(localize.get(LABEL_THEME));
for (int i = 0; i < theme::COUNT; i++)
{
ImGui::RadioButton(theme::STRINGS[i], &editSettings.theme, i);
ImGui::RadioButton(localize.get(theme::STRINGS[i]), &editSettings.theme, i);
ImGui::SameLine();
}
}
@@ -382,76 +477,75 @@ namespace anm2ed::imgui
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("File"))
if (ImGui::BeginTabItem(localize.get(LABEL_FILE_MENU)))
{
if (ImGui::BeginChild("##Tab Child", childSize, true))
{
ImGui::SeparatorText("Autosave");
ImGui::SeparatorText(localize.get(LABEL_AUTOSAVE));
ImGui::Checkbox("Enabled", &editSettings.fileIsAutosave);
ImGui::SetItemTooltip(
"Enables autosaving of documents.\n(Does not overwrite files; makes copies to restore later.)");
ImGui::Checkbox(localize.get(BASIC_ENABLED), &editSettings.fileIsAutosave);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_AUTOSAVE_ENABLED));
ImGui::BeginDisabled(!editSettings.fileIsAutosave);
input_int_range("Time (minutes)", editSettings.fileAutosaveTime, 0, 10);
ImGui::SetItemTooltip("If changed, will autosave documents using this interval.");
input_int_range(localize.get(LABEL_TIME_MINUTES), editSettings.fileAutosaveTime, 0, 10);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_AUTOSAVE_INTERVAL));
ImGui::EndDisabled();
ImGui::SeparatorText("Snapshots");
input_int_range("Stack Size", editSettings.fileSnapshotStackSize, 0, 100);
ImGui::SetItemTooltip("Set the maximum snapshot stack size of a document (i.e., how many undo/redos are "
"preserved at a time).");
ImGui::SeparatorText(localize.get(LABEL_SNAPSHOTS));
input_int_range(localize.get(LABEL_STACK_SIZE), editSettings.fileSnapshotStackSize, 0, 100);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_STACK_SIZE));
ImGui::SeparatorText("Options");
ImGui::Checkbox("Overwrite Warning", &editSettings.fileIsWarnOverwrite);
ImGui::SetItemTooltip("A warning will be shown when saving/overwriting a file.");
ImGui::SeparatorText(localize.get(LABEL_OPTIONS));
ImGui::Checkbox(localize.get(LABEL_OVERWRITE_WARNING), &editSettings.fileIsWarnOverwrite);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_OVERWRITE_WARNING));
}
ImGui::EndChild();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Input"))
if (ImGui::BeginTabItem(localize.get(LABEL_INPUT)))
{
if (ImGui::BeginChild("##Tab Child", childSize, true))
{
ImGui::SeparatorText("Keyboard");
ImGui::SeparatorText(localize.get(LABEL_KEYBOARD));
input_float_range("Repeat Delay (seconds)", editSettings.keyboardRepeatDelay, 0.05f, 1.0f, 0.05f, 0.05f,
"%.2f");
ImGui::SetItemTooltip("Set how often, after repeating begins, key inputs will be fired.");
input_float_range(localize.get(LABEL_REPEAT_DELAY), editSettings.keyboardRepeatDelay, 0.05f, 1.0f, 0.05f,
0.05f, "%.2f");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_REPEAT_DELAY));
input_float_range("Repeat Rate (seconds)", editSettings.keyboardRepeatRate, 0.005f, 1.0f, 0.005f, 0.005f,
"%.3f");
ImGui::SetItemTooltip("Set how often, after repeating begins, key inputs will be fired.");
input_float_range(localize.get(LABEL_REPEAT_RATE), editSettings.keyboardRepeatRate, 0.005f, 1.0f, 0.005f,
0.005f, "%.3f");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_REPEAT_DELAY));
ImGui::SeparatorText("Zoom");
ImGui::SeparatorText(localize.get(LABEL_ZOOM));
input_float_range("Step", editSettings.inputZoomStep, 10.0f, 250.0f, 10.0f, 10.0f, "%.0f%%");
ImGui::SetItemTooltip("When zooming in/out with mouse or shortcut, this value will be used.");
input_float_range(localize.get(LABEL_ZOOM_STEP), editSettings.inputZoomStep, 10.0f, 250.0f, 10.0f, 10.0f,
"%.0f%%");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ZOOM_STEP));
ImGui::SeparatorText("Tool");
ImGui::SeparatorText(localize.get(LABEL_TOOL));
ImGui::Checkbox("Move Tool: Snap to Mouse", &editSettings.inputIsMoveToolSnapToMouse);
ImGui::SetItemTooltip("In Animation Preview, the Move tool will snap the frame's position right to the "
"cursor, instead of being moved at a distance.");
ImGui::Checkbox(localize.get(LABEL_MOVE_TOOL_SNAP), &editSettings.inputIsMoveToolSnapToMouse);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_MOVE_TOOL_SNAP));
}
ImGui::EndChild();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Shortcuts"))
if (ImGui::BeginTabItem(localize.get(LABEL_SHORTCUTS_TAB)))
{
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2());
if (ImGui::BeginChild("##Tab Child", childSize, true))
{
if (ImGui::BeginTable("Shortcuts", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_ScrollY))
if (ImGui::BeginTable(localize.get(LABEL_SHORTCUTS_TAB), 2,
ImGuiTableFlags_Borders | ImGuiTableFlags_ScrollY))
{
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableSetupColumn("Shortcut");
ImGui::TableSetupColumn("Value");
ImGui::TableSetupColumn(localize.get(LABEL_SHORTCUT_COLUMN));
ImGui::TableSetupColumn(localize.get(LABEL_VALUE_COLUMN));
ImGui::TableHeadersRow();
for (int i = 0; i < SHORTCUT_COUNT; ++i)
@@ -465,7 +559,7 @@ namespace anm2ed::imgui
ImGui::PushID(i);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::TextUnformatted(SHORTCUT_STRINGS[i]);
ImGui::TextUnformatted(localize.get(::anm2ed::SHORTCUT_STRING_TYPES[i]));
ImGui::TableSetColumnIndex(1);
if (ImGui::Selectable(chordString.c_str(), isSelected)) selectedShortcut = i;
@@ -509,39 +603,41 @@ namespace anm2ed::imgui
auto widgetSize = widget_size_with_row_get(3);
if (ImGui::Button("Save", widgetSize))
if (ImGui::Button(localize.get(BASIC_SAVE), widgetSize))
{
settings = editSettings;
imgui::theme_set((theme::Type)editSettings.theme);
manager.chords_set(settings);
ImGui::GetIO().KeyRepeatDelay = settings.keyboardRepeatDelay;
ImGui::GetIO().KeyRepeatRate = settings.keyboardRepeatRate;
ImGui::GetStyle().FontScaleMain = settings.uiScale;
SnapshotStack::max_size_set(settings.fileSnapshotStackSize);
imgui::theme_set((theme::Type)settings.theme);
localize.language = (Language)settings.language;
manager.chords_set(settings);
for (auto& document : manager.documents)
document.snapshots.apply_limit();
configurePopup.close();
}
ImGui::SetItemTooltip("Use the configured settings.");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SETTINGS_SAVE));
ImGui::SameLine();
if (ImGui::Button("Use Default Settings", widgetSize)) editSettings = Settings();
ImGui::SetItemTooltip("Reset the settings to their defaults.");
if (ImGui::Button(localize.get(LABEL_USE_DEFAULT_SETTINGS), widgetSize)) editSettings = Settings();
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_USE_DEFAULT_SETTINGS));
ImGui::SameLine();
if (ImGui::Button("Close", widgetSize)) configurePopup.close();
ImGui::SetItemTooltip("Close without updating settings.");
if (ImGui::Button(localize.get(LABEL_CLOSE), widgetSize)) configurePopup.close();
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_CLOSE_SETTINGS));
ImGui::EndPopup();
}
renderPopup.trigger();
if (ImGui::BeginPopupModal(renderPopup.label, &renderPopup.isOpen, ImGuiWindowFlags_NoResize))
if (ImGui::BeginPopupModal(renderPopup.label(), &renderPopup.isOpen, ImGuiWindowFlags_NoResize))
{
auto& ffmpegPath = settings.renderFFmpegPath;
auto& path = settings.renderPath;
@@ -557,59 +653,6 @@ namespace anm2ed::imgui
auto& frames = document->frames.selection;
int length = std::max(1, end - start + 1);
auto ffmpeg_is_executable = [](const std::string& pathString)
{
if (pathString.empty()) return false;
std::error_code ec{};
auto status = std::filesystem::status(pathString, ec);
if (ec || !std::filesystem::is_regular_file(status)) return false;
#ifndef _WIN32
constexpr auto EXEC_PERMS = std::filesystem::perms::owner_exec | std::filesystem::perms::group_exec |
std::filesystem::perms::others_exec;
if ((status.permissions() & EXEC_PERMS) == std::filesystem::perms::none) return false;
#endif
return true;
};
auto png_directory_ensure = [](const std::string& directory)
{
if (directory.empty())
{
toasts.error("PNG output directory must be set.");
return false;
}
std::error_code ec{};
auto pathValue = std::filesystem::path(directory);
auto exists = std::filesystem::exists(pathValue, ec);
if (ec)
{
toasts.error(std::format("Could not access directory: {} ({})", directory, ec.message()));
return false;
}
if (exists)
{
if (!std::filesystem::is_directory(pathValue, ec) || ec)
{
toasts.error(std::format("PNG output path must be a directory: {}", directory));
return false;
}
return true;
}
if (!std::filesystem::create_directories(pathValue, ec) || ec)
{
toasts.error(std::format("Could not create directory: {} ({})", directory, ec.message()));
return false;
}
return true;
};
auto range_to_frames_set = [&]()
{
if (auto item = document->item_get())
@@ -640,11 +683,7 @@ namespace anm2ed::imgui
auto range_set = [&]()
{
if (!frames.empty())
range_to_frames_set();
else if (!isRange)
range_to_animation_set();
if (!isRange) range_to_animation_set();
length = std::max(1, end - (start + 1));
};
@@ -698,9 +737,8 @@ namespace anm2ed::imgui
if (ImGui::ImageButton("##FFmpeg Path Set", resources.icons[icon::FOLDER].id, icon_size_get()))
dialog.file_open(dialog::FFMPEG_PATH_SET);
ImGui::SameLine();
input_text_string("FFmpeg Path", &ffmpegPath);
ImGui::SetItemTooltip("Set the path where the FFmpeg installation is located.\nFFmpeg is required to render "
"animations.\nhttps://ffmpeg.org");
input_text_string(localize.get(LABEL_FFMPEG_PATH), &ffmpegPath);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_FFMPEG_PATH));
dialog.set_string_to_selected_path(ffmpegPath, dialog::FFMPEG_PATH_SET);
if (ImGui::ImageButton("##Path Set", resources.icons[icon::FOLDER].id, icon_size_get()))
@@ -711,89 +749,89 @@ namespace anm2ed::imgui
dialog.file_save(dialogType);
}
ImGui::SameLine();
input_text_string(type == render::PNGS ? "Directory" : "Path", &path);
ImGui::SetItemTooltip("Set the output path or directory for the animation.");
auto pathLabel = type == render::PNGS ? LABEL_OUTPUT_DIRECTORY : LABEL_OUTPUT_PATH;
input_text_string(localize.get(pathLabel), &path);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_OUTPUT_PATH));
dialog.set_string_to_selected_path(path, dialogType);
if (ImGui::Combo("Type", &type, render::STRINGS, render::COUNT)) render_set();
ImGui::SetItemTooltip("Set the type of the output.");
if (ImGui::Combo(localize.get(LABEL_TYPE), &type, render::STRINGS, render::COUNT)) render_set();
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_RENDER_TYPE));
if (type == render::PNGS || type == render::SPRITESHEET) ImGui::Separator();
if (type == render::PNGS)
{
if (input_text_string("Format", &format))
if (input_text_string(localize.get(LABEL_FORMAT), &format))
format = std::filesystem::path(format).replace_extension(".png").string();
ImGui::SetItemTooltip(
"For outputted images, each image will use this format.\n{} represents the index of each image.");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_FORMAT));
}
else if (type == render::SPRITESHEET)
{
input_int_range("Rows", rows, 1, length);
ImGui::SetItemTooltip("Set how many rows the spritesheet will have.");
input_int_range(localize.get(LABEL_GENERATE_ROWS), rows, 1, length);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ROWS));
input_int_range("Columns", columns, 1, length);
ImGui::SetItemTooltip("Set how many columns the spritesheet will have.");
input_int_range(localize.get(LABEL_GENERATE_COLUMNS), columns, 1, length);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_COLUMNS));
if (ImGui::Button("Set to Recommended")) rows_columns_set();
ImGui::SetItemTooltip("Use a recommended value for rows/columns.");
if (ImGui::Button(localize.get(LABEL_SET_TO_RECOMMENDED))) rows_columns_set();
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SET_TO_RECOMMENDED));
}
ImGui::Separator();
if (ImGui::Checkbox("Custom Range", &isRange))
if (ImGui::Checkbox(localize.get(LABEL_CUSTOM_RANGE), &isRange))
{
range_set();
ImGui::SetItemTooltip("Toggle using a custom range for the animation.");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_CUSTOM_RANGE));
}
ImGui::SameLine();
ImGui::BeginDisabled(frames.empty());
if (ImGui::Button("To Selected Frames")) range_to_frames_set();
ImGui::SetItemTooltip("If frames are selected, use that range for the rendered animation.");
if (ImGui::Button(localize.get(LABEL_TO_SELECTED_FRAMES))) range_to_frames_set();
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_TO_SELECTED_FRAMES));
ImGui::EndDisabled();
ImGui::SameLine();
if (ImGui::Button("To Animation Range")) range_to_animation_set();
ImGui::SetItemTooltip("Set the range to the normal range of the animation.");
if (ImGui::Button(localize.get(LABEL_TO_ANIMATION_RANGE))) range_to_animation_set();
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_TO_ANIMATION_RANGE));
ImGui::BeginDisabled(!isRange);
{
input_int_range("Start", start, 0, animation->frameNum);
ImGui::SetItemTooltip("Set the starting time of the animation.");
input_int_range("End", end, start, animation->frameNum);
ImGui::SetItemTooltip("Set the ending time of the animation.");
input_int_range(localize.get(LABEL_START), start, 0, animation->frameNum);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_START));
input_int_range(localize.get(LABEL_END), end, start, animation->frameNum);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_END));
}
ImGui::EndDisabled();
ImGui::Separator();
ImGui::Checkbox("Raw", &isRaw);
ImGui::SetItemTooltip("Record only the raw animation; i.e., only its layers, to its bounds.");
ImGui::Checkbox(localize.get(LABEL_RAW), &isRaw);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_RAW));
ImGui::BeginDisabled(!isRaw);
{
input_float_range("Scale", scale, 1.0f, 100.0f, STEP, STEP_FAST, "%.1fx");
ImGui::SetItemTooltip("Set the output scale of the animation.");
input_float_range(localize.get(BASIC_SCALE), scale, 1.0f, 100.0f, STEP, STEP_FAST, "%.1fx");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SCALE_OUTPUT));
}
ImGui::EndDisabled();
ImGui::Separator();
ImGui::Checkbox("Sound", &settings.timelineIsSound);
ImGui::SetItemTooltip("Toggle sounds playing with triggers.\nBind sounds to events in the Events window.\nThe "
"output animation will use the played sounds.");
ImGui::Checkbox(localize.get(LABEL_SOUND), &settings.timelineIsSound);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SOUND));
ImGui::Separator();
if (ImGui::Button("Render", widgetSize))
if (ImGui::Button(localize.get(LABEL_RENDER), widgetSize))
{
bool isRender = true;
if (!ffmpeg_is_executable(ffmpegPath))
{
toasts.error("FFmpeg path must point to a valid executable file.");
toasts.push(localize.get(TOAST_INVALID_FFMPEG_PATH));
logger.error(localize.get(TOAST_INVALID_FFMPEG_PATH, anm2ed::ENGLISH));
isRender = false;
}
@@ -807,11 +845,11 @@ namespace anm2ed::imgui
renderPopup.close();
}
ImGui::SetItemTooltip("Render the animation using the current settings.");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_RENDER_BUTTON));
ImGui::SameLine();
if (ImGui::Button("Cancel", widgetSize)) renderPopup.close();
if (ImGui::Button(localize.get(BASIC_CANCEL), widgetSize)) renderPopup.close();
ImGui::EndPopup();
}
@@ -820,7 +858,7 @@ namespace anm2ed::imgui
aboutPopup.trigger();
if (ImGui::BeginPopupModal(aboutPopup.label, &aboutPopup.isOpen, ImGuiWindowFlags_NoResize))
if (ImGui::BeginPopupModal(aboutPopup.label(), &aboutPopup.isOpen, ImGuiWindowFlags_NoResize))
{
static CreditsState creditsState{};
@@ -834,14 +872,16 @@ namespace anm2ed::imgui
if (aboutPopup.isJustOpened) credits_reset();
auto size = ImGui::GetContentRegionAvail();
auto applicationLabel = localize.get(LABEL_APPLICATION_NAME);
auto versionLabel = localize.get(LABEL_APPLICATION_VERSION);
ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE_LARGE);
ImGui::SetCursorPosX((size.x - ImGui::CalcTextSize(ANM2ED_LABEL).x) / 2);
ImGui::Text(ANM2ED_LABEL);
ImGui::SetCursorPosX((size.x - ImGui::CalcTextSize(applicationLabel).x) / 2);
ImGui::TextUnformatted(applicationLabel);
ImGui::SetCursorPosX((size.x - ImGui::CalcTextSize(VERSION_LABEL).x) / 2);
ImGui::Text(VERSION_LABEL);
ImGui::SetCursorPosX((size.x - ImGui::CalcTextSize(versionLabel).x) / 2);
ImGui::TextUnformatted(versionLabel);
ImGui::PopFont();
@@ -914,13 +954,13 @@ namespace anm2ed::imgui
overwritePopup.trigger();
if (ImGui::BeginPopupModal(overwritePopup.label, &overwritePopup.isOpen, ImGuiWindowFlags_NoResize))
if (ImGui::BeginPopupModal(overwritePopup.label(), &overwritePopup.isOpen, ImGuiWindowFlags_NoResize))
{
ImGui::Text("Are you sure? This will overwrite the existing file.");
ImGui::TextUnformatted(localize.get(LABEL_OVERWRITE_CONFIRMATION));
auto widgetSize = widget_size_with_row_get(2);
if (ImGui::Button("Yes", widgetSize))
if (ImGui::Button(localize.get(BASIC_YES), widgetSize))
{
manager.save();
overwritePopup.close();
@@ -928,7 +968,7 @@ namespace anm2ed::imgui
ImGui::SameLine();
if (ImGui::Button("No", widgetSize)) overwritePopup.close();
if (ImGui::Button(localize.get(BASIC_NO), widgetSize)) overwritePopup.close();
ImGui::EndPopup();
}
@@ -948,6 +988,3 @@ namespace anm2ed::imgui
if (shortcut(manager.chords[SHORTCUT_EXIT], shortcut::GLOBAL)) isQuitting = true;
}
}
#ifndef ANM2ED_USE_LIBXM
#define ANM2ED_USE_LIBXM 1
#endif
+9 -6
View File
@@ -6,6 +6,7 @@
#include "manager.h"
#include "resources.h"
#include "settings.h"
#include "strings.h"
namespace anm2ed::imgui
{
@@ -13,11 +14,13 @@ namespace anm2ed::imgui
{
Canvas generate;
float generateTime{};
PopupHelper generatePopup{PopupHelper("Generate Animation from Grid")};
PopupHelper overwritePopup{PopupHelper("Overwrite File", imgui::POPUP_SMALL_NO_HEIGHT)};
PopupHelper renderPopup{PopupHelper("Render Animation", imgui::POPUP_SMALL_NO_HEIGHT)};
PopupHelper configurePopup{PopupHelper("Configure")};
PopupHelper aboutPopup{PopupHelper("About")};
PopupHelper generatePopup{PopupHelper(LABEL_TASKBAR_GENERATE_ANIMATION_FROM_GRID)};
PopupHelper overwritePopup{
PopupHelper(LABEL_TASKBAR_OVERWRITE_FILE, imgui::POPUP_SMALL_NO_HEIGHT)};
PopupHelper renderPopup{
PopupHelper(LABEL_TASKBAR_RENDER_ANIMATION, imgui::POPUP_SMALL_NO_HEIGHT)};
PopupHelper configurePopup{PopupHelper(LABEL_TASKBAR_CONFIGURE)};
PopupHelper aboutPopup{PopupHelper(LABEL_TASKBAR_ABOUT)};
Settings editSettings{};
int selectedShortcut{-1};
int creditsIndex{};
@@ -29,4 +32,4 @@ namespace anm2ed::imgui
Taskbar();
void update(Manager&, Settings&, Resources&, Dialog&, bool&);
};
};
};
+1 -18
View File
@@ -66,24 +66,7 @@ namespace anm2ed::imgui
}
}
void Toasts::info(const std::string& message)
{
toasts.emplace_back(Toast(message));
logger.info(message);
}
void Toasts::error(const std::string& message)
{
toasts.emplace_back(Toast(message));
logger.error(message);
}
void Toasts::warning(const std::string& message)
{
toasts.emplace_back(Toast(message));
logger.warning(message);
}
void Toasts::push(const std::string& message) { toasts.emplace_back(Toast(message)); }
}
anm2ed::imgui::Toasts toasts;
+1 -3
View File
@@ -20,9 +20,7 @@ namespace anm2ed::imgui
std::vector<Toast> toasts{};
void update();
void info(const std::string&);
void error(const std::string&);
void warning(const std::string&);
void push(const std::string&);
};
}
+98 -61
View File
@@ -2,6 +2,7 @@
#include <algorithm>
#include <filesystem>
#include <format>
#include <optional>
#include <ranges>
@@ -10,6 +11,7 @@
#include "imgui_.h"
#include "log.h"
#include "math_.h"
#include "strings.h"
#include "toast.h"
#include "tool.h"
#include "types.h"
@@ -69,9 +71,18 @@ namespace anm2ed::imgui
}
if (isSuccess)
toasts.info(std::format("Exported rendered frames to: {}", path));
{
toasts.push(std::vformat(localize.get(TOAST_EXPORT_RENDERED_FRAMES), std::make_format_args(path)));
logger.info(std::vformat(localize.get(TOAST_EXPORT_RENDERED_FRAMES, anm2ed::ENGLISH),
std::make_format_args(path)));
}
else
toasts.warning(std::format("Could not export frames to: {}", path));
{
toasts.push(std::vformat(localize.get(TOAST_EXPORT_RENDERED_FRAMES_FAILED),
std::make_format_args(path)));
logger.error(std::vformat(localize.get(TOAST_EXPORT_RENDERED_FRAMES_FAILED, anm2ed::ENGLISH),
std::make_format_args(path)));
}
}
else if (type == render::SPRITESHEET)
{
@@ -79,12 +90,18 @@ namespace anm2ed::imgui
auto& columns = settings.renderColumns;
if (renderFrames.empty())
toasts.warning("No frames captured for spritesheet export.");
{
toasts.push(localize.get(TOAST_SPRITESHEET_NO_FRAMES));
logger.warning(localize.get(TOAST_SPRITESHEET_NO_FRAMES, anm2ed::ENGLISH));
}
else
{
const auto& firstFrame = renderFrames.front();
auto& firstFrame = renderFrames.front();
if (firstFrame.size.x <= 0 || firstFrame.size.y <= 0 || firstFrame.pixels.empty())
toasts.warning("Spritesheet export failed: captured frames are empty.");
{
toasts.push(localize.get(TOAST_SPRITESHEET_EMPTY));
logger.error(localize.get(TOAST_SPRITESHEET_EMPTY, anm2ed::ENGLISH));
}
else
{
auto frameWidth = firstFrame.size.x;
@@ -113,18 +130,36 @@ namespace anm2ed::imgui
Texture spritesheetTexture(spritesheet.data(), spritesheetSize);
if (spritesheetTexture.write_png(path))
toasts.info(std::format("Exported spritesheet to: {}", path));
{
toasts.push(std::vformat(localize.get(TOAST_EXPORT_SPRITESHEET), std::make_format_args(path)));
logger.info(std::vformat(localize.get(TOAST_EXPORT_SPRITESHEET, anm2ed::ENGLISH),
std::make_format_args(path)));
}
else
toasts.warning(std::format("Could not export spritesheet to: {}", path));
{
toasts.push(std::vformat(localize.get(TOAST_EXPORT_SPRITESHEET_FAILED),
std::make_format_args(path)));
logger.error(std::vformat(localize.get(TOAST_EXPORT_SPRITESHEET_FAILED, anm2ed::ENGLISH),
std::make_format_args(path)));
}
}
}
}
else
{
if (animation_render(ffmpegPath, path, renderFrames, audioStream, (render::Type)type, size, anm2.info.fps))
toasts.info(std::format("Exported rendered animation to: {}", path));
{
toasts.push(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION), std::make_format_args(path)));
logger.info(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION, anm2ed::ENGLISH),
std::make_format_args(path)));
}
else
toasts.warning(std::format("Could not output rendered animation: {}", path));
{
toasts.push(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED),
std::make_format_args(path)));
logger.error(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED, anm2ed::ENGLISH),
std::make_format_args(path)));
}
}
renderFrames.clear();
@@ -242,24 +277,24 @@ namespace anm2ed::imgui
auto center_view = [&]() { pan = vec2(); };
if (ImGui::Begin("Animation Preview", &settings.windowIsAnimationPreview))
if (ImGui::Begin(localize.get(LABEL_ANIMATION_PREVIEW_WINDOW), &settings.windowIsAnimationPreview))
{
auto childSize = ImVec2(row_widget_width_get(4),
(ImGui::GetTextLineHeightWithSpacing() * 4) + (ImGui::GetStyle().WindowPadding.y * 2));
if (ImGui::BeginChild("##Grid Child", childSize, true, ImGuiWindowFlags_HorizontalScrollbar))
{
ImGui::Checkbox("Grid", &isGrid);
ImGui::SetItemTooltip("Toggle the visibility of the grid.");
ImGui::Checkbox(localize.get(BASIC_GRID), &isGrid);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_GRID_VISIBILITY));
ImGui::SameLine();
ImGui::ColorEdit4("Color", value_ptr(gridColor), ImGuiColorEditFlags_NoInputs);
ImGui::SetItemTooltip("Change the grid's color.");
ImGui::ColorEdit4(localize.get(BASIC_COLOR), value_ptr(gridColor), ImGuiColorEditFlags_NoInputs);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_GRID_COLOR));
input_int2_range("Size", gridSize, ivec2(GRID_SIZE_MIN), ivec2(GRID_SIZE_MAX));
ImGui::SetItemTooltip("Change the size of all cells in the grid.");
input_int2_range(localize.get(BASIC_SIZE), gridSize, ivec2(GRID_SIZE_MIN), ivec2(GRID_SIZE_MAX));
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_GRID_SIZE));
input_int2_range("Offset", gridOffset, ivec2(GRID_OFFSET_MIN), ivec2(GRID_OFFSET_MAX));
ImGui::SetItemTooltip("Change the offset of the grid.");
input_int2_range(localize.get(BASIC_OFFSET), gridOffset, ivec2(GRID_OFFSET_MIN), ivec2(GRID_OFFSET_MAX));
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_GRID_OFFSET));
}
ImGui::EndChild();
@@ -267,23 +302,26 @@ namespace anm2ed::imgui
if (ImGui::BeginChild("##View Child", childSize, true, ImGuiWindowFlags_HorizontalScrollbar))
{
ImGui::InputFloat("Zoom", &zoom, zoomStep, zoomStep, "%.0f%%");
ImGui::SetItemTooltip("Change the zoom of the preview.");
ImGui::InputFloat(localize.get(BASIC_ZOOM), &zoom, zoomStep, zoomStep, "%.0f%%");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_PREVIEW_ZOOM));
auto widgetSize = widget_size_with_row_get(2);
shortcut(manager.chords[SHORTCUT_CENTER_VIEW]);
if (ImGui::Button("Center View", widgetSize)) pan = vec2();
set_item_tooltip_shortcut("Centers the view.", settings.shortcutCenterView);
if (ImGui::Button(localize.get(LABEL_CENTER_VIEW), widgetSize)) pan = vec2();
set_item_tooltip_shortcut(localize.get(TOOLTIP_CENTER_VIEW), settings.shortcutCenterView);
ImGui::SameLine();
shortcut(manager.chords[SHORTCUT_FIT]);
if (ImGui::Button("Fit", widgetSize))
if (ImGui::Button(localize.get(LABEL_FIT), widgetSize))
if (animation) set_to_rect(zoom, pan, animation->rect(isRootTransform));
set_item_tooltip_shortcut("Set the view to match the extent of the animation.", settings.shortcutFit);
set_item_tooltip_shortcut(localize.get(TOOLTIP_FIT), settings.shortcutFit);
ImGui::TextUnformatted(std::format(POSITION_FORMAT, (int)mousePos.x, (int)mousePos.y).c_str());
auto mousePosInt = ivec2(mousePos);
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_POSITION_SPACED), std::make_format_args(mousePosInt.x, mousePosInt.y))
.c_str());
}
ImGui::EndChild();
@@ -291,20 +329,21 @@ namespace anm2ed::imgui
if (ImGui::BeginChild("##Background Child", childSize, true, ImGuiWindowFlags_HorizontalScrollbar))
{
ImGui::ColorEdit3("Background", value_ptr(backgroundColor), ImGuiColorEditFlags_NoInputs);
ImGui::SetItemTooltip("Change the background color.");
ImGui::ColorEdit3(localize.get(LABEL_BACKGROUND_COLOR), value_ptr(backgroundColor),
ImGuiColorEditFlags_NoInputs);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_BACKGROUND_COLOR));
ImGui::SameLine();
ImGui::Checkbox("Axes", &isAxes);
ImGui::SetItemTooltip("Toggle the axes' visbility.");
ImGui::Checkbox(localize.get(LABEL_AXES), &isAxes);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_AXES));
ImGui::SameLine();
ImGui::ColorEdit4("Color", value_ptr(axesColor), ImGuiColorEditFlags_NoInputs);
ImGui::SetItemTooltip("Set the color of the axes.");
ImGui::ColorEdit4(localize.get(BASIC_COLOR), value_ptr(axesColor), ImGuiColorEditFlags_NoInputs);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_AXES_COLOR));
combo_negative_one_indexed("Overlay", &overlayIndex, document.animation.labels);
ImGui::SetItemTooltip("Set an animation to be drawn over the current animation.");
combo_negative_one_indexed(localize.get(LABEL_OVERLAY), &overlayIndex, document.animation.labels);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_OVERLAY));
ImGui::InputFloat("Alpha", &overlayTransparency, 0, 0, "%.0f");
ImGui::SetItemTooltip("Set the alpha of the overlayed animation.");
ImGui::InputFloat(localize.get(BASIC_ALPHA), &overlayTransparency, 0, 0, "%.0f");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_OVERLAY_ALPHA));
}
ImGui::EndChild();
@@ -316,10 +355,10 @@ namespace anm2ed::imgui
if (ImGui::BeginChild("##Helpers Child 1", helpersChildSize))
{
ImGui::Checkbox("Root Transform", &isRootTransform);
ImGui::SetItemTooltip("Root frames will transform the rest of the animation.");
ImGui::Checkbox("Pivots", &isPivots);
ImGui::SetItemTooltip("Toggle the visibility of the animation's pivots.");
ImGui::Checkbox(localize.get(LABEL_ROOT_TRANSFORM), &isRootTransform);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ROOT_TRANSFORM));
ImGui::Checkbox(localize.get(LABEL_PIVOTS), &isPivots);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_PIVOTS));
}
ImGui::EndChild();
@@ -327,10 +366,10 @@ namespace anm2ed::imgui
if (ImGui::BeginChild("##Helpers Child 2", helpersChildSize))
{
ImGui::Checkbox("Alt Icons", &isAltIcons);
ImGui::SetItemTooltip("Toggle a different appearance of the target icons.");
ImGui::Checkbox("Border", &isBorder);
ImGui::SetItemTooltip("Toggle the visibility of borders around layers.");
ImGui::Checkbox(localize.get(LABEL_ALT_ICONS), &isAltIcons);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ALT_ICONS));
ImGui::Checkbox(localize.get(LABEL_BORDER), &isBorder);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_BORDER));
}
ImGui::EndChild();
}
@@ -592,12 +631,11 @@ namespace anm2ed::imgui
{
auto layeredOnions = settings.onionskinIsEnabled ? &onionskinSamples : nullptr;
render(animation, frameTime, {}, 0.0f, layeredOnions,
settings.onionskinMode == static_cast<int>(OnionskinMode::INDEX));
render(animation, frameTime, {}, 0.0f, layeredOnions, settings.onionskinMode == (int)OnionskinMode::INDEX);
if (auto overlayAnimation = anm2.animation_get(overlayIndex))
render(overlayAnimation, frameTime, {}, 1.0f - math::uint8_to_float(overlayTransparency), layeredOnions,
settings.onionskinMode == static_cast<int>(OnionskinMode::INDEX));
settings.onionskinMode == (int)OnionskinMode::INDEX);
}
unbind();
@@ -692,7 +730,7 @@ namespace anm2ed::imgui
if (!frame) break;
if (isBegin)
{
document.snapshot("Frame Position");
document.snapshot(localize.get(EDIT_FRAME_POSITION));
if (isMouseClicked)
{
moveOffset = settings.inputIsMoveToolSnapToMouse ? vec2() : mousePos - frame->position;
@@ -710,16 +748,16 @@ namespace anm2ed::imgui
{
if (ImGui::BeginTooltip())
{
auto positionFormat = math::vec2_format_get(frame->position);
auto positionString = std::format("Position: ({}, {})", positionFormat, positionFormat);
ImGui::Text(positionString.c_str(), frame->position.x, frame->position.y);
ImGui::TextUnformatted(std::vformat(localize.get(FORMAT_POSITION),
std::make_format_args(frame->position.x, frame->position.y))
.c_str());
ImGui::EndTooltip();
}
}
break;
case tool::SCALE:
if (!frame) break;
if (isBegin) document.snapshot("Frame Scale");
if (isBegin) document.snapshot(localize.get(EDIT_FRAME_SCALE));
if (isMouseDown)
{
frame->scale += vec2(mouseDelta.x, mouseDelta.y);
@@ -734,9 +772,9 @@ namespace anm2ed::imgui
{
if (ImGui::BeginTooltip())
{
auto scaleFormat = math::vec2_format_get(frame->scale);
auto scaleString = std::format("Scale: ({}, {})", scaleFormat, scaleFormat);
ImGui::Text(scaleString.c_str(), frame->scale.x, frame->scale.y);
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_SCALE), std::make_format_args(frame->scale.x, frame->scale.y))
.c_str());
ImGui::EndTooltip();
}
}
@@ -745,7 +783,7 @@ namespace anm2ed::imgui
break;
case tool::ROTATE:
if (!frame) break;
if (isBegin) document.snapshot("Frame Rotation");
if (isBegin) document.snapshot(localize.get(EDIT_FRAME_ROTATION));
if (isMouseDown) frame->rotation += mouseDelta.y;
if (isLeftPressed || isDownPressed) frame->rotation -= step;
if (isUpPressed || isRightPressed) frame->rotation += step;
@@ -754,9 +792,8 @@ namespace anm2ed::imgui
{
if (ImGui::BeginTooltip())
{
auto rotationFormat = math::float_format_get(frame->rotation);
auto rotationString = std::format("Rotation: {}", rotationFormat);
ImGui::Text(rotationString.c_str(), frame->rotation);
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_ROTATION), std::make_format_args(frame->rotation)).c_str());
ImGui::EndTooltip();
}
}
@@ -779,7 +816,7 @@ namespace anm2ed::imgui
manager.progressPopup.trigger();
if (ImGui::BeginPopupModal(manager.progressPopup.label, &manager.progressPopup.isOpen, ImGuiWindowFlags_NoResize))
if (ImGui::BeginPopupModal(manager.progressPopup.label(), &manager.progressPopup.isOpen, ImGuiWindowFlags_NoResize))
{
if (!animation) return;
@@ -789,9 +826,9 @@ namespace anm2ed::imgui
ImGui::ProgressBar(progress);
ImGui::Text("Once recording is complete, rendering may take some time.\nPlease be patient...");
ImGui::TextUnformatted(localize.get(TEXT_RECORDING_PROGRESS));
if (ImGui::Button("Cancel", ImVec2(ImGui::GetContentRegionAvail().x, 0)))
if (ImGui::Button(localize.get(BASIC_CANCEL), ImVec2(ImGui::GetContentRegionAvail().x, 0)))
{
renderFrames.clear();
+70 -46
View File
@@ -1,8 +1,11 @@
#include "animations.h"
#include <cstddef>
#include <format>
#include <ranges>
#include "log.h"
#include "strings.h"
#include "toast.h"
#include "vector_.h"
@@ -40,7 +43,7 @@ namespace anm2ed::imgui
}
};
if (ImGui::Begin("Animations", &settings.windowIsAnimations))
if (ImGui::Begin(localize.get(LABEL_ANIMATIONS_WINDOW), &settings.windowIsAnimations))
{
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && ImGui::IsKeyPressed(ImGuiKey_Escape))
reference = {};
@@ -75,7 +78,7 @@ namespace anm2ed::imgui
document.frames.clear();
if (renameState == RENAME_BEGIN)
document.snapshot("Rename Animation");
document.snapshot(localize.get(SNAPSHOT_RENAME_ANIMATION));
else if (renameState == RENAME_FINISHED)
{
if (anm2.animations.items.size() == 1) anm2.animations.defaultAnimation = animation.name;
@@ -97,10 +100,17 @@ namespace anm2ed::imgui
ImGui::TextUnformatted(animation.name.c_str());
ImGui::PopFont();
if (isDefault) ImGui::TextUnformatted("(Default Animation)");
if (isDefault)
{
ImGui::PushFont(resources.fonts[font::ITALICS].get(), font::SIZE);
ImGui::TextUnformatted(localize.get(BASIC_DEFAULT));
ImGui::PopFont();
}
ImGui::Text("Length: %d", animation.frameNum);
ImGui::Text("Loop: %s", animation.isLoop ? "true" : "false");
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_LENGTH), std::make_format_args(animation.frameNum)).c_str());
auto loopLabel = animation.isLoop ? localize.get(BASIC_YES) : localize.get(BASIC_NO);
ImGui::TextUnformatted(std::vformat(localize.get(FORMAT_LOOP), std::make_format_args(loopLabel)).c_str());
ImGui::EndTooltip();
}
@@ -124,7 +134,7 @@ namespace anm2ed::imgui
auto payloadCount = payload->DataSize / sizeof(int);
std::vector<int> indices(payloadIndices, payloadIndices + payloadCount);
std::sort(indices.begin(), indices.end());
DOCUMENT_EDIT(document, "Move Animation(s)", Document::ANIMATIONS,
DOCUMENT_EDIT(document, localize.get(EDIT_MOVE_ANIMATIONS), Document::ANIMATIONS,
selection = vector::move_indices(anm2.animations.items, indices, i));
}
ImGui::EndDragDropTarget();
@@ -151,7 +161,7 @@ namespace anm2ed::imgui
auto cut = [&]()
{
copy();
DOCUMENT_EDIT(document, "Cut Animation(s)", Document::ANIMATIONS, animations_remove());
DOCUMENT_EDIT(document, localize.get(EDIT_CUT_ANIMATIONS), Document::ANIMATIONS, animations_remove());
};
auto paste = [&]()
@@ -163,13 +173,18 @@ namespace anm2ed::imgui
auto start = selection.empty() ? anm2.animations.items.size() : *selection.rbegin() + 1;
std::set<int> indices{};
std::string errorString{};
if (anm2.animations_deserialize(clipboardText, start, indices, &errorString))
selection = indices;
else
toasts.error(std::format("Failed to deserialize animation(s): {}", errorString));
if (anm2.animations_deserialize(clipboardText, start, indices, &errorString))
selection = indices;
else
{
toasts.push(std::vformat(localize.get(TOAST_DESERIALIZE_ANIMATIONS_FAILED),
std::make_format_args(errorString)));
logger.error(std::vformat(localize.get(TOAST_DESERIALIZE_ANIMATIONS_FAILED, anm2ed::ENGLISH),
std::make_format_args(errorString)));
}
};
DOCUMENT_EDIT(document, "Paste Animation(s)", Document::ANIMATIONS, deserialize());
DOCUMENT_EDIT(document, localize.get(EDIT_PASTE_ANIMATIONS), Document::ANIMATIONS, deserialize());
};
if (shortcut(manager.chords[SHORTCUT_CUT], shortcut::FOCUSED)) cut();
@@ -178,9 +193,20 @@ namespace anm2ed::imgui
if (ImGui::BeginPopupContextWindow("##Context Menu", ImGuiPopupFlags_MouseButtonRight))
{
if (ImGui::MenuItem("Cut", settings.shortcutCut.c_str(), false, !selection.empty() || hovered > -1)) cut();
if (ImGui::MenuItem("Copy", settings.shortcutCopy.c_str(), false, !selection.empty() || hovered > -1)) copy();
if (ImGui::MenuItem("Paste", settings.shortcutPaste.c_str(), false, !clipboard.is_empty())) paste();
if (ImGui::MenuItem(localize.get(BASIC_CUT), settings.shortcutCut.c_str(), false,
!selection.empty() || hovered > -1))
{
cut();
}
if (ImGui::MenuItem(localize.get(BASIC_COPY), settings.shortcutCopy.c_str(), false,
!selection.empty() || hovered > -1))
{
copy();
}
if (ImGui::MenuItem(localize.get(BASIC_PASTE), settings.shortcutPaste.c_str(), false, !clipboard.is_empty()))
{
paste();
}
ImGui::EndPopup();
}
}
@@ -189,7 +215,7 @@ namespace anm2ed::imgui
auto widgetSize = widget_size_with_row_get(5);
shortcut(manager.chords[SHORTCUT_ADD]);
if (ImGui::Button("Add", widgetSize))
if (ImGui::Button(localize.get(BASIC_ADD), widgetSize))
{
auto add = [&]()
{
@@ -219,16 +245,16 @@ namespace anm2ed::imgui
newAnimationSelectedIndex = index;
};
DOCUMENT_EDIT(document, "Add Animation", Document::ANIMATIONS, add());
DOCUMENT_EDIT(document, localize.get(EDIT_ADD_ANIMATION), Document::ANIMATIONS, add());
}
set_item_tooltip_shortcut("Add a new animation.", settings.shortcutAdd);
set_item_tooltip_shortcut(localize.get(TOOLTIP_ADD_ANIMATION), settings.shortcutAdd);
ImGui::SameLine();
ImGui::BeginDisabled(selection.empty());
{
shortcut(manager.chords[SHORTCUT_DUPLICATE]);
if (ImGui::Button("Duplicate", widgetSize))
if (ImGui::Button(localize.get(BASIC_DUPLICATE), widgetSize))
{
auto duplicate = [&]()
{
@@ -242,9 +268,9 @@ namespace anm2ed::imgui
}
};
DOCUMENT_EDIT(document, "Duplicate Animation(s)", Document::ANIMATIONS, duplicate());
DOCUMENT_EDIT(document, localize.get(EDIT_DUPLICATE_ANIMATIONS), Document::ANIMATIONS, duplicate());
}
set_item_tooltip_shortcut("Duplicate the selected animation(s).", settings.shortcutDuplicate);
set_item_tooltip_shortcut(localize.get(TOOLTIP_DUPLICATE_ANIMATION), settings.shortcutDuplicate);
ImGui::SameLine();
@@ -274,12 +300,12 @@ namespace anm2ed::imgui
reference = {merged};
};
DOCUMENT_EDIT(document, "Merge Animations", Document::ANIMATIONS, merge_quick())
DOCUMENT_EDIT(document, localize.get(EDIT_MERGE_ANIMATIONS), Document::ANIMATIONS, merge_quick())
}
ImGui::BeginDisabled(selection.size() != 1);
{
if (ImGui::Button("Merge", widgetSize))
if (ImGui::Button(localize.get(LABEL_MERGE), widgetSize))
{
mergePopup.open();
mergeSelection.clear();
@@ -287,34 +313,32 @@ namespace anm2ed::imgui
}
}
ImGui::EndDisabled();
set_item_tooltip_shortcut("Open the merge popup.\nUsing the shortcut will merge the animations with\nthe last "
"configured merge settings.",
settings.shortcutMerge);
set_item_tooltip_shortcut(localize.get(TOOLTIP_OPEN_MERGE_POPUP), settings.shortcutMerge);
ImGui::SameLine();
shortcut(manager.chords[SHORTCUT_REMOVE]);
if (ImGui::Button("Remove", widgetSize))
DOCUMENT_EDIT(document, "Remove Animation(s)", Document::ANIMATIONS, animations_remove());
set_item_tooltip_shortcut("Remove the selected animation(s).", settings.shortcutRemove);
if (ImGui::Button(localize.get(BASIC_REMOVE), widgetSize))
DOCUMENT_EDIT(document, localize.get(EDIT_REMOVE_ANIMATIONS), Document::ANIMATIONS, animations_remove());
set_item_tooltip_shortcut(localize.get(TOOLTIP_REMOVE_ANIMATION), settings.shortcutRemove);
ImGui::SameLine();
shortcut(manager.chords[SHORTCUT_DEFAULT]);
ImGui::BeginDisabled(selection.size() != 1);
if (ImGui::Button("Default", widgetSize))
if (ImGui::Button(localize.get(BASIC_DEFAULT), widgetSize))
{
DOCUMENT_EDIT(document, "Default Animation", Document::ANIMATIONS,
DOCUMENT_EDIT(document, localize.get(EDIT_DEFAULT_ANIMATION), Document::ANIMATIONS,
anm2.animations.defaultAnimation = anm2.animations.items[*selection.begin()].name);
}
ImGui::EndDisabled();
set_item_tooltip_shortcut("Set the selected animation as the default.", settings.shortcutDefault);
set_item_tooltip_shortcut(localize.get(TOOLTIP_SET_DEFAULT_ANIMATION), settings.shortcutDefault);
}
ImGui::EndDisabled();
mergePopup.trigger();
if (ImGui::BeginPopupModal(mergePopup.label, &mergePopup.isOpen, ImGuiWindowFlags_NoResize))
if (ImGui::BeginPopupModal(mergePopup.label(), &mergePopup.isOpen, ImGuiWindowFlags_NoResize))
{
auto merge_close = [&]()
{
@@ -332,7 +356,7 @@ namespace anm2ed::imgui
ImVec2(0, ImGui::GetContentRegionAvail().y -
(optionsSize.y + deleteAfterSize.y + footerSize.y + ImGui::GetStyle().ItemSpacing.y * 3));
if (ImGui::BeginChild("Animations", animationsSize, ImGuiChildFlags_Borders))
if (ImGui::BeginChild(localize.get(LABEL_ANIMATIONS_CHILD), animationsSize, ImGuiChildFlags_Borders))
{
mergeSelection.start(anm2.animations.items.size());
@@ -354,37 +378,37 @@ namespace anm2ed::imgui
}
ImGui::EndChild();
if (ImGui::BeginChild("Merge Options", optionsSize, ImGuiChildFlags_Borders))
if (ImGui::BeginChild("##Merge Options", optionsSize, ImGuiChildFlags_Borders))
{
auto size = ImVec2(optionsSize.x * 0.5f, optionsSize.y - ImGui::GetStyle().WindowPadding.y * 2);
if (ImGui::BeginChild("Merge Options 1", size))
if (ImGui::BeginChild("##Merge Options 1", size))
{
ImGui::RadioButton("Append Frames", &type, merge::APPEND);
ImGui::RadioButton("Prepend Frames", &type, merge::PREPEND);
ImGui::RadioButton(localize.get(LABEL_APPEND_FRAMES), &type, merge::APPEND);
ImGui::RadioButton(localize.get(LABEL_PREPEND_FRAMES), &type, merge::PREPEND);
}
ImGui::EndChild();
ImGui::SameLine();
if (ImGui::BeginChild("Merge Options 2", size))
if (ImGui::BeginChild("##Merge Options 2", size))
{
ImGui::RadioButton("Replace Frames", &type, merge::REPLACE);
ImGui::RadioButton("Ignore Frames", &type, merge::IGNORE);
ImGui::RadioButton(localize.get(LABEL_REPLACE_FRAMES), &type, merge::REPLACE);
ImGui::RadioButton(localize.get(LABEL_IGNORE_FRAMES), &type, merge::IGNORE);
}
ImGui::EndChild();
}
ImGui::EndChild();
if (ImGui::BeginChild("Merge Delete After", deleteAfterSize, ImGuiChildFlags_Borders))
ImGui::Checkbox("Delete Animations After", &isDeleteAnimationsAfter);
if (ImGui::BeginChild("##Merge Delete After", deleteAfterSize, ImGuiChildFlags_Borders))
ImGui::Checkbox(localize.get(LABEL_DELETE_ANIMATIONS_AFTER), &isDeleteAnimationsAfter);
ImGui::EndChild();
auto widgetSize = widget_size_with_row_get(2);
ImGui::BeginDisabled(mergeSelection.empty());
{
if (ImGui::Button("Merge", widgetSize))
if (ImGui::Button(localize.get(LABEL_MERGE), widgetSize))
{
auto merge = [&]()
{
@@ -396,13 +420,13 @@ namespace anm2ed::imgui
reference = {merged};
};
DOCUMENT_EDIT(document, "Merge Animations", Document::ANIMATIONS, merge());
DOCUMENT_EDIT(document, localize.get(EDIT_MERGE_ANIMATIONS), Document::ANIMATIONS, merge());
merge_close();
}
}
ImGui::EndDisabled();
ImGui::SameLine();
if (ImGui::Button("Close", widgetSize)) merge_close();
if (ImGui::Button(localize.get(LABEL_CLOSE), widgetSize)) merge_close();
ImGui::EndPopup();
}
+2 -1
View File
@@ -4,12 +4,13 @@
#include "manager.h"
#include "resources.h"
#include "settings.h"
#include "strings.h"
namespace anm2ed::imgui
{
class Animations
{
PopupHelper mergePopup{PopupHelper("Merge Animations")};
PopupHelper mergePopup{PopupHelper(LABEL_ANIMATIONS_MERGE_POPUP)};
int newAnimationSelectedIndex{-1};
RenameState renameState{RENAME_SELECTABLE};
+25 -16
View File
@@ -2,7 +2,9 @@
#include <ranges>
#include "log.h"
#include "map_.h"
#include "strings.h"
#include "toast.h"
using namespace anm2ed::util;
@@ -22,7 +24,7 @@ namespace anm2ed::imgui
hovered = -1;
if (ImGui::Begin("Events", &settings.windowIsEvents))
if (ImGui::Begin(localize.get(LABEL_EVENTS_WINDOW), &settings.windowIsEvents))
{
auto childSize = size_without_footer_get();
@@ -41,7 +43,7 @@ namespace anm2ed::imgui
event.name, selection.contains(id), ImGuiSelectableFlags_None, renameState))
{
if (renameState == RENAME_BEGIN)
document.snapshot("Rename Event");
document.snapshot(localize.get(EDIT_RENAME_EVENT));
else if (renameState == RENAME_FINISHED)
document.change(Document::EVENTS);
}
@@ -58,6 +60,7 @@ namespace anm2ed::imgui
ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE);
ImGui::TextUnformatted(event.name.c_str());
ImGui::PopFont();
ImGui::TextUnformatted(std::vformat(localize.get(FORMAT_ID), std::make_format_args(id)).c_str());
ImGui::EndTooltip();
}
ImGui::PopID();
@@ -81,11 +84,16 @@ namespace anm2ed::imgui
auto paste = [&](merge::Type type)
{
std::string errorString{};
document.snapshot("Paste Event(s)");
document.snapshot(localize.get(EDIT_PASTE_EVENTS));
if (anm2.events_deserialize(clipboard.get(), type, &errorString))
document.change(Document::EVENTS);
else
toasts.error(std::format("Failed to deserialize event(s): {}", errorString));
{
toasts.push(std::vformat(localize.get(TOAST_DESERIALIZE_EVENTS_FAILED),
std::make_format_args(errorString)));
logger.error(std::vformat(localize.get(TOAST_DESERIALIZE_EVENTS_FAILED, anm2ed::ENGLISH),
std::make_format_args(errorString)));
}
};
if (shortcut(manager.chords[SHORTCUT_COPY], shortcut::FOCUSED)) copy();
@@ -93,13 +101,15 @@ namespace anm2ed::imgui
if (ImGui::BeginPopupContextWindow("##Context Menu", ImGuiPopupFlags_MouseButtonRight))
{
ImGui::MenuItem("Cut", settings.shortcutCut.c_str(), false, false);
if (ImGui::MenuItem("Copy", settings.shortcutCopy.c_str(), false, !selection.empty() || hovered > -1)) copy();
ImGui::MenuItem(localize.get(BASIC_CUT), settings.shortcutCut.c_str(), false, false);
if (ImGui::MenuItem(localize.get(BASIC_COPY), settings.shortcutCopy.c_str(), false,
!selection.empty() || hovered > -1))
copy();
if (ImGui::BeginMenu("Paste", !clipboard.is_empty()))
if (ImGui::BeginMenu(localize.get(BASIC_PASTE), !clipboard.is_empty()))
{
if (ImGui::MenuItem("Append", settings.shortcutPaste.c_str())) paste(merge::APPEND);
if (ImGui::MenuItem("Replace")) paste(merge::REPLACE);
if (ImGui::MenuItem(localize.get(BASIC_APPEND), settings.shortcutPaste.c_str())) paste(merge::APPEND);
if (ImGui::MenuItem(localize.get(BASIC_REPLACE))) paste(merge::REPLACE);
ImGui::EndMenu();
}
@@ -112,7 +122,7 @@ namespace anm2ed::imgui
auto widgetSize = widget_size_with_row_get(2);
shortcut(manager.chords[SHORTCUT_ADD]);
if (ImGui::Button("Add", widgetSize))
if (ImGui::Button(localize.get(BASIC_ADD), widgetSize))
{
auto add = [&]()
{
@@ -123,14 +133,14 @@ namespace anm2ed::imgui
newEventId = id;
};
DOCUMENT_EDIT(document, "Add Event", Document::EVENTS, add());
DOCUMENT_EDIT(document, localize.get(EDIT_ADD_EVENT), Document::EVENTS, add());
}
set_item_tooltip_shortcut("Add an event.", settings.shortcutAdd);
set_item_tooltip_shortcut(localize.get(TOOLTIP_ADD_EVENT), settings.shortcutAdd);
ImGui::SameLine();
shortcut(manager.chords[SHORTCUT_REMOVE]);
ImGui::BeginDisabled(unused.empty());
if (ImGui::Button("Remove Unused", widgetSize))
if (ImGui::Button(localize.get(BASIC_REMOVE_UNUSED), widgetSize))
{
auto remove_unused = [&]()
{
@@ -139,11 +149,10 @@ namespace anm2ed::imgui
unused.clear();
};
DOCUMENT_EDIT(document, "Remove Unused Events", Document::EVENTS, remove_unused());
DOCUMENT_EDIT(document, localize.get(EDIT_REMOVE_UNUSED_EVENTS), Document::EVENTS, remove_unused());
}
ImGui::EndDisabled();
set_item_tooltip_shortcut("Remove unused events (i.e., ones not used by any trigger in any animation.)",
settings.shortcutRemove);
set_item_tooltip_shortcut(localize.get(TOOLTIP_REMOVE_UNUSED_EVENTS), settings.shortcutRemove);
}
ImGui::End();
}
+95 -80
View File
@@ -3,6 +3,7 @@
#include <glm/gtc/type_ptr.hpp>
#include "math_.h"
#include "strings.h"
#include "types.h"
using namespace anm2ed::util::math;
@@ -13,7 +14,7 @@ namespace anm2ed::imgui
{
void FrameProperties::update(Manager& manager, Settings& settings)
{
if (ImGui::Begin("Frame Properties", &settings.windowIsFrameProperties))
if (ImGui::Begin(localize.get(LABEL_FRAME_PROPERTIES_WINDOW), &settings.windowIsFrameProperties))
{
auto& document = *manager.get();
auto& frames = document.frames.selection;
@@ -28,103 +29,117 @@ namespace anm2ed::imgui
{
if (type == anm2::TRIGGER)
{
if (combo_negative_one_indexed("Event", frame ? &useFrame.eventID : &dummy_value_negative<int>(),
if (combo_negative_one_indexed(localize.get(BASIC_EVENT),
frame ? &useFrame.eventID : &dummy_value_negative<int>(),
document.event.labels))
DOCUMENT_EDIT(document, "Trigger Event", Document::FRAMES, frame->eventID = useFrame.eventID);
ImGui::SetItemTooltip("Change the event this trigger uses.");
DOCUMENT_EDIT(document, localize.get(EDIT_TRIGGER_EVENT), Document::FRAMES,
frame->eventID = useFrame.eventID);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_TRIGGER_EVENT));
if (combo_negative_one_indexed("Sound", frame ? &useFrame.soundID : &dummy_value_negative<int>(),
if (combo_negative_one_indexed(localize.get(BASIC_SOUND),
frame ? &useFrame.soundID : &dummy_value_negative<int>(),
document.sound.labels))
DOCUMENT_EDIT(document, "Trigger Sound", Document::FRAMES, frame->soundID = useFrame.soundID);
ImGui::SetItemTooltip("Change the sound this trigger uses.");
DOCUMENT_EDIT(document, localize.get(EDIT_TRIGGER_SOUND), Document::FRAMES,
frame->soundID = useFrame.soundID);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_TRIGGER_SOUND));
if (ImGui::InputInt("At Frame", frame ? &useFrame.atFrame : &dummy_value<int>(), STEP, STEP_FAST,
!frame ? ImGuiInputTextFlags_DisplayEmptyRefVal : 0))
DOCUMENT_EDIT(document, "Trigger At Frame", Document::FRAMES, frame->atFrame = useFrame.atFrame);
ImGui::SetItemTooltip("Change the frame the trigger will be activated at.");
if (ImGui::InputInt(localize.get(BASIC_AT_FRAME), frame ? &useFrame.atFrame : &dummy_value<int>(), STEP,
STEP_FAST, !frame ? ImGuiInputTextFlags_DisplayEmptyRefVal : 0))
DOCUMENT_EDIT(document, localize.get(EDIT_TRIGGER_AT_FRAME), Document::FRAMES,
frame->atFrame = useFrame.atFrame);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_TRIGGER_AT_FRAME));
if (ImGui::Checkbox("Visible", frame ? &useFrame.isVisible : &dummy_value<bool>()))
DOCUMENT_EDIT(document, "Trigger Visibility", Document::FRAMES, frame->isVisible = useFrame.isVisible);
ImGui::SetItemTooltip("Toggle the trigger's visibility.");
if (ImGui::Checkbox(localize.get(BASIC_VISIBLE), frame ? &useFrame.isVisible : &dummy_value<bool>()))
DOCUMENT_EDIT(document, localize.get(EDIT_TRIGGER_VISIBILITY), Document::FRAMES,
frame->isVisible = useFrame.isVisible);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_TRIGGER_VISIBILITY));
}
else
{
ImGui::BeginDisabled(type == anm2::ROOT || type == anm2::NULL_);
{
if (ImGui::InputFloat2("Crop", frame ? value_ptr(useFrame.crop) : &dummy_value<float>(),
if (ImGui::InputFloat2(localize.get(BASIC_CROP), frame ? value_ptr(useFrame.crop) : &dummy_value<float>(),
frame ? vec2_format_get(useFrame.crop) : ""))
DOCUMENT_EDIT(document, "Frame Crop", Document::FRAMES, frame->crop = useFrame.crop);
ImGui::SetItemTooltip("Change the crop position the frame uses.");
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_CROP), Document::FRAMES, frame->crop = useFrame.crop);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_CROP));
if (ImGui::InputFloat2("Size", frame ? value_ptr(useFrame.size) : &dummy_value<float>(),
if (ImGui::InputFloat2(localize.get(BASIC_SIZE), frame ? value_ptr(useFrame.size) : &dummy_value<float>(),
frame ? vec2_format_get(useFrame.size) : ""))
DOCUMENT_EDIT(document, "Frame Size", Document::FRAMES, frame->size = useFrame.size);
ImGui::SetItemTooltip("Change the size of the crop the frame uses.");
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_SIZE), Document::FRAMES, frame->size = useFrame.size);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SIZE));
}
ImGui::EndDisabled();
if (ImGui::InputFloat2("Position", frame ? value_ptr(useFrame.position) : &dummy_value<float>(),
if (ImGui::InputFloat2(localize.get(BASIC_POSITION),
frame ? value_ptr(useFrame.position) : &dummy_value<float>(),
frame ? vec2_format_get(useFrame.position) : ""))
DOCUMENT_EDIT(document, "Frame Position", Document::FRAMES, frame->position = useFrame.position);
ImGui::SetItemTooltip("Change the position of the frame.");
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_POSITION), Document::FRAMES,
frame->position = useFrame.position);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_POSITION));
ImGui::BeginDisabled(type == anm2::ROOT || type == anm2::NULL_);
{
if (ImGui::InputFloat2("Pivot", frame ? value_ptr(useFrame.pivot) : &dummy_value<float>(),
if (ImGui::InputFloat2(localize.get(BASIC_PIVOT),
frame ? value_ptr(useFrame.pivot) : &dummy_value<float>(),
frame ? vec2_format_get(useFrame.pivot) : ""))
DOCUMENT_EDIT(document, "Frame Pivot", Document::FRAMES, frame->pivot = useFrame.pivot);
ImGui::SetItemTooltip("Change the pivot of the frame; i.e., where it is centered.");
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_PIVOT), Document::FRAMES,
frame->pivot = useFrame.pivot);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_PIVOT));
}
ImGui::EndDisabled();
if (ImGui::InputFloat2("Scale", frame ? value_ptr(useFrame.scale) : &dummy_value<float>(),
if (ImGui::InputFloat2(localize.get(BASIC_SCALE), frame ? value_ptr(useFrame.scale) : &dummy_value<float>(),
frame ? vec2_format_get(useFrame.scale) : ""))
DOCUMENT_EDIT(document, "Frame Scale", Document::FRAMES, frame->scale = useFrame.scale);
ImGui::SetItemTooltip("Change the scale of the frame, in percent.");
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_SCALE), Document::FRAMES, frame->scale = useFrame.scale);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SCALE));
if (ImGui::InputFloat("Rotation", frame ? &useFrame.rotation : &dummy_value<float>(), STEP, STEP_FAST,
frame ? float_format_get(useFrame.rotation) : ""))
DOCUMENT_EDIT(document, "Frame Rotation", Document::FRAMES, frame->rotation = useFrame.rotation);
ImGui::SetItemTooltip("Change the rotation of the frame.");
if (ImGui::InputFloat(localize.get(BASIC_ROTATION), frame ? &useFrame.rotation : &dummy_value<float>(),
STEP, STEP_FAST, frame ? float_format_get(useFrame.rotation) : ""))
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_ROTATION), Document::FRAMES,
frame->rotation = useFrame.rotation);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ROTATION));
if (input_int_range("Duration", frame ? useFrame.duration : dummy_value<int>(),
if (input_int_range(localize.get(BASIC_DURATION), frame ? useFrame.duration : dummy_value<int>(),
frame ? anm2::FRAME_DURATION_MIN : 0, anm2::FRAME_DURATION_MAX, STEP, STEP_FAST,
!frame ? ImGuiInputTextFlags_DisplayEmptyRefVal : 0))
DOCUMENT_EDIT(document, "Frame Duration", Document::FRAMES, frame->duration = useFrame.duration);
ImGui::SetItemTooltip("Change how long the frame lasts.");
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_DURATION), Document::FRAMES,
frame->duration = useFrame.duration);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_DURATION));
if (ImGui::ColorEdit4("Tint", frame ? value_ptr(useFrame.tint) : &dummy_value<float>()))
DOCUMENT_EDIT(document, "Frame Tint", Document::FRAMES, frame->tint = useFrame.tint);
ImGui::SetItemTooltip("Change the tint of the frame.");
if (ImGui::ColorEdit4(localize.get(BASIC_TINT), frame ? value_ptr(useFrame.tint) : &dummy_value<float>()))
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_TINT), Document::FRAMES, frame->tint = useFrame.tint);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_TINT));
if (ImGui::ColorEdit3("Color Offset", frame ? value_ptr(useFrame.colorOffset) : &dummy_value<float>()))
DOCUMENT_EDIT(document, "Frame Color Offset", Document::FRAMES,
if (ImGui::ColorEdit3(localize.get(BASIC_COLOR_OFFSET),
frame ? value_ptr(useFrame.colorOffset) : &dummy_value<float>()))
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_COLOR_OFFSET), Document::FRAMES,
frame->colorOffset = useFrame.colorOffset);
ImGui::SetItemTooltip("Change the color added onto the frame.");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_COLOR_OFFSET));
if (ImGui::Checkbox("Visible", frame ? &useFrame.isVisible : &dummy_value<bool>()))
DOCUMENT_EDIT(document, "Frame Visibility", Document::FRAMES, frame->isVisible = useFrame.isVisible);
ImGui::SetItemTooltip("Toggle the frame's visibility.");
if (ImGui::Checkbox(localize.get(BASIC_VISIBLE), frame ? &useFrame.isVisible : &dummy_value<bool>()))
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_VISIBILITY), Document::FRAMES,
frame->isVisible = useFrame.isVisible);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_FRAME_VISIBILITY));
ImGui::SameLine();
if (ImGui::Checkbox("Interpolated", frame ? &useFrame.isInterpolated : &dummy_value<bool>()))
DOCUMENT_EDIT(document, "Frame Interpolation", Document::FRAMES,
if (ImGui::Checkbox(localize.get(BASIC_INTERPOLATED),
frame ? &useFrame.isInterpolated : &dummy_value<bool>()))
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_INTERPOLATION), Document::FRAMES,
frame->isInterpolated = useFrame.isInterpolated);
ImGui::SetItemTooltip(
"Toggle the frame interpolating; i.e., blending its values into the next frame based on the time.");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_FRAME_INTERPOLATION));
auto widgetSize = widget_size_with_row_get(2);
if (ImGui::Button("Flip X", widgetSize))
DOCUMENT_EDIT(document, "Frame Flip X", Document::FRAMES, frame->scale.x = -frame->scale.x);
ImGui::SetItemTooltip("%s", "Flip the horizontal scale of the frame, to cheat mirroring the frame "
"horizontally.\n(Note: the format does not support mirroring.)");
if (ImGui::Button(localize.get(LABEL_FLIP_X), widgetSize))
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_FLIP_X), Document::FRAMES,
frame->scale.x = -frame->scale.x);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_FLIP_X));
ImGui::SameLine();
if (ImGui::Button("Flip Y", widgetSize))
DOCUMENT_EDIT(document, "Frame Flip Y", Document::FRAMES, frame->scale.y = -frame->scale.y);
ImGui::SetItemTooltip("%s", "Flip the vertical scale of the frame, to cheat mirroring the frame "
"vertically.\n(Note: the format does not support mirroring.)");
if (ImGui::Button(localize.get(LABEL_FLIP_Y), widgetSize))
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_FLIP_Y), Document::FRAMES,
frame->scale.y = -frame->scale.y);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_FLIP_Y));
}
}
ImGui::EndDisabled();
@@ -184,18 +199,18 @@ namespace anm2ed::imgui
#undef PROPERTIES_WIDGET
float2_value("##Is Crop", "Crop", isCrop, crop);
float2_value("##Is Size", "Size", isSize, size);
float2_value("##Is Position", "Position", isPosition, position);
float2_value("##Is Pivot", "Pivot", isPivot, pivot);
float2_value("##Is Scale", "Scale", isScale, scale);
float_value("##Is Rotation", "Rotation", isRotation, rotation);
duration_value("##Is Duration", "Duration", isDuration, duration);
color4_value("##Is Tint", "Tint", isTint, tint);
color3_value("##Is Color Offset", "Color Offset", isColorOffset, colorOffset);
bool_value("##Is Visible", "Visible", isVisibleSet, isVisible);
float2_value("##Is Crop", localize.get(BASIC_CROP), isCrop, crop);
float2_value("##Is Size", localize.get(BASIC_SIZE), isSize, size);
float2_value("##Is Position", localize.get(BASIC_POSITION), isPosition, position);
float2_value("##Is Pivot", localize.get(BASIC_PIVOT), isPivot, pivot);
float2_value("##Is Scale", localize.get(BASIC_SCALE), isScale, scale);
float_value("##Is Rotation", localize.get(BASIC_ROTATION), isRotation, rotation);
duration_value("##Is Duration", localize.get(BASIC_DURATION), isDuration, duration);
color4_value("##Is Tint", localize.get(BASIC_TINT), isTint, tint);
color3_value("##Is Color Offset", localize.get(BASIC_COLOR_OFFSET), isColorOffset, colorOffset);
bool_value("##Is Visible", localize.get(BASIC_VISIBLE), isVisibleSet, isVisible);
ImGui::SameLine();
bool_value("##Is Interpolated", "Interpolated", isInterpolatedSet, isInterpolated);
bool_value("##Is Interpolated", localize.get(BASIC_INTERPOLATED), isInterpolatedSet, isInterpolated);
auto frame_change = [&](anm2::ChangeType type)
{
@@ -212,30 +227,30 @@ namespace anm2ed::imgui
if (isVisibleSet) frameChange.isVisible = std::make_optional(isVisible);
if (isInterpolatedSet) frameChange.isInterpolated = std::make_optional(isInterpolated);
DOCUMENT_EDIT(document, "Change Frame Properties", Document::FRAMES,
DOCUMENT_EDIT(document, localize.get(EDIT_CHANGE_FRAME_PROPERTIES), Document::FRAMES,
document.item_get()->frames_change(frameChange, type, *frames.begin(), (int)frames.size()));
};
auto rowOneWidgetSize = widget_size_with_row_get(1);
if (ImGui::Button("Adjust", rowOneWidgetSize)) frame_change(anm2::ADJUST);
ImGui::SetItemTooltip("Set the value of each specified value onto the frame's equivalent.");
if (ImGui::Button(localize.get(LABEL_ADJUST), rowOneWidgetSize)) frame_change(anm2::ADJUST);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ADJUST));
auto rowTwoWidgetSize = widget_size_with_row_get(4);
if (ImGui::Button("Add", rowTwoWidgetSize)) frame_change(anm2::ADD);
ImGui::SetItemTooltip("Add the specified values onto each frame.\n(Boolean values will simply be set.)");
if (ImGui::Button(localize.get(BASIC_ADD), rowTwoWidgetSize)) frame_change(anm2::ADD);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ADD_VALUES));
ImGui::SameLine();
if (ImGui::Button("Subtract", rowTwoWidgetSize)) frame_change(anm2::SUBTRACT);
ImGui::SetItemTooltip("Subtract the specified values from each frame.\n(Boolean values will simply be set.)");
if (ImGui::Button(localize.get(LABEL_SUBTRACT), rowTwoWidgetSize)) frame_change(anm2::SUBTRACT);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SUBTRACT_VALUES));
ImGui::SameLine();
if (ImGui::Button("Multiply", rowTwoWidgetSize)) frame_change(anm2::MULTIPLY);
ImGui::SetItemTooltip("Multiply the specified values for each frame.\n(Boolean values will simply be set.)");
if (ImGui::Button(localize.get(LABEL_MULTIPLY), rowTwoWidgetSize)) frame_change(anm2::MULTIPLY);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_MULTIPLY_VALUES));
ImGui::SameLine();
if (ImGui::Button("Divide", rowTwoWidgetSize)) frame_change(anm2::DIVIDE);
ImGui::SetItemTooltip("Divide the specified values for each frame.\n(Boolean values will simply be set.)");
if (ImGui::Button(localize.get(LABEL_DIVIDE), rowTwoWidgetSize)) frame_change(anm2::DIVIDE);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_DIVIDE_VALUES));
}
}
ImGui::End();
}
}
}
+39 -27
View File
@@ -2,7 +2,9 @@
#include <ranges>
#include "log.h"
#include "map_.h"
#include "strings.h"
#include "toast.h"
using namespace anm2ed::util;
@@ -23,7 +25,7 @@ namespace anm2ed::imgui
hovered = -1;
if (ImGui::Begin("Layers", &settings.windowIsLayers))
if (ImGui::Begin(localize.get(LABEL_LAYERS_WINDOW), &settings.windowIsLayers))
{
auto childSize = size_without_footer_get();
@@ -38,7 +40,10 @@ namespace anm2ed::imgui
ImGui::PushID(id);
ImGui::SetNextItemSelectionUserData(id);
ImGui::Selectable(std::format(anm2::LAYER_FORMAT, id, layer.name, layer.spritesheetID).c_str(), isSelected);
ImGui::Selectable(
std::vformat(localize.get(FORMAT_LAYER), std::make_format_args(id, layer.name, layer.spritesheetID))
.c_str(),
isSelected);
if (newLayerId == id)
{
ImGui::SetScrollHereY(0.5f);
@@ -57,8 +62,9 @@ namespace anm2ed::imgui
ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE);
ImGui::TextUnformatted(layer.name.c_str());
ImGui::PopFont();
ImGui::Text("ID: %d", id);
ImGui::Text("Spritesheet ID: %d", layer.spritesheetID);
ImGui::TextUnformatted(std::vformat(localize.get(FORMAT_ID), std::make_format_args(id)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_SPRITESHEET_ID), std::make_format_args(layer.spritesheetID)).c_str());
ImGui::EndTooltip();
}
ImGui::PopID();
@@ -82,11 +88,16 @@ namespace anm2ed::imgui
auto paste = [&](merge::Type type)
{
std::string errorString{};
document.snapshot("Paste Layer(s)");
document.snapshot(localize.get(EDIT_PASTE_LAYERS));
if (anm2.layers_deserialize(clipboard.get(), type, &errorString))
document.change(Document::NULLS);
else
toasts.error(std::format("Failed to deserialize layer(s): {}", errorString));
{
toasts.push(std::vformat(localize.get(TOAST_DESERIALIZE_LAYERS_FAILED),
std::make_format_args(errorString)));
logger.error(std::vformat(localize.get(TOAST_DESERIALIZE_LAYERS_FAILED, anm2ed::ENGLISH),
std::make_format_args(errorString)));
}
};
if (shortcut(manager.chords[SHORTCUT_COPY], shortcut::FOCUSED)) copy();
@@ -94,13 +105,15 @@ namespace anm2ed::imgui
if (ImGui::BeginPopupContextWindow("##Context Menu", ImGuiPopupFlags_MouseButtonRight))
{
ImGui::MenuItem("Cut", settings.shortcutCut.c_str(), false, false);
if (ImGui::MenuItem("Copy", settings.shortcutCopy.c_str(), false, !selection.empty() || hovered > -1)) copy();
ImGui::MenuItem(localize.get(BASIC_CUT), settings.shortcutCut.c_str(), false, false);
if (ImGui::MenuItem(localize.get(BASIC_COPY), settings.shortcutCopy.c_str(), false,
!selection.empty() || hovered > -1))
copy();
if (ImGui::BeginMenu("Paste", !clipboard.is_empty()))
if (ImGui::BeginMenu(localize.get(BASIC_PASTE), !clipboard.is_empty()))
{
if (ImGui::MenuItem("Append", settings.shortcutPaste.c_str())) paste(merge::APPEND);
if (ImGui::MenuItem("Replace")) paste(merge::REPLACE);
if (ImGui::MenuItem(localize.get(BASIC_APPEND), settings.shortcutPaste.c_str())) paste(merge::APPEND);
if (ImGui::MenuItem(localize.get(BASIC_REPLACE))) paste(merge::REPLACE);
ImGui::EndMenu();
}
@@ -113,13 +126,13 @@ namespace anm2ed::imgui
auto widgetSize = widget_size_with_row_get(2);
shortcut(manager.chords[SHORTCUT_ADD]);
if (ImGui::Button("Add", widgetSize)) manager.layer_properties_open();
set_item_tooltip_shortcut("Add a layer.", settings.shortcutAdd);
if (ImGui::Button(localize.get(BASIC_ADD), widgetSize)) manager.layer_properties_open();
set_item_tooltip_shortcut(localize.get(TOOLTIP_ADD_LAYER), settings.shortcutAdd);
ImGui::SameLine();
shortcut(manager.chords[SHORTCUT_REMOVE]);
ImGui::BeginDisabled(unused.empty());
if (ImGui::Button("Remove Unused", widgetSize))
if (ImGui::Button(localize.get(BASIC_REMOVE_UNUSED), widgetSize))
{
auto remove_unused = [&]()
{
@@ -128,34 +141,33 @@ namespace anm2ed::imgui
unused.clear();
};
DOCUMENT_EDIT(document, "Remove Unused Layers", Document::LAYERS, remove_unused());
DOCUMENT_EDIT(document, localize.get(EDIT_REMOVE_UNUSED_LAYERS), Document::LAYERS, remove_unused());
}
ImGui::EndDisabled();
set_item_tooltip_shortcut("Remove unused layers (i.e., ones not used in any animation.)",
settings.shortcutRemove);
set_item_tooltip_shortcut(localize.get(TOOLTIP_REMOVE_UNUSED_LAYERS), settings.shortcutRemove);
}
ImGui::End();
manager.layer_properties_trigger();
if (ImGui::BeginPopupModal(propertiesPopup.label, &propertiesPopup.isOpen, ImGuiWindowFlags_NoResize))
if (ImGui::BeginPopupModal(propertiesPopup.label(), &propertiesPopup.isOpen, ImGuiWindowFlags_NoResize))
{
auto childSize = child_size_get(2);
auto& layer = manager.editLayer;
if (ImGui::BeginChild("Child", childSize, ImGuiChildFlags_Borders))
if (ImGui::BeginChild("##Child", childSize, ImGuiChildFlags_Borders))
{
if (propertiesPopup.isJustOpened) ImGui::SetKeyboardFocusHere();
input_text_string("Name", &layer.name);
ImGui::SetItemTooltip("Set the item's name.");
combo_negative_one_indexed("Spritesheet", &layer.spritesheetID, document.spritesheet.labels);
ImGui::SetItemTooltip("Set the layer item's spritesheet.");
input_text_string(localize.get(BASIC_NAME), &layer.name);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ITEM_NAME));
combo_negative_one_indexed(localize.get(LABEL_SPRITESHEET), &layer.spritesheetID, document.spritesheet.labels);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_LAYER_SPRITESHEET));
}
ImGui::EndChild();
auto widgetSize = widget_size_with_row_get(2);
if (ImGui::Button(reference == -1 ? "Add" : "Confirm", widgetSize))
if (ImGui::Button(reference == -1 ? localize.get(BASIC_ADD) : localize.get(BASIC_CONFIRM), widgetSize))
{
if (reference == -1)
{
@@ -167,7 +179,7 @@ namespace anm2ed::imgui
newLayerId = id;
};
DOCUMENT_EDIT(document, "Add Layer", Document::LAYERS, add());
DOCUMENT_EDIT(document, localize.get(EDIT_ADD_LAYER), Document::LAYERS, add());
}
else
{
@@ -177,7 +189,7 @@ namespace anm2ed::imgui
selection = {reference};
};
DOCUMENT_EDIT(document, "Set Layer Properties", Document::LAYERS, set());
DOCUMENT_EDIT(document, localize.get(EDIT_SET_LAYER_PROPERTIES), Document::LAYERS, set());
}
manager.layer_properties_close();
@@ -185,7 +197,7 @@ namespace anm2ed::imgui
ImGui::SameLine();
if (ImGui::Button("Cancel", widgetSize)) manager.layer_properties_close();
if (ImGui::Button(localize.get(BASIC_CANCEL), widgetSize)) manager.layer_properties_close();
manager.layer_properties_end();
ImGui::EndPopup();
+35 -25
View File
@@ -2,7 +2,9 @@
#include <ranges>
#include "log.h"
#include "map_.h"
#include "strings.h"
#include "toast.h"
using namespace anm2ed::resource;
@@ -23,7 +25,7 @@ namespace anm2ed::imgui
hovered = -1;
if (ImGui::Begin("Nulls", &settings.windowIsNulls))
if (ImGui::Begin(localize.get(LABEL_NULLS_WINDOW), &settings.windowIsNulls))
{
auto childSize = size_without_footer_get();
@@ -39,7 +41,8 @@ namespace anm2ed::imgui
ImGui::PushID(id);
ImGui::SetNextItemSelectionUserData(id);
if (isReferenced) ImGui::PushFont(resources.fonts[font::ITALICS].get(), font::SIZE);
ImGui::Selectable(std::format(anm2::NULL_FORMAT, id, null.name).c_str(), isSelected);
ImGui::Selectable(std::vformat(localize.get(FORMAT_NULL), std::make_format_args(id, null.name)).c_str(),
isSelected);
if (newNullId == id)
{
ImGui::SetScrollHereY(0.5f);
@@ -58,7 +61,7 @@ namespace anm2ed::imgui
ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE);
ImGui::TextUnformatted(null.name.c_str());
ImGui::PopFont();
ImGui::Text("ID: %d", id);
ImGui::TextUnformatted(std::vformat(localize.get(FORMAT_ID), std::make_format_args(id)).c_str());
ImGui::EndTooltip();
}
ImGui::PopID();
@@ -82,11 +85,16 @@ namespace anm2ed::imgui
auto paste = [&](merge::Type type)
{
std::string errorString{};
document.snapshot("Paste Null(s)");
document.snapshot(localize.get(EDIT_PASTE_NULLS));
if (anm2.nulls_deserialize(clipboard.get(), type, &errorString))
document.change(Document::NULLS);
else
toasts.error(std::format("Failed to deserialize null(s): {}", errorString));
{
toasts.push(std::vformat(localize.get(TOAST_DESERIALIZE_NULLS_FAILED),
std::make_format_args(errorString)));
logger.error(std::vformat(localize.get(TOAST_DESERIALIZE_NULLS_FAILED, anm2ed::ENGLISH),
std::make_format_args(errorString)));
}
};
if (shortcut(manager.chords[SHORTCUT_COPY], shortcut::FOCUSED)) copy();
@@ -94,13 +102,15 @@ namespace anm2ed::imgui
if (ImGui::BeginPopupContextWindow("##Context Menu", ImGuiPopupFlags_MouseButtonRight))
{
ImGui::MenuItem("Cut", settings.shortcutCut.c_str(), false, false);
if (ImGui::MenuItem("Copy", settings.shortcutCopy.c_str(), false, selection.empty() || hovered > -1)) copy();
ImGui::MenuItem(localize.get(BASIC_CUT), settings.shortcutCut.c_str(), false, false);
if (ImGui::MenuItem(localize.get(BASIC_COPY), settings.shortcutCopy.c_str(), false,
selection.empty() || hovered > -1))
copy();
if (ImGui::BeginMenu("Paste", !clipboard.is_empty()))
if (ImGui::BeginMenu(localize.get(BASIC_PASTE), !clipboard.is_empty()))
{
if (ImGui::MenuItem("Append", settings.shortcutPaste.c_str())) paste(merge::APPEND);
if (ImGui::MenuItem("Replace")) paste(merge::REPLACE);
if (ImGui::MenuItem(localize.get(BASIC_APPEND), settings.shortcutPaste.c_str())) paste(merge::APPEND);
if (ImGui::MenuItem(localize.get(BASIC_REPLACE))) paste(merge::REPLACE);
ImGui::EndMenu();
}
@@ -113,13 +123,13 @@ namespace anm2ed::imgui
auto widgetSize = widget_size_with_row_get(2);
shortcut(manager.chords[SHORTCUT_ADD]);
if (ImGui::Button("Add", widgetSize)) manager.null_properties_open();
set_item_tooltip_shortcut("Add a null.", settings.shortcutAdd);
if (ImGui::Button(localize.get(BASIC_ADD), widgetSize)) manager.null_properties_open();
set_item_tooltip_shortcut(localize.get(TOOLTIP_ADD_NULL), settings.shortcutAdd);
ImGui::SameLine();
shortcut(manager.chords[SHORTCUT_REMOVE]);
ImGui::BeginDisabled(unused.empty());
if (ImGui::Button("Remove Unused", widgetSize))
if (ImGui::Button(localize.get(LABEL_REMOVE_UNUSED_NULLS), widgetSize))
{
auto remove_unused = [&]()
{
@@ -128,34 +138,34 @@ namespace anm2ed::imgui
unused.clear();
};
DOCUMENT_EDIT(document, "Remove Unused Events", Document::EVENTS, remove_unused());
DOCUMENT_EDIT(document, localize.get(EDIT_REMOVE_UNUSED_NULLS), Document::EVENTS, remove_unused());
}
ImGui::EndDisabled();
set_item_tooltip_shortcut("Remove unused nulls (i.e., ones not used in any animation.)", settings.shortcutRemove);
set_item_tooltip_shortcut(localize.get(TOOLTIP_REMOVE_UNUSED_NULLS), settings.shortcutRemove);
}
ImGui::End();
manager.null_properties_trigger();
if (ImGui::BeginPopupModal(propertiesPopup.label, &propertiesPopup.isOpen, ImGuiWindowFlags_NoResize))
if (ImGui::BeginPopupModal(propertiesPopup.label(), &propertiesPopup.isOpen, ImGuiWindowFlags_NoResize))
{
auto childSize = child_size_get(2);
auto& null = manager.editNull;
if (ImGui::BeginChild("Child", childSize, ImGuiChildFlags_Borders))
if (ImGui::BeginChild("##Child", childSize, ImGuiChildFlags_Borders))
{
if (propertiesPopup.isJustOpened) ImGui::SetKeyboardFocusHere();
input_text_string("Name", &null.name);
ImGui::SetItemTooltip("Set the null's name.");
input_text_string(localize.get(BASIC_NAME), &null.name);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_NULL_NAME));
ImGui::Checkbox("Rect", &null.isShowRect);
ImGui::SetItemTooltip("The null will have a rectangle show around it.");
ImGui::Checkbox(localize.get(LABEL_RECT), &null.isShowRect);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_NULL_RECT));
}
ImGui::EndChild();
auto widgetSize = widget_size_with_row_get(2);
if (ImGui::Button(reference == -1 ? "Add" : "Confirm", widgetSize))
if (ImGui::Button(reference == -1 ? localize.get(BASIC_ADD) : localize.get(BASIC_CONFIRM), widgetSize))
{
if (reference == -1)
{
@@ -167,7 +177,7 @@ namespace anm2ed::imgui
newNullId = id;
};
DOCUMENT_EDIT(document, "Add Null", Document::NULLS, add());
DOCUMENT_EDIT(document, localize.get(EDIT_ADD_NULL), Document::NULLS, add());
}
else
{
@@ -177,7 +187,7 @@ namespace anm2ed::imgui
selection = {reference};
};
DOCUMENT_EDIT(document, "Set Null Properties", Document::NULLS, set());
DOCUMENT_EDIT(document, localize.get(EDIT_SET_NULL_PROPERTIES), Document::NULLS, set());
}
manager.null_properties_close();
@@ -185,7 +195,7 @@ namespace anm2ed::imgui
ImGui::SameLine();
if (ImGui::Button("Cancel", widgetSize)) manager.null_properties_close();
if (ImGui::Button(localize.get(BASIC_CANCEL), widgetSize)) manager.null_properties_close();
ImGui::EndPopup();
}
+15 -14
View File
@@ -3,6 +3,7 @@
#include <glm/gtc/type_ptr.hpp>
#include "imgui_.h"
#include "strings.h"
using namespace anm2ed::types;
using namespace glm;
@@ -20,30 +21,30 @@ namespace anm2ed::imgui
auto& afterColor = settings.onionskinAfterColor;
auto& mode = settings.onionskinMode;
if (ImGui::Begin("Onionskin", &settings.windowIsOnionskin))
if (ImGui::Begin(localize.get(LABEL_ONIONSKIN_WINDOW), &settings.windowIsOnionskin))
{
auto configure_widgets = [&](const char* separator, int& frames, vec3& color)
{
ImGui::PushID(separator);
ImGui::SeparatorText(separator);
input_int_range("Frames", frames, 0, FRAMES_MAX);
ImGui::SetItemTooltip("Change the amount of frames this onionskin will use.");
ImGui::ColorEdit3("Color", value_ptr(color));
ImGui::SetItemTooltip("Change the color of the frames this onionskin will use.");
input_int_range(localize.get(BASIC_FRAMES), frames, 0, FRAMES_MAX);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ONIONSKIN_FRAMES));
ImGui::ColorEdit3(localize.get(BASIC_COLOR), value_ptr(color));
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ONIONSKIN_COLOR));
ImGui::PopID();
};
ImGui::Checkbox("Enabled", &isEnabled);
set_item_tooltip_shortcut("Toggle onionskinning.", settings.shortcutOnionskin);
ImGui::Checkbox(localize.get(BASIC_ENABLED), &isEnabled);
set_item_tooltip_shortcut(localize.get(TOOLTIP_ONIONSKIN_ENABLED), settings.shortcutOnionskin);
configure_widgets("Before", beforeCount, beforeColor);
configure_widgets("After", afterCount, afterColor);
ImGui::SeparatorText("Mode");
ImGui::RadioButton("Time", &mode, (int)OnionskinMode::TIME);
ImGui::SetItemTooltip("The onionskinned frames will be based on frame time.");
configure_widgets(localize.get(BASIC_BEFORE), beforeCount, beforeColor);
configure_widgets(localize.get(BASIC_AFTER), afterCount, afterColor);
ImGui::SeparatorText(localize.get(BASIC_MODE));
ImGui::RadioButton(localize.get(BASIC_TIME), &mode, (int)OnionskinMode::TIME);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ONIONSKIN_TIME));
ImGui::SameLine();
ImGui::RadioButton("Index", &mode, (int)OnionskinMode::INDEX);
ImGui::SetItemTooltip("The onionskinned frames will be based on frame index.");
ImGui::RadioButton(localize.get(BASIC_INDEX), &mode, (int)OnionskinMode::INDEX);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ONIONSKIN_INDEX));
}
ImGui::End();
+28 -13
View File
@@ -2,6 +2,7 @@
#include <ranges>
#include "log.h"
#include "strings.h"
#include "toast.h"
@@ -22,7 +23,7 @@ namespace anm2ed::imgui
hovered = -1;
if (ImGui::Begin(localize.get(LABEL_SOUNDS), &settings.windowIsSounds))
if (ImGui::Begin(localize.get(LABEL_SOUNDS_WINDOW), &settings.windowIsSounds))
{
auto childSize = imgui::size_without_footer_get();
@@ -57,6 +58,11 @@ namespace anm2ed::imgui
ImGui::PopFont();
ImGui::Text("%s: %d", localize.get(BASIC_ID), id);
ImGui::Text("%s", localize.get(TOOLTIP_SOUNDS_PLAY));
if (!sound.is_valid())
{
ImGui::Spacing();
ImGui::TextWrapped("%s", localize.get(TOOLTIP_SOUND_INVALID));
}
ImGui::EndTooltip();
}
ImGui::PopID();
@@ -84,7 +90,11 @@ namespace anm2ed::imgui
if (anm2.sounds_deserialize(clipboard.get(), document.directory_get().string(), type, &errorString))
document.change(Document::SOUNDS);
else
toasts.error(std::format("{}: {}", localize.get(TOAST_SOUNDS_PASTE_ERROR), errorString));
{
toasts.push(std::vformat(localize.get(TOAST_SOUNDS_DESERIALIZE_ERROR), std::make_format_args(errorString)));
logger.error(std::vformat(localize.get(TOAST_SOUNDS_DESERIALIZE_ERROR, anm2ed::ENGLISH),
std::make_format_args(errorString)));
}
};
if (imgui::shortcut(manager.chords[SHORTCUT_COPY], shortcut::FOCUSED)) copy();
@@ -99,8 +109,8 @@ namespace anm2ed::imgui
if (ImGui::BeginMenu(localize.get(BASIC_PASTE), !clipboard.is_empty()))
{
if (ImGui::MenuItem("Append", settings.shortcutPaste.c_str())) paste(merge::APPEND);
if (ImGui::MenuItem("Replace")) paste(merge::REPLACE);
if (ImGui::MenuItem(localize.get(BASIC_APPEND), settings.shortcutPaste.c_str())) paste(merge::APPEND);
if (ImGui::MenuItem(localize.get(BASIC_REPLACE))) paste(merge::REPLACE);
ImGui::EndMenu();
}
@@ -113,13 +123,13 @@ namespace anm2ed::imgui
auto widgetSize = imgui::widget_size_with_row_get(2);
imgui::shortcut(manager.chords[SHORTCUT_ADD]);
if (ImGui::Button("Add", widgetSize)) dialog.file_open(dialog::SOUND_OPEN);
imgui::set_item_tooltip_shortcut("Add a sound.", settings.shortcutAdd);
if (ImGui::Button(localize.get(BASIC_ADD), widgetSize)) dialog.file_open(dialog::SOUND_OPEN);
imgui::set_item_tooltip_shortcut(localize.get(TOOLTIP_SOUND_ADD), settings.shortcutAdd);
ImGui::SameLine();
imgui::shortcut(manager.chords[SHORTCUT_REMOVE]);
ImGui::BeginDisabled(unused.empty());
if (ImGui::Button("Remove Unused", widgetSize))
if (ImGui::Button(localize.get(BASIC_REMOVE_UNUSED), widgetSize))
{
auto remove_unused = [&]()
{
@@ -128,11 +138,10 @@ namespace anm2ed::imgui
unused.clear();
};
DOCUMENT_EDIT(document, "Remove Unused Sounds", Document::SOUNDS, remove_unused());
DOCUMENT_EDIT(document, localize.get(EDIT_REMOVE_UNUSED_SOUNDS), Document::SOUNDS, remove_unused());
};
ImGui::EndDisabled();
imgui::set_item_tooltip_shortcut("Remove unused sounds (i.e., ones not used in any trigger.)",
settings.shortcutRemove);
imgui::set_item_tooltip_shortcut(localize.get(TOOLTIP_REMOVE_UNUSED_SOUNDS), settings.shortcutRemove);
}
ImGui::End();
@@ -145,13 +154,19 @@ namespace anm2ed::imgui
{
selection = {id};
newSoundId = id;
toasts.info(std::format("Initialized sound #{}: {}", id, dialog.path));
toasts.push(std::vformat(localize.get(TOAST_SOUND_INITIALIZED), std::make_format_args(id, dialog.path)));
logger.info(std::vformat(localize.get(TOAST_SOUND_INITIALIZED, anm2ed::ENGLISH),
std::make_format_args(id, dialog.path)));
}
else
toasts.error(std::format("Failed to initialize sound: {}", dialog.path));
{
toasts.push(std::vformat(localize.get(TOAST_SOUND_INITIALIZE_FAILED), std::make_format_args(dialog.path)));
logger.error(std::vformat(localize.get(TOAST_SOUND_INITIALIZE_FAILED, anm2ed::ENGLISH),
std::make_format_args(dialog.path)));
}
};
DOCUMENT_EDIT(document, "Add Sound", Document::SOUNDS, add());
DOCUMENT_EDIT(document, localize.get(EDIT_ADD_SOUND), Document::SOUNDS, add());
dialog.reset();
}
+51 -40
View File
@@ -7,6 +7,7 @@
#include "imgui_.h"
#include "imgui_internal.h"
#include "math_.h"
#include "strings.h"
#include "tool.h"
#include "types.h"
@@ -79,7 +80,7 @@ namespace anm2ed::imgui
auto center_view = [&]() { pan = -size * 0.5f; };
if (ImGui::Begin("Spritesheet Editor", &settings.windowIsSpritesheetEditor))
if (ImGui::Begin(localize.get(LABEL_SPRITESHEET_EDITOR_WINDOW), &settings.windowIsSpritesheetEditor))
{
auto childSize = ImVec2(imgui::row_widget_width_get(3),
@@ -87,20 +88,20 @@ namespace anm2ed::imgui
if (ImGui::BeginChild("##Grid Child", childSize, true, ImGuiWindowFlags_HorizontalScrollbar))
{
ImGui::Checkbox("Grid", &isGrid);
ImGui::SetItemTooltip("Toggle the visibility of the grid.");
ImGui::Checkbox(localize.get(BASIC_GRID), &isGrid);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_GRID_VISIBILITY));
ImGui::SameLine();
ImGui::Checkbox("Snap", &isGridSnap);
ImGui::SetItemTooltip("Cropping will snap points to the grid.");
ImGui::Checkbox(localize.get(LABEL_SNAP), &isGridSnap);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_GRID_SNAP));
ImGui::SameLine();
ImGui::ColorEdit4("Color", value_ptr(gridColor), ImGuiColorEditFlags_NoInputs);
ImGui::SetItemTooltip("Change the grid's color.");
ImGui::ColorEdit4(localize.get(BASIC_COLOR), value_ptr(gridColor), ImGuiColorEditFlags_NoInputs);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_GRID_COLOR));
input_int2_range("Size", gridSize, ivec2(GRID_SIZE_MIN), ivec2(GRID_SIZE_MAX));
ImGui::SetItemTooltip("Change the size of all cells in the grid.");
input_int2_range(localize.get(BASIC_SIZE), gridSize, ivec2(GRID_SIZE_MIN), ivec2(GRID_SIZE_MAX));
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_GRID_SIZE));
input_int2_range("Offset", gridOffset, ivec2(GRID_OFFSET_MIN), ivec2(GRID_OFFSET_MAX));
ImGui::SetItemTooltip("Change the offset of the grid.");
input_int2_range(localize.get(BASIC_OFFSET), gridOffset, ivec2(GRID_OFFSET_MIN), ivec2(GRID_OFFSET_MAX));
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_GRID_OFFSET));
}
ImGui::EndChild();
@@ -108,23 +109,26 @@ namespace anm2ed::imgui
if (ImGui::BeginChild("##View Child", childSize, true, ImGuiWindowFlags_HorizontalScrollbar))
{
ImGui::InputFloat("Zoom", &zoom, zoomStep, zoomStep, "%.0f%%");
ImGui::SetItemTooltip("Change the zoom of the editor.");
ImGui::InputFloat(localize.get(BASIC_ZOOM), &zoom, zoomStep, zoomStep, "%.0f%%");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_EDITOR_ZOOM));
auto widgetSize = ImVec2(imgui::row_widget_width_get(2), 0);
imgui::shortcut(manager.chords[SHORTCUT_CENTER_VIEW]);
if (ImGui::Button("Center View", widgetSize)) center_view();
imgui::set_item_tooltip_shortcut("Centers the view.", settings.shortcutCenterView);
if (ImGui::Button(localize.get(LABEL_CENTER_VIEW), widgetSize)) center_view();
imgui::set_item_tooltip_shortcut(localize.get(TOOLTIP_CENTER_VIEW), settings.shortcutCenterView);
ImGui::SameLine();
imgui::shortcut(manager.chords[SHORTCUT_FIT]);
if (ImGui::Button("Fit", widgetSize))
if (ImGui::Button(localize.get(LABEL_FIT), widgetSize))
if (spritesheet) set_to_rect(zoom, pan, {0, 0, spritesheet->texture.size.x, spritesheet->texture.size.y});
imgui::set_item_tooltip_shortcut("Set the view to match the extent of the spritesheet.", settings.shortcutFit);
imgui::set_item_tooltip_shortcut(localize.get(TOOLTIP_FIT), settings.shortcutFit);
ImGui::TextUnformatted(std::format(POSITION_FORMAT, (int)mousePos.x, (int)mousePos.y).c_str());
auto mousePosInt = ivec2(mousePos);
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_POSITION_SPACED), std::make_format_args(mousePosInt.x, mousePosInt.y))
.c_str());
}
ImGui::EndChild();
@@ -136,11 +140,16 @@ namespace anm2ed::imgui
if (ImGui::BeginChild("##Background Child 1", subChildSize))
{
ImGui::ColorEdit3("Background", value_ptr(backgroundColor), ImGuiColorEditFlags_NoInputs);
ImGui::SetItemTooltip("Change the background color.");
ImGui::BeginDisabled(isTransparent);
{
ImGui::ColorEdit3(localize.get(LABEL_BACKGROUND_COLOR), value_ptr(backgroundColor),
ImGuiColorEditFlags_NoInputs);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_BACKGROUND_COLOR));
}
ImGui::EndDisabled();
ImGui::Checkbox("Border", &isBorder);
ImGui::SetItemTooltip("Toggle a border appearing around the spritesheet.");
ImGui::Checkbox(localize.get(LABEL_BORDER), &isBorder);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SPRITESHEET_BORDER));
}
ImGui::EndChild();
@@ -148,8 +157,8 @@ namespace anm2ed::imgui
if (ImGui::BeginChild("##Background Child 2", subChildSize))
{
ImGui::Checkbox("Transparent", &isTransparent);
ImGui::SetItemTooltip("Toggle the spritesheet editor being transparent.");
ImGui::Checkbox(localize.get(LABEL_TRANSPARENT), &isTransparent);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_TRANSPARENT));
}
ImGui::EndChild();
@@ -201,10 +210,11 @@ namespace anm2ed::imgui
unbind();
sync_checker_pan();
render_checker_background(drawList, min, max, -size * 0.5f - checkerPan, CHECKER_SIZE);
if (!isTransparent) drawList->AddRectFilled(min, max, ImGui::GetColorU32(to_imvec4(vec4(backgroundColor, 1.0f))));
drawList->AddImage(texture, min, max);
ImGui::InvisibleButton("##Spritesheet Editor", to_imvec2(size));
if (isTransparent)
render_checker_background(drawList, min, max, -size * 0.5f - checkerPan, CHECKER_SIZE);
else
drawList->AddRectFilled(min, max, ImGui::GetColorU32(to_imvec4(vec4(backgroundColor, 1.0f))));
ImGui::Image(texture, to_imvec2(size));
if (ImGui::IsItemHovered())
{
@@ -299,7 +309,7 @@ namespace anm2ed::imgui
break;
case tool::MOVE:
if (!frame) break;
if (isBegin) document.snapshot("Frame Pivot");
if (isBegin) document.snapshot(localize.get(EDIT_FRAME_PIVOT));
if (isMouseDown) frame->pivot = vec2(ivec2(mousePos - frame->crop));
if (isLeftPressed) frame->pivot.x -= step;
if (isRightPressed) frame->pivot.x += step;
@@ -310,9 +320,9 @@ namespace anm2ed::imgui
{
if (ImGui::BeginTooltip())
{
auto pivotFormat = math::vec2_format_get(frame->pivot);
auto pivotString = std::format("Pivot: ({}, {})", pivotFormat, pivotFormat);
ImGui::Text(pivotString.c_str(), frame->pivot.x, frame->pivot.y);
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_PIVOT), std::make_format_args(frame->pivot.x, frame->pivot.y))
.c_str());
ImGui::EndTooltip();
}
}
@@ -321,7 +331,7 @@ namespace anm2ed::imgui
break;
case tool::CROP:
if (!frame) break;
if (isBegin) document.snapshot("Frame Crop");
if (isBegin) document.snapshot(localize.get(EDIT_FRAME_CROP));
if (isMouseClicked)
{
@@ -358,12 +368,12 @@ namespace anm2ed::imgui
}
if (ImGui::BeginTooltip())
{
auto cropFormat = math::vec2_format_get(frame->crop);
auto sizeFormat = math::vec2_format_get(frame->size);
auto cropString = std::format("Crop: ({}, {})", cropFormat, cropFormat);
auto sizeString = std::format("Size: ({}, {})", sizeFormat, sizeFormat);
ImGui::Text(cropString.c_str(), frame->crop.x, frame->crop.y);
ImGui::Text(sizeString.c_str(), frame->size.x, frame->size.y);
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_CROP), std::make_format_args(frame->crop.x, frame->crop.y))
.c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_SIZE), std::make_format_args(frame->size.x, frame->size.y))
.c_str());
ImGui::EndTooltip();
}
}
@@ -374,7 +384,8 @@ namespace anm2ed::imgui
{
if (!spritesheet) break;
auto color = useTool == tool::DRAW ? toolColor : vec4();
if (isMouseClicked) document.snapshot(useTool == tool::DRAW ? "Draw" : "Erase");
if (isMouseClicked)
document.snapshot(useTool == tool::DRAW ? localize.get(EDIT_DRAW) : localize.get(EDIT_ERASE));
if (isMouseDown) spritesheet->texture.pixel_line(ivec2(previousMousePos), ivec2(mousePos), color);
if (isMouseReleased) document.change(Document::SPRITESHEETS);
break;
+85 -38
View File
@@ -2,11 +2,17 @@
#include <ranges>
#include <format>
#include "log.h"
#include "document.h"
#include "filesystem_.h"
#include "strings.h"
#include "toast.h"
using namespace anm2ed::types;
using namespace anm2ed::resource;
using namespace anm2ed::util;
using namespace glm;
namespace anm2ed::imgui
@@ -23,7 +29,7 @@ namespace anm2ed::imgui
hovered = -1;
if (ImGui::Begin("Spritesheets", &settings.windowIsSpritesheets))
if (ImGui::Begin(localize.get(LABEL_SPRITESHEETS_WINDOW), &settings.windowIsSpritesheets))
{
auto style = ImGui::GetStyle();
@@ -45,11 +51,16 @@ namespace anm2ed::imgui
auto paste = [&](merge::Type type)
{
std::string errorString{};
document.snapshot("Paste Spritesheet(s)");
if (anm2.spritesheets_deserialize(clipboard.get(), document.directory_get().string(), type, &errorString))
document.change(Document::SPRITESHEETS);
else
toasts.error(std::format("Failed to deserialize spritesheet(s): {}", errorString));
document.snapshot(localize.get(EDIT_PASTE_SPRITESHEETS));
if (anm2.spritesheets_deserialize(clipboard.get(), document.directory_get().string(), type, &errorString))
document.change(Document::SPRITESHEETS);
else
{
toasts.push(std::vformat(localize.get(TOAST_DESERIALIZE_SPRITESHEETS_FAILED),
std::make_format_args(errorString)));
logger.error(std::vformat(localize.get(TOAST_DESERIALIZE_SPRITESHEETS_FAILED, anm2ed::ENGLISH),
std::make_format_args(errorString)));
}
};
if (shortcut(manager.chords[SHORTCUT_COPY], shortcut::FOCUSED)) copy();
@@ -59,14 +70,16 @@ namespace anm2ed::imgui
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing);
if (ImGui::BeginPopupContextWindow("##Context Menu", ImGuiPopupFlags_MouseButtonRight))
{
ImGui::MenuItem("Cut", settings.shortcutCut.c_str(), false, true);
ImGui::MenuItem(localize.get(BASIC_CUT), settings.shortcutCut.c_str(), false, true);
if (ImGui::MenuItem("Copy", settings.shortcutCopy.c_str(), false, !selection.empty() || hovered > -1)) copy();
if (ImGui::MenuItem(localize.get(BASIC_COPY), settings.shortcutCopy.c_str(), false,
!selection.empty() || hovered > -1))
copy();
if (ImGui::BeginMenu("Paste", !clipboard.is_empty()))
if (ImGui::BeginMenu(localize.get(BASIC_PASTE), !clipboard.is_empty()))
{
if (ImGui::MenuItem("Append", settings.shortcutPaste.c_str())) paste(merge::APPEND);
if (ImGui::MenuItem("Replace")) paste(merge::REPLACE);
if (ImGui::MenuItem(localize.get(BASIC_APPEND), settings.shortcutPaste.c_str())) paste(merge::APPEND);
if (ImGui::MenuItem(localize.get(BASIC_REPLACE))) paste(merge::REPLACE);
ImGui::EndMenu();
}
@@ -99,14 +112,21 @@ namespace anm2ed::imgui
auto& texture = isTextureValid ? spritesheet.texture : resources.icons[icon::NONE];
auto textureRef = ImTextureRef(texture.id);
auto tintColor = !isTextureValid ? ImVec4(1.0f, 0.25f, 0.25f, 1.0f) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
const std::string pathString =
spritesheet.path.empty() ? std::string{anm2::NO_PATH} : spritesheet.path.string();
const char* pathCStr = pathString.c_str();
auto pathString = spritesheet.path.empty() ? std::string{anm2::NO_PATH} : spritesheet.path.string();
auto pathCStr = pathString.c_str();
ImGui::SetNextItemSelectionUserData(id);
ImGui::SetNextItemStorageID(id);
if (ImGui::Selectable("##Spritesheet Selectable", isSelected, 0, spritesheetChildSize)) reference = id;
if (ImGui::IsItemHovered()) hovered = id;
if (ImGui::IsItemHovered())
{
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
{
filesystem::WorkingDirectory workingDirectory(document.directory_get());
dialog.file_explorer_open(spritesheet.path.parent_path().string());
}
hovered = id;
}
if (newSpritesheetId == id)
{
ImGui::SetScrollHereY(0.5f);
@@ -150,12 +170,16 @@ namespace anm2ed::imgui
ImGui::TextUnformatted(pathCStr);
ImGui::PopFont();
ImGui::Text("ID: %d", id);
ImGui::TextUnformatted(std::vformat(localize.get(FORMAT_ID), std::make_format_args(id)).c_str());
if (!isTextureValid)
ImGui::Text("This spritesheet isn't valid!\nLoad an existing, valid texture.");
ImGui::TextUnformatted(localize.get(TOOLTIP_SPRITESHEET_INVALID));
else
ImGui::Text("Size: %d x %d", texture.size.x, texture.size.y);
ImGui::TextUnformatted(std::vformat(localize.get(FORMAT_TEXTURE_SIZE),
std::make_format_args(texture.size.x, texture.size.y))
.c_str());
ImGui::TextUnformatted(localize.get(TEXT_OPEN_DIRECTORY));
}
ImGui::EndChild();
@@ -179,7 +203,8 @@ namespace anm2ed::imgui
spritesheetChildSize.y - spritesheetChildSize.y / 2 - ImGui::GetTextLineHeight() / 2));
if (isReferenced) ImGui::PushFont(resources.fonts[font::ITALICS].get(), font::SIZE);
ImGui::Text(anm2::SPRITESHEET_FORMAT_C, id, pathCStr);
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_SPRITESHEET), std::make_format_args(id, pathCStr)).c_str());
if (isReferenced) ImGui::PopFont();
context_menu();
@@ -200,8 +225,8 @@ namespace anm2ed::imgui
auto rowOneWidgetSize = widget_size_with_row_get(3);
shortcut(manager.chords[SHORTCUT_ADD]);
if (ImGui::Button("Add", rowOneWidgetSize)) dialog.file_open(dialog::SPRITESHEET_OPEN);
set_item_tooltip_shortcut("Add a new spritesheet.", settings.shortcutAdd);
if (ImGui::Button(localize.get(BASIC_ADD), rowOneWidgetSize)) dialog.file_open(dialog::SPRITESHEET_OPEN);
set_item_tooltip_shortcut(localize.get(TOOLTIP_ADD_SPRITESHEET), settings.shortcutAdd);
if (dialog.is_selected(dialog::SPRITESHEET_OPEN))
{
@@ -214,7 +239,7 @@ namespace anm2ed::imgui
ImGui::BeginDisabled(selection.empty());
{
if (ImGui::Button("Reload", rowOneWidgetSize))
if (ImGui::Button(localize.get(BASIC_RELOAD), rowOneWidgetSize))
{
auto reload = [&]()
{
@@ -222,13 +247,17 @@ namespace anm2ed::imgui
{
anm2::Spritesheet& spritesheet = anm2.content.spritesheets[id];
spritesheet.reload(document.directory_get());
toasts.info(std::format("Reloaded spritesheet #{}: {}", id, spritesheet.path.string()));
auto pathString = spritesheet.path.string();
toasts.push(std::vformat(localize.get(TOAST_RELOAD_SPRITESHEET),
std::make_format_args(id, pathString)));
logger.info(std::vformat(localize.get(TOAST_RELOAD_SPRITESHEET, anm2ed::ENGLISH),
std::make_format_args(id, pathString)));
}
};
DOCUMENT_EDIT(document, "Reload Spritesheet(s)", Document::SPRITESHEETS, reload());
DOCUMENT_EDIT(document, localize.get(EDIT_RELOAD_SPRITESHEETS), Document::SPRITESHEETS, reload());
}
ImGui::SetItemTooltip("Reloads the selected spritesheets.");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_RELOAD_SPRITESHEETS));
}
ImGui::EndDisabled();
@@ -236,8 +265,8 @@ namespace anm2ed::imgui
ImGui::BeginDisabled(selection.size() != 1);
{
if (ImGui::Button("Replace", rowOneWidgetSize)) dialog.file_open(dialog::SPRITESHEET_REPLACE);
ImGui::SetItemTooltip("Replace the selected spritesheet with a new one.");
if (ImGui::Button(localize.get(BASIC_REPLACE), rowOneWidgetSize)) dialog.file_open(dialog::SPRITESHEET_REPLACE);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_REPLACE_SPRITESHEET));
}
ImGui::EndDisabled();
@@ -248,10 +277,13 @@ namespace anm2ed::imgui
auto& id = *selection.begin();
anm2::Spritesheet& spritesheet = anm2.content.spritesheets[id];
spritesheet = anm2::Spritesheet(document.directory_get().string(), dialog.path);
toasts.info(std::format("Replaced spritesheet #{}: {}", id, spritesheet.path.string()));
auto pathString = spritesheet.path.string();
toasts.push(std::vformat(localize.get(TOAST_REPLACE_SPRITESHEET), std::make_format_args(id, pathString)));
logger.info(std::vformat(localize.get(TOAST_REPLACE_SPRITESHEET, anm2ed::ENGLISH),
std::make_format_args(id, pathString)));
};
DOCUMENT_EDIT(document, "Replace Spritesheet", Document::SPRITESHEETS, replace());
DOCUMENT_EDIT(document, localize.get(EDIT_REPLACE_SPRITESHEET), Document::SPRITESHEETS, replace());
dialog.reset();
}
@@ -260,23 +292,27 @@ namespace anm2ed::imgui
ImGui::BeginDisabled(unused.empty());
{
shortcut(manager.chords[SHORTCUT_REMOVE]);
if (ImGui::Button("Remove Unused", rowTwoWidgetSize))
if (ImGui::Button(localize.get(BASIC_REMOVE_UNUSED), rowTwoWidgetSize))
{
auto remove_unused = [&]()
{
for (auto& id : unused)
{
anm2::Spritesheet& spritesheet = anm2.content.spritesheets[id];
toasts.info(std::format("Removed spritesheet #{}: {}", id, spritesheet.path.string()));
auto pathString = spritesheet.path.string();
toasts.push(std::vformat(localize.get(TOAST_REMOVE_SPRITESHEET),
std::make_format_args(id, pathString)));
logger.info(std::vformat(localize.get(TOAST_REMOVE_SPRITESHEET, anm2ed::ENGLISH),
std::make_format_args(id, pathString)));
anm2.content.spritesheets.erase(id);
}
unused.clear();
};
DOCUMENT_EDIT(document, "Remove Unused Spritesheets", Document::SPRITESHEETS, remove_unused());
DOCUMENT_EDIT(document, localize.get(EDIT_REMOVE_UNUSED_SPRITESHEETS), Document::SPRITESHEETS,
remove_unused());
}
set_item_tooltip_shortcut("Remove all unused spritesheets (i.e., not used in any layer.).",
settings.shortcutRemove);
set_item_tooltip_shortcut(localize.get(TOOLTIP_REMOVE_UNUSED_SPRITESHEETS), settings.shortcutRemove);
}
ImGui::EndDisabled();
@@ -284,20 +320,31 @@ namespace anm2ed::imgui
ImGui::BeginDisabled(selection.empty());
{
if (ImGui::Button("Save", rowTwoWidgetSize))
if (ImGui::Button(localize.get(BASIC_SAVE), rowTwoWidgetSize))
{
for (auto& id : selection)
{
anm2::Spritesheet& spritesheet = anm2.content.spritesheets[id];
auto pathString = spritesheet.path.string();
if (spritesheet.save(document.directory_get().string()))
toasts.info(std::format("Saved spritesheet #{}: {}", id, spritesheet.path.string()));
{
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.info(std::format("Unable to save spritesheet #{}: {}", id, spritesheet.path.string()));
{
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)));
}
}
}
}
ImGui::EndDisabled();
ImGui::SetItemTooltip("Save the selected spritesheets.");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SAVE_SPRITESHEETS));
}
ImGui::End();
}
+318 -186
View File
@@ -7,6 +7,7 @@
#include <imgui_internal.h>
#include "log.h"
#include "math_.h"
#include "toast.h"
@@ -82,16 +83,6 @@ namespace anm2ed::imgui
constexpr auto FRAME_TOOLTIP_HOVER_DELAY = 0.75f; // Extra delay for frame info tooltip.
constexpr int ITEM_SELECTION_NULL_FLAG = 1 << 30;
constexpr auto HELP_FORMAT = R"(- Press {} to decrement time.
- Press {} to increment time.
- Press {} to shorten the selected frame, by one frame.
- Press {} to extend the selected frame, by one frame.
- Press {} to go to the previous frame.
- Press {} to go to the next frame.
- Click and hold on a frame while holding CTRL to change its duration.
- Click and hold on a trigger to change its At Frame.
- Hold Alt while clicking a non-trigger frame to toggle interpolation.)";
void Timeline::update(Manager& manager, Settings& settings, Resources& resources, Clipboard& clipboard)
{
auto& document = *manager.get();
@@ -325,7 +316,10 @@ namespace anm2ed::imgui
item->frames.erase(item->frames.begin() + i);
}
reference.frameIndex = glm::clamp(--reference.frameIndex, -1, (int)item->frames.size() - 1);
if (item->frames.empty())
reference.frameIndex = -1;
else
reference.frameIndex = glm::clamp(--reference.frameIndex, 0, (int)item->frames.size() - 1);
frames_selection_set_reference();
}
};
@@ -376,14 +370,14 @@ namespace anm2ed::imgui
auto cut = [&]()
{
copy();
DOCUMENT_EDIT(document, "Cut Frame(s)", Document::FRAMES, frames_delete());
DOCUMENT_EDIT(document, localize.get(EDIT_CUT_FRAMES), Document::FRAMES, frames_delete());
};
auto paste = [&]()
{
if (auto item = animation->item_get(reference.itemType, reference.itemID))
{
document.snapshot("Paste Frame(s)");
document.snapshot(localize.get(EDIT_PASTE_FRAMES));
std::set<int> indices{};
std::string errorString{};
int insertIndex = (int)item->frames.size();
@@ -403,10 +397,17 @@ namespace anm2ed::imgui
document.change(Document::FRAMES);
}
else
toasts.error(std::format("Failed to deserialize frame(s): {}", errorString));
{
toasts.push(std::format("{} {}", localize.get(TOAST_DESERIALIZE_FRAMES_FAILED), errorString));
logger.error(std::format("{} {}", localize.get(TOAST_DESERIALIZE_FRAMES_FAILED, anm2ed::ENGLISH),
errorString));
}
}
else
toasts.error(std::format("Failed to deserialize frame(s): select an item first!"));
{
toasts.push(localize.get(TOAST_DESERIALIZE_FRAMES_NO_SELECTION));
logger.warning(localize.get(TOAST_DESERIALIZE_FRAMES_NO_SELECTION, anm2ed::ENGLISH));
}
};
if (shortcut(manager.chords[SHORTCUT_CUT], shortcut::FOCUSED)) cut();
@@ -415,9 +416,11 @@ namespace anm2ed::imgui
if (ImGui::BeginPopupContextWindow("##Context Menu", ImGuiPopupFlags_MouseButtonRight))
{
if (ImGui::MenuItem("Cut", settings.shortcutCut.c_str(), false, !frames.selection.empty())) cut();
if (ImGui::MenuItem("Copy", settings.shortcutCopy.c_str(), false, !frames.selection.empty())) copy();
if (ImGui::MenuItem("Paste", nullptr, false, !clipboard.is_empty())) paste();
if (ImGui::MenuItem(localize.get(BASIC_CUT), settings.shortcutCut.c_str(), false, !frames.selection.empty()))
cut();
if (ImGui::MenuItem(localize.get(BASIC_COPY), settings.shortcutCopy.c_str(), false, !frames.selection.empty()))
copy();
if (ImGui::MenuItem(localize.get(BASIC_PASTE), nullptr, false, !clipboard.is_empty())) paste();
ImGui::EndPopup();
}
@@ -529,10 +532,12 @@ namespace anm2ed::imgui
if (isOnlyShowLayers && type != anm2::LAYER) isVisible = false;
auto isActive = reference.itemType == type && reference.itemID == id;
auto label = type == anm2::LAYER ? std::format(anm2::LAYER_FORMAT, id, anm2.content.layers[id].name,
anm2.content.layers[id].spritesheetID)
: type == anm2::NULL_ ? std::format(anm2::NULL_FORMAT, id, anm2.content.nulls[id].name)
: anm2::TYPE_STRINGS[type];
auto label = type == anm2::LAYER ? std::vformat(localize.get(FORMAT_LAYER),
std::make_format_args(id, anm2.content.layers[id].name,
anm2.content.layers[id].spritesheetID))
: type == anm2::NULL_
? std::vformat(localize.get(FORMAT_NULL), std::make_format_args(id, anm2.content.nulls[id].name))
: localize.get(anm2::TYPE_STRINGS[type]);
auto icon = anm2::TYPE_ICONS[type];
auto iconTintCurrent = isLightTheme && type == anm2::NONE ? ImVec4(1.0f, 1.0f, 1.0f, 1.0f) : itemIconTint;
auto baseColorVec = item_color_vec(type);
@@ -605,8 +610,9 @@ namespace anm2ed::imgui
reference_set_item(type, id);
}
ImGui::PopStyleColor(3);
if (ImGui::IsItemHovered()) items.hovered = id;
if (ImGui::IsItemHovered())
bool isItemHovered = ImGui::IsItemHovered();
if (isItemHovered) items.hovered = id;
if (isItemHovered)
{
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
{
@@ -623,6 +629,98 @@ namespace anm2ed::imgui
}
}
if (isItemHovered)
{
auto& imguiStyle = ImGui::GetStyle();
auto previousTooltipFlags = imguiStyle.HoverFlagsForTooltipMouse;
auto previousTooltipDelay = imguiStyle.HoverDelayNormal;
imguiStyle.HoverFlagsForTooltipMouse = ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayNormal |
ImGuiHoveredFlags_AllowWhenDisabled |
ImGuiHoveredFlags_NoSharedDelay;
imguiStyle.HoverDelayNormal = FRAME_TOOLTIP_HOVER_DELAY;
bool showItemTooltip = ImGui::BeginItemTooltip();
imguiStyle.HoverFlagsForTooltipMouse = previousTooltipFlags;
imguiStyle.HoverDelayNormal = previousTooltipDelay;
if (showItemTooltip)
{
auto yesNoLabel = [&](bool value) { return value ? localize.get(BASIC_YES) : localize.get(BASIC_NO); };
auto visibleLabel = yesNoLabel(isVisible);
auto framesCount = item ? (int)item->frames.size() : 0;
switch (type)
{
case anm2::ROOT:
{
ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE);
ImGui::TextUnformatted(localize.get(BASIC_ROOT));
ImGui::PopFont();
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_VISIBLE), std::make_format_args(visibleLabel)).c_str());
auto transformLabel = yesNoLabel(settings.previewIsRootTransform);
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_TRANSFORM), std::make_format_args(transformLabel)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_FRAMES_COUNT), std::make_format_args(framesCount)).c_str());
break;
}
case anm2::LAYER:
{
auto& layer = anm2.content.layers[id];
ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE);
ImGui::TextUnformatted(layer.name.c_str());
ImGui::PopFont();
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_ID), std::make_format_args(id)).c_str());
ImGui::TextUnformatted(std::vformat(localize.get(FORMAT_SPRITESHEET_ID),
std::make_format_args(layer.spritesheetID))
.c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_VISIBLE), std::make_format_args(visibleLabel)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_FRAMES_COUNT), std::make_format_args(framesCount)).c_str());
break;
}
case anm2::NULL_:
{
auto& nullInfo = anm2.content.nulls[id];
ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE);
ImGui::TextUnformatted(nullInfo.name.c_str());
ImGui::PopFont();
auto rectLabel = yesNoLabel(nullInfo.isShowRect);
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_ID), std::make_format_args(id)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_RECT), std::make_format_args(rectLabel)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_VISIBLE), std::make_format_args(visibleLabel)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_FRAMES_COUNT), std::make_format_args(framesCount)).c_str());
break;
}
case anm2::TRIGGER:
{
ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE);
ImGui::TextUnformatted(localize.get(BASIC_TRIGGERS));
ImGui::PopFont();
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_VISIBLE), std::make_format_args(visibleLabel)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_TRIGGERS_COUNT), std::make_format_args(framesCount)).c_str());
break;
}
default:
break;
}
ImGui::EndTooltip();
}
}
if (type == anm2::LAYER)
{
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceNoPreviewTooltip))
@@ -645,7 +743,7 @@ namespace anm2ed::imgui
if (source != -1 && destination != -1) vector::move_index(animation->layerOrder, source, destination);
};
DOCUMENT_EDIT(document, "Move Layer Animation", Document::ITEMS, layer_order_move());
DOCUMENT_EDIT(document, localize.get(EDIT_MOVE_LAYER_ANIMATION), Document::ITEMS, layer_order_move());
}
ImGui::EndDragDropTarget();
}
@@ -673,9 +771,11 @@ namespace anm2ed::imgui
(itemSize.y - ImGui::GetTextLineHeightWithSpacing()) / 2));
int visibleIcon = item->isVisible ? icon::VISIBLE : icon::INVISIBLE;
if (ImGui::ImageButton("##Visible Toggle", resources.icons[visibleIcon].id, icon_size_get()))
DOCUMENT_EDIT(document, "Item Visibility", Document::FRAMES, item->isVisible = !item->isVisible);
DOCUMENT_EDIT(document, localize.get(EDIT_TOGGLE_ITEM_VISIBILITY), Document::FRAMES,
item->isVisible = !item->isVisible);
overlay_icon(resources.icons[visibleIcon].id, iconTintCurrent);
ImGui::SetItemTooltip(isVisible ? "The item is shown. Press to hide." : "The item is hidden. Press to show.");
ImGui::SetItemTooltip("%s", isVisible ? localize.get(TOOLTIP_ITEM_VISIBILITY_SHOWN)
: localize.get(TOOLTIP_ITEM_VISIBILITY_HIDDEN));
if (type == anm2::NULL_)
{
@@ -686,10 +786,11 @@ namespace anm2ed::imgui
ImVec2(itemSize.x - (ImGui::GetTextLineHeightWithSpacing() * 2) - ImGui::GetStyle().ItemSpacing.x,
(itemSize.y - ImGui::GetTextLineHeightWithSpacing()) / 2));
if (ImGui::ImageButton("##Rect Toggle", resources.icons[rectIcon].id, icon_size_get()))
DOCUMENT_EDIT(document, "Null Rect", Document::FRAMES, null.isShowRect = !null.isShowRect);
DOCUMENT_EDIT(document, localize.get(EDIT_TOGGLE_NULL_RECT), Document::FRAMES,
null.isShowRect = !null.isShowRect);
overlay_icon(resources.icons[rectIcon].id, iconTintCurrent);
ImGui::SetItemTooltip(isShowRect ? "The null's rect is shown. Press to hide."
: "The null's rect is hidden. Press to show.");
ImGui::SetItemTooltip("%s", isShowRect ? localize.get(TOOLTIP_NULL_RECT_SHOWN)
: localize.get(TOOLTIP_NULL_RECT_HIDDEN));
}
ImGui::PopStyleVar(2);
@@ -712,8 +813,8 @@ namespace anm2ed::imgui
if (ImGui::ImageButton("##Unused Toggle", resources.icons[unusedIcon].id, icon_size_get()))
isShowUnused = !isShowUnused;
overlay_icon(resources.icons[unusedIcon].id, iconTintCurrent);
ImGui::SetItemTooltip(isShowUnused ? "Unused layers/nulls are shown. Press to hide."
: "Unused layers/nulls are hidden. Press to show.");
ImGui::SetItemTooltip("%s", isShowUnused ? localize.get(TOOLTIP_UNUSED_ITEMS_SHOWN)
: localize.get(TOOLTIP_UNUSED_ITEMS_HIDDEN));
auto& showLayersOnly = settings.timelineIsOnlyShowLayers;
auto layersIcon = showLayersOnly ? icon::SHOW_LAYERS : icon::HIDE_LAYERS;
@@ -723,8 +824,8 @@ namespace anm2ed::imgui
if (ImGui::ImageButton("##Layers Toggle", resources.icons[layersIcon].id, icon_size_get()))
showLayersOnly = !showLayersOnly;
overlay_icon(resources.icons[layersIcon].id, iconTintCurrent);
ImGui::SetItemTooltip(showLayersOnly ? "Only layers are visible. Press to show all items."
: "All items are visible. Press to only show layers.");
ImGui::SetItemTooltip("%s", showLayersOnly ? localize.get(TOOLTIP_ONLY_LAYERS_VISIBLE)
: localize.get(TOOLTIP_ALL_ITEMS_VISIBLE));
ImGui::PopStyleVar(2);
ImGui::PopStyleColor(3);
@@ -734,11 +835,12 @@ namespace anm2ed::imgui
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::Text("(?)");
ImGui::PopStyleColor();
ImGui::SetItemTooltip("%s", std::format(HELP_FORMAT, settings.shortcutMovePlayheadBack,
settings.shortcutMovePlayheadForward, settings.shortcutShortenFrame,
settings.shortcutExtendFrame, settings.shortcutPreviousFrame,
settings.shortcutNextFrame)
.c_str());
auto tooltipShortcuts = std::vformat(
localize.get(TOOLTIP_TIMELINE_SHORTCUTS),
std::make_format_args(settings.shortcutMovePlayheadBack, settings.shortcutMovePlayheadForward,
settings.shortcutShortenFrame, settings.shortcutExtendFrame,
settings.shortcutPreviousFrame, settings.shortcutNextFrame));
ImGui::SetItemTooltip("%s", tooltipShortcuts.c_str());
ImGui::EndDisabled();
}
}
@@ -863,12 +965,12 @@ namespace anm2ed::imgui
ImGui::BeginDisabled(!animation);
{
shortcut(manager.chords[SHORTCUT_ADD]);
if (ImGui::Button("Add", widgetSize))
if (ImGui::Button(localize.get(BASIC_ADD), widgetSize))
{
item_properties_reset();
propertiesPopup.open();
}
set_item_tooltip_shortcut("Add a new item to the animation.", settings.shortcutAdd);
set_item_tooltip_shortcut(localize.get(TOOLTIP_ADD_ITEM), settings.shortcutAdd);
ImGui::SameLine();
auto selectionType = item_selection_type_get();
@@ -877,7 +979,7 @@ namespace anm2ed::imgui
ImGui::BeginDisabled(!hasSelection && !hasReferenceItem);
{
shortcut(manager.chords[SHORTCUT_REMOVE]);
if (ImGui::Button("Remove", widgetSize))
if (ImGui::Button(localize.get(BASIC_REMOVE), widgetSize))
{
auto remove = [&]()
{
@@ -897,9 +999,9 @@ namespace anm2ed::imgui
reference_clear();
};
DOCUMENT_EDIT(document, "Remove Item(s)", Document::ITEMS, remove());
DOCUMENT_EDIT(document, localize.get(EDIT_REMOVE_ITEMS), Document::ITEMS, remove());
}
set_item_tooltip_shortcut("Remove the selected item(s) from the animation.", settings.shortcutRemove);
set_item_tooltip_shortcut(localize.get(TOOLTIP_REMOVE_ITEMS), settings.shortcutRemove);
}
ImGui::EndDisabled();
}
@@ -956,7 +1058,7 @@ namespace anm2ed::imgui
auto drawList = ImGui::GetWindowDrawList();
auto clipMax = drawList->GetClipRectMax();
auto length = animation ? animation->frameNum : anm2.animations.length();
auto length = animation ? animation->frameNum : 0;
auto frameSize = ImVec2(ImGui::GetTextLineHeight(), ImGui::GetContentRegionAvail().y);
auto framesSize = ImVec2(frameSize.x * length, frameSize.y);
auto cursorPos = ImGui::GetCursorPos();
@@ -969,20 +1071,23 @@ namespace anm2ed::imgui
if (type == anm2::NONE)
{
if (isLightTheme)
if (length > 0)
{
auto totalMax = ImVec2(cursorScreenPos.x + framesSize.x, cursorScreenPos.y + framesSize.y);
drawList->AddRectFilled(cursorScreenPos, totalMax, ImGui::GetColorU32(timelineBackgroundColor));
float animationWidth = std::min(framesSize.x, frameSize.x * (float)length);
drawList->AddRectFilled(cursorScreenPos,
ImVec2(cursorScreenPos.x + animationWidth, cursorScreenPos.y + framesSize.y),
ImGui::GetColorU32(timelinePlayheadRectColor));
}
else
{
drawList->AddRectFilled(cursorScreenPos,
ImVec2(cursorScreenPos.x + framesSize.x, cursorScreenPos.y + framesSize.y),
ImGui::GetColorU32(ImGui::GetStyleColorVec4(ImGuiCol_Header)));
if (isLightTheme)
{
auto totalMax = ImVec2(cursorScreenPos.x + framesSize.x, cursorScreenPos.y + framesSize.y);
drawList->AddRectFilled(cursorScreenPos, totalMax, ImGui::GetColorU32(timelineBackgroundColor));
float animationWidth = std::min(framesSize.x, frameSize.x * (float)length);
drawList->AddRectFilled(cursorScreenPos,
ImVec2(cursorScreenPos.x + animationWidth, cursorScreenPos.y + framesSize.y),
ImGui::GetColorU32(timelinePlayheadRectColor));
}
else
{
drawList->AddRectFilled(cursorScreenPos,
ImVec2(cursorScreenPos.x + framesSize.x, cursorScreenPos.y + framesSize.y),
ImGui::GetColorU32(ImGui::GetStyleColorVec4(ImGuiCol_Header)));
}
}
for (int i = frameMin; i < frameMax; i++)
@@ -1029,9 +1134,12 @@ namespace anm2ed::imgui
if (ImGui::IsMouseReleased(0)) isDragging = false;
ImGui::SetCursorPos(ImVec2(cursorPos.x + frameSize.x * floorf(playback.time), cursorPos.y));
ImGui::Image(resources.icons[icon::PLAYHEAD].id, frameSize);
overlay_icon(resources.icons[icon::PLAYHEAD].id, playheadIconTint, true);
if (length > 0)
{
ImGui::SetCursorPos(ImVec2(cursorPos.x + frameSize.x * floorf(playback.time), cursorPos.y));
ImGui::Image(resources.icons[icon::PLAYHEAD].id, frameSize);
overlay_icon(resources.icons[icon::PLAYHEAD].id, playheadIconTint, true);
}
}
else if (animation)
{
@@ -1116,7 +1224,7 @@ namespace anm2ed::imgui
if (type != anm2::TRIGGER)
{
if (ImGui::IsKeyDown(ImGuiMod_Alt))
DOCUMENT_EDIT(document, "Frame Interpolation", Document::FRAMES,
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_INTERPOLATION), Document::FRAMES,
frame.isInterpolated = !frame.isInterpolated);
document.frameTime = frameTime;
@@ -1145,59 +1253,80 @@ namespace anm2ed::imgui
if (showFrameTooltip)
{
if (type != anm2::TRIGGER)
{
auto cropX = frame.crop.x;
auto cropY = frame.crop.y;
auto sizeX = frame.size.x;
auto sizeY = frame.size.y;
auto pivotX = frame.pivot.x;
auto pivotY = frame.pivot.y;
auto scaleX = frame.scale.x;
auto scaleY = frame.scale.y;
auto rotationValue = frame.rotation;
auto durationValue = frame.duration;
auto tintR = math::float_to_uint8(frame.tint.r);
auto tintG = math::float_to_uint8(frame.tint.g);
auto tintB = math::float_to_uint8(frame.tint.b);
auto tintA = math::float_to_uint8(frame.tint.a);
auto visibleLabel = frame.isVisible ? localize.get(BASIC_YES) : localize.get(BASIC_NO);
auto interpolatedLabel = frame.isInterpolated ? localize.get(BASIC_YES) : localize.get(BASIC_NO);
ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE);
ImGui::Text("%s Frame", anm2::TYPE_STRINGS[type]);
ImGui::Text("%s %s", localize.get(anm2::TYPE_STRINGS[type]), localize.get(BASIC_FRAME));
ImGui::PopFont();
auto float_text = [&](std::string label, float& value)
{
std::string useFormat = math::float_format_get(value);
std::string format(label + ": " + useFormat);
ImGui::Text(format.c_str(), value);
};
auto vec2_text = [&](std::string label, vec2& value)
{
std::string useFormat = math::vec2_format_get(value);
std::string format(label + ": " + useFormat + ", " + useFormat);
ImGui::Text(format.c_str(), value.x, value.y);
};
ImGui::Text("Index: %i", (int)i);
auto indexValue = (int)i;
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_INDEX), std::make_format_args(indexValue)).c_str());
if (type == anm2::LAYER)
{
vec2_text("Crop", frame.crop);
vec2_text("Size", frame.size);
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_CROP), std::make_format_args(cropX, cropY)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_SIZE), std::make_format_args(sizeX, sizeY)).c_str());
}
vec2_text("Position", frame.size);
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_POSITION), std::make_format_args(sizeX, sizeY)).c_str());
if (type == anm2::LAYER) vec2_text("Pivot", frame.pivot);
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_PIVOT), std::make_format_args(pivotX, pivotY)).c_str());
vec2_text("Scale", frame.scale);
float_text("Rotation", frame.rotation);
ImGui::Text("Duration: %i", frame.duration);
ImGui::Text("Tint: %i, %i, %i, %i", math::float_to_uint8(frame.tint.r),
math::float_to_uint8(frame.tint.g), math::float_to_uint8(frame.tint.b),
math::float_to_uint8(frame.tint.a));
ImGui::Text("Color Offset: %i, %i, %i", math::float_to_uint8(frame.tint.r),
math::float_to_uint8(frame.tint.g), math::float_to_uint8(frame.tint.b));
ImGui::Text("Visible: %s", frame.isVisible ? "true" : "false");
ImGui::Text("Interpolated: %s", frame.isInterpolated ? "true" : "false");
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_SCALE), std::make_format_args(scaleX, scaleY)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_ROTATION), std::make_format_args(rotationValue)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_DURATION), std::make_format_args(durationValue)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_TINT), std::make_format_args(tintR, tintG, tintB, tintA)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_COLOR_OFFSET), std::make_format_args(tintR, tintG, tintB))
.c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_VISIBLE), std::make_format_args(visibleLabel)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_INTERPOLATED), std::make_format_args(interpolatedLabel)).c_str());
}
else
{
auto atFrameValue = frame.atFrame;
auto eventLabel = document.event.labels[frame.eventID + 1];
auto soundLabel = document.sound.labels[frame.soundID + 1];
ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE);
ImGui::Text("%s", anm2::TYPE_STRINGS[type]);
ImGui::Text("%s %s", localize.get(anm2::TYPE_STRINGS[type]), localize.get(BASIC_FRAME));
ImGui::PopFont();
ImGui::Text("At Frame: %i", frame.atFrame);
ImGui::Text("Event: %s", document.event.labels[frame.eventID + 1]);
ImGui::Text("Sound: %s", document.sound.labels[frame.soundID + 1]);
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_AT_FRAME), std::make_format_args(atFrameValue)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_EVENT_LABEL), std::make_format_args(eventLabel)).c_str());
ImGui::TextUnformatted(
std::vformat(localize.get(FORMAT_SOUND_LABEL), std::make_format_args(soundLabel)).c_str());
}
ImGui::EndTooltip();
@@ -1294,7 +1423,7 @@ namespace anm2ed::imgui
int insertPosResult = -1;
int insertedCount = 0;
DOCUMENT_EDIT(document, "Move Frame(s)", Document::FRAMES, {
DOCUMENT_EDIT(document, localize.get(EDIT_MOVE_FRAMES), Document::FRAMES, {
std::vector<anm2::Frame> movedFrames;
movedFrames.reserve(indices.size());
@@ -1393,7 +1522,8 @@ namespace anm2ed::imgui
if (!isDraggedFrameSnapshot && hoveredTime != draggedFrameStart)
{
isDraggedFrameSnapshot = true;
document.snapshot(type == anm2::TRIGGER ? "Trigger At Frame" : "Frame Duration");
document.snapshot(type == anm2::TRIGGER ? localize.get(EDIT_TRIGGER_AT_FRAME)
: localize.get(EDIT_FRAME_DURATION));
}
if (type == anm2::TRIGGER)
@@ -1562,8 +1692,9 @@ namespace anm2ed::imgui
ImGui::BeginDisabled(!animation);
{
auto label = playback.isPlaying ? "Pause" : "Play";
auto tooltip = playback.isPlaying ? "Pause the animation." : "Play the animation.";
auto label = playback.isPlaying ? localize.get(LABEL_PAUSE) : localize.get(LABEL_PLAY);
auto tooltip =
playback.isPlaying ? localize.get(TOOLTIP_PAUSE_ANIMATION) : localize.get(TOOLTIP_PLAY_ANIMATION);
shortcut(manager.chords[SHORTCUT_PLAY_PAUSE]);
if (ImGui::Button(label, widgetSize)) playback.toggle();
@@ -1576,7 +1707,7 @@ namespace anm2ed::imgui
ImGui::BeginDisabled(!item);
{
shortcut(manager.chords[SHORTCUT_INSERT_FRAME]);
if (ImGui::Button("Insert", widgetSize))
if (ImGui::Button(localize.get(LABEL_INSERT), widgetSize))
{
auto insert_frame = [&]()
{
@@ -1616,23 +1747,23 @@ namespace anm2ed::imgui
frames_selection_set_reference();
};
DOCUMENT_EDIT(document, "Insert Frame", Document::FRAMES, insert_frame());
DOCUMENT_EDIT(document, localize.get(EDIT_INSERT_FRAME), Document::FRAMES, insert_frame());
}
set_item_tooltip_shortcut("Insert a frame, based on the current selection.", settings.shortcutInsertFrame);
set_item_tooltip_shortcut(localize.get(TOOLTIP_INSERT_FRAME), settings.shortcutInsertFrame);
ImGui::SameLine();
ImGui::BeginDisabled(!document.frame_get());
{
shortcut(manager.chords[SHORTCUT_REMOVE]);
if (ImGui::Button("Delete", widgetSize))
DOCUMENT_EDIT(document, "Delete Frame(s)", Document::FRAMES, frames_delete());
set_item_tooltip_shortcut("Delete the selected frames.", settings.shortcutRemove);
if (ImGui::Button(localize.get(LABEL_DELETE), widgetSize))
DOCUMENT_EDIT(document, localize.get(EDIT_DELETE_FRAMES), Document::FRAMES, frames_delete());
set_item_tooltip_shortcut(localize.get(TOOLTIP_DELETE_FRAMES), settings.shortcutRemove);
ImGui::SameLine();
if (ImGui::Button("Bake", widgetSize)) bakePopup.open();
ImGui::SetItemTooltip("Turn interpolated frames into uninterpolated ones.");
if (ImGui::Button(localize.get(LABEL_BAKE), widgetSize)) bakePopup.open();
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_BAKE_FRAMES));
}
ImGui::EndDisabled();
}
@@ -1641,27 +1772,29 @@ namespace anm2ed::imgui
ImGui::SameLine();
ImGui::BeginDisabled(!animation || animation->frameNum == animation->length());
if (ImGui::Button("Fit Animation Length", widgetSize))
DOCUMENT_EDIT(document, "Fit Animation Length", Document::ANIMATIONS, animation->fit_length());
ImGui::SetItemTooltip("The animation length will be set to the effective length of the animation.");
if (ImGui::Button(localize.get(LABEL_FIT_ANIMATION_LENGTH), widgetSize))
DOCUMENT_EDIT(document, localize.get(EDIT_FIT_ANIMATION_LENGTH), Document::ANIMATIONS,
animation->fit_length());
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_FIT_ANIMATION_LENGTH));
ImGui::EndDisabled();
ImGui::SameLine();
auto frameNum = animation ? animation->frameNum : dummy_value<int>();
ImGui::SetNextItemWidth(widgetSize.x);
if (input_int_range("Animation Length", frameNum, anm2::FRAME_NUM_MIN, anm2::FRAME_NUM_MAX, STEP, STEP_FAST,
!animation ? ImGuiInputTextFlags_DisplayEmptyRefVal : 0))
DOCUMENT_EDIT(document, "Animation Length", Document::ANIMATIONS, animation->frameNum = frameNum);
ImGui::SetItemTooltip("Set the animation's length.");
if (input_int_range(localize.get(LABEL_ANIMATION_LENGTH), frameNum, anm2::FRAME_NUM_MIN, anm2::FRAME_NUM_MAX,
STEP, STEP_FAST, !animation ? ImGuiInputTextFlags_DisplayEmptyRefVal : 0))
DOCUMENT_EDIT(document, localize.get(EDIT_ANIMATION_LENGTH), Document::ANIMATIONS,
animation->frameNum = frameNum);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ANIMATION_LENGTH));
ImGui::SameLine();
auto isLoop = animation ? animation->isLoop : dummy_value<bool>();
ImGui::SetNextItemWidth(widgetSize.x);
if (ImGui::Checkbox("Loop", &isLoop))
DOCUMENT_EDIT(document, "Loop", Document::ANIMATIONS, animation->isLoop = isLoop);
ImGui::SetItemTooltip("Toggle the animation looping.");
if (ImGui::Checkbox(localize.get(LABEL_LOOP), &isLoop))
DOCUMENT_EDIT(document, localize.get(EDIT_LOOP), Document::ANIMATIONS, animation->isLoop = isLoop);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_LOOP_ANIMATION));
}
ImGui::EndDisabled();
@@ -1669,23 +1802,23 @@ namespace anm2ed::imgui
auto fps = anm2.info.fps;
ImGui::SetNextItemWidth(widgetSize.x);
if (input_int_range("FPS", fps, anm2::FPS_MIN, anm2::FPS_MAX))
DOCUMENT_EDIT(document, "FPS", Document::ANIMATIONS, anm2.info.fps = fps);
ImGui::SetItemTooltip("Set the FPS of all animations.");
if (input_int_range(localize.get(LABEL_FPS), fps, anm2::FPS_MIN, anm2::FPS_MAX))
DOCUMENT_EDIT(document, localize.get(EDIT_FPS), Document::ANIMATIONS, anm2.info.fps = fps);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_FPS));
ImGui::SameLine();
auto createdBy = anm2.info.createdBy;
ImGui::SetNextItemWidth(widgetSize.x);
if (input_text_string("Author", &createdBy))
DOCUMENT_EDIT(document, "Author", Document::ANIMATIONS, anm2.info.createdBy = createdBy);
ImGui::SetItemTooltip("Set the author of the document.");
if (input_text_string(localize.get(LABEL_AUTHOR), &createdBy))
DOCUMENT_EDIT(document, localize.get(EDIT_AUTHOR), Document::ANIMATIONS, anm2.info.createdBy = createdBy);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_AUTHOR));
ImGui::SameLine();
ImGui::SetNextItemWidth(widgetSize.x);
ImGui::Checkbox("Sound", &settings.timelineIsSound);
ImGui::SetItemTooltip("Toggle sounds playing with triggers.\nBind sounds to events in the Events window.");
ImGui::Checkbox(localize.get(LABEL_SOUND), &settings.timelineIsSound);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SOUND));
ImGui::PopStyleVar();
}
@@ -1695,7 +1828,7 @@ namespace anm2ed::imgui
};
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2());
if (ImGui::Begin("Timeline", &settings.windowIsTimeline))
if (ImGui::Begin(localize.get(LABEL_TIMELINE_WINDOW), &settings.windowIsTimeline))
{
isWindowHovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
frames_child();
@@ -1706,7 +1839,7 @@ namespace anm2ed::imgui
propertiesPopup.trigger();
if (ImGui::BeginPopupModal(propertiesPopup.label, &propertiesPopup.isOpen, ImGuiWindowFlags_NoResize))
if (ImGui::BeginPopupModal(propertiesPopup.label(), &propertiesPopup.isOpen, ImGuiWindowFlags_NoResize))
{
auto item_properties_close = [&]()
{
@@ -1722,80 +1855,79 @@ namespace anm2ed::imgui
auto optionsSize = child_size_get(11);
auto itemsSize = ImVec2(0, ImGui::GetContentRegionAvail().y -
(optionsSize.y + footerSize.y + ImGui::GetStyle().ItemSpacing.y * 4));
if (ImGui::BeginChild("Options", optionsSize, ImGuiChildFlags_Borders))
if (ImGui::BeginChild("##Options", optionsSize, ImGuiChildFlags_Borders))
{
ImGui::SeparatorText("Type");
ImGui::SeparatorText(localize.get(LABEL_TYPE));
auto size = ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, ImGui::GetFrameHeightWithSpacing());
if (ImGui::BeginChild("Type Layer", size))
if (ImGui::BeginChild("##Type 1", size))
{
ImGui::RadioButton("Layer", &type, anm2::LAYER);
ImGui::SetItemTooltip("Layers are a basic visual element in an animation, used for displaying spritesheets.");
ImGui::RadioButton(localize.get(LABEL_LAYER), &type, anm2::LAYER);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_LAYER_TYPE));
}
ImGui::EndChild();
ImGui::SameLine();
if (ImGui::BeginChild("Type Null", size))
if (ImGui::BeginChild("##Type 2", size))
{
ImGui::RadioButton("Null", &type, anm2::NULL_);
ImGui::SetItemTooltip(
"Nulls are invisible elements in an animation, used for interfacing with a game engine.");
ImGui::RadioButton(localize.get(LABEL_NULL), &type, anm2::NULL_);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_NULL_TYPE));
}
ImGui::EndChild();
ImGui::SeparatorText("Source");
ImGui::SeparatorText(localize.get(LABEL_SOURCE));
if (ImGui::BeginChild("Source New", size))
if (ImGui::BeginChild("##Source 1", size))
{
ImGui::RadioButton("New", &source, source::NEW);
ImGui::SetItemTooltip("Create a new item to be used.");
ImGui::RadioButton(localize.get(LABEL_NEW), &source, source::NEW);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_NEW_ITEM));
}
ImGui::EndChild();
ImGui::SameLine();
if (ImGui::BeginChild("Source Existing", size))
if (ImGui::BeginChild("##Source 2", size))
{
auto hasUnusedItems = animation && !unused_items_get((anm2::Type)type).empty();
ImGui::BeginDisabled(!hasUnusedItems);
ImGui::RadioButton("Existing", &source, source::EXISTING);
auto isUnusedItems = animation && !unused_items_get((anm2::Type)type).empty();
ImGui::BeginDisabled(!isUnusedItems);
ImGui::RadioButton(localize.get(LABEL_EXISTING), &source, source::EXISTING);
ImGui::EndDisabled();
auto tooltip =
hasUnusedItems ? "Use a pre-existing, presently unused item." : "No unused items are available.";
ImGui::SetItemTooltip("%s", tooltip);
ImGui::SetItemTooltip("%s", isUnusedItems ? localize.get(TOOLTIP_USE_EXISTING_ITEM)
: localize.get(TOOLTIP_NO_UNUSED_ITEMS));
}
ImGui::EndChild();
ImGui::SeparatorText("Locale");
ImGui::SeparatorText(localize.get(LABEL_LOCALE));
if (ImGui::BeginChild("Locale Global", size))
if (ImGui::BeginChild("##Locale 1", size))
{
ImGui::RadioButton("Global", &locale, locale::GLOBAL);
ImGui::SetItemTooltip("The item will be inserted into all animations, if not already present.");
ImGui::RadioButton(localize.get(LABEL_GLOBAL), &locale, locale::GLOBAL);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_GLOBAL_LOCALE));
}
ImGui::EndChild();
ImGui::SameLine();
if (ImGui::BeginChild("Locale Local", size))
if (ImGui::BeginChild("##Locale 2", size))
{
ImGui::RadioButton("Local", &locale, locale::LOCAL);
ImGui::SetItemTooltip("The item will only be inserted into this animation.");
ImGui::RadioButton(localize.get(LABEL_LOCAL), &locale, locale::LOCAL);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_LOCAL_LOCALE));
}
ImGui::EndChild();
ImGui::SeparatorText("Options");
ImGui::SeparatorText(localize.get(LABEL_OPTIONS));
ImGui::BeginDisabled(source == source::EXISTING);
{
input_text_string("Name", &addItemName);
ImGui::SetItemTooltip("Set the item's name.");
input_text_string(localize.get(BASIC_NAME), &addItemName);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ITEM_NAME));
ImGui::BeginDisabled(type != anm2::LAYER);
{
combo_negative_one_indexed("Spritesheet", &addItemSpritesheetID, document.spritesheet.labels);
ImGui::SetItemTooltip("Set the layer item's spritesheet.");
combo_negative_one_indexed(localize.get(LABEL_SPRITESHEET), &addItemSpritesheetID,
document.spritesheet.labels);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_LAYER_SPRITESHEET));
}
ImGui::EndDisabled();
}
@@ -1803,7 +1935,7 @@ namespace anm2ed::imgui
}
ImGui::EndChild();
if (ImGui::BeginChild("Items", itemsSize, ImGuiChildFlags_Borders))
if (ImGui::BeginChild("##Items", itemsSize, ImGuiChildFlags_Borders))
{
if (animation && source == source::EXISTING)
{
@@ -1819,15 +1951,15 @@ namespace anm2ed::imgui
if (type == anm2::LAYER)
{
auto& layer = anm2.content.layers[id];
if (ImGui::Selectable(
std::format("#{} {} (Spritesheet: #{})", id, layer.name, layer.spritesheetID).c_str(),
isSelected))
addItemID = id;
auto label =
std::vformat(localize.get(FORMAT_LAYER), std::make_format_args(id, layer.name, layer.spritesheetID));
if (ImGui::Selectable(label.c_str(), isSelected)) addItemID = id;
}
else if (type == anm2::NULL_)
{
auto& null = anm2.content.nulls[id];
if (ImGui::Selectable(std::format("#{} {}", id, null.name).c_str(), isSelected)) addItemID = id;
auto label = std::vformat(localize.get(FORMAT_NULL), std::make_format_args(id, null.name));
if (ImGui::Selectable(label.c_str(), isSelected)) addItemID = id;
}
ImGui::PopID();
@@ -1839,11 +1971,11 @@ namespace anm2ed::imgui
auto widgetSize = widget_size_with_row_get(2);
ImGui::BeginDisabled(source == source::EXISTING && addItemID == -1);
if (ImGui::Button("Add", widgetSize))
if (ImGui::Button(localize.get(BASIC_ADD), widgetSize))
{
anm2::Reference addReference{};
document.snapshot("Add Item");
document.snapshot(localize.get(EDIT_ADD_ITEM));
if (type == anm2::LAYER)
addReference = anm2.layer_animation_add({reference.animationIndex, anm2::LAYER, addItemID}, addItemName,
addItemSpritesheetID - 1, (locale::Type)locale);
@@ -1864,19 +1996,19 @@ namespace anm2ed::imgui
item_properties_close();
}
ImGui::EndDisabled();
ImGui::SetItemTooltip("Add the item, with the settings specified.");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ADD_ITEM));
ImGui::SameLine();
if (ImGui::Button("Cancel", widgetSize)) item_properties_close();
ImGui::SetItemTooltip("Cancel adding an item.");
if (ImGui::Button(localize.get(BASIC_CANCEL), widgetSize)) item_properties_close();
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_CANCEL_ADD_ITEM));
ImGui::EndPopup();
}
bakePopup.trigger();
if (ImGui::BeginPopupModal(bakePopup.label, &bakePopup.isOpen, ImGuiWindowFlags_NoResize))
if (ImGui::BeginPopupModal(bakePopup.label(), &bakePopup.isOpen, ImGuiWindowFlags_NoResize))
{
auto& interval = settings.bakeInterval;
auto& isRoundRotation = settings.bakeIsRoundRotation;
@@ -1884,19 +2016,19 @@ namespace anm2ed::imgui
auto frame = document.frame_get();
input_int_range("Interval", interval, anm2::FRAME_DURATION_MIN,
input_int_range(localize.get(LABEL_INTERVAL), interval, anm2::FRAME_DURATION_MIN,
frame ? frame->duration : anm2::FRAME_DURATION_MIN);
ImGui::SetItemTooltip("Set the maximum duration of each frame that will be baked.");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_INTERVAL));
ImGui::Checkbox("Round Rotation", &isRoundRotation);
ImGui::SetItemTooltip("Rotation will be rounded to the nearest whole number.");
ImGui::Checkbox(localize.get(LABEL_ROUND_ROTATION), &isRoundRotation);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ROUND_ROTATION));
ImGui::Checkbox("Round Scale", &isRoundScale);
ImGui::SetItemTooltip("Scale will be rounded to the nearest whole number.");
ImGui::Checkbox(localize.get(LABEL_ROUND_SCALE), &isRoundScale);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ROUND_SCALE));
auto widgetSize = widget_size_with_row_get(2);
if (ImGui::Button("Bake", widgetSize))
if (ImGui::Button(localize.get(LABEL_BAKE), widgetSize))
{
auto frames_bake = [&]()
{
@@ -1907,16 +2039,16 @@ namespace anm2ed::imgui
frames.clear();
};
DOCUMENT_EDIT(document, "Bake Frames", Document::FRAMES, frames_bake());
DOCUMENT_EDIT(document, localize.get(EDIT_BAKE_FRAMES), Document::FRAMES, frames_bake());
bakePopup.close();
}
ImGui::SetItemTooltip("Bake the selected frame(s) with the options selected.");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_BAKE_FRAMES_OPTIONS));
ImGui::SameLine();
if (ImGui::Button("Cancel", widgetSize)) bakePopup.close();
ImGui::SetItemTooltip("Cancel baking frames.");
if (ImGui::Button(localize.get(BASIC_CANCEL), widgetSize)) bakePopup.close();
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_CANCEL_BAKE_FRAMES));
ImGui::EndPopup();
}
@@ -1940,7 +2072,7 @@ namespace anm2ed::imgui
static bool isShortenChordHeld = false;
auto isShortenFrame = shortcut(manager.chords[SHORTCUT_SHORTEN_FRAME], shortcut::GLOBAL);
if (isShortenFrame && !isShortenChordHeld) document.snapshot("Shorten Frame");
if (isShortenFrame && !isShortenChordHeld) document.snapshot(localize.get(EDIT_SHORTEN_FRAME));
if (isShortenFrame)
{
@@ -1954,7 +2086,7 @@ namespace anm2ed::imgui
static bool isExtendChordHeld = false;
auto isExtendFrame = shortcut(manager.chords[SHORTCUT_EXTEND_FRAME], shortcut::GLOBAL);
if (isExtendFrame && !isExtendChordHeld) document.snapshot("Extend Frame");
if (isExtendFrame && !isExtendChordHeld) document.snapshot(localize.get(EDIT_EXTEND_FRAME));
if (isExtendFrame)
{
+4 -4
View File
@@ -1,12 +1,12 @@
#pragma once
#include <set>
#include <vector>
#include "clipboard.h"
#include "manager.h"
#include "resources.h"
#include "settings.h"
#include "strings.h"
namespace anm2ed::imgui
{
@@ -23,9 +23,9 @@ namespace anm2ed::imgui
bool isDragging{};
bool isWindowHovered{};
bool isHorizontalScroll{};
PopupHelper propertiesPopup{PopupHelper("Item Properties", POPUP_NORMAL)};
PopupHelper bakePopup{PopupHelper("Bake", POPUP_SMALL_NO_HEIGHT)};
std::string addItemName{};
PopupHelper propertiesPopup{PopupHelper(LABEL_TIMELINE_PROPERTIES_POPUP, POPUP_NORMAL)};
PopupHelper bakePopup{PopupHelper(LABEL_TIMELINE_BAKE_POPUP, POPUP_SMALL_NO_HEIGHT)};
std::string addItemName{"New Item"};
bool addItemIsRect{};
int addItemID{-1};
int addItemSpritesheetID{-1};
+8 -6
View File
@@ -3,6 +3,7 @@
#include <glm/gtc/type_ptr.hpp>
#include "strings.h"
#include "tool.h"
#include "types.h"
@@ -16,7 +17,7 @@ namespace anm2ed::imgui
{
auto& document = *manager.get();
if (ImGui::Begin("Tools", &settings.windowIsTools))
if (ImGui::Begin(localize.get(LABEL_TOOLS_WINDOW), &settings.windowIsTools))
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 2));
@@ -54,10 +55,11 @@ namespace anm2ed::imgui
if (shortcut(manager.chords[info.shortcut], shortcut::GLOBAL)) tool_use((tool::Type)i);
auto labelText = info.label;
if (i == tool::COLOR)
{
size += to_vec2(ImGui::GetStyle().FramePadding) * 2.0f;
if (ImGui::ColorButton(info.label, to_imvec4(settings.toolColor), ImGuiColorEditFlags_NoTooltip,
if (ImGui::ColorButton(labelText, to_imvec4(settings.toolColor), ImGuiColorEditFlags_NoTooltip,
to_imvec2(size)))
tool_use((tool::Type)i);
@@ -67,7 +69,7 @@ namespace anm2ed::imgui
{
if (i == tool::UNDO) ImGui::BeginDisabled(!document.is_able_to_undo());
if (i == tool::REDO) ImGui::BeginDisabled(!document.is_able_to_redo());
if (ImGui::ImageButton(info.label, resources.icons[info.icon].id, to_imvec2(size), ImVec2(0, 0), ImVec2(1, 1),
if (ImGui::ImageButton(labelText, resources.icons[info.icon].id, to_imvec2(size), ImVec2(0, 0), ImVec2(1, 1),
ImVec4(0, 0, 0, 0), iconTint))
tool_use((tool::Type)i);
if (i == tool::UNDO) ImGui::EndDisabled();
@@ -81,7 +83,7 @@ namespace anm2ed::imgui
ImGui::SameLine();
else
usedWidth = ImGui::GetStyle().WindowPadding.x;
set_item_tooltip_shortcut(info.tooltip, settings.*SHORTCUT_MEMBERS[info.shortcut]);
set_item_tooltip_shortcut(localize.get(info.tooltip), settings.*SHORTCUT_MEMBERS[info.shortcut]);
if (isSelected) ImGui::PopStyleColor();
}
@@ -90,9 +92,9 @@ namespace anm2ed::imgui
colorEditPopup.trigger();
if (ImGui::BeginPopup(colorEditPopup.label))
if (ImGui::BeginPopup(colorEditPopup.label()))
{
ImGui::ColorPicker4(colorEditPopup.label, value_ptr(settings.toolColor));
ImGui::ColorPicker4(colorEditPopup.label(), value_ptr(settings.toolColor));
ImGui::EndPopup();
}
}
+3 -1
View File
@@ -3,6 +3,7 @@
#include "manager.h"
#include "resources.h"
#include "settings.h"
#include "strings.h"
namespace anm2ed::imgui
{
@@ -11,7 +12,8 @@ namespace anm2ed::imgui
bool isOpenColorEdit{};
ImVec2 colorEditPosition{};
PopupHelper colorEditPopup{PopupHelper("##Color Edit", POPUP_TO_CONTENT, POPUP_BY_ITEM)};
PopupHelper colorEditPopup{
PopupHelper(LABEL_TOOLS_COLOR_EDIT_POPUP, POPUP_TO_CONTENT, POPUP_BY_ITEM)};
public:
void update(Manager&, Settings&, Resources&);
+11 -10
View File
@@ -2,6 +2,8 @@
#include <ranges>
#include "strings.h"
using namespace anm2ed::resource;
namespace anm2ed::imgui
@@ -15,24 +17,23 @@ namespace anm2ed::imgui
ImGui::SetNextWindowPos(ImVec2(viewport->Pos.x, viewport->Pos.y + taskbar.height + documents.height));
ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, windowHeight));
if (ImGui::Begin("Welcome", nullptr,
if (ImGui::Begin(localize.get(LABEL_WELCOME_WINDOW), nullptr,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoScrollWithMouse))
{
ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE_LARGE);
ImGui::TextUnformatted("Anm2Ed");
ImGui::TextUnformatted(localize.get(LABEL_APPLICATION_NAME));
ImGui::PopFont();
ImGui::TextUnformatted("Select a recent file or open a new or existing document. You can also drag and drop "
"files into the window to open them.");
ImGui::TextUnformatted(localize.get(LABEL_WELCOME_DESCRIPTION));
auto widgetSize = widget_size_with_row_get(2);
if (ImGui::Button("New", widgetSize)) dialog.file_save(dialog::ANM2_NEW); // handled in taskbar.cpp
if (ImGui::Button(localize.get(BASIC_NEW), widgetSize)) dialog.file_save(dialog::ANM2_NEW); // handled in taskbar.cpp
ImGui::SameLine();
if (ImGui::Button("Open", widgetSize)) dialog.file_open(dialog::ANM2_OPEN); // handled in taskbar.cpp
if (ImGui::Button(localize.get(BASIC_OPEN), widgetSize)) dialog.file_open(dialog::ANM2_OPEN); // handled in taskbar.cpp
if (ImGui::BeginChild("##Recent Files Child", {}, ImGuiChildFlags_Borders))
{
@@ -61,9 +62,9 @@ namespace anm2ed::imgui
restorePopup.trigger();
if (ImGui::BeginPopupModal(restorePopup.label, &restorePopup.isOpen, ImGuiWindowFlags_NoResize))
if (ImGui::BeginPopupModal(restorePopup.label(), &restorePopup.isOpen, ImGuiWindowFlags_NoResize))
{
ImGui::TextUnformatted("Autosaved documents detected. Would you like to restore them?");
ImGui::TextUnformatted(localize.get(LABEL_RESTORE_AUTOSAVES_PROMPT));
auto childSize = child_size_get(5);
@@ -80,7 +81,7 @@ namespace anm2ed::imgui
auto widgetSize = widget_size_with_row_get(2);
if (ImGui::Button("Yes", widgetSize))
if (ImGui::Button(localize.get(BASIC_YES), widgetSize))
{
manager.autosave_files_open();
restorePopup.close();
@@ -88,7 +89,7 @@ namespace anm2ed::imgui
ImGui::SameLine();
if (ImGui::Button("No", widgetSize))
if (ImGui::Button(localize.get(BASIC_NO), widgetSize))
{
manager.autosave_files_clear();
restorePopup.close();
+3 -2
View File
@@ -2,15 +2,16 @@
#include "documents.h"
#include "manager.h"
#include "strings.h"
#include "taskbar.h"
namespace anm2ed::imgui
{
class Welcome
{
PopupHelper restorePopup{PopupHelper("Restore", imgui::POPUP_SMALL_NO_HEIGHT)};
PopupHelper restorePopup{PopupHelper(LABEL_WELCOME_RESTORE_POPUP, imgui::POPUP_SMALL_NO_HEIGHT)};
public:
void update(Manager&, Resources&, Dialog&, Taskbar&, Documents&);
};
};
};