From fba8edb56931a466c2f5bc4b6433b91cc5eff19d Mon Sep 17 00:00:00 2001 From: shweet Date: Fri, 1 May 2026 21:01:57 -0400 Subject: [PATCH] Added previous/next item, default keybind is Shift+F7/Shift+F8 --- src/imgui/window/timeline.cpp | 71 ++++++++++++++++++++++++++++++----- src/resource/strings.hpp | 4 +- src/settings.hpp | 5 ++- 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/imgui/window/timeline.cpp b/src/imgui/window/timeline.cpp index 1b4502c..eed8797 100644 --- a/src/imgui/window/timeline.cpp +++ b/src/imgui/window/timeline.cpp @@ -381,6 +381,55 @@ namespace anm2ed::imgui frames_selection_reset(); }; + auto reference_set_timeline_item = [&](anm2::Type type, int id) + { + if (type == anm2::LAYER) + if (auto it = anm2.content.layers.find(id); it != anm2.content.layers.end()) + document.spritesheet.reference = it->second.spritesheetID; + reference_set_item(type, id); + }; + + auto timeline_item_references_get = [&]() + { + std::vector itemReferences; + if (!animation) return itemReferences; + + itemReferences.push_back({reference.animationIndex, anm2::ROOT}); + + for (auto& id : animation->layerOrder | std::views::reverse) + { + auto item = animation->item_get(anm2::LAYER, id); + if (!item || (!settings.timelineIsShowUnused && item->frames.empty())) continue; + itemReferences.push_back({reference.animationIndex, anm2::LAYER, id}); + } + + for (auto& [id, item] : animation->nullAnimations) + { + if (!settings.timelineIsShowUnused && item.frames.empty()) continue; + itemReferences.push_back({reference.animationIndex, anm2::NULL_, id}); + } + + itemReferences.push_back({reference.animationIndex, anm2::TRIGGER}); + return itemReferences; + }; + + auto reference_set_adjacent_item = [&](int direction) + { + auto itemReferences = timeline_item_references_get(); + if (itemReferences.empty()) return; + + auto it = std::find_if(itemReferences.begin(), itemReferences.end(), [&](const anm2::Reference& itemReference) { + return itemReference.itemType == reference.itemType && itemReference.itemID == reference.itemID; + }); + + int index = direction > 0 ? 0 : (int)itemReferences.size() - 1; + if (it != itemReferences.end()) index = (int)std::distance(itemReferences.begin(), it) + direction; + index = std::clamp(index, 0, (int)itemReferences.size() - 1); + + auto& itemReference = itemReferences[index]; + reference_set_timeline_item(itemReference.itemType, itemReference.itemID); + }; + auto item_remove = [&]() { auto behavior = [&]() @@ -715,10 +764,7 @@ namespace anm2ed::imgui ImGui::SetNextItemStorageID(id); if (ImGui::Selectable("##Item Button", isReferenced, ImGuiSelectableFlags_SelectOnClick, itemSize)) { - if (type == anm2::LAYER) - if (auto it = anm2.content.layers.find(id); it != anm2.content.layers.end()) - document.spritesheet.reference = it->second.spritesheetID; - reference_set_item(type, id); + reference_set_timeline_item(type, id); } ImGui::PopStyleColor(3); if (ImGui::IsItemHovered()) @@ -934,11 +980,13 @@ namespace anm2ed::imgui ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::Text("(?)"); ImGui::PopStyleColor(); - 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)); + 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, settings.shortcutPreviousItem, + settings.shortcutNextItem)); ImGui::SetItemTooltip("%s", tooltipShortcuts.c_str()); ImGui::EndDisabled(); } @@ -2042,6 +2090,8 @@ namespace anm2ed::imgui auto isPreviousFrame = shortcut(manager.chords[SHORTCUT_PREVIOUS_FRAME], shortcut::GLOBAL); auto isNextFrame = shortcut(manager.chords[SHORTCUT_NEXT_FRAME], shortcut::GLOBAL); + auto isPreviousItem = shortcut(manager.chords[SHORTCUT_PREVIOUS_ITEM], shortcut::GLOBAL); + auto isNextItem = shortcut(manager.chords[SHORTCUT_NEXT_ITEM], shortcut::GLOBAL); if (isPreviousFrame) if (auto item = document.item_get(); item && !item->frames.empty()) @@ -2059,6 +2109,9 @@ namespace anm2ed::imgui document.frameTime = item->frame_time_from_index_get(reference.frameIndex); } } + + if (isPreviousItem) reference_set_adjacent_item(-1); + if (isNextItem) reference_set_adjacent_item(1); } if (isTextPushed) ImGui::PopStyleColor(); diff --git a/src/resource/strings.hpp b/src/resource/strings.hpp index 433e71e..2d4b6b0 100644 --- a/src/resource/strings.hpp +++ b/src/resource/strings.hpp @@ -420,6 +420,7 @@ namespace anm2ed X(SHORTCUT_STRING_NEW, "New", "Nuevo", "Новый", "新", "새 파일") \ X(SHORTCUT_STRING_NEXT_ANIMATION, "Next Animation", "Siguiente Animacion", "Следующая анимация", "下一动画", "다음 애니메이션") \ X(SHORTCUT_STRING_NEXT_FRAME, "Next Frame", "Siguiente Frame", "Следующий кадр", "下一帧", "다음 프레임") \ + X(SHORTCUT_STRING_NEXT_ITEM, "Next Item", "Siguiente Item", "Следующий предмет", "下一物品", "다음 항목") \ X(SHORTCUT_STRING_ONIONSKIN, "Onionskin", "Papel Cebolla", "Оньонскин", "洋葱皮预览", "전후 비교") \ X(SHORTCUT_STRING_OPEN, "Open", "Abrir", "Открыть", "打开", "열기") \ X(SHORTCUT_STRING_PAN, "Pan", "Panoramico", "Панорамирование", "平移", "시점 이동") \ @@ -429,6 +430,7 @@ namespace anm2ed X(SHORTCUT_STRING_PLAY_PAUSE, "Play/Pause", "Reproducir/Pausar", "Возпроизвести/Пауза", "播放/暂停", "재생/일시정지") \ X(SHORTCUT_STRING_PREVIOUS_ANIMATION, "Previous Animation", "Animacion Anterior", "Предыдущая анимация", "上一动画", "이전 애니메이션") \ X(SHORTCUT_STRING_PREVIOUS_FRAME, "Previous Frame", "Frame Anterior", "Предыдущий кадр", "前一帧", "이전 프레임") \ + X(SHORTCUT_STRING_PREVIOUS_ITEM, "Previous Item", "Item Anterior", "Предыдущий предмет", "上一物品", "이전 항목") \ X(SHORTCUT_STRING_REDO, "Redo", "Rehacer", "Повторить", "重做", "다시 실행") \ X(SHORTCUT_STRING_RENAME, "Rename", "Renombrar", "Переименовать", "重命名", "이름 변경") \ X(SHORTCUT_STRING_REMOVE, "Remove", "Remover", "Удалить", "去除", "제거") \ @@ -645,7 +647,7 @@ namespace anm2ed X(TOOLTIP_STACK_SIZE, "Set the maximum snapshot stack size of a document (i.e., how many undo/redos are preserved at a time).", "Ajusta el tamaño maximo del stack de snapshot de un documento (i. e., cuantos deshacer/rehacer se preservan a lo largo del tiempo.", "Установить максимальный размер стека снимков документа (т. е. количество отмен/повторов, сохраняемых одновременно).", "设置文件的快照栈的最大存储空间. (也就是最大可以存储多少撤销与重做)", "파일의 최대 스냅숏 스택 크기(즉 한 번에 보존되는 실행 취소/다시 실행 수)를 설정합니다.") \ X(TOOLTIP_START, "Set the starting time of the animation.", "Ajusta el tiempo de inicio de la animacion.", "Установить начальное время анимации.", "设置动画的起始时间.", "애니메이션의 시작 시간을 설정합니다.") \ X(TOOLTIP_SUBTRACT_VALUES, "Subtract the specified values from each frame.\n(Boolean/mapped values will simply be set.)", "Subtrae los valores especificos de cada Frame.\n(Los valores booleanos/mapeados simplemente se estableceran.)", "Вычтить указанные значения из каждого кадра.\n(Булевы/сопоставленные значения будут просто установлены.)", "将每一帧的指定值进行相减操作. (布尔/映射值将直接被设置.)", "각 프레임의 속성에 지정한 값을 뺍니다.\n(불리언/매핑 값은 그대로 설정됩니다.)") \ - X(TOOLTIP_TIMELINE_SHORTCUTS, "- Press {0} to decrement time.\n- Press {1} to increment time.\n- Press {2} to shorten the selected frame, by one frame.\n- Press {3} to extend the selected frame, by one frame.\n- Press {4} to go to the previous frame.\n- Press {5} to go to the next frame.\n- Click and hold on a frame while holding CTRL to change its duration.\n- Click and hold on a trigger to change its At Frame.\n- Hold Alt while clicking a non-trigger frame to toggle interpolation.", "- Presiona{0} para reducir el tiempo.\n- Presiona {1} para incrementar el tiempo.\n- Presiona {2} para acortar el Frame selecionado, por uno.\n- Presiona {3} para extender el Frame seleccionado, por uno.\n- Presiona {4} para ir al Frame anterior.\n- Presiona {5} para ir al siguiente Frame.\n- Haz click y mantiene en un Frame mientras apretas CTRL para cambiar su duracion.\n- Haz click y mantiene en un trigger para cambiar su \"En Frame\".\n- Manten Alt mientras haces click en un frame sin trigger para alternar la interpolacion.", "- Нажмите {0}, чтобы уменьшить время.\n- Нажмите {1}, чтобы увеличить время.\n- Нажмите {2}, чтобы укоротить выбранный кадр одной мерной единицей.\n- Нажмите {3}, чтобы продлить выбранный кадр на одну мерную единицу.\n- Нажмите {4}, чтобы перейти к предыдущему кадру.\n- Нажмите {5}, чтобы перейти к следующему кадру.\n- Удерживайте нажатой кнопку мыши по кадру, удерживая CTRL, чтобы изменить его длительность.\n- Нажмите и удерживайте кнопку мыши по триггеру, чтобы изменить параметр «На кадре».\n- Удерживайте Alt и нажмите по кадру, который не является триггером, чтобы переключить интерполяцию.", "- 按下 {0} 减少时间.\n- 按下 {1} 增加时间.\n- 按下 {2} 将所选帧缩短一帧.\n- 按下 {3} 将所选帧延长一帧.\n- 按下 {4} 跳到上一帧.\n- 按下 {5} 跳到下一帧.\n- 在按住 CTRL 的同时点击并按住某一帧以更改其持续时间.\n- 点击并按住触发器即可更改其触发帧.\n- 按住 Alt 并点击任何无触发器的帧以切换线性插值的使用.", "- {0} 키: 플레이헤드를 뒤로 보냅니다.\n- {1} 키: 플레이헤드를 앞으로 보냅니다.\n- {2} 키: 선택한 프레임을 한 프레임 단축합니다.\n- {3} 키: 선택한 프레임을 한 프레임 연장합니다.\n- {4} 키: 이전 프레임을 선택합니다.\n- {5} 키: 다음 프레임을 선택합니다.\n- CTRL 키를 누른 채 프레임을 클릭하고 드래그하면 프레임의 유지 시간을 변경할 수 있습니다.\n- 트리거를 클릭하고 드래그하면 트리거의 시작 프레임을 변경할 수 있습니다.\n- Alt 키를 누른 채 트리거를 제외한 프레임을 클릭하면 매끄럽게 연결 설정을 켤 수 있습니다.") \ + X(TOOLTIP_TIMELINE_SHORTCUTS, "- Press {0}/{1} to move the playhead backward/forward.\n- Press {2}/{3} to shorten/extend the selected frame by one frame.\n- Press {4}/{5} to select the previous/next frame.\n- Press {6}/{7} to select the previous/next item.\n- Click and hold on a frame while holding CTRL to change its duration.\n- Click and hold on a trigger to change its At Frame.\n- Hold Alt while clicking a non-trigger frame to toggle interpolation.", "- Presiona {0}/{1} para mover el cabezal hacia atras/adelante.\n- Presiona {2}/{3} para acortar/extender el Frame seleccionado por uno.\n- Presiona {4}/{5} para seleccionar el Frame anterior/siguiente.\n- Presiona {6}/{7} para seleccionar el Item anterior/siguiente.\n- Haz click y mantiene en un Frame mientras apretas CTRL para cambiar su duracion.\n- Haz click y mantiene en un trigger para cambiar su \"En Frame\".\n- Manten Alt mientras haces click en un frame sin trigger para alternar la interpolacion.", "- Нажмите {0}/{1}, чтобы переместить воспроизводящую головку назад/вперёд.\n- Нажмите {2}/{3}, чтобы укоротить/продлить выбранный кадр на одну мерную единицу.\n- Нажмите {4}/{5}, чтобы выбрать предыдущий/следующий кадр.\n- Нажмите {6}/{7}, чтобы выбрать предыдущий/следующий предмет.\n- Удерживайте нажатой кнопку мыши по кадру, удерживая CTRL, чтобы изменить его длительность.\n- Нажмите и удерживайте кнопку мыши по триггеру, чтобы изменить параметр «На кадре».\n- Удерживайте Alt и нажмите по кадру, который не является триггером, чтобы переключить интерполяцию.", "- 按下 {0}/{1} 可向后/向前移动播放指针.\n- 按下 {2}/{3} 可将所选帧缩短/延长一帧.\n- 按下 {4}/{5} 可选择上一帧/下一帧.\n- 按下 {6}/{7} 可选择上一物品/下一物品.\n- 在按住 CTRL 的同时点击并按住某一帧以更改其持续时间.\n- 点击并按住触发器即可更改其触发帧.\n- 按住 Alt 并点击任何无触发器的帧以切换线性插值的使用.", "- {0}/{1} 키: 플레이헤드를 뒤로/앞으로 보냅니다.\n- {2}/{3} 키: 선택한 프레임을 한 프레임 단축/연장합니다.\n- {4}/{5} 키: 이전/다음 프레임을 선택합니다.\n- {6}/{7} 키: 이전/다음 항목을 선택합니다.\n- CTRL 키를 누른 채 프레임을 클릭하고 드래그하면 프레임의 유지 시간을 변경할 수 있습니다.\n- 트리거를 클릭하고 드래그하면 트리거의 시작 프레임을 변경할 수 있습니다.\n- Alt 키를 누른 채 트리거를 제외한 프레임을 클릭하면 매끄럽게 연결 설정을 켤 수 있습니다.") \ X(TOOLTIP_TINT, "Change the tint of the frame.", "Cambia el matiz del Frame", "Изменить оттенок кадра.", "更改此帧的色调.", "프레임의 색조를 변경합니다.") \ X(TOOLTIP_TOOL_COLOR, "Selects the color to be used for drawing.\n(Spritesheet Editor only.)", "Selecciona el color que se usara para dibujar.\n(Solo en el Editor de Spritesheet.)", "Выбирает цвет, который будет использоваться для рисования.\n(Только в редакторе спрайт-листов.)", "选择用于绘画的颜色.\n(仅应用于图集编辑器.)", "그리기용으로 사용할 색을 선택합니다.\n(스프라이트 시트 편집기 전용)") \ X(TOOLTIP_TOOL_COLOR_PICKER, "Selects a color from the canvas.\n(Spritesheet Editor only.)", "Selecciona un color del lienzo.\n(Solo en el Editor de Spritesheet.)", "Выбирает цвет из холста.\n(Только в редакторе спрайт-листов.)", "从画板上选择一个颜色.\n(仅应用于图集编辑器.)", "캔버스에서 색을 선택합니다.\n(스프라이트시트 편집기 전용)") \ diff --git a/src/settings.hpp b/src/settings.hpp index 1e62a19..2b3dac8 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -240,7 +240,10 @@ namespace anm2ed X(SHORTCUT_INSERT_FRAME, shortcutInsertFrame, SHORTCUT_STRING_INSERT_FRAME, STRING, "F6") \ X(SHORTCUT_PREVIOUS_FRAME, shortcutPreviousFrame, SHORTCUT_STRING_PREVIOUS_FRAME, STRING, "F7") \ X(SHORTCUT_NEXT_FRAME, shortcutNextFrame, SHORTCUT_STRING_NEXT_FRAME, STRING, "F8") \ - /* Animations */ \ + /* Item */ \ + X(SHORTCUT_PREVIOUS_ITEM, shortcutPreviousItem, SHORTCUT_STRING_PREVIOUS_ITEM, STRING, "Shift+F7") \ + X(SHORTCUT_NEXT_ITEM, shortcutNextItem, SHORTCUT_STRING_NEXT_ITEM, STRING, "Shift+F8") \ + /* Animation */ \ X(SHORTCUT_PREVIOUS_ANIMATION, shortcutPreviousAnimation, SHORTCUT_STRING_PREVIOUS_ANIMATION, STRING, "F9") \ X(SHORTCUT_NEXT_ANIMATION, shortcutNextAnimation, SHORTCUT_STRING_NEXT_ANIMATION, STRING, "F10") \ /* Toggles */ \