some issues with item selection, fixed
This commit is contained in:
@@ -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};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user