Company
교육 철학

Docking Space(imgui)

ImGui Docking Space: 에디터 레이아웃 시스템

현대 게임 엔진 에디터의 핵심은 사용자가 자유롭게 창을 배치하고 작업 환경을 커스터마이징할 수 있는 Docking 시스템입니다. ImGui의 Docking Space는 Unity, Unreal Engine, Visual Studio처럼 여러 패널을 드래그하여 도킹하고, 탭으로 그룹화하며, 레이아웃을 저장하고 복원할 수 있는 완전한 도킹 시스템을 제공합니다. 이 문서에서는 ImGui Docking Space를 활용하여 전문적인 에디터 인터페이스를 구현하는 방법을 상세히 다룹니다.

Docking System의 필요성

게임 엔진 에디터는 수십 개의 패널(Scene View, Hierarchy, Inspector, Console 등)을 동시에 표시해야 합니다. Docking 시스템이 없으면 다음과 같은 문제가 발생합니다.

Docking 없이 발생하는 문제

고정된 레이아웃
모든 패널의 위치가 코드에 하드코딩되어 사용자가 변경할 수 없습니다.
// 나쁜 예: 고정된 위치 ImGui::SetNextWindowPos(ImVec2(0, 0)); ImGui::Begin("Scene View"); // ... ImGui::SetNextWindowPos(ImVec2(800, 0)); ImGui::Begin("Inspector"); // ...
C++
복사
창 관리의 어려움
여러 창이 겹쳐서 표시되면 원하는 창을 찾기 어렵습니다.
작업 흐름 비효율
특정 작업에 맞는 레이아웃을 구성할 수 없어 생산성이 저하됩니다.

Docking System의 이점

자유로운 레이아웃
사용자가 드래그 앤 드롭으로 패널을 원하는 위치에 도킹할 수 있습니다.
탭 그룹화
여러 패널을 탭으로 그룹화하여 공간을 효율적으로 사용할 수 있습니다.
레이아웃 저장/복원
작업 환경을 저장하고 언제든지 복원할 수 있습니다.

ImGui Docking 초기화

Docking 기능을 사용하려면 먼저 ImGui를 적절히 초기화해야 합니다.

ImGui 초기화 설정

