timeline refactor, bit broken rn
This commit is contained in:
@@ -74,12 +74,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 label = std::format("{}###Document{}", string, i);
|
||||
|
||||
auto flags = isDirty ? ImGuiTabItemFlags_UnsavedDocument : 0;
|
||||
@@ -89,7 +86,9 @@ namespace anm2ed::imgui
|
||||
if (ImGui::BeginTabItem(label.c_str(), &document.isOpen, flags))
|
||||
{
|
||||
manager.set(i);
|
||||
|
||||
if (isRequested) manager.pendingSelected = -1;
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::PopFont();
|
||||
|
||||
@@ -166,10 +166,7 @@ namespace anm2ed::imgui
|
||||
return (width - (ImGui::GetStyle().ItemSpacing.x * (float)(count - 1))) / (float)count;
|
||||
}
|
||||
|
||||
ImVec2 widget_size_with_row_get(int count, float width)
|
||||
{
|
||||
return ImVec2(row_widget_width_get(count, width), 0);
|
||||
}
|
||||
ImVec2 widget_size_with_row_get(int count, float width) { return ImVec2(row_widget_width_get(count, width), 0); }
|
||||
|
||||
float footer_height_get(int itemCount)
|
||||
{
|
||||
@@ -265,17 +262,13 @@ namespace anm2ed::imgui
|
||||
return ImGui::Shortcut(string_to_chord(string), flags);
|
||||
}
|
||||
|
||||
MultiSelectStorage::MultiSelectStorage()
|
||||
{
|
||||
internal.AdapterSetItemSelected = external_storage_set;
|
||||
}
|
||||
MultiSelectStorage::MultiSelectStorage() { internal.AdapterSetItemSelected = external_storage_set; }
|
||||
|
||||
void MultiSelectStorage::start(size_t size)
|
||||
void MultiSelectStorage::start(size_t size, ImGuiMultiSelectFlags flags)
|
||||
{
|
||||
internal.UserData = this;
|
||||
|
||||
auto io = ImGui::BeginMultiSelect(ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d,
|
||||
this->size(), size);
|
||||
auto io = ImGui::BeginMultiSelect(flags, this->size(), size);
|
||||
internal.ApplyRequests(io);
|
||||
}
|
||||
|
||||
@@ -299,10 +292,7 @@ namespace anm2ed::imgui
|
||||
isJustOpened = true;
|
||||
}
|
||||
|
||||
bool PopupHelper::is_open()
|
||||
{
|
||||
return isOpen;
|
||||
}
|
||||
bool PopupHelper::is_open() { return isOpen; }
|
||||
|
||||
void PopupHelper::trigger()
|
||||
{
|
||||
@@ -322,13 +312,7 @@ namespace anm2ed::imgui
|
||||
ImGui::SetNextWindowSize(ImVec2(viewport->Size.x * POPUP_MULTIPLIERS[type], 0));
|
||||
}
|
||||
|
||||
void PopupHelper::end()
|
||||
{
|
||||
isJustOpened = false;
|
||||
}
|
||||
void PopupHelper::end() { isJustOpened = false; }
|
||||
|
||||
void PopupHelper::close()
|
||||
{
|
||||
isOpen = false;
|
||||
}
|
||||
void PopupHelper::close() { isOpen = false; }
|
||||
}
|
||||
|
||||
@@ -190,7 +190,9 @@ namespace anm2ed::imgui
|
||||
using std::set<int>::erase;
|
||||
|
||||
MultiSelectStorage();
|
||||
void start(size_t);
|
||||
void start(size_t, ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_BoxSelect2d |
|
||||
ImGuiMultiSelectFlags_ClearOnEscape |
|
||||
ImGuiMultiSelectFlags_ScopeWindow);
|
||||
void finish();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
#include "taskbar.h"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include "math_.h"
|
||||
#include "render.h"
|
||||
#include "shader.h"
|
||||
#include "toast.h"
|
||||
#include "types.h"
|
||||
|
||||
#include "icon.h"
|
||||
|
||||
using namespace anm2ed::resource;
|
||||
using namespace anm2ed::types;
|
||||
using namespace anm2ed::canvas;
|
||||
@@ -16,10 +26,111 @@ using namespace glm;
|
||||
|
||||
namespace anm2ed::imgui
|
||||
{
|
||||
Taskbar::Taskbar() : generate(vec2())
|
||||
#ifdef __unix__
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr std::array<int, 7> ICON_SIZES{16, 24, 32, 48, 64, 128, 256};
|
||||
|
||||
bool ensure_parent_directory_exists(const std::filesystem::path& path)
|
||||
{
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(path.parent_path(), ec);
|
||||
if (ec)
|
||||
{
|
||||
toasts.warning(std::format("Could not create directory for {} ({})", path.string(), ec.message()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write_binary_blob(const std::filesystem::path& path, const std::uint8_t* data, size_t size)
|
||||
{
|
||||
if (!ensure_parent_directory_exists(path)) return false;
|
||||
|
||||
std::ofstream file(path, std::ios::binary | std::ios::trunc);
|
||||
if (!file.is_open())
|
||||
{
|
||||
toasts.warning(std::format("Could not open {} for writing", path.string()));
|
||||
return false;
|
||||
}
|
||||
|
||||
file.write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool run_command_checked(const std::string& command, const std::string& description)
|
||||
{
|
||||
auto result = std::system(command.c_str());
|
||||
if (result != 0)
|
||||
{
|
||||
toasts.warning(std::format("{} failed (exit code {})", description, result));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool install_icon_set(const std::string& context, const std::string& iconName, const std::filesystem::path& path)
|
||||
{
|
||||
bool success = true;
|
||||
for (auto size : ICON_SIZES)
|
||||
{
|
||||
auto command = std::format("xdg-icon-resource install --noupdate --novendor --context {} --size {} \"{}\" {}",
|
||||
context, size, path.string(), iconName);
|
||||
success &= run_command_checked(command, std::format("Install {} icon ({}px)", iconName, size));
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool uninstall_icon_set(const std::string& context, const std::string& iconName)
|
||||
{
|
||||
bool success = true;
|
||||
for (auto size : ICON_SIZES)
|
||||
{
|
||||
auto command =
|
||||
std::format("xdg-icon-resource uninstall --noupdate --context {} --size {} {}", context, size, iconName);
|
||||
success &= run_command_checked(command, std::format("Remove {} icon ({}px)", iconName, size));
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool remove_file_if_exists(const std::filesystem::path& path)
|
||||
{
|
||||
std::error_code ec;
|
||||
if (!std::filesystem::exists(path, ec)) return true;
|
||||
std::filesystem::remove(path, ec);
|
||||
if (ec)
|
||||
{
|
||||
toasts.warning(std::format("Could not remove {} ({})", path.string(), ec.message()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto MIME_TYPE = R"(<?xml version="1.0" encoding="utf-8"?>
|
||||
<mime-type xmlns="http://www.freedesktop.org/standards/shared-mime-info" type="application/x-anm2+xml">
|
||||
<!--Created automatically by update-mime-database. DO NOT EDIT!-->
|
||||
<comment>Anm2 Animation</comment>
|
||||
<glob pattern="*.anm2"/>
|
||||
</mime-type>
|
||||
)";
|
||||
|
||||
constexpr auto DESKTOP_ENTRY_FORMAT = R"([Desktop Entry]
|
||||
Type=Application
|
||||
Name=Anm2Ed
|
||||
Icon=anm2ed
|
||||
Comment=Animation editor for .anm2 files
|
||||
Exec={}
|
||||
Terminal=false
|
||||
Categories=Graphics;Development;
|
||||
MimeType=application/x-anm2+xml;
|
||||
)";
|
||||
|
||||
#endif
|
||||
|
||||
Taskbar::Taskbar() : generate(vec2()) {}
|
||||
|
||||
void Taskbar::update(Manager& manager, Settings& settings, Resources& resources, Dialog& dialog, bool& isQuitting)
|
||||
{
|
||||
auto document = manager.get();
|
||||
@@ -119,6 +230,141 @@ namespace anm2ed::imgui
|
||||
configurePopup.open();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem("Associate .anm2 Files with Editor", nullptr, false,
|
||||
!isAnm2Association || !isAbleToAssociateAnm2))
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
#elif __unix__
|
||||
auto cache_icons = []()
|
||||
{
|
||||
auto programIconPath = std::filesystem::path(filesystem::path_icon_get());
|
||||
auto fileIconPath = std::filesystem::path(filesystem::path_icon_file_get());
|
||||
auto iconBytes = std::size(resource::icon::PROGRAM);
|
||||
|
||||
bool isSuccess = write_binary_blob(programIconPath, resource::icon::PROGRAM, iconBytes) &&
|
||||
write_binary_blob(fileIconPath, resource::icon::PROGRAM, iconBytes);
|
||||
|
||||
if (isSuccess)
|
||||
{
|
||||
isSuccess = install_icon_set("apps", "anm2ed", programIconPath) &&
|
||||
install_icon_set("mimetypes", "application-x-anm2+xml", fileIconPath) &&
|
||||
run_command_checked("xdg-icon-resource forceupdate --theme hicolor", "Refresh icon cache");
|
||||
}
|
||||
|
||||
remove_file_if_exists(programIconPath);
|
||||
remove_file_if_exists(fileIconPath);
|
||||
|
||||
if (isSuccess) toasts.info("Cached program and file icons.");
|
||||
return isSuccess;
|
||||
};
|
||||
|
||||
auto register_mime = []()
|
||||
{
|
||||
auto path = std::filesystem::path(filesystem::path_mime_get());
|
||||
if (!ensure_parent_directory_exists(path)) return false;
|
||||
|
||||
std::ofstream file(path, std::ofstream::out | std::ofstream::trunc);
|
||||
if (!file.is_open())
|
||||
{
|
||||
toasts.warning(std::format("Could not write .anm2 MIME type: {}", path.string()));
|
||||
return false;
|
||||
}
|
||||
|
||||
file << MIME_TYPE;
|
||||
file.close();
|
||||
toasts.info(std::format("Wrote .anm2 MIME type to: {}", path.string()));
|
||||
|
||||
auto mimeRoot = path.parent_path().parent_path();
|
||||
auto command = std::format("update-mime-database \"{}\"", mimeRoot.string());
|
||||
return run_command_checked(command, "Update MIME database");
|
||||
};
|
||||
|
||||
auto register_desktop_entry = []()
|
||||
{
|
||||
auto path = std::filesystem::path(filesystem::path_application_get());
|
||||
if (!ensure_parent_directory_exists(path)) return false;
|
||||
|
||||
std::ofstream file(path, std::ofstream::out | std::ofstream::trunc);
|
||||
if (!file.is_open())
|
||||
{
|
||||
toasts.warning(std::format("Could not write desktop entry: {}", path.string()));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto desktopEntry = std::format(DESKTOP_ENTRY_FORMAT, filesystem::path_executable_get());
|
||||
file << desktopEntry;
|
||||
file.close();
|
||||
toasts.info(std::format("Wrote desktop entry to: {}", path.string()));
|
||||
|
||||
auto desktopDir = path.parent_path();
|
||||
auto desktopUpdate =
|
||||
std::format("update-desktop-database \"{}\"", desktopDir.empty() ? "." : desktopDir.string());
|
||||
auto desktopFileName = path.filename().string();
|
||||
auto setDefault = std::format("xdg-mime default {} application/x-anm2+xml",
|
||||
desktopFileName.empty() ? path.string() : desktopFileName);
|
||||
|
||||
auto databaseUpdated = run_command_checked(desktopUpdate, "Update desktop database");
|
||||
auto defaultRegistered = run_command_checked(setDefault, "Set default handler for .anm2");
|
||||
return databaseUpdated && defaultRegistered;
|
||||
};
|
||||
|
||||
auto iconsCached = cache_icons();
|
||||
auto mimeRegistered = register_mime();
|
||||
auto desktopRegistered = register_desktop_entry();
|
||||
|
||||
isAnm2Association = iconsCached && mimeRegistered && desktopRegistered;
|
||||
if (isAnm2Association)
|
||||
toasts.info("Associated .anm2 files with the editor.");
|
||||
else
|
||||
toasts.warning("Association incomplete. Please review the warnings above.");
|
||||
#endif
|
||||
}
|
||||
ImGui::SetItemTooltip(
|
||||
"Associate .anm2 files with the application (i.e., clicking on them in a file explorer will "
|
||||
"open the application).");
|
||||
|
||||
if (ImGui::MenuItem("Remove .anm2 File Association", nullptr, false,
|
||||
isAnm2Association || !isAbleToAssociateAnm2))
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
#elif __unix__
|
||||
{
|
||||
auto iconsRemoved =
|
||||
uninstall_icon_set("apps", "anm2ed") && uninstall_icon_set("mimetypes", "application-x-anm2+xml") &&
|
||||
run_command_checked("xdg-icon-resource forceupdate --theme hicolor", "Refresh icon cache");
|
||||
if (iconsRemoved)
|
||||
toasts.info("Removed cached icons.");
|
||||
else
|
||||
toasts.warning("Could not remove all cached icons.");
|
||||
}
|
||||
|
||||
{
|
||||
auto path = std::filesystem::path(filesystem::path_mime_get());
|
||||
auto removed = remove_file_if_exists(path);
|
||||
if (removed) toasts.info(std::format("Removed .anm2 MIME type: {}", path.string()));
|
||||
|
||||
auto mimeRoot = path.parent_path().parent_path();
|
||||
run_command_checked(std::format("update-mime-database \"{}\"", mimeRoot.string()), "Update MIME database");
|
||||
}
|
||||
|
||||
{
|
||||
auto path = std::filesystem::path(filesystem::path_application_get());
|
||||
if (remove_file_if_exists(path)) toasts.info(std::format("Removed desktop entry: {}", path.string()));
|
||||
|
||||
auto desktopDir = path.parent_path();
|
||||
run_command_checked(
|
||||
std::format("update-desktop-database \"{}\"", desktopDir.empty() ? "." : desktopDir.string()),
|
||||
"Update desktop database");
|
||||
}
|
||||
#endif
|
||||
isAnm2Association = false;
|
||||
}
|
||||
ImGui::SetItemTooltip("Unassociate .anm2 files with the application.");
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
@@ -546,7 +792,7 @@ namespace anm2ed::imgui
|
||||
if (dialogType == dialog::PNG_DIRECTORY_SET)
|
||||
dialog.folder_open(dialogType);
|
||||
else
|
||||
dialog.file_open(dialogType);
|
||||
dialog.file_save(dialogType);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
input_text_string(type == render::PNGS ? "Directory" : "Path", &path);
|
||||
@@ -581,11 +827,16 @@ namespace anm2ed::imgui
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::Checkbox("Raw", &isRaw);
|
||||
ImGui::SetItemTooltip("Record only the layers of the animation.");
|
||||
ImGui::SetItemTooltip("Record only the raw animation; i.e., only its layers, to its bounds.");
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
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.");
|
||||
|
||||
if (ImGui::Button("Render", widgetSize))
|
||||
{
|
||||
manager.isRecording = true;
|
||||
manager.isRecordingStart = true;
|
||||
playback.time = start;
|
||||
playback.isPlaying = true;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "canvas.h"
|
||||
#include "dialog.h"
|
||||
#include "filesystem_.h"
|
||||
#include "imgui_.h"
|
||||
#include "manager.h"
|
||||
#include "resources.h"
|
||||
@@ -20,6 +21,15 @@ namespace anm2ed::imgui
|
||||
PopupHelper aboutPopup{PopupHelper("About")};
|
||||
Settings editSettings{};
|
||||
int selectedShortcut{-1};
|
||||
|
||||
#if defined(_WIN32) || defined(__unix__)
|
||||
bool isAbleToAssociateAnm2 = true;
|
||||
#else
|
||||
bool isAbleToAssociateAnm2 = false;
|
||||
#endif
|
||||
|
||||
bool isAnm2Association = std::filesystem::exists(util::filesystem::path_application_get());
|
||||
|
||||
bool isQuittingMode{};
|
||||
|
||||
public:
|
||||
|
||||
@@ -9,7 +9,8 @@ using namespace anm2ed::types;
|
||||
|
||||
namespace anm2ed::imgui
|
||||
{
|
||||
constexpr auto LIFETIME = 3.0f;
|
||||
constexpr auto LIFETIME = 4.0f;
|
||||
constexpr auto FADE_THRESHOLD = 1.0f;
|
||||
|
||||
Toast::Toast(const std::string& message)
|
||||
{
|
||||
@@ -30,8 +31,6 @@ namespace anm2ed::imgui
|
||||
{
|
||||
Toast& toast = toasts[i];
|
||||
|
||||
toast.lifetime -= ImGui::GetIO().DeltaTime;
|
||||
|
||||
if (toast.lifetime <= 0.0f)
|
||||
{
|
||||
toasts.erase(toasts.begin() + i);
|
||||
@@ -39,7 +38,9 @@ namespace anm2ed::imgui
|
||||
continue;
|
||||
}
|
||||
|
||||
auto alpha = toast.lifetime / LIFETIME;
|
||||
toast.lifetime -= ImGui::GetIO().DeltaTime;
|
||||
|
||||
auto alpha = toast.lifetime <= FADE_THRESHOLD ? toast.lifetime / FADE_THRESHOLD : 1.0f;
|
||||
borderColor.w = alpha;
|
||||
textColor.w = alpha;
|
||||
|
||||
@@ -57,6 +58,8 @@ namespace anm2ed::imgui
|
||||
{
|
||||
ImGui::TextUnformatted(toast.message.c_str());
|
||||
position.y -= ImGui::GetWindowSize().y + ImGui::GetStyle().ItemSpacing.y;
|
||||
|
||||
if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) toast.lifetime = 0.0f;
|
||||
}
|
||||
ImGui::End();
|
||||
ImGui::PopStyleColor(2);
|
||||
|
||||
@@ -42,51 +42,22 @@ namespace anm2ed::imgui
|
||||
auto& isSound = settings.timelineIsSound;
|
||||
auto& isOnlyShowLayers = settings.timelineIsOnlyShowLayers;
|
||||
|
||||
if (isSound && !anm2.content.sounds.empty())
|
||||
if (auto animation = document.animation_get(); animation)
|
||||
if (animation->triggers.isVisible && !isOnlyShowLayers)
|
||||
if (auto trigger = animation->triggers.frame_generate(playback.time, anm2::TRIGGER);
|
||||
trigger.is_visible(anm2::TRIGGER))
|
||||
if (anm2.content.sounds.contains(trigger.soundID)) anm2.content.sounds[trigger.soundID].audio.play();
|
||||
if (!anm2.content.sounds.empty() && isSound)
|
||||
{
|
||||
if (auto animation = document.animation_get();
|
||||
animation && animation->triggers.isVisible && (!isOnlyShowLayers || manager.isRecording))
|
||||
{
|
||||
if (auto trigger = animation->triggers.frame_generate(playback.time, anm2::TRIGGER);
|
||||
trigger.is_visible(anm2::TRIGGER))
|
||||
if (anm2.content.sounds.contains(trigger.soundID)) anm2.content.sounds[trigger.soundID].audio.play(mixer);
|
||||
}
|
||||
}
|
||||
|
||||
document.reference.frameTime = playback.time;
|
||||
}
|
||||
|
||||
if (manager.isRecording)
|
||||
{
|
||||
if (manager.isRecordingStart)
|
||||
{
|
||||
if (settings.renderIsRawAnimation)
|
||||
{
|
||||
savedSettings = settings;
|
||||
settings.previewBackgroundColor = vec4();
|
||||
settings.previewIsGrid = false;
|
||||
settings.previewIsAxes = false;
|
||||
settings.timelineIsOnlyShowLayers = true;
|
||||
|
||||
savedZoom = zoom;
|
||||
savedPan = pan;
|
||||
|
||||
if (auto animation = document.animation_get())
|
||||
{
|
||||
auto rect = animation->rect(isRootTransform);
|
||||
size = vec2(rect.z, rect.w) * scale;
|
||||
set_to_rect(zoom, pan, rect);
|
||||
}
|
||||
|
||||
isSizeTrySet = false;
|
||||
|
||||
bind();
|
||||
viewport_set();
|
||||
clear(settings.previewBackgroundColor);
|
||||
unbind();
|
||||
}
|
||||
|
||||
manager.isRecordingStart = false;
|
||||
|
||||
return; // Need to wait an additional frame. Kind of hacky, but oh well.
|
||||
}
|
||||
|
||||
auto pixels = pixels_get();
|
||||
renderFrames.push_back(Texture(pixels.data(), size));
|
||||
|
||||
@@ -120,7 +91,7 @@ namespace anm2ed::imgui
|
||||
}
|
||||
else
|
||||
{
|
||||
if (animation_render(ffmpegPath, path, renderFrames, (render::Type)type, size, anm2.info.fps))
|
||||
if (animation_render(ffmpegPath, path, renderFrames, audioStream, (render::Type)type, size, anm2.info.fps))
|
||||
toasts.info(std::format("Exported rendered animation to: {}", path));
|
||||
else
|
||||
toasts.warning(std::format("Could not output rendered animation: {}", path));
|
||||
@@ -133,12 +104,49 @@ namespace anm2ed::imgui
|
||||
settings = savedSettings;
|
||||
isSizeTrySet = true;
|
||||
|
||||
if (settings.timelineIsSound) audioStream.capture_end(mixer);
|
||||
|
||||
playback.isPlaying = false;
|
||||
playback.isFinished = false;
|
||||
manager.isRecording = false;
|
||||
manager.progressPopup.close();
|
||||
}
|
||||
}
|
||||
if (manager.isRecordingStart)
|
||||
{
|
||||
savedSettings = settings;
|
||||
|
||||
if (settings.timelineIsSound) audioStream.capture_begin(mixer);
|
||||
|
||||
if (settings.renderIsRawAnimation)
|
||||
{
|
||||
settings.previewBackgroundColor = vec4();
|
||||
settings.previewIsGrid = false;
|
||||
settings.previewIsAxes = false;
|
||||
settings.timelineIsOnlyShowLayers = true;
|
||||
|
||||
savedZoom = zoom;
|
||||
savedPan = pan;
|
||||
|
||||
if (auto animation = document.animation_get())
|
||||
{
|
||||
if (auto rect = animation->rect(isRootTransform); rect != vec4(-1.0f))
|
||||
{
|
||||
size_set(vec2(rect.w, rect.z) * scale);
|
||||
set_to_rect(zoom, pan, rect);
|
||||
}
|
||||
}
|
||||
|
||||
isSizeTrySet = false;
|
||||
|
||||
bind();
|
||||
clear(settings.previewBackgroundColor);
|
||||
unbind();
|
||||
}
|
||||
|
||||
manager.isRecordingStart = false;
|
||||
manager.isRecording = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationPreview::update(Manager& manager, Settings& settings, Resources& resources)
|
||||
@@ -270,8 +278,8 @@ namespace anm2ed::imgui
|
||||
auto cursorScreenPos = ImGui::GetCursorScreenPos();
|
||||
|
||||
if (isSizeTrySet) size_set(to_vec2(ImGui::GetContentRegionAvail()));
|
||||
bind();
|
||||
viewport_set();
|
||||
bind();
|
||||
clear(backgroundColor);
|
||||
if (isAxes) axes_render(shaderAxes, zoom, pan, axesColor);
|
||||
if (isGrid) grid_render(shaderGrid, zoom, pan, gridSize, gridOffset, gridColor);
|
||||
@@ -412,7 +420,7 @@ namespace anm2ed::imgui
|
||||
|
||||
isPreviewHovered = ImGui::IsItemHovered();
|
||||
|
||||
if (animation && animation->triggers.isVisible && !isOnlyShowLayers)
|
||||
if (animation && animation->triggers.isVisible && !isOnlyShowLayers && !manager.isRecording)
|
||||
{
|
||||
if (auto trigger = animation->triggers.frame_generate(frameTime, anm2::TRIGGER);
|
||||
trigger.isVisible && trigger.eventID > -1)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "audio_stream.h"
|
||||
#include "canvas.h"
|
||||
#include "manager.h"
|
||||
#include "resources.h"
|
||||
@@ -9,6 +10,8 @@ namespace anm2ed::imgui
|
||||
{
|
||||
class AnimationPreview : public Canvas
|
||||
{
|
||||
MIX_Mixer* mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, nullptr);
|
||||
AudioStream audioStream = AudioStream(mixer);
|
||||
bool isPreviewHovered{};
|
||||
bool isSizeTrySet{true};
|
||||
Settings savedSettings{};
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace anm2ed::imgui
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2());
|
||||
|
||||
selection.start(anm2.content.spritesheets.size());
|
||||
selection.start(anm2.content.spritesheets.size(), ImGuiMultiSelectFlags_ClearOnEscape);
|
||||
|
||||
for (auto& [id, spritesheet] : anm2.content.spritesheets)
|
||||
{
|
||||
@@ -168,16 +168,16 @@ namespace anm2ed::imgui
|
||||
|
||||
context_menu();
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
selection.finish();
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
context_menu();
|
||||
selection.finish();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "clipboard.h"
|
||||
#include "document.h"
|
||||
#include "manager.h"
|
||||
#include "resources.h"
|
||||
#include "settings.h"
|
||||
@@ -25,14 +24,6 @@ namespace anm2ed::imgui
|
||||
ImDrawList* pickerLineDrawList{};
|
||||
ImGuiStyle style{};
|
||||
|
||||
void context_menu(Document&, Settings&, Clipboard&);
|
||||
void item_child(Manager&, Document&, anm2::Animation*, Settings&, Resources&, Clipboard&, anm2::Type, int, int&);
|
||||
void items_child(Manager&, Document&, anm2::Animation*, Settings&, Resources&, Clipboard&);
|
||||
void frame_child(Document&, anm2::Animation*, Settings&, Resources&, Clipboard&, anm2::Type, int, int&, float);
|
||||
void frames_child(Document&, anm2::Animation*, Settings&, Resources&, Clipboard&);
|
||||
|
||||
void popups(Document&, anm2::Animation*, Settings&);
|
||||
|
||||
public:
|
||||
void update(Manager&, Settings&, Resources&, Clipboard&);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user