some issues with item selection, fixed

This commit is contained in:
2025-11-19 20:04:42 -05:00
parent f44ce80bc0
commit 631c9c02fa

View File

@@ -109,9 +109,7 @@ namespace anm2ed::imgui
};
auto item_selection_decode = [&](int value) -> int { return value & ~ITEM_SELECTION_NULL_FLAG; };
auto item_selection_value_type = [&](int value) -> anm2::Type
{
return (value & ITEM_SELECTION_NULL_FLAG) ? anm2::NULL_ : anm2::LAYER;
};
{ return (value & ITEM_SELECTION_NULL_FLAG) ? anm2::NULL_ : anm2::LAYER; };
std::vector<int> itemSelectionIndexMap{};
std::unordered_map<int, int> layerSelectionIndex{};
std::unordered_map<int, int> nullSelectionIndex{};
@@ -174,18 +172,31 @@ namespace anm2ed::imgui
items.hovered = -1;
auto item_selection_type_get = [&]() -> anm2::Type
auto item_selection_type_get = [&](anm2::Type preferredType = anm2::NONE) -> anm2::Type
{
if (itemSelection.empty() || !animation) return anm2::NONE;
bool hasLayer = false;
bool hasNull = false;
for (auto encoded : itemSelection)
{
auto valueType = item_selection_value_type(encoded);
auto valueID = item_selection_decode(encoded);
if (valueType == anm2::LAYER && animation->layerAnimations.contains(valueID)) return anm2::LAYER;
if (valueType == anm2::NULL_ && animation->nullAnimations.contains(valueID)) return anm2::NULL_;
if (valueType == anm2::LAYER && animation->layerAnimations.contains(valueID)) hasLayer = true;
if (valueType == anm2::NULL_ && animation->nullAnimations.contains(valueID)) hasNull = true;
}
auto type_available = [&](anm2::Type type)
{
if (type == anm2::LAYER) return hasLayer;
if (type == anm2::NULL_) return hasNull;
return false;
};
if (preferredType != anm2::NONE && type_available(preferredType)) return preferredType;
if (hasLayer) return anm2::LAYER;
if (hasNull) return anm2::NULL_;
return anm2::NONE;
};
@@ -193,8 +204,6 @@ namespace anm2ed::imgui
{
itemSelection.clear();
items.reference = -1;
document.layer.selection.clear();
document.null.selection.clear();
};
auto item_selection_sync = [&]()
@@ -205,25 +214,26 @@ namespace anm2ed::imgui
return;
}
auto type = item_selection_type_get();
items.reference = (int)type;
auto preferredType = items.reference == (int)anm2::LAYER || items.reference == (int)anm2::NULL_
? (anm2::Type)items.reference
: anm2::NONE;
auto type = item_selection_type_get(preferredType);
auto assign_selection = [&](MultiSelectStorage& target, anm2::Type assignType)
if (type == anm2::NONE)
{
target.clear();
for (auto encoded : itemSelection)
{
if (item_selection_value_type(encoded) != assignType) continue;
target.insert(item_selection_decode(encoded));
}
};
if (type == anm2::LAYER)
assign_selection(document.layer.selection, anm2::LAYER);
else if (type == anm2::NULL_)
assign_selection(document.null.selection, anm2::NULL_);
else
item_selection_clear();
return;
}
for (auto it = itemSelection.begin(); it != itemSelection.end();)
{
if (item_selection_value_type(*it) != type)
it = itemSelection.erase(it);
else
++it;
}
items.reference = (int)type;
};
auto item_selection_prune = [&]()
@@ -256,8 +266,8 @@ namespace anm2ed::imgui
}
auto valueID = item_selection_decode(*it);
bool exists =
type == anm2::LAYER ? animation->layerAnimations.contains(valueID) : animation->nullAnimations.contains(valueID);
bool exists = type == anm2::LAYER ? animation->layerAnimations.contains(valueID)
: animation->nullAnimations.contains(valueID);
if (!exists)
it = itemSelection.erase(it);
else
@@ -447,6 +457,75 @@ namespace anm2ed::imgui
return -1;
};
auto item_type_has_visible = [&](anm2::Type type)
{
if (!animation) return false;
auto& showUnused = settings.timelineIsShowUnused;
auto& showLayersOnly = settings.timelineIsOnlyShowLayers;
if (type == anm2::LAYER)
{
for (auto id : animation->layerOrder)
{
if (!showUnused && animation->layerAnimations[id].frames.empty()) continue;
return true;
}
return false;
}
if (type == anm2::NULL_)
{
if (showLayersOnly) return false;
for (auto& [id, nullAnimation] : animation->nullAnimations)
{
if (!showUnused && nullAnimation.frames.empty()) continue;
return true;
}
return false;
}
return false;
};
auto item_selection_select_all = [&](anm2::Type type)
{
if (!animation || (type != anm2::LAYER && type != anm2::NULL_)) return;
auto& showUnused = settings.timelineIsShowUnused;
auto& showLayersOnly = settings.timelineIsOnlyShowLayers;
itemSelection.clear();
bool hasInserted = false;
auto try_insert = [&](int id)
{
itemSelection.insert(item_selection_encode(type, id));
hasInserted = true;
};
if (type == anm2::LAYER)
{
for (auto id : animation->layerOrder)
{
if (!showUnused && animation->layerAnimations[id].frames.empty()) continue;
try_insert(id);
}
}
else if (type == anm2::NULL_ && !showLayersOnly)
{
for (auto& [id, nullAnimation] : animation->nullAnimations)
{
if (!showUnused && nullAnimation.frames.empty()) continue;
try_insert(id);
}
}
if (!hasInserted)
{
item_selection_clear();
return;
}
item_selection_sync();
};
auto item_child = [&](anm2::Type type, int id, int& index)
{
ImGui::PushID(index);
@@ -483,6 +562,12 @@ namespace anm2ed::imgui
color = !isVisible ? to_imvec4(colorVec * COLOR_HIDDEN_MULTIPLIER) : color;
ImGui::PushStyleColor(ImGuiCol_ChildBg, color);
if (index == 1 && type != anm2::NONE)
{
auto cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x, cursor.y - style.ItemSpacing.y));
}
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.WindowPadding);
@@ -504,14 +589,14 @@ namespace anm2ed::imgui
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4());
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4());
if (isSelectableItem && selectionIndex != -1) ImGui::SetNextItemSelectionUserData(selectionIndex);
bool isRootLike = type == anm2::ROOT || type == anm2::TRIGGER;
if (ImGui::Selectable("##Item Button", isSelectableItem && isMultiSelected, ImGuiSelectableFlags_SelectOnNav,
itemSize))
{
if (isSelectableItem)
{
auto previousType = item_selection_type_get();
bool typeMismatch =
!itemSelection.empty() && previousType != anm2::NONE && previousType != type;
bool typeMismatch = !itemSelection.empty() && previousType != anm2::NONE && previousType != type;
if (typeMismatch)
{
itemSelection.clear();
@@ -519,6 +604,8 @@ namespace anm2ed::imgui
}
item_selection_sync();
}
else if (isRootLike)
item_selection_clear();
if (type == anm2::LAYER) document.spritesheet.reference = anm2.content.layers[id].spritesheetID;
@@ -576,7 +663,7 @@ namespace anm2ed::imgui
ImGui::Image(resources.icons[icon].id, icon_size_get());
overlay_icon(resources.icons[icon].id, iconTintCurrent);
ImGui::SameLine();
if (isReferenced) ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE);
if (isReferenced) ImGui::PushFont(resources.fonts[font::ITALICS].get(), font::SIZE);
ImGui::PushStyleColor(ImGuiCol_Text, itemTextColor);
ImGui::TextUnformatted(label.c_str());
ImGui::PopStyleColor();
@@ -674,17 +761,49 @@ namespace anm2ed::imgui
{
auto itemsChildSize = ImVec2(ImGui::GetTextLineHeightWithSpacing() * 15, ImGui::GetContentRegionAvail().y);
if (ImGui::BeginChild("##Items Child", itemsChildSize, ImGuiChildFlags_Borders))
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2());
bool isItemsChildOpen = ImGui::BeginChild("##Items Child", itemsChildSize, ImGuiChildFlags_Borders);
ImGui::PopStyleVar();
if (isItemsChildOpen)
{
auto itemsListChildSize = ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y -
ImGui::GetTextLineHeightWithSpacing() -
ImGui::GetStyle().ItemSpacing.y * 2);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2());
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2());
if (ImGui::BeginChild("##Items List Child", itemsListChildSize, ImGuiChildFlags_Borders,
ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar))
{
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2());
ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarSize, 0.0f);
if (animation && ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_A, ImGuiInputFlags_RouteFocused))
{
auto preferredType = reference.itemType == anm2::LAYER || reference.itemType == anm2::NULL_
? reference.itemType
: (items.reference == (int)anm2::LAYER || items.reference == (int)anm2::NULL_
? (anm2::Type)items.reference
: item_selection_type_get());
auto targetType = preferredType;
if (targetType == anm2::NONE || !item_type_has_visible(targetType))
{
if (item_type_has_visible(anm2::LAYER))
targetType = anm2::LAYER;
else if (item_type_has_visible(anm2::NULL_))
targetType = anm2::NULL_;
else
targetType = anm2::NONE;
}
if (targetType != anm2::NONE) item_selection_select_all(targetType);
}
if (animation && ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
ImGui::Shortcut(ImGuiKey_Escape, ImGuiInputFlags_RouteFocused))
{
item_selection_clear();
reference_clear();
}
if (ImGui::BeginTable("##Item Table", 1, ImGuiTableFlags_Borders | ImGuiTableFlags_ScrollY))
{
ImGui::GetCurrentWindow()->Flags |= ImGuiWindowFlags_NoScrollWithMouse;
@@ -707,7 +826,7 @@ namespace anm2ed::imgui
if (animation)
{
item_selection_prune();
itemSelection.start(itemSelectionIndexMap.size(), ImGuiMultiSelectFlags_ClearOnEscape);
itemSelection.start(itemSelectionIndexMap.size());
item_child_row(anm2::ROOT);
@@ -740,6 +859,7 @@ namespace anm2ed::imgui
}
ImGui::PopStyleVar(2);
}
ImGui::PopStyleVar(2);
ImGui::EndChild();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.WindowPadding);
@@ -829,6 +949,18 @@ namespace anm2ed::imgui
if (ImGui::BeginChild("##Frames Child", childSize, ImGuiChildFlags_Borders))
{
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
ImGui::Shortcut(ImGuiKey_Escape, ImGuiInputFlags_RouteFocused))
{
if (!frames.selection.empty())
{
reference.frameIndex = -1;
frames_selection_set_reference();
}
else if (reference.itemType != anm2::NONE || reference.itemID != -1)
reference_clear();
}
auto drawList = ImGui::GetWindowDrawList();
auto clipMax = drawList->GetClipRectMax();
auto length = animation ? animation->frameNum : anm2.animations.length();
@@ -977,15 +1109,16 @@ namespace anm2ed::imgui
ImGui::SetNextItemAllowOverlap();
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, FRAME_ROUNDING);
ImGui::SetNextItemSelectionUserData((int)i);
bool isDifferentItem = reference.itemType != type || reference.itemID != id;
if (ImGui::Selectable("##Frame Button", isSelected, ImGuiSelectableFlags_None, buttonSize))
{
if (type == anm2::LAYER)
if (type == anm2::LAYER) document.spritesheet.reference = anm2.content.layers[id].spritesheetID;
if (type == anm2::LAYER || type == anm2::NULL_)
{
document.spritesheet.reference = anm2.content.layers[id].spritesheetID;
document.layer.selection = {id};
itemSelection.clear();
itemSelection.insert(item_selection_encode(type, id));
item_selection_sync();
}
else if (type == anm2::NULL_)
document.null.selection = {id};
if (type != anm2::TRIGGER)
{
@@ -998,6 +1131,7 @@ namespace anm2ed::imgui
reference = frameReference;
isReferenced = true;
if (isDifferentItem) frames_selection_set_reference();
}
ImGui::PopStyleVar();
@@ -1215,10 +1349,7 @@ namespace anm2ed::imgui
if (type == anm2::LAYER)
{
document.spritesheet.reference = anm2.content.layers[id].spritesheetID;
document.layer.selection = {id};
}
else if (type == anm2::NULL_)
document.null.selection = {id};
}
}
}