Compare commits

...

3 Commits

Author SHA1 Message Date
51251f08a4 fix: 修复层级面板右键无法弹出创建菜单的问题 2026-03-12 19:17:59 +08:00
0c02aa2ae6 refactor: 将SceneView拆分为Scene和Game两个独立窗口
- 新增GameViewPanel作为独立窗口
- 移除SceneViewPanel中的TabBar
- Scene和Game现在像Console/Project一样并排显示
2026-03-12 19:03:32 +08:00
6e12efb67e fix: 修复多个UI框架问题
- 修复 InspectorPanel InputText 使用 data()/capacity() 的错误
- 修复未使用变量警告
- 修复 ProjectManager 路径重复拼接 bug (Assets/Assets)
- 返回按钮在 Assets 目录时禁用但保持显示
- 删除 ProjectPanel 创建按钮,调整 Refresh 位置
- 修复 ProjectPanel 搜索过滤时的 ID 冲突
- 修复 InspectorPanel CollapsingHeader ID 冲突
2026-03-12 18:58:06 +08:00
11 changed files with 94 additions and 58 deletions

View File

@@ -39,6 +39,7 @@ add_executable(${PROJECT_NAME} WIN32
src/panels/MenuBar.cpp
src/panels/HierarchyPanel.cpp
src/panels/SceneViewPanel.cpp
src/panels/GameViewPanel.cpp
src/panels/InspectorPanel.cpp
src/panels/ConsolePanel.cpp
src/panels/ProjectPanel.cpp

View File

@@ -30,10 +30,8 @@ bool Application::Initialize(HWND hwnd) {
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
ImFont* font = io.Fonts->AddFontFromFileTTF("C:/Windows/Fonts/msyh.ttc", 16.0f);
ImFont* defaultFont = io.Fonts->AddFontDefault();
(void)font;
(void)defaultFont;
io.Fonts->AddFontFromFileTTF("C:/Windows/Fonts/msyh.ttc", 16.0f);
io.Fonts->AddFontDefault();
unsigned char* pixels;
int width, height;
@@ -49,6 +47,7 @@ bool Application::Initialize(HWND hwnd) {
m_menuBar = std::make_unique<MenuBar>();
m_hierarchyPanel = std::make_unique<HierarchyPanel>();
m_sceneViewPanel = std::make_unique<SceneViewPanel>();
m_gameViewPanel = std::make_unique<GameViewPanel>();
m_inspectorPanel = std::make_unique<InspectorPanel>();
m_consolePanel = std::make_unique<ConsolePanel>();
m_projectPanel = std::make_unique<ProjectPanel>();
@@ -279,6 +278,7 @@ void Application::SetupDockspace() {
ImGui::DockBuilderDockWindow("Hierarchy", dockLeft);
ImGui::DockBuilderDockWindow("Scene", dockMain);
ImGui::DockBuilderDockWindow("Game", dockMain);
ImGui::DockBuilderDockWindow("Inspector", dockRight);
ImGui::DockBuilderDockWindow("Console", dockBottom);
ImGui::DockBuilderDockWindow("Project", dockBottom);
@@ -294,6 +294,7 @@ void Application::RenderUI() {
m_hierarchyPanel->Render();
m_sceneViewPanel->Render();
m_gameViewPanel->Render();
m_inspectorPanel->Render();
m_consolePanel->Render();
m_projectPanel->Render();

View File

@@ -10,6 +10,7 @@
#include "panels/MenuBar.h"
#include "panels/HierarchyPanel.h"
#include "panels/SceneViewPanel.h"
#include "panels/GameViewPanel.h"
#include "panels/InspectorPanel.h"
#include "panels/ConsolePanel.h"
#include "panels/ProjectPanel.h"
@@ -55,6 +56,7 @@ private:
std::unique_ptr<MenuBar> m_menuBar;
std::unique_ptr<HierarchyPanel> m_hierarchyPanel;
std::unique_ptr<SceneViewPanel> m_sceneViewPanel;
std::unique_ptr<GameViewPanel> m_gameViewPanel;
std::unique_ptr<InspectorPanel> m_inspectorPanel;
std::unique_ptr<ConsolePanel> m_consolePanel;
std::unique_ptr<ProjectPanel> m_projectPanel;

View File

@@ -34,10 +34,10 @@ void ProjectManager::NavigateBack() {
}
std::string ProjectManager::GetCurrentPath() const {
if (m_path.empty()) return "";
std::string result;
for (size_t i = 0; i < m_path.size(); i++) {
if (i > 0) result += "/";
if (m_path.empty()) return "Assets";
std::string result = "Assets";
for (size_t i = 1; i < m_path.size(); i++) {
result += "/";
result += m_path[i]->name;
}
return result;
@@ -99,8 +99,10 @@ void ProjectManager::Initialize(const std::string& projectPath) {
}
std::wstring ProjectManager::GetCurrentFullPathW() const {
if (m_path.empty()) return Utf8ToWstring(m_projectPath);
std::wstring fullPath = Utf8ToWstring(m_projectPath);
for (size_t i = 0; i < m_path.size(); i++) {
for (size_t i = 1; i < m_path.size(); i++) {
fullPath += L"/" + Utf8ToWstring(m_path[i]->name);
}
return fullPath;

View File

@@ -0,0 +1,31 @@
#include "GameViewPanel.h"
#include <imgui.h>
#include <imgui_internal.h>
namespace UI {
GameViewPanel::GameViewPanel() : Panel("Game") {}
void GameViewPanel::Render() {
ImGui::Begin(m_name.c_str(), &m_isOpen, ImGuiWindowFlags_None);
RenderGameView();
ImGui::End();
}
void GameViewPanel::RenderGameView() {
ImVec2 canvasSize = ImGui::GetContentRegionAvail();
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 canvasPos = ImGui::GetCursorScreenPos();
ImU32 bgColor = IM_COL32(20, 20, 25, 255);
drawList->AddRectFilled(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y), bgColor);
const char* text = "Game View (Press Play)";
ImVec2 textSize = ImGui::CalcTextSize(text);
ImVec2 textPos(canvasPos.x + (canvasSize.x - textSize.x) * 0.5f, canvasPos.y + (canvasSize.y - textSize.y) * 0.5f);
drawList->AddText(textPos, IM_COL32(128, 128, 128, 255), text);
}
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include "Panel.h"
namespace UI {
class GameViewPanel : public Panel {
public:
GameViewPanel();
void Render() override;
private:
void RenderGameView();
};
}

View File

@@ -18,7 +18,7 @@ HierarchyPanel::~HierarchyPanel() {
}
void HierarchyPanel::Render() {
ImGui::Begin(m_name.c_str(), &m_isOpen, ImGuiWindowFlags_None);
ImGui::Begin(m_name.c_str(), nullptr, ImGuiWindowFlags_None);
RenderSearchBar();
@@ -40,7 +40,7 @@ void HierarchyPanel::Render() {
}
}
if (ImGui::BeginPopupContextWindow("HierarchyContextMenu", ImGuiPopupFlags_MouseButtonRight | ImGuiPopupFlags_NoOpenOverItems)) {
if (ImGui::BeginPopupContextWindow("HierarchyContextMenu", ImGuiPopupFlags_MouseButtonRight)) {
RenderCreateMenu(INVALID_ENTITY);
ImGui::EndPopup();
}

View File

@@ -2,6 +2,7 @@
#include "Managers/SceneManager.h"
#include "Managers/SelectionManager.h"
#include <imgui.h>
#include <string>
namespace UI {
@@ -45,7 +46,9 @@ void InspectorPanel::RenderComponent(Component* component) {
const char* name = component->GetName().c_str();
if (ImGui::CollapsingHeader(name, ImGuiTreeNodeFlags_DefaultOpen)) {
std::string headerId = name + std::string("##") + std::to_string(reinterpret_cast<uintptr_t>(component));
if (ImGui::CollapsingHeader(headerId.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Indent(10.0f);
if (auto* transform = dynamic_cast<TransformComponent*>(component)) {
@@ -65,15 +68,23 @@ void InspectorPanel::RenderComponent(Component* component) {
ImGui::DragFloat3("##Scale", transform->scale, 0.1f);
}
else if (auto* meshRenderer = dynamic_cast<MeshRendererComponent*>(component)) {
char materialBuffer[256] = {};
strncpy_s(materialBuffer, meshRenderer->materialName.c_str(), sizeof(materialBuffer) - 1);
ImGui::Text("Material");
ImGui::SameLine(80);
ImGui::SetNextItemWidth(180);
ImGui::InputText("##Material", meshRenderer->materialName.data(), meshRenderer->materialName.capacity());
if (ImGui::InputText("##Material", materialBuffer, sizeof(materialBuffer))) {
meshRenderer->materialName = materialBuffer;
}
char meshBuffer[256] = {};
strncpy_s(meshBuffer, meshRenderer->meshName.c_str(), sizeof(meshBuffer) - 1);
ImGui::Text("Mesh");
ImGui::SameLine(80);
ImGui::SetNextItemWidth(180);
ImGui::InputText("##Mesh", meshRenderer->meshName.data(), meshRenderer->meshName.capacity());
if (ImGui::InputText("##Mesh", meshBuffer, sizeof(meshBuffer))) {
meshRenderer->meshName = meshBuffer;
}
}
ImGui::Unindent(10.0f);

View File

@@ -18,27 +18,24 @@ void ProjectPanel::Render() {
auto& manager = ProjectManager::Get();
if (manager.CanNavigateBack()) {
if (ImGui::Button("<")) {
bool canGoBack = manager.CanNavigateBack();
ImGui::BeginDisabled(!canGoBack);
if (ImGui::Button("<")) {
if (canGoBack) {
manager.NavigateBack();
}
ImGui::SameLine();
}
ImGui::EndDisabled();
ImGui::SameLine();
ImGui::Text("%s", manager.GetCurrentPath().c_str());
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 140.0f);
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 80.0f);
if (ImGui::Button("Refresh")) {
manager.RefreshCurrentFolder();
}
ImGui::SameLine();
if (ImGui::Button("+")) {
m_showCreateFolderPopup = true;
strcpy_s(m_newFolderName, "NewFolder");
}
ImGui::Separator();
ImGui::PushItemWidth(-1);
@@ -69,7 +66,7 @@ void ProjectPanel::Render() {
if (itemIndex > 0 && itemIndex % columns != 0) {
ImGui::SameLine();
}
RenderAssetItem(items[i], i);
RenderAssetItem(items[i], itemIndex);
itemIndex++;
}

View File

@@ -9,38 +9,14 @@ SceneViewPanel::SceneViewPanel() : Panel("Scene") {}
void SceneViewPanel::Render() {
ImGui::Begin(m_name.c_str(), &m_isOpen, ImGuiWindowFlags_None);
if (ImGui::BeginTabBar("SceneGameTabs")) {
if (ImGui::BeginTabItem("Scene")) {
m_isSceneView = true;
ImVec2 canvasSize = ImGui::GetContentRegionAvail();
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 canvasPos = ImGui::GetCursorScreenPos();
ImU32 bgColor = IM_COL32(30, 30, 30, 255);
drawList->AddRectFilled(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y), bgColor);
RenderGrid();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Game")) {
m_isSceneView = false;
ImVec2 canvasSize = ImGui::GetContentRegionAvail();
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 canvasPos = ImGui::GetCursorScreenPos();
ImU32 bgColor = IM_COL32(20, 20, 25, 255);
drawList->AddRectFilled(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y), bgColor);
const char* text = "Game View (Press Play)";
ImVec2 textSize = ImGui::CalcTextSize(text);
ImVec2 textPos(canvasPos.x + (canvasSize.x - textSize.x) * 0.5f, canvasPos.y + (canvasSize.y - textSize.y) * 0.5f);
drawList->AddText(textPos, IM_COL32(128, 128, 128, 255), text);
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
ImVec2 canvasSize = ImGui::GetContentRegionAvail();
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 canvasPos = ImGui::GetCursorScreenPos();
ImU32 bgColor = IM_COL32(30, 30, 30, 255);
drawList->AddRectFilled(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y), bgColor);
RenderGrid();
ImGui::End();
}

View File

@@ -10,7 +10,6 @@ public:
void Render() override;
private:
bool m_isSceneView = true;
void RenderGrid();
};