Timeline context menu update; baking/splitting shortcuts

This commit is contained in:
2025-12-04 02:38:18 -05:00
parent cc6a502ff9
commit 183f3390fa
5 changed files with 101 additions and 37 deletions

View File

@@ -73,13 +73,12 @@ namespace anm2ed::imgui
if (isSuccess)
{
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)));
logger.info(
std::vformat(localize.get(TOAST_EXPORT_RENDERED_FRAMES, anm2ed::ENGLISH), std::make_format_args(path)));
}
else
{
toasts.push(std::vformat(localize.get(TOAST_EXPORT_RENDERED_FRAMES_FAILED),
std::make_format_args(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)));
}
@@ -132,13 +131,12 @@ namespace anm2ed::imgui
if (spritesheetTexture.write_png(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)));
logger.info(
std::vformat(localize.get(TOAST_EXPORT_SPRITESHEET, anm2ed::ENGLISH), std::make_format_args(path)));
}
else
{
toasts.push(std::vformat(localize.get(TOAST_EXPORT_SPRITESHEET_FAILED),
std::make_format_args(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)));
}
@@ -155,8 +153,8 @@ namespace anm2ed::imgui
}
else
{
toasts.push(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED),
std::make_format_args(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)));
}
@@ -640,8 +638,11 @@ namespace anm2ed::imgui
unbind();
if (manager.isRecording && settings.renderIsRawAnimation)
{
sync_checker_pan();
render_checker_background(ImGui::GetWindowDrawList(), min, max, -size - checkerPan, CHECKER_SIZE);
}
ImGui::Image(texture, to_imvec2(size));
isPreviewHovered = ImGui::IsItemHovered();

View File

@@ -89,8 +89,8 @@ namespace anm2ed::imgui
document.change(Document::EVENTS);
else
{
toasts.push(std::vformat(localize.get(TOAST_DESERIALIZE_EVENTS_FAILED),
std::make_format_args(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)));
}

View File

