From 8148d10f8347ad0471248da242f5aa8d2a186dc6 Mon Sep 17 00:00:00 2001 From: Dlizzio <77717521+Dlizzio@users.noreply.github.com> Date: Mon, 23 Mar 2026 11:13:59 -0700 Subject: [PATCH 1/5] init --- .../Icons/Action Icons/free-camera.png | Bin 0 -> 15199 bytes .../Icons/Action Icons/pause.png | Bin 3230 -> 17537 bytes .../Icons/Action Icons/play-mode.png | Bin 0 -> 11876 bytes .../Icons/Action Icons/undo.png | Bin 2352 -> 12535 bytes src/Menu.cpp | 27 +- src/Menu.h | 2 + src/Menu/IconLoader.cpp | 15 +- src/Menu/OverlayRenderer.cpp | 8 +- src/Utils/UI.cpp | 14 + src/Utils/UI.h | 8 + src/WeatherEditor/EditorWindow.cpp | 334 ++++++++++++------ src/WeatherEditor/EditorWindow.h | 27 ++ 12 files changed, 313 insertions(+), 122 deletions(-) create mode 100644 package/Interface/CommunityShaders/Icons/Action Icons/free-camera.png create mode 100644 package/Interface/CommunityShaders/Icons/Action Icons/play-mode.png diff --git a/package/Interface/CommunityShaders/Icons/Action Icons/free-camera.png b/package/Interface/CommunityShaders/Icons/Action Icons/free-camera.png new file mode 100644 index 0000000000000000000000000000000000000000..0de1b88ab7262e0d0190e0409aad637c34e19469 GIT binary patch literal 15199 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 literal 0 HcmV?d00001 diff --git a/package/Interface/CommunityShaders/Icons/Action Icons/pause.png b/package/Interface/CommunityShaders/Icons/Action Icons/pause.png index 4763dab681fceea50bf5f1efc8f2f1fb9f06ab9d..36ddaa041d2ab3ef283daefab7ea547ca0e462f1 100644 GIT binary patch literal 17537 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 b`T^A?HU9ZR&|Mlb@B@&OR+g%kFbw=3BmX$& literal 0 HcmV?d00001 diff --git a/package/Interface/CommunityShaders/Icons/Action Icons/undo.png b/package/Interface/CommunityShaders/Icons/Action Icons/undo.png index 78043ca422507b09b6cef935f04e8bac8a04a00a..893b346e7496d07b9e5f5f2af4cae74acc3dcd0b 100644 GIT binary patch literal 12535 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 WZe8ic#%==u0000A> diff --git a/src/Menu.cpp b/src/Menu.cpp index b85abe8571..d361beabb8 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -949,9 +949,15 @@ void Menu::ProcessInputEventQueue() } if (event.device == RE::INPUT_DEVICE::kMouse) { logger::trace("Detect mouse scan code {} value {} pressed: {}", event.keyCode, event.value, event.IsPressed()); + auto* ew = EditorWindow::GetSingleton(); + bool inPreview = ew && ew->IsInPreviewMode(); if (event.keyCode > 7) { // middle scroll - io.AddMouseWheelEvent(0, event.value * (event.keyCode == 8 ? 1 : -1)); - } else { + if (ew && ew->previewMode == EditorWindow::PreviewMode::FreeCamera) { + ew->AdjustFlySpeed(event.keyCode == 8 ? 1.0f : -1.0f); + } else { + io.AddMouseWheelEvent(0, event.value * (event.keyCode == 8 ? 1 : -1)); + } + } else if (!inPreview) { if (event.keyCode > 5) event.keyCode = 5; io.AddMouseButtonEvent(event.keyCode, event.IsPressed()); @@ -1043,7 +1049,16 @@ void Menu::ProcessInputEventQueue() { settings.ShaderBlockPrevKey, [this, shaderCache]() { if (settings.EnableShaderBlocking) shaderCache->IterateShaderBlock(); } }, { settings.ShaderBlockNextKey, [this, shaderCache]() { if (settings.EnableShaderBlocking) shaderCache->IterateShaderBlock(false); } }, { settings.OverlayToggleKey, []() { Menu::GetSingleton()->overlayVisible = !Menu::GetSingleton()->overlayVisible; } }, - { settings.WeatherEditorToggleKey, []() { auto p = RE::PlayerCharacter::GetSingleton(); if (p && p->parentCell) EditorWindow::GetSingleton()->open = !EditorWindow::GetSingleton()->open; } }, + { settings.WeatherEditorToggleKey, []() { + auto* ew = EditorWindow::GetSingleton(); + if (ew->IsInPreviewMode()) { + ew->ExitPreviewMode(); + } else { + auto p = RE::PlayerCharacter::GetSingleton(); + if (p && p->parentCell) + ew->open = !ew->open; + } + } }, }; for (const auto& ka : keyActions) { // Check if key matches last key in combo and all modifiers are held (exact match) @@ -1083,7 +1098,9 @@ void Menu::ProcessInputEventQueue() // Handle ESC key for menu and editor window auto* editorWindow = EditorWindow::GetSingleton(); if (key == VK_ESCAPE) { - if (editorWindow && editorWindow->open && editorWindow->ShouldHandleEscapeKey()) { + if (editorWindow && editorWindow->IsInPreviewMode()) { + editorWindow->ExitPreviewMode(); + } else if (editorWindow && editorWindow->open && editorWindow->ShouldHandleEscapeKey()) { editorWindow->open = false; } else if (IsEnabled && (!editorWindow || !editorWindow->open)) { IsEnabled = false; @@ -1151,6 +1168,8 @@ void Menu::ProcessInputEvents(RE::InputEvent* const* a_events) bool Menu::ShouldSwallowInput() { auto editorWindow = EditorWindow::GetSingleton(); + if (editorWindow && editorWindow->IsInPreviewMode()) + return false; // let game handle movement/camera input during preview return IsEnabled || HomePageRenderer::ShouldShowFirstTimeSetup() || (editorWindow && editorWindow->open); } diff --git a/src/Menu.h b/src/Menu.h index 55b3916ff1..0773870e65 100644 --- a/src/Menu.h +++ b/src/Menu.h @@ -200,6 +200,8 @@ class Menu UIIcon applyToGame; // Apply changes to game icon (weather editor) UIIcon pauseTime; // Pause time icon (weather editor) UIIcon undo; // Undo icon (weather editor) + UIIcon freeCamera; // Free camera preview icon (weather editor) + UIIcon playMode; // Play mode preview icon (weather editor) // Social media/external link icons UIIcon discord; diff --git a/src/Menu/IconLoader.cpp b/src/Menu/IconLoader.cpp index 951100f49f..8cad6d20c9 100644 --- a/src/Menu/IconLoader.cpp +++ b/src/Menu/IconLoader.cpp @@ -105,6 +105,8 @@ namespace Util::IconLoader { std::string(iconFolder) + "\\apply-to-game.png", &menu->uiIcons.applyToGame.texture, &menu->uiIcons.applyToGame.size }, { std::string(iconFolder) + "\\pause.png", &menu->uiIcons.pauseTime.texture, &menu->uiIcons.pauseTime.size }, { std::string(iconFolder) + "\\undo.png", &menu->uiIcons.undo.texture, &menu->uiIcons.undo.size }, + { std::string(iconFolder) + "\\free-camera.png", &menu->uiIcons.freeCamera.texture, &menu->uiIcons.freeCamera.size }, + { std::string(iconFolder) + "\\play-mode.png", &menu->uiIcons.playMode.texture, &menu->uiIcons.playMode.size }, { "Categories\\characters.png", &menu->uiIcons.characters.texture, &menu->uiIcons.characters.size }, { "Categories\\display.png", &menu->uiIcons.display.texture, &menu->uiIcons.display.size }, @@ -219,24 +221,17 @@ namespace Util::IconLoader anyIconLoaded = true; } else { // If monochrome icon failed to load, try fallback to colored version - if (basePath.find("Monochrome") != std::string::npos) { - std::string fallbackPath = basePath; + if (fullPath.find("Monochrome") != std::string::npos) { + std::string fallbackPath = fullPath; size_t pos = fallbackPath.find("\\Monochrome"); if (pos != std::string::npos) { fallbackPath.erase(pos, 11); // Remove "\Monochrome" } - fallbackPath += iconDef.filename; - // Try to extract just the filename from iconDef.filename if it has path - size_t lastSlash = iconDef.filename.find_last_of("\\/"); - if (lastSlash != std::string::npos) { - std::string justFilename = iconDef.filename.substr(lastSlash + 1); - fallbackPath = fallbackPath.substr(0, fallbackPath.find_last_of("\\/") + 1) + justFilename; - } if (LoadTextureFromFile(device, fallbackPath.c_str(), iconDef.texture, *iconDef.size)) { iconsLoaded++; anyIconLoaded = true; } else { - logger::warn("InitializeMenuIcons: Failed to load icon from: {} (and fallback)", fullPath); + logger::warn("InitializeMenuIcons: Failed to load icon from: {} (and fallback: {})", fullPath, fallbackPath); } } else { logger::warn("InitializeMenuIcons: Failed to load icon from: {}", fullPath); diff --git a/src/Menu/OverlayRenderer.cpp b/src/Menu/OverlayRenderer.cpp index 503ec06569..f74bfdc7d6 100644 --- a/src/Menu/OverlayRenderer.cpp +++ b/src/Menu/OverlayRenderer.cpp @@ -58,9 +58,15 @@ void OverlayRenderer::RenderOverlay( auto player = RE::PlayerCharacter::GetSingleton(); if (editorWindow->open && !(player && player->parentCell)) { editorWindow->open = false; + if (editorWindow->IsInPreviewMode()) + editorWindow->ExitPreviewMode(); } if (editorWindow->open) { - ImGui::GetIO().MouseDrawCursor = true; + bool inPreview = editorWindow->IsInPreviewMode(); + auto& io = ImGui::GetIO(); + io.MouseDrawCursor = !inPreview; + if (inPreview) + io.MousePos = { -FLT_MAX, -FLT_MAX }; // prevent hover/tooltips during preview editorWindow->Draw(); } else if (menu.IsEnabled || HomePageRenderer::ShouldShowFirstTimeSetup()) { ImGui::GetIO().MouseDrawCursor = true; diff --git a/src/Utils/UI.cpp b/src/Utils/UI.cpp index b2135c299e..39bf3e4495 100644 --- a/src/Utils/UI.cpp +++ b/src/Utils/UI.cpp @@ -520,6 +520,20 @@ namespace Util return StyledButtonWrapper(color, hover, active); } + StyledButtonWrapper TransparentIconButtonStyle() + { + constexpr float kHoverAlpha = 0.25f; + auto hoverColor = Menu::GetSingleton()->GetTheme().Palette.Text; + hoverColor.w = kHoverAlpha; + return StyledButtonWrapper(ImVec4(0, 0, 0, 0), hoverColor, hoverColor); + } + + ImVec4 GetIconTint() + { + const auto& theme = Menu::GetSingleton()->GetTheme(); + return theme.UseMonochromeIcons ? theme.Palette.Text : ImVec4(1, 1, 1, 1); + } + // SectionWrapper implementation SectionWrapper::SectionWrapper(const char* title, const char* description, const ImVec4& titleColor, bool isVisible) : m_shouldDraw(isVisible), diff --git a/src/Utils/UI.h b/src/Utils/UI.h index 254161db42..8ccd4927c5 100644 --- a/src/Utils/UI.h +++ b/src/Utils/UI.h @@ -220,6 +220,14 @@ namespace Util */ StyledButtonWrapper ErrorButtonStyle(); + /** + * Creates a transparent button with theme text color hover. Caller must push/pop FrameBorderSize=0 separately. + */ + StyledButtonWrapper TransparentIconButtonStyle(); + + /** Returns theme text color if monochrome icons enabled, otherwise white. */ + ImVec4 GetIconTint(); + /** * Button with simple flash feedback (matches action icon hover effect style) * @param label Button text diff --git a/src/WeatherEditor/EditorWindow.cpp b/src/WeatherEditor/EditorWindow.cpp index a8902750e6..20fb059445 100644 --- a/src/WeatherEditor/EditorWindow.cpp +++ b/src/WeatherEditor/EditorWindow.cpp @@ -1088,140 +1088,211 @@ void EditorWindow::RenderUI() ImGui::EndMenu(); } - // Pause Time button + // Clip buttons above the bottom border so highlights don't overlap it + const auto clipMin = ImGui::GetWindowDrawList()->GetClipRectMin(); + const auto clipMax = ImGui::GetWindowDrawList()->GetClipRectMax(); + ImGui::PushClipRect(clipMin, ImVec2(clipMax.x, clipMax.y - ImGui::GetStyle().WindowBorderSize), true); + auto menu = globals::menu; - if (menu && menu->uiIcons.pauseTime.texture) { - bool isPaused = IsTimePaused(); + constexpr float kIconButtonPadding = 1.0f; // minimal padding so icons render larger and smoother + const float iconButtonDim = ImGui::GetFrameHeight() - kIconButtonPadding * 2; + const ImVec2 iconButtonSize(iconButtonDim, iconButtonDim); + const auto iconTint = Util::GetIconTint(); + // Undo button (stays on left side) + if (menu && menu->uiIcons.undo.texture) { + bool canUndo = CanUndo(); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); - if (isPaused) { - auto pausedColor = Menu::GetSingleton()->GetTheme().StatusPalette.SuccessColor; - pausedColor.w = 0.6f; - auto pausedHoverColor = pausedColor; - pausedHoverColor.w = 0.8f; - ImGui::PushStyleColor(ImGuiCol_Button, pausedColor); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, pausedHoverColor); - } else { - auto transparentColor = ImVec4(0, 0, 0, 0); - ImGui::PushStyleColor(ImGuiCol_Button, transparentColor); - auto hoverColor = Menu::GetSingleton()->GetSettings().Theme.Palette.Text; - hoverColor.w = 0.25f; - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, hoverColor); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(kIconButtonPadding, kIconButtonPadding)); + { + auto _style = Util::TransparentIconButtonStyle(); + auto textColor = canUndo ? menu->GetTheme().Palette.Text : menu->GetTheme().StatusPalette.Disable; + if (!canUndo) + textColor.w = 0.5f; + ImGui::PushStyleColor(ImGuiCol_Text, textColor); + if (ImGui::ImageButton("##GlobalUndo", menu->uiIcons.undo.texture, iconButtonSize, ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), iconTint) && canUndo) + PerformUndo(); + ImGui::PopStyleColor(); } - - const float menuBarHeight = ImGui::GetFrameHeight(); - const float buttonDim = menuBarHeight * 0.85f; - const ImVec2 buttonSize(buttonDim, buttonDim); - - if (ImGui::ImageButton("##GlobalPauseTime", menu->uiIcons.pauseTime.texture, buttonSize)) - TogglePause(); - - ImGui::PopStyleColor(2); - ImGui::PopStyleVar(); - + ImGui::PopStyleVar(2); if (ImGui::IsItemHovered()) - ImGui::SetTooltip(isPaused ? "Resume Time" : "Pause Time"); + ImGui::SetTooltip(canUndo ? "Undo (Ctrl+Z) - %d states" : "Undo (Ctrl+Z) - No changes to undo", (int)undoStack.size()); } - // Undo button - if (menu && menu->uiIcons.undo.texture) { - bool canUndo = CanUndo(); + // Right-aligned items — use SetCursorScreenPos to bypass menu bar GroupOffset + const float scale = Util::GetUIScale(); + const float clipRight = ImGui::GetWindowDrawList()->GetClipRectMax().x; + const float cursorY = ImGui::GetCursorScreenPos().y; + const float closeButtonSize = ImGui::GetFrameHeight(); + const float& itemSpacing = ImGui::GetStyle().ItemSpacing.x; + const float sliderWidth = kMenuBarSliderWidth * scale; + + // Measure right-side elements to compute positions right-to-left + float rightCursor = clipRight; + + // X button + rightCursor -= closeButtonSize; + const float xButtonX = rightCursor; + + // Time slider + rightCursor -= itemSpacing + sliderWidth; + const float sliderX = rightCursor; + + // Period text + char periodBuf[64]; + std::snprintf(periodBuf, sizeof(periodBuf), "(%s)", TOD::GetPeriodName(TOD::GetActivePeriod())); + float periodWidth = ImGui::CalcTextSize(periodBuf).x; + rightCursor -= itemSpacing + periodWidth; + const float periodX = rightCursor; - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); - if (!canUndo) { - auto transparentColor = ImVec4(0, 0, 0, 0); - ImGui::PushStyleColor(ImGuiCol_Button, transparentColor); - auto disabledColor = Menu::GetSingleton()->GetSettings().Theme.StatusPalette.Disable; - disabledColor.w = 0.25f; - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, disabledColor); - auto disabledTextColor = Menu::GetSingleton()->GetSettings().Theme.StatusPalette.Disable; - disabledTextColor.w = 0.5f; - ImGui::PushStyleColor(ImGuiCol_Text, disabledTextColor); - } else { - auto transparentColor = ImVec4(0, 0, 0, 0); - ImGui::PushStyleColor(ImGuiCol_Button, transparentColor); - auto hoverColor = Menu::GetSingleton()->GetSettings().Theme.Palette.Text; - hoverColor.w = 0.25f; - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, hoverColor); - ImGui::PushStyleColor(ImGuiCol_Text, Menu::GetSingleton()->GetSettings().Theme.Palette.Text); - } + // Pause Time button + float pauseButtonX = 0; + bool hasPauseButton = menu && menu->uiIcons.pauseTime.texture; + if (hasPauseButton) { + rightCursor -= itemSpacing + iconButtonDim + kIconButtonPadding * 2; + pauseButtonX = rightCursor; + } - const float menuBarHeight = ImGui::GetFrameHeight(); - const float buttonDim = menuBarHeight * 0.85f; - const ImVec2 buttonSize(buttonDim, buttonDim); + // Preview mode buttons (free camera / play mode) + const float previewButtonWidth = iconButtonDim + kIconButtonPadding * 2; + float freeCameraX = 0, playModeX = 0; + bool hasFreeCam = menu && menu->uiIcons.freeCamera.texture; + bool hasPlayMode = menu && menu->uiIcons.playMode.texture; + if (hasPlayMode) { + rightCursor -= itemSpacing + previewButtonWidth; + playModeX = rightCursor; + } + if (hasFreeCam) { + rightCursor -= itemSpacing + previewButtonWidth; + freeCameraX = rightCursor; + } - if (ImGui::ImageButton("##GlobalUndo", menu->uiIcons.undo.texture, buttonSize) && canUndo) { - PerformUndo(); - } + // Preview mode status text (mirrors TIME PAUSED pattern, with hotkey + pulsating color) + float previewStatusX = 0; + char previewStatusBuf[128] = {}; + bool showPreviewStatus = previewMode != PreviewMode::None; + if (showPreviewStatus) { + std::string hotkey = Util::Input::KeyIdToString(menu->GetSettings().WeatherEditorToggleKey); + if (previewMode == PreviewMode::FreeCamera) + std::snprintf(previewStatusBuf, sizeof(previewStatusBuf), " [ %s ] FREE CAMERA (Speed: %.0f)", hotkey.c_str(), flySpeed); + else + std::snprintf(previewStatusBuf, sizeof(previewStatusBuf), " [ %s ] PLAY MODE", hotkey.c_str()); + rightCursor -= itemSpacing + ImGui::CalcTextSize(previewStatusBuf).x; + previewStatusX = rightCursor; + } - ImGui::PopStyleColor(3); - ImGui::PopStyleVar(); + // Time paused text + float timePausedX = 0; + bool showTimePaused = IsTimePaused(); + const char* timePausedText = " [TIME PAUSED]"; + if (showTimePaused) { + rightCursor -= itemSpacing + ImGui::CalcTextSize(timePausedText).x; + timePausedX = rightCursor; + } - if (ImGui::IsItemHovered()) { - if (canUndo) { - ImGui::SetTooltip("Undo (Ctrl+Z) - %d states", (int)undoStack.size()); - } else { - ImGui::SetTooltip("Undo (Ctrl+Z) - No changes to undo"); - } - } - } // Weather lock indicator - if (weatherLockActive && lockedWeather) { - ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Text, Menu::GetSingleton()->GetSettings().Theme.StatusPalette.SuccessColor); + // Weather lock text + float weatherLockX = 0; + char weatherLockBuf[128] = {}; + bool showWeatherLock = weatherLockActive && lockedWeather; + if (showWeatherLock) { const char* weatherName = lockedWeather->GetFormEditorID(); - ImGui::Text(" [LOCKED: %s]", weatherName ? weatherName : "Unknown"); + std::snprintf(weatherLockBuf, sizeof(weatherLockBuf), " [LOCKED: %s]", weatherName ? weatherName : "Unknown"); + rightCursor -= itemSpacing + ImGui::CalcTextSize(weatherLockBuf).x; + weatherLockX = rightCursor; + } + + // Render right-aligned items left to right + const auto& statusPalette = menu->GetTheme().StatusPalette; + + if (showWeatherLock) { + ImGui::SetCursorScreenPos(ImVec2(weatherLockX, cursorY)); + ImGui::PushStyleColor(ImGuiCol_Text, statusPalette.SuccessColor); + ImGui::TextUnformatted(weatherLockBuf); ImGui::PopStyleColor(); } - // Time pause indicator - if (IsTimePaused()) { - ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Text, Menu::GetSingleton()->GetSettings().Theme.StatusPalette.CurrentHotkey); - ImGui::Text(" [TIME PAUSED]"); + if (showTimePaused) { + ImGui::SetCursorScreenPos(ImVec2(timePausedX, cursorY)); + ImGui::PushStyleColor(ImGuiCol_Text, statusPalette.CurrentHotkey); + ImGui::TextUnformatted(timePausedText); ImGui::PopStyleColor(); } - // Time slider and close button - float menuBarHeight = ImGui::GetFrameHeight(); - float closeButtonSize = menuBarHeight * 0.9f; - const float scale = Util::GetUIScale(); - const float closeButtonMargin = 10.0f * scale; + if (showPreviewStatus) { + ImGui::SetCursorScreenPos(ImVec2(previewStatusX, cursorY)); + ImGui::TextColored(Util::GetPulsingColor(statusPalette.CurrentHotkey), "%s", previewStatusBuf); + } - // Time slider anchored to the right - { - const float& itemSpacing = ImGui::GetStyle().ItemSpacing.x; - char periodBuf[64]; - std::snprintf(periodBuf, sizeof(periodBuf), "(%s)", TOD::GetPeriodName(TOD::GetActivePeriod())); - float periodWidth = ImGui::CalcTextSize(periodBuf).x; - const float sliderStartX = ImGui::GetWindowWidth() - closeButtonSize - closeButtonMargin - itemSpacing - kMenuBarSliderWidth * scale; - auto calendar = globals::game::calendar ? globals::game::calendar : RE::Calendar::GetSingleton(); - if (calendar && calendar->gameHour) { - ImGui::SameLine(sliderStartX - itemSpacing - periodWidth); - ImGui::TextUnformatted(periodBuf); - ImGui::SameLine(sliderStartX); - ImGui::SetNextItemWidth(kMenuBarSliderWidth * scale); - DrawGameHourSlider("##MenuBarSlider", "Time: %.2f"); + // Toggle-style icon button helper (active: SuccessColor bg, inactive: transparent) + auto DrawToggleIconButton = [&](const char* id, ImTextureID texture, bool isActive, float posX) -> bool { + ImGui::SetCursorScreenPos(ImVec2(posX, cursorY)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(kIconButtonPadding, kIconButtonPadding)); + if (isActive) { + auto color = statusPalette.SuccessColor; + color.w = kToggleActiveAlpha; + auto hover = color; + hover.w = kToggleHoverAlpha; + ImGui::PushStyleColor(ImGuiCol_Button, color); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, hover); + } else { + auto hover = menu->GetTheme().Palette.Text; + hover.w = kInactiveHoverAlpha; + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, hover); } + bool clicked = ImGui::ImageButton(id, texture, iconButtonSize, ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), iconTint); + ImGui::PopStyleColor(2); + ImGui::PopStyleVar(2); + return clicked; + }; + + // Preview mode buttons + if (hasFreeCam) { + bool isActive = previewMode == PreviewMode::FreeCamera; + if (DrawToggleIconButton("##FreeCamera", menu->uiIcons.freeCamera.texture, isActive, freeCameraX)) + EnterPreviewMode(PreviewMode::FreeCamera); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip(isActive ? "Exit Free Camera" : "Free Camera (scroll to adjust speed)"); + } + if (hasPlayMode) { + bool isActive = previewMode == PreviewMode::PlayMode; + if (DrawToggleIconButton("##PlayMode", menu->uiIcons.playMode.texture, isActive, playModeX)) + EnterPreviewMode(PreviewMode::PlayMode); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip(isActive ? "Exit Play Mode" : "Play Mode - Walk around normally"); + } + + if (hasPauseButton) { + bool isPaused = IsTimePaused(); + if (DrawToggleIconButton("##GlobalPauseTime", menu->uiIcons.pauseTime.texture, isPaused, pauseButtonX)) + TogglePause(); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip(isPaused ? "Resume Time" : "Pause Time"); + } + + // Period text and time slider + auto calendar = globals::game::calendar ? globals::game::calendar : RE::Calendar::GetSingleton(); + if (calendar && calendar->gameHour) { + ImGui::SetCursorScreenPos(ImVec2(periodX, cursorY)); + ImGui::TextUnformatted(periodBuf); + ImGui::SetCursorScreenPos(ImVec2(sliderX, cursorY)); + ImGui::SetNextItemWidth(sliderWidth); + DrawGameHourSlider("##MenuBarSlider", "Time: %.2f"); } - ImGui::SameLine(ImGui::GetWindowWidth() - closeButtonSize - closeButtonMargin); - auto errorColor = Menu::GetSingleton()->GetSettings().Theme.StatusPalette.Error; - auto errorHoverColor = errorColor; - errorHoverColor.x = std::min(1.0f, errorColor.x * 1.2f); - errorHoverColor.y = std::min(1.0f, errorColor.y * 0.75f); - auto errorActiveColor = errorColor; - errorActiveColor.x = std::max(0.0f, errorColor.x * 0.875f); - errorActiveColor.y = std::max(0.0f, errorColor.y * 0.25f); - ImGui::PushStyleColor(ImGuiCol_Button, errorColor); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, errorHoverColor); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, errorActiveColor); - if (ImGui::Button("X", ImVec2(closeButtonSize, closeButtonSize))) { - open = false; + // Close button + ImGui::SetCursorScreenPos(ImVec2(xButtonX, cursorY)); + { + auto _style = Util::ErrorButtonStyle(); + if (ImGui::Button("X", ImVec2(closeButtonSize, closeButtonSize))) { + open = false; + } } - ImGui::PopStyleColor(3); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Close Weather Editor (Esc)"); } + ImGui::PopClipRect(); ImGui::EndMainMenuBar(); } @@ -1866,6 +1937,55 @@ void EditorWindow::RestoreVanityCamera() } } +void EditorWindow::EnterPreviewMode(PreviewMode mode) +{ + if (mode == PreviewMode::None) + return; + + // Toggle off if already in the requested mode + if (previewMode == mode) { + ExitPreviewMode(); + return; + } + + // Switch from a different active mode first + if (previewMode != PreviewMode::None) + ExitPreviewMode(); + + previewMode = mode; + savedMousePos = ImGui::GetIO().MousePos; + + if (mode == PreviewMode::FreeCamera) { + flySpeed = kDefaultFlySpeed; + RE::Console::ExecuteCommand("tfc"); + RE::Console::ExecuteCommand(std::format("sucsm {:.0f}", flySpeed).c_str()); + } + + logger::info("Entered preview mode: {}", mode == PreviewMode::FreeCamera ? "FreeCamera" : "PlayMode"); +} + +void EditorWindow::ExitPreviewMode() +{ + if (previewMode == PreviewMode::FreeCamera) + RE::Console::ExecuteCommand("tfc"); + + logger::info("Exited preview mode"); + previewMode = PreviewMode::None; + + // Restore cursor to where it was before entering preview + ImGui::GetIO().MousePos = savedMousePos; + ImGui::GetIO().WantSetMousePos = true; +} + +void EditorWindow::AdjustFlySpeed(float scrollDelta) +{ + if (previewMode != PreviewMode::FreeCamera) + return; + + flySpeed = std::clamp(flySpeed + scrollDelta * kFlySpeedScrollStep, kMinFlySpeed, kMaxFlySpeed); + RE::Console::ExecuteCommand(std::format("sucsm {:.0f}", flySpeed).c_str()); +} + bool EditorWindow::ShouldHandleEscapeKey() const { return !ImGui::IsPopupOpen("", ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel); diff --git a/src/WeatherEditor/EditorWindow.h b/src/WeatherEditor/EditorWindow.h index 2ad7505865..e2951b837b 100644 --- a/src/WeatherEditor/EditorWindow.h +++ b/src/WeatherEditor/EditorWindow.h @@ -24,7 +24,16 @@ class EditorWindow return &singleton; } + // Preview modes for exploring the scene without the full editor UI + enum class PreviewMode + { + None, // Full editor UI visible + FreeCamera, // Free camera (tfc) with scroll-wheel speed control + PlayMode // Normal gameplay, no scroll interception + }; + bool open = false; + PreviewMode previewMode = PreviewMode::None; const static int maxRecordMarkers = 10; // Owned by EditorWindow, created in Draw(), released in destructor @@ -61,6 +70,24 @@ class EditorWindow static constexpr float kTimeScaleMax = 4000.0f; static constexpr float kMenuBarSliderWidth = 400.0f; + // Preview mode constants + static constexpr float kDefaultFlySpeed = 10.0f; + static constexpr float kMinFlySpeed = 1.0f; + static constexpr float kMaxFlySpeed = 100.0f; + static constexpr float kFlySpeedScrollStep = 2.0f; + static constexpr float kToggleActiveAlpha = 0.6f; + static constexpr float kToggleHoverAlpha = 0.8f; + static constexpr float kInactiveHoverAlpha = 0.25f; + + // Preview mode state + float flySpeed = kDefaultFlySpeed; + ImVec2 savedMousePos = { -FLT_MAX, -FLT_MAX }; + + void EnterPreviewMode(PreviewMode mode); + void ExitPreviewMode(); + bool IsInPreviewMode() const { return previewMode != PreviewMode::None; } + void AdjustFlySpeed(float scrollDelta); + // Vanity camera control bool vanityCameraDisabled = false; float savedVanityCameraDelay = 180.0f; From 095e119c6f1e5e9a687fa1217af419b74a388045 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 18:24:43 +0000 Subject: [PATCH 2/5] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commit.?= =?UTF-8?q?ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/Menu.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Menu.cpp b/src/Menu.cpp index d361beabb8..d3ebb793a2 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -1050,15 +1050,15 @@ void Menu::ProcessInputEventQueue() { settings.ShaderBlockNextKey, [this, shaderCache]() { if (settings.EnableShaderBlocking) shaderCache->IterateShaderBlock(false); } }, { settings.OverlayToggleKey, []() { Menu::GetSingleton()->overlayVisible = !Menu::GetSingleton()->overlayVisible; } }, { settings.WeatherEditorToggleKey, []() { - auto* ew = EditorWindow::GetSingleton(); - if (ew->IsInPreviewMode()) { - ew->ExitPreviewMode(); - } else { - auto p = RE::PlayerCharacter::GetSingleton(); - if (p && p->parentCell) - ew->open = !ew->open; - } - } }, + auto* ew = EditorWindow::GetSingleton(); + if (ew->IsInPreviewMode()) { + ew->ExitPreviewMode(); + } else { + auto p = RE::PlayerCharacter::GetSingleton(); + if (p && p->parentCell) + ew->open = !ew->open; + } + } }, }; for (const auto& ka : keyActions) { // Check if key matches last key in combo and all modifiers are held (exact match) From 0bc6d693fb957b26e870d77fdb9c57a09832270f Mon Sep 17 00:00:00 2001 From: Dlizzio <77717521+Dlizzio@users.noreply.github.com> Date: Mon, 23 Mar 2026 12:24:32 -0700 Subject: [PATCH 3/5] AI and free camera lock --- src/Hooks.cpp | 5 ++++ src/Menu.cpp | 18 +++++++++---- src/Menu.h | 1 + src/Menu/IconLoader.cpp | 22 ++++++++-------- src/Menu/OverlayRenderer.cpp | 8 +++--- src/WeatherEditor/EditorWindow.cpp | 41 ++++++++++++++++++++++++------ src/WeatherEditor/EditorWindow.h | 10 +++++--- 7 files changed, 73 insertions(+), 32 deletions(-) diff --git a/src/Hooks.cpp b/src/Hooks.cpp index 156d754d66..4f0218cf41 100644 --- a/src/Hooks.cpp +++ b/src/Hooks.cpp @@ -391,6 +391,11 @@ struct BSInputDeviceManager_PollInputDevices } if (blockedDevice && menu->ShouldSwallowInput()) { //the menu is open, eat all keypresses + // During active flying preview, let input reach the game for movement/camera + if (menu->IsPreviewFlying()) { + func(a_dispatcher, a_events); + return; + } constexpr RE::InputEvent* const dummy[] = { nullptr }; func(a_dispatcher, dummy); return; diff --git a/src/Menu.cpp b/src/Menu.cpp index d3ebb793a2..1760e1d0d3 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -950,14 +950,14 @@ void Menu::ProcessInputEventQueue() if (event.device == RE::INPUT_DEVICE::kMouse) { logger::trace("Detect mouse scan code {} value {} pressed: {}", event.keyCode, event.value, event.IsPressed()); auto* ew = EditorWindow::GetSingleton(); - bool inPreview = ew && ew->IsInPreviewMode(); + bool flying = ew && ew->IsPreviewFlying(); if (event.keyCode > 7) { // middle scroll if (ew && ew->previewMode == EditorWindow::PreviewMode::FreeCamera) { ew->AdjustFlySpeed(event.keyCode == 8 ? 1.0f : -1.0f); } else { io.AddMouseWheelEvent(0, event.value * (event.keyCode == 8 ? 1 : -1)); } - } else if (!inPreview) { + } else if (!flying) { if (event.keyCode > 5) event.keyCode = 5; io.AddMouseButtonEvent(event.keyCode, event.IsPressed()); @@ -1051,7 +1051,11 @@ void Menu::ProcessInputEventQueue() { settings.OverlayToggleKey, []() { Menu::GetSingleton()->overlayVisible = !Menu::GetSingleton()->overlayVisible; } }, { settings.WeatherEditorToggleKey, []() { auto* ew = EditorWindow::GetSingleton(); - if (ew->IsInPreviewMode()) { + if (ew->GetPreviewMode() == EditorWindow::PreviewMode::FreeCamera) { + // Flying → lock camera position for editing + ew->ToggleFreeCameraLock(); + } else if (ew->IsInPreviewMode()) { + // Locked or PlayMode → fully exit preview ew->ExitPreviewMode(); } else { auto p = RE::PlayerCharacter::GetSingleton(); @@ -1168,11 +1172,15 @@ void Menu::ProcessInputEvents(RE::InputEvent* const* a_events) bool Menu::ShouldSwallowInput() { auto editorWindow = EditorWindow::GetSingleton(); - if (editorWindow && editorWindow->IsInPreviewMode()) - return false; // let game handle movement/camera input during preview return IsEnabled || HomePageRenderer::ShouldShowFirstTimeSetup() || (editorWindow && editorWindow->open); } +bool Menu::IsPreviewFlying() +{ + auto editorWindow = EditorWindow::GetSingleton(); + return editorWindow && editorWindow->IsPreviewFlying(); +} + void Menu::SelectFeatureMenu(const std::string& featureName) { pendingFeatureSelection = featureName; diff --git a/src/Menu.h b/src/Menu.h index 0773870e65..3ef3d6d927 100644 --- a/src/Menu.h +++ b/src/Menu.h @@ -129,6 +129,7 @@ class Menu void ProcessInputEvents(RE::InputEvent* const* a_events); bool ShouldSwallowInput(); + bool IsPreviewFlying(); std::string BuildFontSignature(float baseFontSize) const; public: diff --git a/src/Menu/IconLoader.cpp b/src/Menu/IconLoader.cpp index 8cad6d20c9..823d497df2 100644 --- a/src/Menu/IconLoader.cpp +++ b/src/Menu/IconLoader.cpp @@ -196,20 +196,18 @@ namespace Util::IconLoader auto iconDefs = GetIconDefinitions(menu); - for (auto* texturePtr : { &menu->uiIcons.saveSettings.texture, &menu->uiIcons.loadSettings.texture, - &menu->uiIcons.clearCache.texture, &menu->uiIcons.deleteSettings.texture, &menu->uiIcons.logo.texture, - &menu->uiIcons.featureSettingRevert.texture, &menu->uiIcons.applyToGame.texture, &menu->uiIcons.pauseTime.texture, - &menu->uiIcons.undo.texture, &menu->uiIcons.search.texture, &menu->uiIcons.discord.texture, - &menu->uiIcons.characters.texture, &menu->uiIcons.display.texture, - &menu->uiIcons.grass.texture, &menu->uiIcons.lighting.texture, - &menu->uiIcons.sky.texture, &menu->uiIcons.landscape.texture, - &menu->uiIcons.water.texture, &menu->uiIcons.debug.texture, - &menu->uiIcons.materials.texture, &menu->uiIcons.postProcessing.texture }) { - if (*texturePtr) { - (*texturePtr)->Release(); - *texturePtr = nullptr; + // Release all existing textures using the same definitions list (avoids stale hardcoded list) + for (const auto& iconDef : iconDefs) { + if (*iconDef.texture) { + (*iconDef.texture)->Release(); + *iconDef.texture = nullptr; } } + // Also release search icon (not in iconDefs) + if (menu->uiIcons.search.texture) { + menu->uiIcons.search.texture->Release(); + menu->uiIcons.search.texture = nullptr; + } bool anyIconLoaded = false; int iconsLoaded = 0; diff --git a/src/Menu/OverlayRenderer.cpp b/src/Menu/OverlayRenderer.cpp index f74bfdc7d6..d959ed4564 100644 --- a/src/Menu/OverlayRenderer.cpp +++ b/src/Menu/OverlayRenderer.cpp @@ -62,11 +62,11 @@ void OverlayRenderer::RenderOverlay( editorWindow->ExitPreviewMode(); } if (editorWindow->open) { - bool inPreview = editorWindow->IsInPreviewMode(); + bool flying = editorWindow->IsPreviewFlying(); auto& io = ImGui::GetIO(); - io.MouseDrawCursor = !inPreview; - if (inPreview) - io.MousePos = { -FLT_MAX, -FLT_MAX }; // prevent hover/tooltips during preview + io.MouseDrawCursor = !flying; + if (flying) + io.MousePos = { -FLT_MAX, -FLT_MAX }; // prevent hover/tooltips during active flying editorWindow->Draw(); } else if (menu.IsEnabled || HomePageRenderer::ShouldShowFirstTimeSetup()) { ImGui::GetIO().MouseDrawCursor = true; diff --git a/src/WeatherEditor/EditorWindow.cpp b/src/WeatherEditor/EditorWindow.cpp index 20fb059445..b0ed176d08 100644 --- a/src/WeatherEditor/EditorWindow.cpp +++ b/src/WeatherEditor/EditorWindow.cpp @@ -1175,6 +1175,8 @@ void EditorWindow::RenderUI() std::string hotkey = Util::Input::KeyIdToString(menu->GetSettings().WeatherEditorToggleKey); if (previewMode == PreviewMode::FreeCamera) std::snprintf(previewStatusBuf, sizeof(previewStatusBuf), " [ %s ] FREE CAMERA (Speed: %.0f)", hotkey.c_str(), flySpeed); + else if (previewMode == PreviewMode::FreeCameraLocked) + std::snprintf(previewStatusBuf, sizeof(previewStatusBuf), " [ %s ] FREE CAMERA LOCKED", hotkey.c_str()); else std::snprintf(previewStatusBuf, sizeof(previewStatusBuf), " [ %s ] PLAY MODE", hotkey.c_str()); rightCursor -= itemSpacing + ImGui::CalcTextSize(previewStatusBuf).x; @@ -1249,7 +1251,7 @@ void EditorWindow::RenderUI() // Preview mode buttons if (hasFreeCam) { - bool isActive = previewMode == PreviewMode::FreeCamera; + bool isActive = previewMode == PreviewMode::FreeCamera || previewMode == PreviewMode::FreeCameraLocked; if (DrawToggleIconButton("##FreeCamera", menu->uiIcons.freeCamera.texture, isActive, freeCameraX)) EnterPreviewMode(PreviewMode::FreeCamera); if (ImGui::IsItemHovered()) @@ -1942,9 +1944,14 @@ void EditorWindow::EnterPreviewMode(PreviewMode mode) if (mode == PreviewMode::None) return; - // Toggle off if already in the requested mode - if (previewMode == mode) { - ExitPreviewMode(); + // Already in free camera flying — ignore duplicate click + if (mode == previewMode) + return; + + // Re-enter flying from locked state via button click + if (mode == PreviewMode::FreeCamera && previewMode == PreviewMode::FreeCameraLocked) { + previewMode = PreviewMode::FreeCamera; + logger::info("Free camera unlocked (re-entered flying)"); return; } @@ -1966,15 +1973,33 @@ void EditorWindow::EnterPreviewMode(PreviewMode mode) void EditorWindow::ExitPreviewMode() { - if (previewMode == PreviewMode::FreeCamera) + bool wasFlying = IsPreviewFlying(); + + if (previewMode == PreviewMode::FreeCamera || previewMode == PreviewMode::FreeCameraLocked) RE::Console::ExecuteCommand("tfc"); logger::info("Exited preview mode"); previewMode = PreviewMode::None; - // Restore cursor to where it was before entering preview - ImGui::GetIO().MousePos = savedMousePos; - ImGui::GetIO().WantSetMousePos = true; + // Only restore cursor if exiting from a flying state; FreeCameraLocked already has the cursor active + if (wasFlying) { + ImGui::GetIO().MousePos = savedMousePos; + ImGui::GetIO().WantSetMousePos = true; + } +} + +void EditorWindow::ToggleFreeCameraLock() +{ + if (previewMode == PreviewMode::FreeCamera) { + previewMode = PreviewMode::FreeCameraLocked; + ImGui::GetIO().MousePos = savedMousePos; + ImGui::GetIO().WantSetMousePos = true; + logger::info("Free camera locked"); + } else if (previewMode == PreviewMode::FreeCameraLocked) { + savedMousePos = ImGui::GetIO().MousePos; + previewMode = PreviewMode::FreeCamera; + logger::info("Free camera unlocked"); + } } void EditorWindow::AdjustFlySpeed(float scrollDelta) diff --git a/src/WeatherEditor/EditorWindow.h b/src/WeatherEditor/EditorWindow.h index e2951b837b..251507ac69 100644 --- a/src/WeatherEditor/EditorWindow.h +++ b/src/WeatherEditor/EditorWindow.h @@ -27,9 +27,10 @@ class EditorWindow // Preview modes for exploring the scene without the full editor UI enum class PreviewMode { - None, // Full editor UI visible - FreeCamera, // Free camera (tfc) with scroll-wheel speed control - PlayMode // Normal gameplay, no scroll interception + None, // Full editor UI visible + FreeCamera, // Flying free camera (tfc), input to game + FreeCameraLocked, // Camera locked in place, editor interactive + PlayMode // Normal gameplay, no scroll interception }; bool open = false; @@ -86,6 +87,9 @@ class EditorWindow void EnterPreviewMode(PreviewMode mode); void ExitPreviewMode(); bool IsInPreviewMode() const { return previewMode != PreviewMode::None; } + bool IsPreviewFlying() const { return previewMode == PreviewMode::FreeCamera || previewMode == PreviewMode::PlayMode; } + PreviewMode GetPreviewMode() const { return previewMode; } + void ToggleFreeCameraLock(); void AdjustFlySpeed(float scrollDelta); // Vanity camera control From 6e7bcee9e212c416a0c470d4ebcee659d2f8118e Mon Sep 17 00:00:00 2001 From: Dlizzio <77717521+Dlizzio@users.noreply.github.com> Date: Mon, 23 Mar 2026 12:32:27 -0700 Subject: [PATCH 4/5] AI --- src/Menu.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Menu.cpp b/src/Menu.cpp index 1760e1d0d3..a65f41e96b 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -225,6 +225,9 @@ Menu::~Menu() uiIcons.debug.Release(); uiIcons.materials.Release(); uiIcons.postProcessing.Release(); + uiIcons.freeCamera.Release(); + uiIcons.playMode.Release(); + uiIcons.search.Release(); // Clean up blur resources BackgroundBlur::Cleanup(); From a20ba384858ed4d29569640cbaac44812809b536 Mon Sep 17 00:00:00 2001 From: Dlizzio <77717521+Dlizzio@users.noreply.github.com> Date: Mon, 23 Mar 2026 12:50:44 -0700 Subject: [PATCH 5/5] AI --- src/Menu.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Menu.cpp b/src/Menu.cpp index a65f41e96b..515cb13e1c 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -957,7 +957,7 @@ void Menu::ProcessInputEventQueue() if (event.keyCode > 7) { // middle scroll if (ew && ew->previewMode == EditorWindow::PreviewMode::FreeCamera) { ew->AdjustFlySpeed(event.keyCode == 8 ? 1.0f : -1.0f); - } else { + } else if (!flying) { io.AddMouseWheelEvent(0, event.value * (event.keyCode == 8 ? 1 : -1)); } } else if (!flying) { @@ -1054,6 +1054,8 @@ void Menu::ProcessInputEventQueue() { settings.OverlayToggleKey, []() { Menu::GetSingleton()->overlayVisible = !Menu::GetSingleton()->overlayVisible; } }, { settings.WeatherEditorToggleKey, []() { auto* ew = EditorWindow::GetSingleton(); + if (!ew) + return; if (ew->GetPreviewMode() == EditorWindow::PreviewMode::FreeCamera) { // Flying → lock camera position for editing ew->ToggleFreeCameraLock();