Refactor editor dock and panel chrome styling

This commit is contained in:
2026-03-26 16:43:06 +08:00
parent e174862b8a
commit 45842e961e
13 changed files with 623 additions and 328 deletions

View File

@@ -5,6 +5,8 @@
#include "Core/IUndoManager.h"
#include "Core/ISelectionManager.h"
#include "Core/AssetItem.h"
#include "UI/Core.h"
#include "UI/PanelChrome.h"
#include "Utils/SceneEditorUtils.h"
#include <imgui.h>
#include <imgui_internal.h>
@@ -14,6 +16,31 @@ namespace Editor {
const char* DRAG_DROP_TYPE = "ASSET_ITEM";
namespace {
constexpr float kProjectToolbarHeight = 60.0f;
void DrawFolderIcon(ImDrawList* drawList, const ImVec2& min, const ImVec2& max, ImU32 fillColor, ImU32 lineColor) {
const float width = max.x - min.x;
const float height = max.y - min.y;
const ImVec2 tabMax(min.x + width * 0.45f, min.y + height * 0.35f);
drawList->AddRectFilled(ImVec2(min.x, min.y + height * 0.14f), tabMax, fillColor, 2.0f);
drawList->AddRectFilled(ImVec2(min.x, min.y + height * 0.28f), max, fillColor, 2.0f);
drawList->AddRect(ImVec2(min.x, min.y + height * 0.14f), tabMax, lineColor, 2.0f);
drawList->AddRect(ImVec2(min.x, min.y + height * 0.28f), max, lineColor, 2.0f);
}
void DrawFileIcon(ImDrawList* drawList, const ImVec2& min, const ImVec2& max, ImU32 fillColor, ImU32 lineColor) {
const ImVec2 foldA(max.x - 8.0f, min.y);
const ImVec2 foldB(max.x, min.y + 8.0f);
drawList->AddRectFilled(min, max, fillColor, 2.0f);
drawList->AddRect(min, max, lineColor, 2.0f);
drawList->AddTriangleFilled(foldA, ImVec2(max.x, min.y), foldB, IM_COL32(235, 235, 235, 40));
drawList->AddLine(foldA, foldB, lineColor);
}
} // namespace
ProjectPanel::ProjectPanel() : Panel("Project") {
}
@@ -29,58 +56,67 @@ void ProjectPanel::Render() {
m_draggingPath.clear();
}
ImGui::Begin(m_name.c_str(), nullptr, ImGuiWindowFlags_None);
UI::PanelWindowScope panel(m_name.c_str());
if (!panel.IsOpen()) {
return;
}
auto& manager = m_context->GetProjectManager();
bool canGoBack = manager.CanNavigateBack();
ImGui::BeginDisabled(!canGoBack);
if (ImGui::Button("<")) {
if (canGoBack) {
manager.NavigateBack();
}
}
ImGui::EndDisabled();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0));
size_t pathDepth = manager.GetPathDepth();
for (size_t i = 0; i < pathDepth; i++) {
if (i > 0) {
ImGui::SameLine();
ImGui::Text("/");
ImGui::SameLine();
}
std::string name = manager.GetPathName(i);
if (i < pathDepth - 1) {
if (ImGui::Button(name.c_str())) {
manager.NavigateToIndex(i);
UI::PanelToolbarScope toolbar("ProjectToolbar", kProjectToolbarHeight);
if (toolbar.IsOpen()) {
bool canGoBack = manager.CanNavigateBack();
ImGui::BeginDisabled(!canGoBack);
if (UI::ToolbarButton("<", false, ImVec2(28.0f, 0.0f))) {
if (canGoBack) {
manager.NavigateBack();
}
} else {
ImGui::Text("%s", name.c_str());
}
ImGui::EndDisabled();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
size_t pathDepth = manager.GetPathDepth();
if (pathDepth == 0) {
ImGui::TextUnformatted("Assets");
} else {
for (size_t i = 0; i < pathDepth; i++) {
if (i > 0) {
ImGui::SameLine();
ImGui::TextDisabled("/");
ImGui::SameLine();
}
std::string name = manager.GetPathName(i);
if (i < pathDepth - 1) {
if (ImGui::Button(name.c_str())) {
manager.NavigateToIndex(i);
}
} else {
ImGui::Text("%s", name.c_str());
}
}
}
ImGui::PopStyleColor(2);
ImGui::Dummy(ImVec2(0.0f, 2.0f));
ImGui::SetNextItemWidth(-1.0f);
ImGui::InputTextWithHint("##Search", "Search assets", m_searchBuffer, sizeof(m_searchBuffer));
}
ImGui::PopStyleColor(2);
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 80.0f);
if (ImGui::Button("Refresh")) {
manager.RefreshCurrentFolder();
UI::PanelContentScope content(
"ProjectContent",
UI::AssetPanelContentPadding(),
ImGuiWindowFlags_None,
true,
ImVec2(8.0f, 10.0f));
if (!content.IsOpen()) {
return;
}
ImGui::Separator();
ImGui::PushItemWidth(-1);
ImGui::InputTextWithHint("##Search", "Search...", m_searchBuffer, sizeof(m_searchBuffer));
ImGui::PopItemWidth();
ImGui::Separator();
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10, 10));
float buttonWidth = 80.0f;
float padding = 10.0f;
float buttonWidth = 104.0f;
float padding = 8.0f;
float panelWidth = ImGui::GetContentRegionAvail().x;
int columns = (int)(panelWidth / (buttonWidth + padding));
if (columns < 1) columns = 1;
@@ -102,9 +138,7 @@ void ProjectPanel::Render() {
RenderAssetItem(items[i], i);
displayedCount++;
}
ImGui::PopStyleVar();
if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered()) {
manager.SetSelectedIndex(-1);
}
@@ -142,15 +176,9 @@ void ProjectPanel::Render() {
m_showCreateFolderPopup = true;
strcpy_s(m_newFolderName, "NewFolder");
}
ImGui::Separator();
if (ImGui::MenuItem("Refresh")) {
manager.RefreshCurrentFolder();
}
ImGui::EndPopup();
}
ImGui::End();
if (m_showCreateFolderPopup) {
ImGui::OpenPopup("Create Folder");
m_showCreateFolderPopup = false;
@@ -176,17 +204,11 @@ void ProjectPanel::RenderAssetItem(const AssetItemPtr& item, int index) {
bool isSelected = (manager.GetSelectedIndex() == index);
ImGui::PushID(index);
if (isSelected) {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.40f, 0.40f, 0.40f, 0.50f));
} else {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.30f, 0.30f, 0.30f, 0.40f));
}
ImVec2 buttonSize(80.0f, 90.0f);
if (ImGui::Button("##AssetBtn", buttonSize)) {
ImVec2 buttonSize(104.0f, 82.0f);
ImGui::InvisibleButton("##AssetBtn", buttonSize);
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
manager.SetSelectedIndex(index);
}
@@ -202,46 +224,39 @@ void ProjectPanel::RenderAssetItem(const AssetItemPtr& item, int index) {
openContextMenu = true;
}
if (isSelected) {
ImGui::PopStyleColor();
} else {
ImGui::PopStyleColor(2);
}
ImVec2 min = ImGui::GetItemRectMin();
ImVec2 max = ImVec2(min.x + buttonSize.x, min.y + buttonSize.y);
ImDrawList* drawList = ImGui::GetWindowDrawList();
const bool hovered = ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem);
if (hovered || isSelected) {
drawList->AddRectFilled(min, max, isSelected ? IM_COL32(156, 156, 156, 30) : IM_COL32(255, 255, 255, 10), 2.0f);
}
if (isSelected) {
drawList->AddRect(min, max, IM_COL32(188, 188, 188, 110), 2.0f);
}
if (!m_draggingPath.empty() && item->fullPath == m_draggingPath) {
drawList->AddRectFilled(min, max, IM_COL32(0, 0, 0, 60), 0.0f);
}
ImU32 iconColor;
ImU32 iconFillColor = item->isFolder ? IM_COL32(118, 118, 118, 255) : IM_COL32(104, 104, 104, 255);
ImU32 iconLineColor = item->isFolder ? IM_COL32(184, 184, 184, 220) : IM_COL32(166, 166, 166, 220);
const ImVec2 iconMin(min.x + 14.0f, min.y + 12.0f);
const ImVec2 iconMax(iconMin.x + 28.0f, iconMin.y + 22.0f);
if (item->isFolder) {
iconColor = IM_COL32(200, 180, 100, 255);
} else if (item->type == "Texture") {
iconColor = IM_COL32(150, 200, 150, 255);
} else if (item->type == "Model") {
iconColor = IM_COL32(150, 150, 200, 255);
} else if (item->type == "Script") {
iconColor = IM_COL32(200, 150, 150, 255);
} else if (item->type == "Scene") {
iconColor = IM_COL32(200, 200, 150, 255);
DrawFolderIcon(drawList, iconMin, iconMax, iconFillColor, iconLineColor);
} else {
iconColor = IM_COL32(100, 150, 200, 255);
DrawFileIcon(drawList, iconMin, iconMax, iconFillColor, iconLineColor);
}
float iconSize = 40.0f;
ImVec2 iconMin(min.x + (80.0f - iconSize) * 0.5f, min.y + 10.0f);
ImVec2 iconMax(iconMin.x + iconSize, iconMin.y + iconSize);
drawList->AddRectFilled(iconMin, iconMax, iconColor, 4.0f);
ImVec4 textColor = isSelected ? ImVec4(1.0f, 1.0f, 1.0f, 1.0f) : ImVec4(0.8f, 0.8f, 0.8f, 1.0f);
ImVec4 textColor = isSelected ? ImVec4(0.93f, 0.93f, 0.93f, 1.0f) : ImVec4(0.76f, 0.76f, 0.76f, 1.0f);
ImVec2 textSize = ImGui::CalcTextSize(item->name.c_str());
float textOffset = std::max(0.0f, (80.0f - textSize.x) * 0.5f);
ImGui::PushClipRect(min, ImVec2(min.x + 80.0f, min.y + 90.0f), true);
drawList->AddText(ImVec2(min.x + textOffset, min.y + 60.0f), ImGui::GetColorU32(textColor), item->name.c_str());
float textY = max.y - textSize.y - 10.0f;
ImGui::PushClipRect(ImVec2(min.x + 6.0f, min.y), ImVec2(max.x - 6.0f, max.y), true);
drawList->AddText(ImVec2(min.x + 6.0f, textY), ImGui::GetColorU32(textColor), item->name.c_str());
ImGui::PopClipRect();
if (item->isFolder) {
@@ -253,35 +268,19 @@ void ProjectPanel::RenderAssetItem(const AssetItemPtr& item, int index) {
}
ImGui::EndDragDropTarget();
}
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) {
ImDrawList* hoverDrawList = ImGui::GetWindowDrawList();
hoverDrawList->AddRect(min, ImVec2(min.x + buttonSize.x, min.y + buttonSize.y), IM_COL32(255, 255, 255, 80), 4.0f);
}
}
if (!item->fullPath.empty()) {
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
ImGui::SetDragDropPayload(DRAG_DROP_TYPE, item->fullPath.c_str(), item->fullPath.length() + 1);
ImU32 iconColor;
if (item->isFolder) {
iconColor = IM_COL32(200, 180, 100, 100);
} else if (item->type == "Texture") {
iconColor = IM_COL32(150, 200, 150, 100);
} else if (item->type == "Model") {
iconColor = IM_COL32(150, 150, 200, 100);
} else if (item->type == "Script") {
iconColor = IM_COL32(200, 150, 150, 100);
} else if (item->type == "Scene") {
iconColor = IM_COL32(200, 200, 150, 100);
} else {
iconColor = IM_COL32(100, 150, 200, 100);
}
ImVec2 previewMin = ImGui::GetMousePos();
ImVec2 previewMax = ImVec2(previewMin.x + 40, previewMin.y + 40);
ImGui::GetForegroundDrawList()->AddRectFilled(previewMin, previewMax, iconColor, 4.0f);
ImVec2 previewMax = ImVec2(previewMin.x + 24.0f, previewMin.y + 20.0f);
if (item->isFolder) {
DrawFolderIcon(ImGui::GetForegroundDrawList(), previewMin, previewMax, iconFillColor, iconLineColor);
} else {
DrawFileIcon(ImGui::GetForegroundDrawList(), previewMin, previewMax, iconFillColor, iconLineColor);
}
ImGui::EndDragDropSource();
}