@@ -324,6 +324,55 @@ namespace anm2ed::imgui
}
};
auto frames_bake = [&]()
{
if (auto item = document.item_get())
for (auto i : frames.selection | std::views::reverse)
item->frames_bake(i, settings.bakeInterval, settings.bakeIsRoundScale, settings.bakeIsRoundRotation);
frames.clear();
};
auto frame_split = [&]()
{
if (reference.itemType == anm2::TRIGGER) return;
auto item = document.item_get();
auto frame = document.frame_get();
if (!item || !frame) return;
auto originalDuration = frame->duration;
if (originalDuration <= 1) return;
auto frameStartTime = item->frame_time_from_index_get(reference.frameIndex);
int frameStart = (int)std::round(frameStartTime);
int playheadTime = (int)std::floor(playback.time);
int firstDuration = playheadTime - frameStart + 1;
if (firstDuration <= 0 || firstDuration >= originalDuration) return;
int secondDuration = originalDuration - firstDuration;
anm2::Frame splitFrame = *frame;
splitFrame.duration = secondDuration;
auto nextFrame =
vector::in_bounds(item->frames, reference.frameIndex + 1) ? &item->frames[reference.frameIndex + 1] : nullptr;
if (frame->isInterpolated && nextFrame)
{
float interpolation = (float)firstDuration / (float)originalDuration;
splitFrame.rotation = glm::mix(frame->rotation, nextFrame->rotation, interpolation);
splitFrame.position = glm::mix(frame->position, nextFrame->position, interpolation);
splitFrame.scale = glm::mix(frame->scale, nextFrame->scale, interpolation);
splitFrame.colorOffset = glm::mix(frame->colorOffset, nextFrame->colorOffset, interpolation);
splitFrame.tint = glm::mix(frame->tint, nextFrame->tint, interpolation);
}
frame->duration = firstDuration;
item->frames.insert(item->frames.begin() + reference.frameIndex + 1, splitFrame);
frames_selection_set_reference();
};
auto frames_selection_reset = [&]()
{
frames.clear();
@@ -399,8 +448,8 @@ namespace anm2ed::imgui
else
{
toasts.push(std::format("{} {}", localize.get(TOAST_DESERIALIZE_FRAMES_FAILED), errorString));
logger.error(std::format("{} {}", localize.get(TOAST_DESERIALIZE_FRAMES_FAILED, anm2ed::ENGLISH),
errorString));
logger.error(
std::format("{} {}", localize.get(TOAST_DESERIALIZE_FRAMES_FAILED, anm2ed::ENGLISH), errorString));
}
}
else
@@ -420,7 +469,20 @@ namespace anm2ed::imgui
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();
if (ImGui::MenuItem(localize.get(BASIC_PASTE), settings.shortcutPaste.c_str(), false, !clipboard.is_empty()))
paste();
ImGui::Separator();
if (ImGui::MenuItem(localize.get(LABEL_BAKE), settings.shortcutBake.c_str(), false, !frames.selection.empty()))
DOCUMENT_EDIT(document, localize.get(EDIT_BAKE_FRAMES), Document::FRAMES, frames_bake());
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_BAKE_FRAMES_OPTIONS));
if (ImGui::MenuItem(localize.get(LABEL_SPLIT), settings.shortcutSplit.c_str(), false,
!frames.selection.empty()))
DOCUMENT_EDIT(document, localize.get(EDIT_SPLIT_FRAME), Document::FRAMES, frame_split());
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SPLIT));
ImGui::EndPopup();
}
@@ -672,10 +734,9 @@ namespace anm2ed::imgui
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_ID), std::make_format_args(id)).c_str());
ImGui::TextUnformatted(std::vformat(localize.get(FORMAT_SPRITESHEET_ID),
std::make_format_args(layer.spritesheetID))
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());
@@ -691,8 +752,7 @@ namespace anm2ed::imgui
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_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(
@@ -1763,7 +1823,7 @@ namespace anm2ed::imgui
ImGui::SameLine();
if (ImGui::Button(localize.get(LABEL_BAKE), widgetSize)) bakePopup.open();
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_BAKE_FRAMES));
set_item_tooltip_shortcut(localize.get(TOOLTIP_BAKE_FRAMES), settings.shortcutBake);
}
ImGui::EndDisabled();
}
@@ -2030,17 +2090,7 @@ namespace anm2ed::imgui
if (ImGui::Button(localize.get(LABEL_BAKE), widgetSize))
{
auto frames_bake = [&]()
{
if (auto item = document.item_get())
for (auto i : frames.selection | std::views::reverse)
item->frames_bake(i, interval, isRoundScale, isRoundRotation);
frames.clear();
};
DOCUMENT_EDIT(document, localize.get(EDIT_BAKE_FRAMES), Document::FRAMES, frames_bake());
bakePopup.close();
}
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_BAKE_FRAMES_OPTIONS));
@@ -2117,6 +2167,12 @@ namespace anm2ed::imgui
document.frameTime = item->frame_time_from_index_get(reference.frameIndex);
}
}
if (shortcut(manager.chords[SHORTCUT_SPLIT], shortcut::GLOBAL))
DOCUMENT_EDIT(document, localize.get(EDIT_BAKE_FRAMES), Document::FRAMES, frame_split());
if (shortcut(manager.chords[SHORTCUT_BAKE], shortcut::GLOBAL))
DOCUMENT_EDIT(document, localize.get(EDIT_BAKE_FRAMES), Document::FRAMES, frames_bake());
}
if (isTextPushed) ImGui::PopStyleColor();

View File