void Application::InitializeImGui() { // ImGui 컨텍스트 생성 IMGUI_CHECKVERSION(); ImGui::CreateContext(); // IO 설정 가져오기 ImGuiIO& io = ImGui::GetIO(); // 1. Docking 활성화 (필수) io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // 2. 멀티 뷰포트 지원 (선택적) io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // 3. 키보드 내비게이션 (선택적) io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // 4. 설정 파일 경로 설정 (레이아웃 저장용) io.IniFilename = "imgui.ini"; // 5. 스타일 설정 ImGui::StyleColorsDark(); // 6. 플랫폼 및 렌더러 초기화 ImGui_ImplWin32_Init(mHwnd); ImGui_ImplDX11_Init(mDevice, mDeviceContext); }
C++
복사
ConfigFlags 상세
ImGuiConfigFlags_DockingEnable
도킹 기능을 활성화합니다. 이 플래그가 없으면 DockSpace 함수가 작동하지 않습니다.
// 활성화 확인 ImGuiIO& io = ImGui::GetIO(); if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) { // 도킹 사용 가능 }
C++
복사
ImGuiConfigFlags_ViewportsEnable
ImGui 창을 메인 윈도우 밖으로 끌어낼 수 있게 합니다 (Floating Windows).
ImGuiConfigFlags_NavEnableKeyboard
키보드로 UI를 내비게이션할 수 있게 합니다 (Tab, 화살표 키 등).
// 키보드 내비게이션 Tab: 다음 위젯으로 이동 Shift+Tab: 이전 위젯으로 이동 Enter: 활성화/선택 Esc: 취소/닫기
C++
복사

설정 파일 (imgui.ini)

io.IniFilename을 설정하면 ImGui가 창 위치, 크기, 도킹 레이아웃을 자동으로 저장하고 복원합니다.
[Window][DockSpaceViewport_11111111] Pos=0,19 Size=1920,1061 Collapsed=0 [Window][Scene View] Pos=0,19 Size=1280,720 Collapsed=0 DockId=0x00000001,0 [Window][Inspector] Pos=1282,19 Size=638,720 Collapsed=0 DockId=0x00000002,0 [Docking][Data] DockSpace ID=0x8B93E3BD Window=0xA787BDB4 Pos=0,19 Size=1920,1061 Split=X DockNode ID=0x00000001 Parent=0x8B93E3BD SizeRef=1280,720 DockNode ID=0x00000002 Parent=0x8B93E3BD SizeRef=638,720
Plain Text
복사

DockSpace 생성

DockSpace는 창들이 도킹될 수 있는 영역을 정의합니다.

기본 DockSpace 생성

void EditorLayer::OnImGuiRender() { // 1. 전체 화면 크기의 투명한 윈도우 생성 ImGuiViewport* viewport = ImGui::GetMainViewport(); ImGui::SetNextWindowPos(viewport->WorkPos); ImGui::SetNextWindowSize(viewport->WorkSize); ImGui::SetNextWindowViewport(viewport->ID); // 2. 윈도우 스타일 설정 (배경 없음, 타이틀바 없음) ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoBackground; // 3. 패딩 제거 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); // 4. DockSpace 윈도우 시작 ImGui::Begin("DockSpace Window", nullptr, window_flags); ImGui::PopStyleVar(); // 5. DockSpace 생성 ImGuiIO& io = ImGui::GetIO(); if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) { ImGuiID dockspace_id = ImGui::GetID("MyDockSpace"); ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), mDockspaceFlags); } // 6. 메뉴바 렌더링 RenderMenuBar(); // 7. DockSpace 윈도우 종료 ImGui::End(); // 8. 각 패널 렌더링 RenderSceneView(); RenderHierarchy(); RenderInspector(); RenderConsole(); }
C++
복사

DockSpace 플래그

mDockspaceFlags는 DockSpace의 동작을 제어합니다.
class EditorLayer { private: ImGuiDockNodeFlags mDockspaceFlags = ImGuiDockNodeFlags_None; public: void SetDockspaceFlags() { // 1. 중앙 노드를 비울 수 없음 (항상 창이 있어야 함) mDockspaceFlags |= ImGuiDockNodeFlags_PassthruCentralNode; // 2. 자동 숨김 탭바 비활성화 (항상 탭 표시) mDockspaceFlags |= ImGuiDockNodeFlags_NoTabBar; // 3. 분할 비활성화 (더 이상 분할 불가) mDockspaceFlags |= ImGuiDockNodeFlags_NoSplit; // 4. 크기 조정 비활성화 mDockspaceFlags |= ImGuiDockNodeFlags_NoResize; // 5. 도킹 비활성화 (이 노드에는 도킹 불가) mDockspaceFlags |= ImGuiDockNodeFlags_NoDocking; // 6. 윈도우 밖으로 드래그 비활성화 mDockspaceFlags |= ImGuiDockNodeFlags_NoDockingInCentralNode; } };
C++
복사
플래그 조합 예시
// 완전히 자유로운 DockSpace mDockspaceFlags = ImGuiDockNodeFlags_None; // 중앙 노드를 항상 채움 (Scene View 고정용) mDockspaceFlags = ImGuiDockNodeFlags_PassthruCentralNode; // 탭바 없이 고정 레이아웃 mDockspaceFlags = ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_NoResize | ImGuiDockNodeFlags_NoDocking;
C++
복사

메뉴바 구현

메뉴바는 에디터의 주요 기능에 빠르게 접근할 수 있는 인터페이스를 제공합니다.

기본 메뉴바

void EditorLayer::RenderMenuBar() { if (ImGui::BeginMenuBar()) { // File 메뉴 if (ImGui::BeginMenu("File")) { RenderFileMenu(); ImGui::EndMenu(); } // Edit 메뉴 if (ImGui::BeginMenu("Edit")) { RenderEditMenu(); ImGui::EndMenu(); } // View 메뉴 if (ImGui::BeginMenu("View")) { RenderViewMenu(); ImGui::EndMenu(); } // Script 메뉴 if (ImGui::BeginMenu("Script")) { RenderScriptMenu(); ImGui::EndMenu(); } // Help 메뉴 if (ImGui::BeginMenu("Help")) { RenderHelpMenu(); ImGui::EndMenu(); } ImGui::EndMenuBar(); } }
C++
복사

File 메뉴 상세 구현

void EditorLayer::RenderFileMenu() { // 프로젝트 관리 if (ImGui::MenuItem("New Project", "Ctrl+Shift+N")) { NewProject(); } if (ImGui::MenuItem("Open Project...", "Ctrl+O")) { OpenProjectDialog(); } if (ImGui::BeginMenu("Recent Projects")) { for (const auto& path : mRecentProjects) { if (ImGui::MenuItem(path.filename().string().c_str())) { OpenProject(path); } } ImGui::EndMenu(); } ImGui::Separator(); // 씬 관리 if (ImGui::MenuItem("New Scene", "Ctrl+N")) { NewScene(); } if (ImGui::MenuItem("Open Scene...", "Ctrl+Shift+O")) { OpenSceneDialog(); } if (ImGui::MenuItem("Save Scene", "Ctrl+S", false, mActiveScene != nullptr)) { SaveScene(); } if (ImGui::MenuItem("Save Scene As...", "Ctrl+Shift+S", false, mActiveScene != nullptr)) { SaveSceneAs(); } ImGui::Separator(); // 빌드 if (ImGui::MenuItem("Build Settings...", "Ctrl+Shift+B")) { OpenBuildSettings(); } if (ImGui::MenuItem("Build", "Ctrl+B")) { BuildProject(); } ImGui::Separator(); // 종료 if (ImGui::MenuItem("Exit", "Alt+F4")) { Application::Get().Close(); } }
C++
복사

Edit 메뉴 구현

void EditorLayer::RenderEditMenu() { // 실행 취소/다시 실행 bool canUndo = mCommandHistory.CanUndo(); bool canRedo = mCommandHistory.CanRedo(); if (ImGui::MenuItem("Undo", "Ctrl+Z", false, canUndo)) { mCommandHistory.Undo(); } if (ImGui::MenuItem("Redo", "Ctrl+Y", false, canRedo)) { mCommandHistory.Redo(); } ImGui::Separator(); // 클립보드 bool hasSelection = mSelectedEntity != Entity::Null; if (ImGui::MenuItem("Cut", "Ctrl+X", false, hasSelection)) { CutEntity(mSelectedEntity); } if (ImGui::MenuItem("Copy", "Ctrl+C", false, hasSelection)) { CopyEntity(mSelectedEntity); } if (ImGui::MenuItem("Paste", "Ctrl+V", false, mClipboard.HasEntity())) { PasteEntity(); } if (ImGui::MenuItem("Duplicate", "Ctrl+D", false, hasSelection)) { DuplicateEntity(mSelectedEntity); } if (ImGui::MenuItem("Delete", "Delete", false, hasSelection)) { DeleteEntity(mSelectedEntity); } ImGui::Separator(); // 선택 if (ImGui::MenuItem("Select All", "Ctrl+A")) { SelectAllEntities(); } if (ImGui::MenuItem("Deselect All", "Ctrl+Shift+A")) { DeselectAll(); } ImGui::Separator(); // 설정 if (ImGui::MenuItem("Preferences...", "Ctrl+,")) { OpenPreferences(); } }
C++
복사

View 메뉴 구현

void EditorLayer::RenderViewMenu() { // 패널 표시/숨기기 ImGui::MenuItem("Scene View", nullptr, &mShowSceneView); ImGui::MenuItem("Game View", nullptr, &mShowGameView); ImGui::MenuItem("Hierarchy", nullptr, &mShowHierarchy); ImGui::MenuItem("Inspector", nullptr, &mShowInspector); ImGui::MenuItem("Project Browser", nullptr, &mShowProjectBrowser); ImGui::MenuItem("Console", nullptr, &mShowConsole); ImGui::MenuItem("Profiler", nullptr, &mShowProfiler); ImGui::MenuItem("Animation", nullptr, &mShowAnimation); ImGui::Separator(); // 레이아웃 if (ImGui::BeginMenu("Layout")) { if (ImGui::MenuItem("Default")) { LoadLayout("Default"); } if (ImGui::MenuItem("Level Design")) { LoadLayout("LevelDesign"); } if (ImGui::MenuItem("Animation")) { LoadLayout("Animation"); } if (ImGui::MenuItem("Scripting")) { LoadLayout("Scripting"); } ImGui::Separator(); if (ImGui::MenuItem("Save Layout...")) { SaveLayoutDialog(); } if (ImGui::MenuItem("Reset Layout")) { ResetLayout(); } ImGui::EndMenu(); } ImGui::Separator(); // 카메라 if (ImGui::BeginMenu("Camera")) { if (ImGui::MenuItem("Focus on Selected", "F")) { FocusOnSelectedEntity(); } if (ImGui::MenuItem("Align with View", "Ctrl+Shift+F")) { AlignCameraWithView(); } ImGui::Separator(); ImGui::MenuItem("Orthographic", nullptr, &mEditorCamera.IsOrthographic); ImGui::EndMenu(); } ImGui::Separator(); // 그리드와 기즈모 ImGui::MenuItem("Show Grid", nullptr, &mShowGrid); ImGui::MenuItem("Show Gizmos", nullptr, &mShowGizmos); ImGui::MenuItem("Show Icons", nullptr, &mShowIcons); ImGui::Separator(); // 통계 ImGui::MenuItem("Show Statistics", nullptr, &mShowStats); }
C++
복사

Script 메뉴 구현

void EditorLayer::RenderScriptMenu() { if (ImGui::MenuItem("Reload Assembly", "Ctrl+R")) { ReloadScriptAssembly(); } ImGui::Separator(); if (ImGui::MenuItem("Regenerate Project Files")) { RegenerateProjectFiles(); } if (ImGui::MenuItem("Open C# Project", "Ctrl+Shift+P")) { OpenCSharpProject(); } ImGui::Separator(); if (ImGui::MenuItem("Script Settings...")) { OpenScriptSettings(); } }
C++
복사

초기 레이아웃 설정

애플리케이션을 처음 실행할 때 기본 레이아웃을 프로그래밍 방식으로 설정할 수 있습니다.

레이아웃 빌더

void EditorLayer::BuildDefaultLayout() { // 이미 레이아웃이 있으면 무시 if (ImGui::DockBuilderGetNode(mDockspaceID) != nullptr) return; // 1. 기존 레이아웃 초기화 ImGui::DockBuilderRemoveNode(mDockspaceID); ImGui::DockBuilderAddNode(mDockspaceID, ImGuiDockNodeFlags_DockSpace); ImGui::DockBuilderSetNodeSize(mDockspaceID, ImGui::GetMainViewport()->Size); // 2. 메인 영역 분할 ImGuiID dock_main_id = mDockspaceID; ImGuiID dock_left_id = ImGui::DockBuilderSplitNode(dock_main_id, ImGuiDir_Left, 0.2f, nullptr, &dock_main_id); ImGuiID dock_right_id = ImGui::DockBuilderSplitNode(dock_main_id, ImGuiDir_Right, 0.25f, nullptr, &dock_main_id); ImGuiID dock_bottom_id = ImGui::DockBuilderSplitNode(dock_main_id, ImGuiDir_Down, 0.25f, nullptr, &dock_main_id); // 3. 왼쪽 영역 분할 (Hierarchy + Project Browser) ImGuiID dock_left_top_id = ImGui::DockBuilderSplitNode(dock_left_id, ImGuiDir_Up, 0.5f, nullptr, &dock_left_id); // 4. 창 도킹 ImGui::DockBuilderDockWindow("Hierarchy", dock_left_top_id); ImGui::DockBuilderDockWindow("Project Browser", dock_left_id); ImGui::DockBuilderDockWindow("Scene View", dock_main_id); ImGui::DockBuilderDockWindow("Inspector", dock_right_id); ImGui::DockBuilderDockWindow("Console", dock_bottom_id); // 5. 레이아웃 완료 ImGui::DockBuilderFinish(mDockspaceID); }
C++
복사
레이아웃 시각화

프리셋 레이아웃

다양한 작업 환경에 맞는 레이아웃 프리셋을 제공할 수 있습니다.
void EditorLayer::BuildLevelDesignLayout() { ImGui::DockBuilderRemoveNode(mDockspaceID); ImGui::DockBuilderAddNode(mDockspaceID); ImGui::DockBuilderSetNodeSize(mDockspaceID, ImGui::GetMainViewport()->Size); ImGuiID dock_main_id = mDockspaceID; // Scene View를 크게 ImGuiID dock_right_id = ImGui::DockBuilderSplitNode(dock_main_id, ImGuiDir_Right, 0.25f, nullptr, &dock_main_id); ImGuiID dock_right_top_id = ImGui::DockBuilderSplitNode(dock_right_id, ImGuiDir_Up, 0.5f, nullptr, &dock_right_id); ImGui::DockBuilderDockWindow("Scene View", dock_main_id); ImGui::DockBuilderDockWindow("Hierarchy", dock_right_top_id); ImGui::DockBuilderDockWindow("Inspector", dock_right_id); ImGui::DockBuilderFinish(mDockspaceID); } void EditorLayer::BuildAnimationLayout() { ImGui::DockBuilderRemoveNode(mDockspaceID); ImGui::DockBuilderAddNode(mDockspaceID); ImGui::DockBuilderSetNodeSize(mDockspaceID, ImGui::GetMainViewport()->Size); ImGuiID dock_main_id = mDockspaceID; // Scene View + Timeline 수직 배치 ImGuiID dock_bottom_id = ImGui::DockBuilderSplitNode(dock_main_id, ImGuiDir_Down, 0.3f, nullptr, &dock_main_id); ImGuiID dock_right_id = ImGui::DockBuilderSplitNode(dock_main_id, ImGuiDir_Right, 0.25f, nullptr, &dock_main_id); ImGui::DockBuilderDockWindow("Scene View", dock_main_id); ImGui::DockBuilderDockWindow("Animation Timeline", dock_bottom_id); ImGui::DockBuilderDockWindow("Inspector", dock_right_id); ImGui::DockBuilderFinish(mDockspaceID); }
C++
복사

레이아웃 저장 및 복원

사용자 정의 레이아웃을 파일로 저장하고 복원할 수 있습니다.

레이아웃 저장

void EditorLayer::SaveLayout(const std::string& name) { // 1. 레이아웃 파일 경로 생성 std::filesystem::path layoutPath = GetLayoutsDirectory() / (name + ".layout"); // 2. 현재 레이아웃을 임시 파일에 저장 std::string tempPath = layoutPath.string() + ".tmp"; ImGui::SaveIniSettingsToDisk(tempPath.c_str()); // 3. 임시 파일을 레이아웃 파일로 복사 std::filesystem::copy_file(tempPath, layoutPath, std::filesystem::copy_options::overwrite_existing); std::filesystem::remove(tempPath); LOG_INFO("Layout saved: {}", name); } void EditorLayer::LoadLayout(const std::string& name) { // 1. 레이아웃 파일 경로 std::filesystem::path layoutPath = GetLayoutsDirectory() / (name + ".layout"); // 2. 파일 존재 확인 if (!std::filesystem::exists(layoutPath)) { LOG_WARNING("Layout not found: {}", name); return; } // 3. 레이아웃 로드 ImGui::LoadIniSettingsFromDisk(layoutPath.string().c_str()); LOG_INFO("Layout loaded: {}", name); }
C++
복사

레이아웃 관리자

class LayoutManager { public: void SaveCurrentLayout(const std::string& name) { std::string layoutData = ImGui::SaveIniSettingsToMemory(); mLayouts[name] = layoutData; SaveLayoutToFile(name, layoutData); } void LoadLayout(const std::string& name) { auto it = mLayouts.find(name); if (it != mLayouts.end()) { ImGui::LoadIniSettingsFromMemory(it->second.c_str()); } else { LoadLayoutFromFile(name); } } std::vector<std::string> GetLayoutNames() const { std::vector<std::string> names; for (const auto& [name, data] : mLayouts) { names.push_back(name); } return names; } void DeleteLayout(const std::string& name) { mLayouts.erase(name); DeleteLayoutFile(name); } private: std::unordered_map<std::string, std::string> mLayouts; void SaveLayoutToFile(const std::string& name, const std::string& data) { std::ofstream file(GetLayoutPath(name)); file << data; } void LoadLayoutFromFile(const std::string& name) { std::ifstream file(GetLayoutPath(name)); if (file.is_open()) { std::string data((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); mLayouts[name] = data; ImGui::LoadIniSettingsFromMemory(data.c_str()); } } void DeleteLayoutFile(const std::string& name) { std::filesystem::remove(GetLayoutPath(name)); } std::filesystem::path GetLayoutPath(const std::string& name) const { return "Layouts/" + name + ".ini"; } };
C++
복사

고급 기능

동적 패널 표시/숨기기

void EditorLayer::OnImGuiRender() { // DockSpace 설정... // 패널 렌더링 (플래그에 따라) if (mShowSceneView) { ImGui::Begin("Scene View", &mShowSceneView); RenderSceneViewContent(); ImGui::End(); } if (mShowHierarchy) { ImGui::Begin("Hierarchy", &mShowHierarchy); RenderHierarchyContent(); ImGui::End(); } if (mShowInspector) { ImGui::Begin("Inspector", &mShowInspector); RenderInspectorContent(); ImGui::End(); } if (mShowConsole) { ImGui::Begin("Console", &mShowConsole); RenderConsoleContent(); ImGui::End(); } }
C++
복사
창 닫기 버튼
ImGui::Begin()의 두 번째 인자로 bool*를 전달하면 창에 닫기 버튼(X)이 생성됩니다.
bool showWindow = true; ImGui::Begin("My Window", &showWindow); // showWindow가 false가 되면 창이 닫힘 ImGui::End();
C++
복사

탭 그룹화

여러 패널을 같은 위치에 도킹하면 자동으로 탭으로 그룹화됩니다.
// Scene View와 Game View를 같은 위치에 도킹 ImGui::DockBuilderDockWindow("Scene View", dock_center_id); ImGui::DockBuilderDockWindow("Game View", dock_center_id); // 결과: // ┌─────────────────────────────────┐ // │ [Scene View] [Game View] │ // │ │ // │ (탭으로 전환 가능) │ // └─────────────────────────────────┘
C++
복사

창 크기 제약

ImGui::SetNextWindowSizeConstraints( ImVec2(400, 300), // 최소 크기 ImVec2(FLT_MAX, FLT_MAX) // 최대 크기 (무제한) ); ImGui::Begin("Constrained Window"); // ... ImGui::End();
C++
복사

단축키 처리

메뉴 단축키는 수동으로 구현해야 합니다.

단축키 처리기

void EditorLayer::ProcessShortcuts() { ImGuiIO& io = ImGui::GetIO(); bool ctrl = io.KeyCtrl; bool shift = io.KeyShift; bool alt = io.KeyAlt; // Ctrl+N: 새 씬 if (ctrl && !shift && ImGui::IsKeyPressed(ImGuiKey_N)) { NewScene(); } // Ctrl+O: 프로젝트 열기 if (ctrl && !shift && ImGui::IsKeyPressed(ImGuiKey_O)) { OpenProjectDialog(); } // Ctrl+S: 씬 저장 if (ctrl && !shift && ImGui::IsKeyPressed(ImGuiKey_S)) { SaveScene(); } // Ctrl+Shift+S: 다른 이름으로 저장 if (ctrl && shift && ImGui::IsKeyPressed(ImGuiKey_S)) { SaveSceneAs(); } // Ctrl+Z: 실행 취소 if (ctrl && !shift && ImGui::IsKeyPressed(ImGuiKey_Z)) { mCommandHistory.Undo(); } // Ctrl+Y or Ctrl+Shift+Z: 다시 실행 if ((ctrl && !shift && ImGui::IsKeyPressed(ImGuiKey_Y)) || (ctrl && shift && ImGui::IsKeyPressed(ImGuiKey_Z))) { mCommandHistory.Redo(); } // Ctrl+D: 복제 if (ctrl && !shift && ImGui::IsKeyPressed(ImGuiKey_D)) { if (mSelectedEntity != Entity::Null) { DuplicateEntity(mSelectedEntity); } } // Delete: 삭제 if (ImGui::IsKeyPressed(ImGuiKey_Delete)) { if (mSelectedEntity != Entity::Null) { DeleteEntity(mSelectedEntity); } } // F: 선택 항목으로 포커스 if (ImGui::IsKeyPressed(ImGuiKey_F)) { if (mSelectedEntity != Entity::Null) { FocusOnSelectedEntity(); } } }
C++
복사

성능 고려사항

조건부 렌더링

// 보이지 않는 창은 렌더링하지 않음 if (mShowConsole) { ImGui::Begin("Console", &mShowConsole); // 창이 실제로 보이는지 확인 if (ImGui::IsWindowAppearing() || ImGui::IsWindowFocused() || ImGui::IsWindowHovered()) { // 비용이 높은 렌더링 작업 RenderConsoleContent(); } else { // 최소한의 업데이트만 UpdateConsoleMinimal(); } ImGui::End(); }
C++
복사

창 최소화 감지

if (ImGui::IsWindowCollapsed()) { // 최소화된 창은 간단한 업데이트만 return; }
C++
복사

요약

ImGui Docking Space 시스템은 다음과 같은 핵심 구성 요소로 이루어집니다.
구성 요소
역할
Docking 초기화
ImGuiConfigFlags_DockingEnable 플래그를 설정하여 도킹 기능을 활성화합니다. ViewportsEnable로 창을 메인 윈도우 밖으로 끌어낼 수 있습니다.
DockSpace 생성
전체 화면 크기의 투명한 윈도우를 만들고 DockSpace를 생성하여 모든 패널이 도킹될 수 있는 영역을 정의합니다.
메뉴바
File, Edit, View, Script, Help 메뉴를 제공하여 에디터의 모든 주요 기능에 빠르게 접근할 수 있게 합니다.
레이아웃 빌더
DockBuilderSplitNode를 사용하여 프로그래밍 방식으로 초기 레이아웃을 설정합니다. 다양한 작업 환경에 맞는 프리셋을 제공할 수 있습니다.
레이아웃 저장/복원
imgui.ini 파일이나 커스텀 파일로 레이아웃을 저장하고 복원합니다. 사용자가 원하는 작업 환경을 유지할 수 있습니다.
단축키 시스템
Ctrl, Shift, Alt와 키 조합을 감지하여 빠른 작업 흐름을 제공합니다. 메뉴 항목에 단축키를 표시하여 사용자 편의성을 높입니다.
이 시스템은 Unity, Unreal Engine, Visual Studio와 같은 전문적인 도킹 인터페이스를 제공하며, 사용자가 작업 환경을 자유롭게 커스터마이징할 수 있게 합니다.