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