@@ -143,6 +143,7 @@ namespace anm2ed
X(EDIT_REPLACE_SPRITESHEET, "Replace Spritesheet", "Заменить спрайт-лист", "替换图集", "스프라이트 시트 교체") \
X(EDIT_SET_LAYER_PROPERTIES, "Set Layer Properties", "Установить свойства слоя", "更改动画层属性", "레이어 속성 설정") \
X(EDIT_SET_NULL_PROPERTIES, "Set Null Properties", "Установить свойства нуля", "更改Null属性", "Null 속성 설정") \
X(EDIT_SPLIT_FRAME, "Split Frame", "Разделить кадр", "拆分帧", "프레임 분할") \
X(EDIT_SHORTEN_FRAME, "Shorten Frame", "Укоротить кадр", "缩短帧时长", "프레임 단축") \
X(EDIT_TOGGLE_ITEM_VISIBILITY, "Toggle Item Visibility", "Переключить видимость предмета", "物品可见", "항목 표시/숨기기") \
X(EDIT_TOGGLE_NULL_RECT, "Toggle Null Rectangle", "Переключить прямоугольник нуля", "Null框可见", "Null 사각형 표시/숨기기") \
@@ -195,6 +196,7 @@ namespace anm2ed
X(LABEL_AXES, "Axes", "Оси", "坐标轴", "가로/세로 축") \
X(LABEL_BACKGROUND_COLOR, "Background", "Фон", "背景", "배경색") \
X(LABEL_BAKE, "Bake", "Запечь", "提前渲染", "베이크") \
X(LABEL_SPLIT, "Split", "Разделить", "拆分", "분할") \
X(LABEL_BORDER, "Border", "Границы", "边框", "경계선") \
X(LABEL_CENTER_VIEW, "Center View", "Центрировать вид", "视角中心", "가운데서 보기") \
X(LABEL_CLAMP, "Clamp", "Ограничить", "限制数值范围", "작업 영역 제한") \
@@ -365,6 +367,8 @@ namespace anm2ed
X(SHORTCUT_STRING_SAVE, "Save", "Сохранить", "保存", "저장") \
X(SHORTCUT_STRING_SAVE_AS, "Save As", "Сохранить как", "保存为", "다른 이름으로 저장") \
X(SHORTCUT_STRING_SCALE, "Scale", "Изменить масштаб", "缩放", "비율") \
X(SHORTCUT_STRING_SPLIT, "Split", "", "", "") \
X(SHORTCUT_STRING_BAKE, "Bake", "Запечь", "提前渲染", "베이크") \
X(SHORTCUT_STRING_SHORTEN_FRAME, "Shorten Frame", "Укоротить кадр", "缩短帧时长", "프레임 단축") \
X(SHORTCUT_STRING_UNDO, "Undo", "Отменить", "撤销", "실행 취소") \
X(SHORTCUT_STRING_ZOOM_IN, "Zoom In", "Увеличить", "视图放大", "확대") \
@@ -433,7 +437,7 @@ namespace anm2ed
X(TOOLTIP_AXES, "Toggle the axes' visibility.", "Переключить видимость осей.", "切换坐标轴是否可见.", "가로/세로 축을 표시하거나 숨깁니다.") \
X(TOOLTIP_AXES_COLOR, "Set the color of the axes.", "Установить цвет осей.", "设置坐标轴的颜色.", "가로/세로 축의 색상을 설정합니다.") \
X(TOOLTIP_BACKGROUND_COLOR, "Change the background color.", "Изменить цвет фона.", "更改背景颜色.", "배경색을 변경합니다.") \
X(TOOLTIP_BAKE_FRAMES, "Turn interpolated frames into uninterpolated ones.", "Превратить интерполированные кадры в неинтерполированных.", "转换线性插值的帧为正常(未线性插值)的帧.", "연결된 프레임을 연결되지 않은 프레임으로 고정화합니다.") \
X(TOOLTIP_BAKE_FRAMES, "Turn interpolated frames into uninterpolated ones.\nUse the shortcut to bake frames quickly.", "Превратить интерполированные кадры в неинтерполированные.\nИспользуйте горячую клавишу, чтобы быстро запечь кадры.", "线性插值的帧转换为普通帧。\n使用快捷键可快速烘焙帧.", "연결된 프레임을 연결되지 않은 프레임으로 고정화합니다.\n단축키를 사용하면 프레임을 빠르게 베이크할 수 있습니다.") \
X(TOOLTIP_BAKE_FRAMES_OPTIONS, "Bake the selected frame(s) with the options selected.", "Запечь выбранные кадры с выбранными настройками.", "替换所选旧图集为新图集.", "선택된 프레임을 선택한 옵션으로 베이킹합니다.") \
X(TOOLTIP_BORDER, "Toggle the visibility of borders around layers.", "Переключить видимость границ около слоев.", "切换动画层边框是否可见.", "레이어 주변 경계선을 표시하거나 숨깁니다.") \
X(TOOLTIP_CANCEL_ADD_ITEM, "Cancel adding an item.", "Отменить добавление предмета.", "取消添加物品.", "항목 추가를 취소합니다.") \
@@ -491,7 +495,7 @@ namespace anm2ed
X(TOOLTIP_ONIONSKIN_INDEX, "The onionskinned frames will be based on frame index.", "Кадры оньонскина будут основаны на индексе кадров.", "洋葱皮预览的帧会基于帧下标.", "프레임 비교를 프레임 인덱스를 기준으로 합니다.") \
X(TOOLTIP_ONIONSKIN_TIME, "The onionskinned frames will be based on frame time.", "Кадры оньонскина будут основаны на времени кадров.", "洋葱皮预览的帧会基于帧时间.", "프레임 비교를 프레임 시간을 기준으로 합니다.") \
X(TOOLTIP_ONLY_LAYERS_VISIBLE, "Only layers are visible. Press to show all items.", "Только слои видимы. Нажмите, чтобы показать все предметы.", "当前仅有动画层可见. 点击以显示所有物品.", "레이어만 표시합니다. 모두 보려면 누르세요.") \
X(TOOLTIP_OPEN_MERGE_POPUP, "Open merge popup.", "Открыть всплывающее окно соединения.", "打开合并弹窗.", "병합 팝업을 엽니다.") \
X(TOOLTIP_OPEN_MERGE_POPUP, "Open merge popup.\nUse the shortcut to merge quickly.", "Открыть всплывающее окно соединения.\nИспользуйте горячую клавишу, чтобы быстро выполнить слияние.", "打开合并弹窗\n使用快捷键可快速合并。", "병합 팝업을 엽니다.\n단축키로 빠르게 병합하세요.") \
X(TOOLTIP_OUTPUT_PATH, "Set the output path or directory for the animation.", "Установить путь или директорию вывода для анимации.", "更改动画的输出路径/目录.", "애니메이션의 출력 경로 또는 디렉터리를 설정합니다.") \
X(TOOLTIP_OVERLAY, "Set an animation to be drawn over the current animation.", "Установить анимацию, которая будет выведена над текущей анимацией.", "设置一个当前动画的覆盖动画.", "현재 애니메이션 위에 그려질 애니메이션을 설정합니다.") \
X(TOOLTIP_OVERLAY_ALPHA, "Set the alpha of the overlayed animation.", "Установить прозрачность наложенной анимации.", "更改覆盖动画的透明度.", "오버레이된 애니메이션의 불투명도를 설정합니다.") \
@@ -528,6 +532,7 @@ namespace anm2ed
X(TOOLTIP_SETTINGS_SAVE, "Use the configured settings.", "Использовать настроенные настройки.", "应用更改的设置.", "구성된 설정을 사용합니다.") \
X(TOOLTIP_SET_DEFAULT_ANIMATION, "Set the selected animation as the default.", "Установить выбранную анимацию как анимацию по умолчанию.", "把当前所选动画设置为默认动画.", "선택한 애니메이션을 기본 애니메이션으로 설정합니다.") \
X(TOOLTIP_SET_TO_RECOMMENDED, "Use a recommended value for rows/columns.", "Использовать рекомендованное значение для рядов/колонн.", "应用列/行的推荐值.", "행/열에 권장값을 사용합니다.") \
X(TOOLTIP_SPLIT, "Based on the playhead time, split the selected frame into two.", "С учётом позиции ползунка воспроизведения разделяет выбранный кадр на два.", "根据播放头位置,将所选帧拆分成两个。", "재생 헤드 시간에 따라 선택한 프레임을 두 개로 분할합니다.") \
X(TOOLTIP_SIZE, "Change the crop size the frame uses.", "Изменить размер обрезки, который использует этот кадр.", "更改此帧的裁剪大小.", "프레임에 대응되는 스프라이트 시트의 사용 영역의 크기를 변경합니다.") \
X(TOOLTIP_SOUND, "Toggle sounds playing with triggers.\nBind sounds to events in the Events window.", "Переключить воспроизведения звуков с помощью триггеров.\nПривязывайте звуки к событиям в окне событий.", "切换是否在触发器触发时播放声音.\n可以在事件窗口里链接声音与事件.", "트리거와 함께 사운드를 재생할지 정합니다.\n사운드는 이벤트 창에서 이벤트에 연결하세요.") \
X(TOOLTIP_SOUNDS_PLAY, "Click to play.", "Нажмите, чтобы возпроизвести.", "点击播放.", "클릭하여 재생합니다.") \

View File

@@ -194,6 +194,8 @@ namespace anm2ed
X(SHORTCUT_ZOOM_IN, shortcutZoomIn, SHORTCUT_STRING_ZOOM_IN, STRING, "Ctrl+Equal") \
X(SHORTCUT_ZOOM_OUT, shortcutZoomOut, SHORTCUT_STRING_ZOOM_OUT, STRING, "Ctrl+Minus") \
/* Timeline / Playback */ \
X(SHORTCUT_BAKE, shortcutBake, SHORTCUT_STRING_BAKE, STRING, "Ctrl+B") \
X(SHORTCUT_SPLIT, shortcutSplit, SHORTCUT_STRING_SPLIT, STRING, "Ctrl+P") \
X(SHORTCUT_PLAY_PAUSE, shortcutPlayPause, SHORTCUT_STRING_PLAY_PAUSE, STRING, "Space") \
X(SHORTCUT_MOVE_PLAYHEAD_BACK, shortcutMovePlayheadBack, SHORTCUT_STRING_PLAYHEAD_BACK, STRING, "Comma") \
X(SHORTCUT_MOVE_PLAYHEAD_FORWARD, shortcutMovePlayheadForward, SHORTCUT_STRING_PLAYHEAD_FORWARD, STRING, "Period") \