Editor: 更新编辑器面板和UI控件系统
- 添加新的UI控件系统(Core.h, ScalarControls.h, VectorControls.h, UI.h) - 更新SceneManager支持场景层级管理 - 优化SelectionManager选择管理 - 改进InspectorPanel/GameViewPanel/HierarchyPanel等面板 - 更新RHI文档说明Vulkan实现计划
This commit is contained in:
61
editor/src/UI/Core.h
Normal file
61
editor/src/UI/Core.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
namespace UI {
|
||||
|
||||
inline void StyleVarPush(ImGuiStyleVar idx, float val) {
|
||||
ImGui::PushStyleVar(idx, val);
|
||||
}
|
||||
|
||||
inline void StyleVarPush(ImGuiStyleVar idx, ImVec2 val) {
|
||||
ImGui::PushStyleVar(idx, val);
|
||||
}
|
||||
|
||||
inline void StyleColorPush(ImGuiCol idx, ImU32 col) {
|
||||
ImGui::PushStyleColor(idx, col);
|
||||
}
|
||||
|
||||
inline void StyleColorPush(ImGuiCol idx, ImVec4 col) {
|
||||
ImGui::PushStyleColor(idx, col);
|
||||
}
|
||||
|
||||
inline void PopStyleVar(int count = 1) {
|
||||
ImGui::PopStyleVar(count);
|
||||
}
|
||||
|
||||
inline void PopStyleColor(int count = 1) {
|
||||
ImGui::PopStyleColor(count);
|
||||
}
|
||||
|
||||
inline bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(12.0f, 10.0f));
|
||||
bool is_open = ImGui::BeginPopup(str_id, flags);
|
||||
if (!is_open) {
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
return is_open;
|
||||
}
|
||||
|
||||
inline void EndPopup() {
|
||||
ImGui::EndPopup();
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
inline void BeginDisabled(bool disabled = true) {
|
||||
if (disabled) {
|
||||
ImGui::BeginDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
inline void EndDisabled(bool disabled = true) {
|
||||
if (disabled) {
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
322
editor/src/UI/ScalarControls.h
Normal file
322
editor/src/UI/ScalarControls.h
Normal file
@@ -0,0 +1,322 @@
|
||||
#pragma once
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
namespace UI {
|
||||
|
||||
inline bool DrawFloat(
|
||||
const char* label,
|
||||
float& value,
|
||||
float columnWidth = 100.0f,
|
||||
float dragSpeed = 0.1f,
|
||||
float min = 0.0f,
|
||||
float max = 0.0f,
|
||||
const char* format = "%.2f"
|
||||
) {
|
||||
bool changed = false;
|
||||
ImGui::PushID(label);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{0, 1});
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{4, 1});
|
||||
|
||||
if (ImGui::BeginTable("##FloatTable", 2, ImGuiTableFlags_NoSavedSettings)) {
|
||||
ImGui::TableSetupColumn("##label", ImGuiTableColumnFlags_WidthFixed, columnWidth);
|
||||
ImGui::TableSetupColumn("##control", ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_None, ImGui::GetFontSize() + 2.0f);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(label);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (max != min) {
|
||||
if (ImGui::SliderFloat("##value", &value, min, max, format)) {
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if (ImGui::DragFloat("##value", &value, dragSpeed, min, max, format)) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
inline bool DrawInt(
|
||||
const char* label,
|
||||
int& value,
|
||||
float columnWidth = 100.0f,
|
||||
int step = 1,
|
||||
int min = 0,
|
||||
int max = 0
|
||||
) {
|
||||
bool changed = false;
|
||||
ImGui::PushID(label);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{0, 1});
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{4, 1});
|
||||
|
||||
if (ImGui::BeginTable("##IntTable", 2, ImGuiTableFlags_NoSavedSettings)) {
|
||||
ImGui::TableSetupColumn("##label", ImGuiTableColumnFlags_WidthFixed, columnWidth);
|
||||
ImGui::TableSetupColumn("##control", ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_None, ImGui::GetFontSize() + 2.0f);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(label);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (ImGui::DragInt("##value", &value, static_cast<float>(step), min, max)) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
inline bool DrawBool(
|
||||
const char* label,
|
||||
bool& value,
|
||||
float columnWidth = 100.0f
|
||||
) {
|
||||
bool changed = false;
|
||||
ImGui::PushID(label);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{0, 1});
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{4, 1});
|
||||
|
||||
if (ImGui::BeginTable("##BoolTable", 2, ImGuiTableFlags_NoSavedSettings)) {
|
||||
ImGui::TableSetupColumn("##label", ImGuiTableColumnFlags_WidthFixed, columnWidth);
|
||||
ImGui::TableSetupColumn("##control", ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_None, ImGui::GetFontSize() + 2.0f);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(label);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (ImGui::Checkbox("##value", &value)) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
inline bool DrawColor3(
|
||||
const char* label,
|
||||
float color[3],
|
||||
float columnWidth = 100.0f
|
||||
) {
|
||||
bool changed = false;
|
||||
ImGui::PushID(label);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{0, 1});
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{4, 1});
|
||||
|
||||
if (ImGui::BeginTable("##Color3Table", 2, ImGuiTableFlags_NoSavedSettings)) {
|
||||
ImGui::TableSetupColumn("##label", ImGuiTableColumnFlags_WidthFixed, columnWidth);
|
||||
ImGui::TableSetupColumn("##control", ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_None, ImGui::GetFontSize() + 2.0f);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(label);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (ImGui::ColorEdit3("##value", color, ImGuiColorEditFlags_NoInputs)) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
inline bool DrawColor4(
|
||||
const char* label,
|
||||
float color[4],
|
||||
float columnWidth = 100.0f
|
||||
) {
|
||||
bool changed = false;
|
||||
ImGui::PushID(label);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{0, 1});
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{4, 1});
|
||||
|
||||
if (ImGui::BeginTable("##Color4Table", 2, ImGuiTableFlags_NoSavedSettings)) {
|
||||
ImGui::TableSetupColumn("##label", ImGuiTableColumnFlags_WidthFixed, columnWidth);
|
||||
ImGui::TableSetupColumn("##control", ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_None, ImGui::GetFontSize() + 2.0f);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(label);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (ImGui::ColorEdit4("##value", color, ImGuiColorEditFlags_NoInputs)) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
inline bool DrawSliderFloat(
|
||||
const char* label,
|
||||
float& value,
|
||||
float min,
|
||||
float max,
|
||||
float columnWidth = 100.0f,
|
||||
const char* format = "%.2f"
|
||||
) {
|
||||
bool changed = false;
|
||||
ImGui::PushID(label);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{0, 1});
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{4, 1});
|
||||
|
||||
if (ImGui::BeginTable("##SliderTable", 2, ImGuiTableFlags_NoSavedSettings)) {
|
||||
ImGui::TableSetupColumn("##label", ImGuiTableColumnFlags_WidthFixed, columnWidth);
|
||||
ImGui::TableSetupColumn("##control", ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_None, ImGui::GetFontSize() + 2.0f);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(label);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (ImGui::SliderFloat("##value", &value, min, max, format)) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
inline bool DrawSliderInt(
|
||||
const char* label,
|
||||
int& value,
|
||||
int min,
|
||||
int max,
|
||||
float columnWidth = 100.0f
|
||||
) {
|
||||
bool changed = false;
|
||||
ImGui::PushID(label);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{0, 1});
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{4, 1});
|
||||
|
||||
if (ImGui::BeginTable("##SliderIntTable", 2, ImGuiTableFlags_NoSavedSettings)) {
|
||||
ImGui::TableSetupColumn("##label", ImGuiTableColumnFlags_WidthFixed, columnWidth);
|
||||
ImGui::TableSetupColumn("##control", ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_None, ImGui::GetFontSize() + 2.0f);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(label);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (ImGui::SliderInt("##value", &value, min, max)) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
inline int DrawCombo(
|
||||
const char* label,
|
||||
int currentItem,
|
||||
const char* const items[],
|
||||
int itemCount,
|
||||
float columnWidth = 100.0f,
|
||||
int heightInItems = -1
|
||||
) {
|
||||
ImGui::PushID(label);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{0, 1});
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{4, 1});
|
||||
|
||||
int changedItem = currentItem;
|
||||
|
||||
if (ImGui::BeginTable("##ComboTable", 2, ImGuiTableFlags_NoSavedSettings)) {
|
||||
ImGui::TableSetupColumn("##label", ImGuiTableColumnFlags_WidthFixed, columnWidth);
|
||||
ImGui::TableSetupColumn("##control", ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_None, ImGui::GetFontSize() + 2.0f);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(label);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
if (ImGui::Combo("##value", ¤tItem, items, itemCount, heightInItems)) {
|
||||
changedItem = currentItem;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopID();
|
||||
|
||||
return changedItem;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
13
editor/src/UI/UI.h
Normal file
13
editor/src/UI/UI.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core.h"
|
||||
#include "VectorControls.h"
|
||||
#include "ScalarControls.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
namespace UI {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
150
editor/src/UI/VectorControls.h
Normal file
150
editor/src/UI/VectorControls.h
Normal file
@@ -0,0 +1,150 @@
|
||||
#pragma once
|
||||
|
||||
#include <imgui.h>
|
||||
#include <XCEngine/Core/Math/Vector3.h>
|
||||
#include <XCEngine/Core/Math/Vector2.h>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
namespace UI {
|
||||
|
||||
inline bool DrawVec3(
|
||||
const char* label,
|
||||
::XCEngine::Math::Vector3& values,
|
||||
float resetValue = 0.0f,
|
||||
float columnWidth = 100.0f,
|
||||
float dragSpeed = 0.1f
|
||||
) {
|
||||
bool changed = false;
|
||||
ImGui::PushID(label);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{0, 1});
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{4, 1});
|
||||
|
||||
if (ImGui::BeginTable("##Vec3Table", 2, ImGuiTableFlags_NoSavedSettings)) {
|
||||
ImGui::TableSetupColumn("##label", ImGuiTableColumnFlags_WidthFixed, columnWidth);
|
||||
ImGui::TableSetupColumn("##controls", ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_None, ImGui::GetFontSize() + 2.0f);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(label);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{0, 0});
|
||||
|
||||
float lineHeight = ImGui::GetFontSize() + ImGui::GetStyle().FramePadding.y * 2.0f;
|
||||
ImVec2 buttonSize = {lineHeight + 3.0f, lineHeight};
|
||||
float itemWidth = (ImGui::GetContentRegionAvail().x - buttonSize.x * 3.0f) / 3.0f;
|
||||
|
||||
auto drawAxisControl = [&](const char* axisLabel, float& value, ImVec4 color, ImVec4 colorHovered) {
|
||||
bool axisChanged = false;
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, color);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colorHovered);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, color);
|
||||
|
||||
if (ImGui::Button(axisLabel, buttonSize)) {
|
||||
value = resetValue;
|
||||
axisChanged = true;
|
||||
}
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(itemWidth);
|
||||
|
||||
if (ImGui::DragFloat((std::string("##") + axisLabel).c_str(), &value, dragSpeed, 0.0f, 0.0f, "%.2f")) {
|
||||
axisChanged = true;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
return axisChanged;
|
||||
};
|
||||
|
||||
changed |= drawAxisControl("X", values.x, ImVec4{0.8f, 0.1f, 0.15f, 1.0f}, ImVec4{0.9f, 0.2f, 0.2f, 1.0f});
|
||||
changed |= drawAxisControl("Y", values.y, ImVec4{0.2f, 0.7f, 0.2f, 1.0f}, ImVec4{0.3f, 0.8f, 0.3f, 1.0f});
|
||||
changed |= drawAxisControl("Z", values.z, ImVec4{0.1f, 0.25f, 0.8f, 1.0f}, ImVec4{0.2f, 0.35f, 0.9f, 1.0f});
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
inline bool DrawVec2(
|
||||
const char* label,
|
||||
::XCEngine::Math::Vector2& values,
|
||||
float resetValue = 0.0f,
|
||||
float columnWidth = 100.0f,
|
||||
float dragSpeed = 0.1f
|
||||
) {
|
||||
bool changed = false;
|
||||
ImGui::PushID(label);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{0, 1});
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{4, 1});
|
||||
|
||||
if (ImGui::BeginTable("##Vec2Table", 2, ImGuiTableFlags_NoSavedSettings)) {
|
||||
ImGui::TableSetupColumn("##label", ImGuiTableColumnFlags_WidthFixed, columnWidth);
|
||||
ImGui::TableSetupColumn("##controls", ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_None, ImGui::GetFontSize() + 2.0f);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(label);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{0, 0});
|
||||
|
||||
float lineHeight = ImGui::GetFontSize() + ImGui::GetStyle().FramePadding.y * 2.0f;
|
||||
ImVec2 buttonSize = {lineHeight + 3.0f, lineHeight};
|
||||
float itemWidth = (ImGui::GetContentRegionAvail().x - buttonSize.x * 2.0f) / 2.0f;
|
||||
|
||||
auto drawAxisControl = [&](const char* axisLabel, float& value, ImVec4 color, ImVec4 colorHovered) {
|
||||
bool axisChanged = false;
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, color);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colorHovered);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, color);
|
||||
|
||||
if (ImGui::Button(axisLabel, buttonSize)) {
|
||||
value = resetValue;
|
||||
axisChanged = true;
|
||||
}
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(itemWidth);
|
||||
|
||||
if (ImGui::DragFloat((std::string("##") + axisLabel).c_str(), &value, dragSpeed, 0.0f, 0.0f, "%.2f")) {
|
||||
axisChanged = true;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
return axisChanged;
|
||||
};
|
||||
|
||||
changed |= drawAxisControl("X", values.x, ImVec4{0.8f, 0.1f, 0.15f, 1.0f}, ImVec4{0.9f, 0.2f, 0.2f, 1.0f});
|
||||
changed |= drawAxisControl("Y", values.y, ImVec4{0.2f, 0.7f, 0.2f, 1.0f}, ImVec4{0.3f, 0.8f, 0.3f, 1.0f});
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user