diff --git a/editor/editor.exe b/editor/editor.exe index d0db4a1..b3b4f49 100644 Binary files a/editor/editor.exe and b/editor/editor.exe differ diff --git a/editor/src/editor_app.cpp b/editor/src/editor_app.cpp index cd7ae90..eed4b58 100644 --- a/editor/src/editor_app.cpp +++ b/editor/src/editor_app.cpp @@ -1535,6 +1535,98 @@ void EditorApp::HandleHotkeys() { if (ImGui::IsKeyPressed(ImGuiKey_L, false)) currentTool = TOOL_LIGHT_SPAWN; } +// ----------------------------------------------------------------------------- +// Interactive Splitters (Unreal Engine / Unity style with <--> cursor) +// ----------------------------------------------------------------------------- +static bool DrawSplitter(const char* id, float* width, bool isLeftEdge, float minWidth, float maxWidth, float thickness = 6.0f) { + ImVec2 screenPos = ImGui::GetCursorScreenPos(); + float height = ImGui::GetContentRegionAvail().y; + if (height < 20.0f) height = 100.0f; + + ImGui::PushID(id); + ImGui::InvisibleButton("##split", ImVec2(thickness, height)); + bool hovered = ImGui::IsItemHovered(); + bool active = ImGui::IsItemActive(); + + if (hovered || active) { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + } + + if (active) { + float mouseDelta = ImGui::GetIO().MouseDelta.x; + if (mouseDelta != 0.0f) { + float newW = isLeftEdge ? (*width - mouseDelta) : (*width + mouseDelta); + if (newW < minWidth) newW = minWidth; + if (newW > maxWidth) newW = maxWidth; + *width = newW; + } + } + + ImDrawList* drawList = ImGui::GetWindowDrawList(); + ImU32 col = active ? IM_COL32(20, 150, 255, 255) : + hovered ? IM_COL32(70, 110, 180, 200) : + IM_COL32(36, 40, 48, 255); + drawList->AddRectFilled(screenPos, ImVec2(screenPos.x + thickness, screenPos.y + height), col); + + // Center handle indicator (<--> grip) + float midY = screenPos.y + height * 0.5f; + float midX = screenPos.x + thickness * 0.5f; + if (hovered || active) { + drawList->AddLine(ImVec2(midX, midY - 18.0f), ImVec2(midX, midY + 18.0f), IM_COL32(255, 255, 255, 240), 2.0f); + } else { + drawList->AddCircleFilled(ImVec2(midX, midY - 6.0f), 1.5f, IM_COL32(110, 120, 140, 180)); + drawList->AddCircleFilled(ImVec2(midX, midY), 1.5f, IM_COL32(110, 120, 140, 180)); + drawList->AddCircleFilled(ImVec2(midX, midY + 6.0f), 1.5f, IM_COL32(110, 120, 140, 180)); + } + + ImGui::PopID(); + return active; +} + +static bool DrawRatioSplitter(const char* id, float* ratio, float totalWidth, float minRatio = 0.15f, float maxRatio = 0.85f, float thickness = 6.0f) { + ImVec2 screenPos = ImGui::GetCursorScreenPos(); + float height = ImGui::GetContentRegionAvail().y; + if (height < 20.0f) height = 100.0f; + + ImGui::PushID(id); + ImGui::InvisibleButton("##split_ratio", ImVec2(thickness, height)); + bool hovered = ImGui::IsItemHovered(); + bool active = ImGui::IsItemActive(); + + if (hovered || active) { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + } + + if (active && totalWidth > 10.0f) { + float mouseDelta = ImGui::GetIO().MouseDelta.x; + if (mouseDelta != 0.0f) { + float newRatio = *ratio + (mouseDelta / totalWidth); + if (newRatio < minRatio) newRatio = minRatio; + if (newRatio > maxRatio) newRatio = maxRatio; + *ratio = newRatio; + } + } + + ImDrawList* drawList = ImGui::GetWindowDrawList(); + ImU32 col = active ? IM_COL32(20, 150, 255, 255) : + hovered ? IM_COL32(70, 110, 180, 200) : + IM_COL32(36, 40, 48, 255); + drawList->AddRectFilled(screenPos, ImVec2(screenPos.x + thickness, screenPos.y + height), col); + + float midY = screenPos.y + height * 0.5f; + float midX = screenPos.x + thickness * 0.5f; + if (hovered || active) { + drawList->AddLine(ImVec2(midX, midY - 18.0f), ImVec2(midX, midY + 18.0f), IM_COL32(255, 255, 255, 240), 2.0f); + } else { + drawList->AddCircleFilled(ImVec2(midX, midY - 6.0f), 1.5f, IM_COL32(110, 120, 140, 180)); + drawList->AddCircleFilled(ImVec2(midX, midY), 1.5f, IM_COL32(110, 120, 140, 180)); + drawList->AddCircleFilled(ImVec2(midX, midY + 6.0f), 1.5f, IM_COL32(110, 120, 140, 180)); + } + + ImGui::PopID(); + return active; +} + // ----------------------------------------------------------------------------- // UI Rendering // ----------------------------------------------------------------------------- @@ -1560,29 +1652,40 @@ void EditorApp::RenderUI() { // Main layout ImGuiViewport* vp = ImGui::GetMainViewport(); - ImGui::SetNextWindowPos(ImVec2(vp->Pos.x, vp->Pos.y + 60)); - ImGui::SetNextWindowSize(ImVec2(vp->Size.x, vp->Size.y - 85)); + ImGui::SetNextWindowPos(ImVec2(vp->Pos.x, vp->Pos.y + 64)); + ImGui::SetNextWindowSize(ImVec2(vp->Size.x, vp->Size.y - 89)); ImGui::Begin("Workspace", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus); // Columns: Left = Hierarchy & Tile Palette, Middle = Workspace Viewport/IDE, Right = Inspector - float leftWidth = 260.0f; - float rightWidth = 320.0f; - float canvasWidth = ImGui::GetContentRegionAvail().x - leftWidth - rightWidth - 20.0f; + float totalAvailX = ImGui::GetContentRegionAvail().x; + const float splitterW = 6.0f; + const float spacingX = ImGui::GetStyle().ItemSpacing.x; + + float maxLeftW = (std::max)(180.0f, totalAvailX - rightPanelWidth - 320.0f); + if (leftPanelWidth > maxLeftW) leftPanelWidth = maxLeftW; + if (leftPanelWidth < 180.0f) leftPanelWidth = 180.0f; + + float maxRightW = (std::max)(240.0f, totalAvailX - leftPanelWidth - 320.0f); + if (rightPanelWidth > maxRightW) rightPanelWidth = maxRightW; + if (rightPanelWidth < 240.0f) rightPanelWidth = 240.0f; + + float canvasWidth = totalAvailX - leftPanelWidth - rightPanelWidth - (splitterW * 2.0f) - (spacingX * 4.0f); + if (canvasWidth < 200.0f) canvasWidth = 200.0f; // Left Panel (Unity / Unreal Docked Tabs) - ImGui::BeginChild("LeftPanel", ImVec2(leftWidth, 0), true); + ImGui::BeginChild("LeftPanel", ImVec2(leftPanelWidth, 0), true); if (ImGui::BeginTabBar("LeftPanelTabs", ImGuiTabBarFlags_None)) { - if (ImGui::BeginTabItem("🗂 Сцена")) { + if (ImGui::BeginTabItem("Сцена")) { RenderHierarchy(); ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("🎨 Палитра")) { + if (ImGui::BeginTabItem("Палитра")) { RenderTilePalette(); ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("📁 Файлы")) { + if (ImGui::BeginTabItem("Файлы")) { ImGui::TextColored(ImVec4(0.2f, 0.8f, 1.0f, 1.0f), "Браузер ассетов"); ImGui::Separator(); RenderAssetManagerContents(); @@ -1592,6 +1695,8 @@ void EditorApp::RenderUI() { } ImGui::EndChild(); + ImGui::SameLine(); + DrawSplitter("LeftSplitter", &leftPanelWidth, false, 180.0f, maxLeftW, splitterW); ImGui::SameLine(); // Center Panel (Grid Canvas / 3D Scene Viewport / MASM32 IDE / Asset Browser) @@ -1616,15 +1721,15 @@ void EditorApp::RenderUI() { ImGui::PopStyleColor(2); }; - ModeTabButton("🗺 2D Карта", 2); + ModeTabButton("2D Карта", 2); ImGui::SameLine(); - ModeTabButton("🎮 3D Сцена", 1); + ModeTabButton("3D Сцена", 1); ImGui::SameLine(); - ModeTabButton("🪟 2D + 3D", 0); + ModeTabButton("2D + 3D", 0); ImGui::SameLine(); - ModeTabButton("💻 Скрипты (IDE)", 3); + ModeTabButton("Код / IDE", 3); ImGui::SameLine(); - ModeTabButton("📦 Ассеты", 4); + ModeTabButton("Ассеты", 4); if (viewportMode == 0 || viewportMode == 2) { ImGui::SameLine(); @@ -1647,19 +1752,36 @@ void EditorApp::RenderUI() { } else { float timelineHeight = showCutsceneTimeline ? (std::min)(340.0f, ImGui::GetContentRegionAvail().y * 0.48f) : 0.0f; ImGui::BeginChild("CanvasPanel", ImVec2(0, showCutsceneTimeline ? -timelineHeight - 6 : 0), true); - float sceneWidth = viewportMode == 0 ? ImGui::GetContentRegionAvail().x * 0.5f : 0; - if (viewportMode != 2) { - ImGui::BeginChild("SceneViewport", ImVec2(sceneWidth,0), true); + + float availCanvasW = ImGui::GetContentRegionAvail().x; + if (viewportMode == 0) { + float availForViews = availCanvasW - splitterW - (spacingX * 2.0f); + float sceneW = availForViews * centerSplitRatio; + if (sceneW < 120.0f) sceneW = 120.0f; + if (sceneW > availForViews - 120.0f) sceneW = availForViews - 120.0f; + + ImGui::BeginChild("SceneViewport", ImVec2(sceneW, 0), true); RenderSceneViewport(); ImGui::EndChild(); - if (viewportMode == 0) ImGui::SameLine(); - } - if (viewportMode != 1) { - ImGui::BeginChild("MapViewport", ImVec2(0,0), false); + + ImGui::SameLine(); + DrawRatioSplitter("CenterRatioSplitter", ¢erSplitRatio, availForViews, 0.15f, 0.85f, splitterW); + ImGui::SameLine(); + + ImGui::BeginChild("MapViewport", ImVec2(0, 0), false); + RenderGridCanvas(); + ImGui::EndChild(); + } else if (viewportMode == 1) { + ImGui::BeginChild("SceneViewport", ImVec2(0, 0), true); + RenderSceneViewport(); + ImGui::EndChild(); + } else { + ImGui::BeginChild("MapViewport", ImVec2(0, 0), false); RenderGridCanvas(); ImGui::EndChild(); } ImGui::EndChild(); + if (showCutsceneTimeline) { ImGui::BeginChild("CutsceneTimeline", ImVec2(0, 0), true); RenderCutsceneTimeline(); @@ -1668,10 +1790,12 @@ void EditorApp::RenderUI() { } ImGui::EndChild(); + ImGui::SameLine(); + DrawSplitter("RightSplitter", &rightPanelWidth, true, 240.0f, maxRightW, splitterW); ImGui::SameLine(); // Right Panel (Unity / Unreal Component Inspector) - ImGui::BeginChild("RightPanel", ImVec2(rightWidth, 0), true); + ImGui::BeginChild("RightPanel", ImVec2(rightPanelWidth, 0), true); RenderInspector(); ImGui::EndChild(); @@ -1811,168 +1935,177 @@ void EditorApp::RenderMenuBar() { void EditorApp::RenderToolbar() { ImGuiViewport* vp = ImGui::GetMainViewport(); ImGui::SetNextWindowPos(ImVec2(vp->Pos.x, vp->Pos.y + 20)); - ImGui::SetNextWindowSize(ImVec2(vp->Size.x, 38)); + ImGui::SetNextWindowSize(ImVec2(vp->Size.x, 42)); ImGui::Begin("Toolbar", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar); - // Play / Stop Button + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(5.0f, 4.0f)); + + // 1. PLAY / STOP if (!isEngineRunning) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.15f, 0.65f, 0.25f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.20f, 0.80f, 0.30f, 1.0f)); - if (ImGui::Button(" ▶ ЗАПУСК (F5) ", ImVec2(130, 24))) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.12f, 0.60f, 0.26f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.18f, 0.72f, 0.32f, 1.0f)); + if (ImGui::Button(" ▶ Запуск (F5) ", ImVec2(110, 26))) { LaunchPlaytest(); } ImGui::PopStyleColor(2); } else { ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.80f, 0.20f, 0.20f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.95f, 0.25f, 0.25f, 1.0f)); - if (ImGui::Button(" ■ СТОП (F5) ", ImVec2(130, 24))) { + if (ImGui::Button(" ■ Стоп (F5) ", ImVec2(110, 26))) { StopPlaytest(); } ImGui::PopStyleColor(2); } + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Запустить игру в тестовом режиме (F5)"); - ImGui::SameLine(); - ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); - // Game Mode Quick Selector (Peaceful Adventure vs Action Shooter) + // GAME GENRE BADGE if (project && project->gameMode == 0) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.12f, 0.45f, 0.40f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.18f, 0.58f, 0.50f, 1.0f)); - if (ImGui::Button(" ☮ КВЕСТ / БЕЗ ОРУЖИЯ ")) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.14f, 0.38f, 0.44f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.20f, 0.48f, 0.55f, 1.0f)); + if (ImGui::Button(" Квест (Без оружия) ", ImVec2(0, 26))) { project->gameMode = 1; project->showWeapons = true; char module[MAX_PATH]{}; GetModuleFileNameA(nullptr, module, MAX_PATH); std::string projPath = (fs::path(module).parent_path() / "project.eblanproj").string(); project->Save(projPath); - statusMessage = "Режим игры: ЭКШЕН / ШУТЕР (с оружием и стрельбой)"; + statusMessage = "Режим игры переключён: Экшен / Шутер (с оружием)"; } ImGui::PopStyleColor(2); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Текущий режим: Мирное приключение / Квест. Нажмите для переключения на Экшен / Шутер."); } else if (project) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.55f, 0.30f, 0.10f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.70f, 0.38f, 0.12f, 1.0f)); - if (ImGui::Button(" ⚔ ЭКШЕН / С ОРУЖИЕМ ")) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.55f, 0.30f, 0.12f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.68f, 0.38f, 0.16f, 1.0f)); + if (ImGui::Button(" Экшен (С оружием) ", ImVec2(0, 26))) { project->gameMode = 0; project->showWeapons = false; char module[MAX_PATH]{}; GetModuleFileNameA(nullptr, module, MAX_PATH); std::string projPath = (fs::path(module).parent_path() / "project.eblanproj").string(); project->Save(projPath); - statusMessage = "Режим игры: КВЕСТ / МИРНЫЙ (без оружия)"; + statusMessage = "Режим игры переключён: Мирное исследование / Квест (без оружия)"; } ImGui::PopStyleColor(2); - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Нажмите для быстрого переключения жанра игры (Квест без оружия / Шутер с оружием)"); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Текущий режим: Боевик / Шутер с арсеналом. Нажмите для переключения на Квест."); } ImGui::SameLine(); ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); - // Lighting Controls in Toolbar - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.80f, 0.50f, 0.05f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.95f, 0.65f, 0.10f, 1.0f)); - if (ImGui::Button(" 💡 ЗАПЕЧЬ СВЕТ ")) { + // 2. TOOLS SELECTOR (Photoshop / Unreal style button group) + auto ToolButton = [&](const char* label, ToolMode mode, const char* tooltip) { + bool active = (currentTool == mode); + if (active) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.08f, 0.48f, 0.88f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.14f, 0.58f, 0.98f, 1.0f)); + } else { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.18f, 0.20f, 0.25f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.26f, 0.30f, 0.38f, 1.0f)); + } + if (ImGui::Button(label, ImVec2(0, 26))) currentTool = mode; + ImGui::PopStyleColor(2); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", tooltip); + ImGui::SameLine(); + }; + + ToolButton(" [B] Кисть ", TOOL_BRUSH, "Кисть для рисования стен [B]"); + ToolButton(" [E] Ластик ", TOOL_ERASER, "Ластик для очистки ячеек [E]"); + ToolButton(" [F] Заливка ", TOOL_FILL, "Заливка замкнутой области стен [F]"); + ToolButton(" [P] Игрок ", TOOL_PLAYER_SPAWN, "Точка старта игрока [P]"); + ToolButton(" [S] Спрайт ", TOOL_SPRITE_SPAWN, "Размещение сущностей и спрайтов [S]"); + ToolButton(" [L] Свет ", TOOL_LIGHT_SPAWN, "Размещение источников освещения [L]"); + + ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); + ImGui::SameLine(); + + // 3. LIGHTING SUBSYSTEM + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.80f, 0.48f, 0.05f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.95f, 0.60f, 0.10f, 1.0f)); + if (ImGui::Button(" Запечь свет ", ImVec2(0, 26))) { PushUndo(); BakeLighting(); } ImGui::PopStyleColor(2); if (ImGui::IsItemHovered()) ImGui::SetTooltip("Запечь постоянное освещение (Lightmap) для всей карты с учетом стен и препятствий"); ImGui::SameLine(); - const char* lModeBtn = (lightingMode == 0) ? " ☀ Свет: ВЫКЛ " : - (lightingMode == 1) ? " 🕯 Свет: ЗАПЕЧЁН " : - " ⚡ Свет: ДИНАМИКА "; - if (ImGui::Button(lModeBtn)) { + const char* lModeBtn = (lightingMode == 0) ? " Свет: Выкл " : + (lightingMode == 1) ? " Свет: Запечён " : + " Свет: Динамика "; + if (ImGui::Button(lModeBtn, ImVec2(0, 26))) { PushUndo(); lightingMode = (lightingMode + 1) % 3; - statusMessage = (lightingMode == 0) ? "Режим света: ВЫКЛ (Wolf3D flat)" : - (lightingMode == 1) ? "Режим света: ЗАПЕЧЁННЫЙ (Lightmap)" : - "Режим света: ДИНАМИЧЕСКИЙ (Point lights + Flashlight)"; + statusMessage = (lightingMode == 0) ? "Режим света: Выкл (Wolf3D fullbright)" : + (lightingMode == 1) ? "Режим света: Запечённый (Lightmap)" : + "Режим света: Динамический (Point lights + Flashlight)"; } - if (ImGui::IsItemHovered()) ImGui::SetTooltip("Переключение режима освещения (Без света / Запечённый / Динамический)"); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Режим освещения: Без света / Запечённый / Динамический с тенями"); ImGui::SameLine(); if (isFlashlightOn) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.18f, 0.55f, 0.70f, 1.0f)); - if (ImGui::Button(" 🔦 Фонарик: ВКЛ ")) {PushUndo();isFlashlightOn = false;} + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.14f, 0.50f, 0.68f, 1.0f)); + if (ImGui::Button(" Фонарик [F] ", ImVec2(0, 26))) { PushUndo(); isFlashlightOn = false; } ImGui::PopStyleColor(); } else { - if (ImGui::Button(" 🔦 Фонарик: ВЫКЛ ")) {PushUndo();isFlashlightOn = true;} + if (ImGui::Button(" Фонарик: Выкл ", ImVec2(0, 26))) { PushUndo(); isFlashlightOn = true; } } - if (ImGui::IsItemHovered()) ImGui::SetTooltip("Переключить фонарик игрока [F]"); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Включить/выключить фонарик игрока [F]"); ImGui::SameLine(); if (showLightHeatmap) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.70f, 0.40f, 0.10f, 1.0f)); - if (ImGui::Button(" 🗺 Карта: ВКЛ ")) showLightHeatmap = false; + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.68f, 0.38f, 0.08f, 1.0f)); + if (ImGui::Button(" Хитмап 2D ", ImVec2(0, 26))) showLightHeatmap = false; ImGui::PopStyleColor(); } else { - if (ImGui::Button(" 🗺 Карта: ВЫКЛ ")) showLightHeatmap = true; + if (ImGui::Button(" Хитмап: Выкл ", ImVec2(0, 26))) showLightHeatmap = true; } - if (ImGui::IsItemHovered()) ImGui::SetTooltip("Отображать световую карту (Heatmap) на 2D сетке"); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Отображение тепловой карты освещения на 2D сетке"); ImGui::SameLine(); ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); - // Tools - auto ToolButton = [&](const char* label, ToolMode mode) { - bool active = (currentTool == mode); - if (active) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.25f, 0.45f, 0.75f, 1.0f)); - if (ImGui::Button(label)) currentTool = mode; - if (active) ImGui::PopStyleColor(); - ImGui::SameLine(); - }; - - ToolButton(" [B] Кисть ", TOOL_BRUSH); - ToolButton(" [E] Ластик ", TOOL_ERASER); - ToolButton(" [F] Заливка ", TOOL_FILL); - ToolButton(" [P] Игрок ", TOOL_PLAYER_SPAWN); - ToolButton(" [S] Спрайт ", TOOL_SPRITE_SPAWN); - ToolButton(" [L] Свет ", TOOL_LIGHT_SPAWN); - + // 4. STUDIO WINDOWS / MODULES + if (ImGui::Button(" Код (F7) ", ImVec2(0, 26))) showCodeEditorModal = !showCodeEditorModal; + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Открыть встроенную среду разработки скриптов MASM32 (F7)"); ImGui::SameLine(); + + if (ImGui::Button(" Кат-сцены (F6) ", ImVec2(0, 26))) showCutsceneTimeline = !showCutsceneTimeline; + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Открыть таймлайн кинематографических кат-сцен (F6)"); + ImGui::SameLine(); + + if (ImGui::Button(" Ассеты (F4) ", ImVec2(0, 26))) showAssetManagerModal = !showAssetManagerModal; + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Менеджер текстур и аудиофайлов (F4)"); + ImGui::SameLine(); + + if (ImGui::Button(" Экспорт (.exe) ", ImVec2(0, 26))) showExportGameModal = true; + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Экспорт готовой автономной игры (.exe)"); + ImGui::SameLine(); + ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); - // Undo / Redo buttons - if (ImGui::Button(" Отмена ")) Undo(); + // 5. HISTORY & SAVE + if (ImGui::Button(" Отмена ", ImVec2(0, 26))) Undo(); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Отменить последнее действие (Ctrl+Z)"); ImGui::SameLine(); - if (ImGui::Button(" Повтор ")) Redo(); - ImGui::SameLine(); - ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); + if (ImGui::Button(" Повтор ", ImVec2(0, 26))) Redo(); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Повторить отменённое действие (Ctrl+Y)"); ImGui::SameLine(); - if (ImGui::Button("Кат-сцена (F6)")) showCutsceneTimeline = !showCutsceneTimeline; - ImGui::SameLine(); - - // Asset Manager button - if (ImGui::Button(" 🖼 Ассеты (F4) ")) { - showAssetManagerModal = !showAssetManagerModal; - } - ImGui::SameLine(); - - // Code Editor button - if (ImGui::Button(" 💻 Код (F7) ")) { - showCodeEditorModal = !showCodeEditorModal; - } - ImGui::SameLine(); - - // Standalone Exporter button - if (ImGui::Button(" 📦 Экспорт (.exe) ")) { - showExportGameModal = true; - } - ImGui::SameLine(); - ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); - ImGui::SameLine(); - - if (ImGui::Button(" Сохранить (Ctrl+S) ")) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.18f, 0.44f, 0.70f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.24f, 0.54f, 0.84f, 1.0f)); + if (ImGui::Button(" Сохранить (Ctrl+S) ", ImVec2(0, 26))) { SaveLevel(currentFilePath); } + ImGui::PopStyleColor(2); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Сохранить уровень в файл (Ctrl+S)"); + ImGui::PopStyleVar(2); ImGui::End(); } @@ -2451,7 +2584,7 @@ void EditorApp::RenderHierarchy() { ImGui::Separator(); // Search filter + Quick Add button (Unity / Unreal style) - ImGui::InputTextWithHint("##HierarchySearch", "🔍 Поиск...", searchHierarchyBuf, sizeof(searchHierarchyBuf)); + ImGui::InputTextWithHint("##HierarchySearch", "Поиск...", searchHierarchyBuf, sizeof(searchHierarchyBuf)); ImGui::SameLine(); if (ImGui::Button("+ Добавить")) { ImGui::OpenPopup("QuickEntitySpawnPopup"); @@ -2483,14 +2616,14 @@ void EditorApp::RenderHierarchy() { } } }; - AddEntityItem("⚔ Враг (Guard AI)", ENTITY_ARCHETYPE_GUARD); - AddEntityItem("🩹 Аптечка (+25 HP)", ENTITY_ARCHETYPE_MEDKIT); - AddEntityItem("📦 Патроны (+20)", ENTITY_ARCHETYPE_AMMO); - AddEntityItem("🔑 Ключ от двери", ENTITY_ARCHETYPE_KEY); - AddEntityItem("🕹 Рычаг / Переключатель", ENTITY_ARCHETYPE_SWITCH); - AddEntityItem("💥 Взрывная бочка", ENTITY_ARCHETYPE_BARREL); - AddEntityItem("🏺 Декорация / Проп", ENTITY_ARCHETYPE_PROP); - if (ImGui::MenuItem("💡 Источник света [L]")) { + AddEntityItem("Враг (Guard AI)", ENTITY_ARCHETYPE_GUARD); + AddEntityItem("Аптечка (+25 HP)", ENTITY_ARCHETYPE_MEDKIT); + AddEntityItem("Патроны (+20)", ENTITY_ARCHETYPE_AMMO); + AddEntityItem("Ключ от двери", ENTITY_ARCHETYPE_KEY); + AddEntityItem("Рычаг / Переключатель", ENTITY_ARCHETYPE_SWITCH); + AddEntityItem("Взрывная бочка", ENTITY_ARCHETYPE_BARREL); + AddEntityItem("Декорация / Проп", ENTITY_ARCHETYPE_PROP); + if (ImGui::MenuItem("Источник света [L]")) { currentTool = TOOL_LIGHT_SPAWN; statusMessage = "Режим размещения света: кликните на карте для создания источника."; } @@ -2510,7 +2643,7 @@ void EditorApp::RenderHierarchy() { // 1. Player Spawn (Always at top of hierarchy) char playerLabel[96]; - snprintf(playerLabel, sizeof(playerLabel), "👤 Игрок [Spawn: (%d, %d)]", playerStartX, playerStartY); + snprintf(playerLabel, sizeof(playerLabel), "Игрок [Spawn: (%d, %d)]", playerStartX, playerStartY); if (MatchesSearch(playerLabel) || MatchesSearch("player") || MatchesSearch("игрок")) { bool isPlayerSelected = (selectedSpriteIdx == -1 && selectedTransitionIdx == -1 && selectedLightIdx == -1); if (ImGui::Selectable(playerLabel, isPlayerSelected)) { @@ -2518,7 +2651,7 @@ void EditorApp::RenderHierarchy() { selectedTransitionIdx = -1; } if (ImGui::BeginPopupContextItem("PlayerContextMenu")) { - if (ImGui::MenuItem("🎯 Сфокусировать камеру", "F")) { + if (ImGui::MenuItem("Сфокусировать камеру", "F")) { FocusSelectedEntity(); } ImGui::EndPopup(); @@ -2561,16 +2694,16 @@ void EditorApp::RenderHierarchy() { FocusSelectedEntity(); } if (ImGui::BeginPopupContextItem()) { - if (ImGui::MenuItem("📋 Дублировать", "Ctrl+D")) { + if (ImGui::MenuItem("Дублировать", "Ctrl+D")) { selectedSpriteIdx = static_cast(i); selectedLightIdx=-1; DuplicateSelectedEntity(); } - if (ImGui::MenuItem("🎯 Сфокусировать", "F")) { + if (ImGui::MenuItem("Сфокусировать", "F")) { selectedSpriteIdx = static_cast(i); selectedLightIdx=-1; FocusSelectedEntity(); } ImGui::Separator(); - if (ImGui::MenuItem("🗑 Удалить", "Del")) { + if (ImGui::MenuItem("Удалить", "Del")) { selectedSpriteIdx = static_cast(i); selectedLightIdx=-1; DeleteSelectedEntity(); } @@ -2580,7 +2713,7 @@ void EditorApp::RenderHierarchy() { // Enemies Category char enemyHdr[64]; - snprintf(enemyHdr, sizeof(enemyHdr), "⚔ Враги и Guard AI (%zu)", guardCount); + snprintf(enemyHdr, sizeof(enemyHdr), "Враги и Guard AI (%zu)", guardCount); if (ImGui::TreeNodeEx(enemyHdr, ImGuiTreeNodeFlags_DefaultOpen)) { for (size_t i = 0; i < sprites.size(); ++i) { if (GetSpriteEntityType(sprites[i]) == ENTITY_ARCHETYPE_GUARD) RenderSpriteItem(i); @@ -2590,7 +2723,7 @@ void EditorApp::RenderHierarchy() { // Pickups Category char pickupHdr[64]; - snprintf(pickupHdr, sizeof(pickupHdr), "📦 Лут и предметы (%zu)", pickupCount); + snprintf(pickupHdr, sizeof(pickupHdr), "Лут и предметы (%zu)", pickupCount); if (ImGui::TreeNodeEx(pickupHdr, ImGuiTreeNodeFlags_DefaultOpen)) { for (size_t i = 0; i < sprites.size(); ++i) { uint8_t a = GetSpriteEntityType(sprites[i]); @@ -2601,7 +2734,7 @@ void EditorApp::RenderHierarchy() { // Interactive & Props Category char objHdr[64]; - snprintf(objHdr, sizeof(objHdr), "⚙ Объекты и окружение (%zu)", objectCount); + snprintf(objHdr, sizeof(objHdr), "Объекты и окружение (%zu)", objectCount); if (ImGui::TreeNodeEx(objHdr, ImGuiTreeNodeFlags_DefaultOpen)) { for (size_t i = 0; i < sprites.size(); ++i) { uint8_t a = GetSpriteEntityType(sprites[i]); @@ -2610,7 +2743,7 @@ void EditorApp::RenderHierarchy() { ImGui::TreePop(); } - if(ImGui::TreeNodeEx("💡 Источники света", ImGuiTreeNodeFlags_DefaultOpen)) { + if(ImGui::TreeNodeEx("Источники света", ImGuiTreeNodeFlags_DefaultOpen)) { for(int i = 0; i < static_cast(lightSources.size()); ++i) { const auto& ls = lightSources[i]; const char* typeName = (ls.lightType == LIGHT_TYPE_STATIC) ? "Постоянный" : @@ -2631,19 +2764,19 @@ void EditorApp::RenderHierarchy() { selectedSpriteIdx = selectedTransitionIdx = -1; } if (ImGui::BeginPopupContextItem()) { - if (ImGui::MenuItem("🎯 Сфокусировать", "F")) { + if (ImGui::MenuItem("Сфокусировать", "F")) { selectedLightIdx = i; selectedSpriteIdx = selectedTransitionIdx = -1; FocusSelectedEntity(); } - if (ImGui::MenuItem("📋 Дублировать", "Ctrl+D")) { + if (ImGui::MenuItem("Дублировать", "Ctrl+D")) { selectedLightIdx = i; selectedSpriteIdx = selectedTransitionIdx = -1; DuplicateSelectedEntity(); } - if (ImGui::MenuItem("🧲 Выровнять по центру клетки")) { + if (ImGui::MenuItem("Выровнять по центру клетки")) { SnapLightToGrid(i); } ImGui::Separator(); - if (ImGui::MenuItem("🗑 Удалить источник", "Del")) { + if (ImGui::MenuItem("Удалить источник", "Del")) { selectedLightIdx = i; DeleteSelectedEntity(); } @@ -2659,7 +2792,7 @@ void EditorApp::RenderHierarchy() { } // 3. Sublevel Transitions Category char transHdr[64]; - snprintf(transHdr, sizeof(transHdr), "🌀 Порталы перехода (%zu)", transitions.size()); + snprintf(transHdr, sizeof(transHdr), "Порталы перехода (%zu)", transitions.size()); if (ImGui::TreeNodeEx(transHdr, ImGuiTreeNodeFlags_DefaultOpen)) { for (size_t i = 0; i < transitions.size(); ++i) { char label[96]; @@ -2675,13 +2808,13 @@ void EditorApp::RenderHierarchy() { selectedSpriteIdx = -1; } if (ImGui::BeginPopupContextItem()) { - if (ImGui::MenuItem("🎯 Сфокусировать", "F")) { + if (ImGui::MenuItem("Сфокусировать", "F")) { selectedTransitionIdx = static_cast(i); selectedLightIdx=-1; canvasPanX = 150.0f - (transitions[i].triggerCellX * canvasZoom); canvasPanY = 150.0f - (transitions[i].triggerCellY * canvasZoom); } ImGui::Separator(); - if (ImGui::MenuItem("🗑 Удалить портал", "Del")) { + if (ImGui::MenuItem("Удалить портал", "Del")) { selectedTransitionIdx = static_cast(i); selectedLightIdx=-1; DeleteSelectedEntity(); } @@ -2720,15 +2853,15 @@ void EditorApp::RenderInspector() { // Entity Header Card (Unity / Unreal style) ImGui::TextColored(ImVec4(0.4f, 0.9f, 1.0f, 1.0f), "Сущность #%d: %s", selectedSpriteIdx + 1, typeName); - if (ImGui::SmallButton("📋 Дублировать (Ctrl+D)")) { DuplicateSelectedEntity(); } + if (ImGui::SmallButton("Дублировать (Ctrl+D)")) { DuplicateSelectedEntity(); } ImGui::SameLine(); - if (ImGui::SmallButton("🎯 Фокус (F)")) { FocusSelectedEntity(); } + if (ImGui::SmallButton("Фокус (F)")) { FocusSelectedEntity(); } ImGui::SameLine(); - if (ImGui::SmallButton("🗑 Удалить (Del)")) { DeleteSelectedEntity(); return; } + if (ImGui::SmallButton("Удалить (Del)")) { DeleteSelectedEntity(); return; } ImGui::Separator(); // Component 1: Transform - if (ImGui::CollapsingHeader("📍 Transform (Координаты и масштаб)", ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::CollapsingHeader("Трансформ (Координаты и масштаб)", ImGuiTreeNodeFlags_DefaultOpen)) { float sx = spr.x / 64.0f; float sy = spr.y / 64.0f; if (ImGui::SliderFloat("Позиция X", &sx, 0.0f, MAP_GRID_W - 0.01f, "%.2f ячеек")) { @@ -2746,7 +2879,7 @@ void EditorApp::RenderInspector() { } // Component 2: Sprite Renderer - if (ImGui::CollapsingHeader("🖼 Sprite Renderer (Текстура)", ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::CollapsingHeader("Спрайт / Текстура", ImGuiTreeNodeFlags_DefaultOpen)) { int tid = static_cast(spr.textureId & 15); if (ImGui::Combo("Слот текстуры", &tid, g_TexSlotNames, 16)) { spr.textureId = static_cast(tid); @@ -2763,7 +2896,7 @@ void EditorApp::RenderInspector() { } // Component 3: Gameplay & AI Controller - if (ImGui::CollapsingHeader("🧠 Gameplay & AI Controller", ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::CollapsingHeader("Параметры сущности / AI", ImGuiTreeNodeFlags_DefaultOpen)) { static const char* s_ArchetypeNames[7] = { "0: Декорация / Проп (Static)", "1: Враг (Enemy Guard AI)", @@ -2806,13 +2939,13 @@ void EditorApp::RenderInspector() { ImGui::TextColored(ImVec4(1.0f, 0.45f, 0.15f, 1.0f), "● Взрывается от пуль, нанося 60 AOE урона вокруг!"); } - if (ImGui::Button("💻 Открыть логику в MASM32 IDE (F7)", ImVec2(-1, 28))) { + if (ImGui::Button("Открыть логику в MASM32 IDE (F7)", ImVec2(-1, 28))) { viewportMode = 3; } } // Component 4: Interaction & Lore Notes - if (ImGui::CollapsingHeader("💬 Интерактивный диалог / Записка", ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::CollapsingHeader("Интерактивный диалог / Записка", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::TextDisabled("При взаимодействии [E] вызывается ShowGameDialog:"); static char szSpeaker[32] = "ПЕРСОНАЖ"; static char szDialog[128] = "ПРИВЕТСТВУЮ В EBLAN ENGINE 3D!"; @@ -2830,31 +2963,31 @@ void EditorApp::RenderInspector() { ImGui::OpenPopup("AddComponentPopup"); } if (ImGui::BeginPopup("AddComponentPopup")) { - if (ImGui::MenuItem("🧠 Guard AI Controller")) { + if (ImGui::MenuItem("Guard AI Controller")) { PushUndo(); SetSpriteEntityData(spr, ENTITY_ARCHETYPE_GUARD, 60, 2, 6); } - if (ImGui::MenuItem("🩹 Medkit Heal Component")) { + if (ImGui::MenuItem("Medkit Heal Component")) { PushUndo(); SetSpriteEntityData(spr, ENTITY_ARCHETYPE_MEDKIT, 100, 0, 0); } - if (ImGui::MenuItem("📦 Ammo Pickup Component")) { + if (ImGui::MenuItem("Ammo Pickup Component")) { PushUndo(); SetSpriteEntityData(spr, ENTITY_ARCHETYPE_AMMO, 100, 0, 0); } - if (ImGui::MenuItem("🔑 Keycard Door Component")) { + if (ImGui::MenuItem("Keycard Door Component")) { PushUndo(); SetSpriteEntityData(spr, ENTITY_ARCHETYPE_KEY, 100, 0, 0); } - if (ImGui::MenuItem("🕹 Switch Trigger Component")) { + if (ImGui::MenuItem("Switch Trigger Component")) { PushUndo(); SetSpriteEntityData(spr, ENTITY_ARCHETYPE_SWITCH, 100, 0, 0); } - if (ImGui::MenuItem("💥 Explosive Barrel Component")) { + if (ImGui::MenuItem("Explosive Barrel Component")) { PushUndo(); SetSpriteEntityData(spr, ENTITY_ARCHETYPE_BARREL, 100, 0, 0); } - if (ImGui::MenuItem("🏺 Static Prop Decorator")) { + if (ImGui::MenuItem("Static Prop Decorator")) { PushUndo(); SetSpriteEntityData(spr, ENTITY_ARCHETYPE_PROP, 100, 0, 0); } @@ -2865,7 +2998,7 @@ void EditorApp::RenderInspector() { // Case 2: Portal Selected if (selectedTransitionIdx >= 0 && selectedTransitionIdx < static_cast(transitions.size())) { - if (ImGui::CollapsingHeader("🌀 Портал перехода (Sublevel Portal)", ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::CollapsingHeader("Портал перехода (Sublevel Portal)", ImGuiTreeNodeFlags_DefaultOpen)) { auto& trans = transitions[selectedTransitionIdx]; ImGui::TextColored(ImVec4(0.7f, 0.4f, 1.0f, 1.0f), "Триггер-ячейка: (%d, %d)", trans.triggerCellX, trans.triggerCellY); diff --git a/editor/src/editor_app.h b/editor/src/editor_app.h index a3f0d78..db34cd0 100644 --- a/editor/src/editor_app.h +++ b/editor/src/editor_app.h @@ -152,6 +152,11 @@ public: bool LightingNeedsBake() const; LightingSettings GetLightingSettings() const; + // Panel Dimensions & Splitters (Interactive Resizing like Unreal / Unity) + float leftPanelWidth = 260.0f; + float rightPanelWidth = 350.0f; + float centerSplitRatio = 0.5f; + // Viewport pan & zoom float canvasZoom = 20.0f; // pixels per tile float canvasPanX = 20.0f; diff --git a/editor/src/editor_lighting.inl b/editor/src/editor_lighting.inl index c25b2dd..cf0a17d 100644 --- a/editor/src/editor_lighting.inl +++ b/editor/src/editor_lighting.inl @@ -131,34 +131,52 @@ void EditorApp::RenderLightingInspector() { (light.lightType == LIGHT_TYPE_PULSE) ? "Пульсирующий (Сирена)" : (light.flags & LIGHT_FLAG_FLICKER) ? "Мерцающий факел" : "Точечный (Динамический)"; - ImGui::TextColored(ImVec4(1.0f, 0.85f, 0.25f, 1.0f), "💡 Источник света #%d из %d: %s", + ImGui::TextColored(ImVec4(1.0f, 0.85f, 0.25f, 1.0f), "Источник света #%d из %d: %s", selectedLightIdx + 1, static_cast(lightSources.size()), typeDesc); ImGui::Separator(); - // Quick Action Bar (Unity / Unreal style) - if (ImGui::SmallButton("🎯 Фокус (F)")) { FocusSelectedEntity(); } + // Quick Action Bar (2x2 Grid) + float colW2 = (ImGui::GetContentRegionAvail().x - 6.0f) * 0.5f; + if (ImGui::Button("Фокус (F)", ImVec2(colW2, 24))) { FocusSelectedEntity(); } ImGui::SameLine(); - if (ImGui::SmallButton("📋 Дублировать (Ctrl+D)")) { DuplicateSelectedEntity(); } + if (ImGui::Button("Дублировать (Ctrl+D)", ImVec2(colW2, 24))) { DuplicateSelectedEntity(); } + + if (ImGui::Button("К сетке (Snap)", ImVec2(colW2, 24))) { SnapLightToGrid(selectedLightIdx); } ImGui::SameLine(); - if (ImGui::SmallButton("🧲 К сетке (Snap)")) { SnapLightToGrid(selectedLightIdx); } - ImGui::SameLine(); - if (ImGui::SmallButton("🗑 Удалить (Del)")) { DeleteSelectedEntity(); return; } + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.55f, 0.15f, 0.15f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.75f, 0.20f, 0.20f, 1.0f)); + if (ImGui::Button("Удалить (Del)", ImVec2(colW2, 24))) { + ImGui::PopStyleColor(2); + DeleteSelectedEntity(); + return; + } + ImGui::PopStyleColor(2); ImGui::Spacing(); - ImGui::TextColored(ImVec4(0.4f, 0.9f, 1.0f, 1.0f), "Быстрые пресеты:"); + ImGui::TextColored(ImVec4(0.4f, 0.85f, 1.0f, 1.0f), "Быстрые пресеты источников:"); - // Preset Buttons - if (ImGui::SmallButton("🕯 Факел")) ApplyLightPreset(selectedLightIdx, LIGHT_PRESET_TORCH); + // Preset Buttons: Clean 3-Column Grid (all 7 presets visible!) + float colW3 = (ImGui::GetContentRegionAvail().x - 12.0f) / 3.0f; + if (ImGui::Button("Факел", ImVec2(colW3, 24))) ApplyLightPreset(selectedLightIdx, LIGHT_PRESET_TORCH); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Факел: Тёплый огонь (оранжевый, 240px, мерцание, тени)"); ImGui::SameLine(); - if (ImGui::SmallButton("💡 Лампа")) ApplyLightPreset(selectedLightIdx, LIGHT_PRESET_LAMP); + if (ImGui::Button("Лампа", ImVec2(colW3, 24))) ApplyLightPreset(selectedLightIdx, LIGHT_PRESET_LAMP); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Лампа: Запекаемый дневной свет (280px, статика)"); ImGui::SameLine(); - if (ImGui::SmallButton("🚨 Сирена")) ApplyLightPreset(selectedLightIdx, LIGHT_PRESET_ALARM); + if (ImGui::Button("Сирена", ImVec2(colW3, 24))) ApplyLightPreset(selectedLightIdx, LIGHT_PRESET_ALARM); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Сирена: Аварийный маяк (красный, 300px, пульсация)"); + + if (ImGui::Button("Свеча", ImVec2(colW3, 24))) ApplyLightPreset(selectedLightIdx, LIGHT_PRESET_CANDLE); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Свеча: Мягкий тёплый огонёк (140px, мерцание)"); ImGui::SameLine(); - if (ImGui::SmallButton("🕯 Свеча")) ApplyLightPreset(selectedLightIdx, LIGHT_PRESET_CANDLE); + if (ImGui::Button("Неон", ImVec2(colW3, 24))) ApplyLightPreset(selectedLightIdx, LIGHT_PRESET_NEON); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Неон: Циановый неоновый свет (260px, динамика)"); ImGui::SameLine(); - if (ImGui::SmallButton("🔮 Неон")) ApplyLightPreset(selectedLightIdx, LIGHT_PRESET_NEON); - ImGui::SameLine(); - if (ImGui::SmallButton("🔦 Прожектор")) ApplyLightPreset(selectedLightIdx, LIGHT_PRESET_SPOTLIGHT); + if (ImGui::Button("Токсик", ImVec2(colW3, 24))) ApplyLightPreset(selectedLightIdx, LIGHT_PRESET_TOXIC); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Токсик: Зелёное радиационное свечение (250px, пульс)"); + + if (ImGui::Button("Прожектор (Направленный)", ImVec2(-1, 24))) ApplyLightPreset(selectedLightIdx, LIGHT_PRESET_SPOTLIGHT); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Прожектор: Мощный белый свет (380px, статика)"); ImGui::Separator(); diff --git a/editor/src/main.cpp b/editor/src/main.cpp index 69a75ce..82bf38f 100644 --- a/editor/src/main.cpp +++ b/editor/src/main.cpp @@ -95,7 +95,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine return 1; } - ShowWindow(hWnd, SW_SHOWDEFAULT); + ShowWindow(hWnd, SW_MAXIMIZE); UpdateWindow(hWnd); DragAcceptFiles(hWnd, TRUE); diff --git a/engine.exe b/engine.exe index 55d9dc2..b71c770 100644 Binary files a/engine.exe and b/engine.exe differ diff --git a/main.obj b/main.obj index 10eb606..8024d95 100644 Binary files a/main.obj and b/main.obj differ