瀏覽代碼

fix: address main overlay UX review

saulo benigno 3 周之前
父節點
當前提交
e80f8cdd81

+ 14 - 13
Sunrise/src/core/ui/hud/overlays/ui_hud_startup_hint_overlay.cpp

@@ -8,7 +8,6 @@
 #include <string_view>
 
 #include "../../../settings/parser.h"
-#include "../../animation/transition/ui_transition_animation.h"
 #include "../../runtime/ui_visibility_runtime.h"
 
 namespace sunrise::core::ui::hud::overlays::startup_hint {
@@ -18,12 +17,12 @@ namespace {
 constexpr float kDelaySeconds = 2.0F;
 /** 30 seconds is long enough to notice the hint and short enough to clear itself. */
 constexpr float kVisibleSeconds = 30.0F;
-/** Fixed animation key. Every visibility-lane user needs its own, so keep these distinct. */
-constexpr ImGuiID kOverlayAnimationId = 4;
-/** Response rates for fading in and out, slower than the menus so the hint stays subtle. */
-constexpr animation::transition::Rates kVisibilityRates{8.0F, 6.0F};
-/** A hidden hint has finished its transition and draws nothing. */
-constexpr float kHiddenProgress = 0.0F;
+/** Half a second to fade in or out, slower than the menus so the hint stays subtle. */
+constexpr float kFadeSeconds = 0.5F;
+/** A hidden hint has finished fading out and draws nothing. */
+constexpr float kHiddenOpacity = 0.0F;
+/** A shown hint has finished fading in. */
+constexpr float kShownOpacity = 1.0F;
 /** Longest supported toggle key name, plus the null. */
 constexpr std::size_t kKeyNameCapacity = 16;
 
@@ -31,6 +30,8 @@ constexpr std::size_t kKeyNameCapacity = 16;
 float g_elapsedSeconds = 0.0F;
 /** Set once the surface opened or the stay ran out. The hint never returns in this run. */
 bool g_dismissed = false;
+/** The hint's own fade, so it needs no shared animation key. */
+float g_opacity = kHiddenOpacity;
 
 /**
  * Names the configured toggle key in upper case, so it stands out from the muted text around it.
@@ -52,19 +53,19 @@ bool g_dismissed = false;
 
 /** Advances the hint's one-time lifetime by this frame. */
 float progress() noexcept {
+    const float deltaSeconds = ImGui::GetIO().DeltaTime;
     if (!g_dismissed) {
-        g_elapsedSeconds += ImGui::GetIO().DeltaTime;
+        g_elapsedSeconds += deltaSeconds;
         // An open surface has taught the key, and a hint that came back later would nag.
         if (runtime::snapshot().visible || g_elapsedSeconds >= kDelaySeconds + kVisibleSeconds) {
             g_dismissed = true;
         }
     }
     const bool shown = !g_dismissed && g_elapsedSeconds >= kDelaySeconds;
-    return animation::transition::update(kOverlayAnimationId,
-                                         animation::transition::Lane::visibility,
-                                         shown,
-                                         kVisibilityRates,
-                                         kHiddenProgress);
+    const float step = deltaSeconds / kFadeSeconds;
+    g_opacity = shown ? (std::min)(g_opacity + step, kShownOpacity)
+                      : (std::max)(g_opacity - step, kHiddenOpacity);
+    return g_opacity;
 }
 
 /** Draws the startup hint inside the overlay window the stack has already started. */

+ 26 - 9
Sunrise/src/core/ui/layout/ui_layout_render.cpp

@@ -1,7 +1,6 @@
 #include <algorithm>
 #include <array>
 #include <imgui.h>
-#include <imgui_internal.h>
 #include <string_view>
 
 #include "../../../../resources/resource.h"
@@ -62,6 +61,10 @@ constexpr float kHalfExtent = 2.0F;
 constexpr char kTitle[] = "SUNRISE";
 /** The hidden close action label is scoped by the main window. */
 constexpr char kCloseWidgetId[] = "##close";
+/** The close cross spans this fraction of its button, so it reads as a glyph and not a frame. */
+constexpr float kCloseCrossRatio = 0.5F;
+/** One pixel keeps the close cross as thin as the body text. */
+constexpr float kCloseCrossThickness = 1.0F;
 
 /**
  * Copies one display name into null-terminated component storage.
@@ -156,15 +159,30 @@ void draw_companion_windows() noexcept {
         titleY + ((std::max)(titleHeight - ImGui::GetTextLineHeight(), 0.0F) / kHalfExtent));
     ImGui::TextDisabled(SUNRISE_VER_STRING);
 
-    // The same Dear ImGui title-bar close button the Activity Host tool windows carry, at the
-    // right edge of the title row and centered on it. It takes no layout space, so the row
-    // and the separator below keep their places.
+    // A cross at the right edge of the title row, centered on it. It stays on the row the logo
+    // opened, like the version, so the row and the separator below keep their places.
+    ImGui::SameLine();
     const float buttonExtent = ImGui::GetFontSize();
     const float rowHeight = logoDrawn ? extent : titleHeight;
     const ImVec2 buttonPosition{
         rowRight - buttonExtent,
         rowOrigin.y + ((std::max)(rowHeight - buttonExtent, 0.0F) / kHalfExtent)};
-    return ImGui::CloseButton(ImGui::GetID(kCloseWidgetId), buttonPosition);
+    ImGui::SetCursorScreenPos(buttonPosition);
+    const bool pressed = ImGui::InvisibleButton(kCloseWidgetId, {buttonExtent, buttonExtent});
+
+    // Muted like the version until hovered, then white like the title.
+    const ImU32 color =
+        ImGui::GetColorU32(ImGui::IsItemHovered() ? ImGuiCol_Text : ImGuiCol_TextDisabled);
+    const float half = buttonExtent * kCloseCrossRatio / kHalfExtent;
+    const ImVec2 center{buttonPosition.x + (buttonExtent / kHalfExtent),
+                        buttonPosition.y + (buttonExtent / kHalfExtent)};
+    ImDrawList* drawList = ImGui::GetWindowDrawList();
+    const float thickness = scaling::dpi::pixels(kCloseCrossThickness);
+    drawList->AddLine(
+        {center.x - half, center.y - half}, {center.x + half, center.y + half}, color, thickness);
+    drawList->AddLine(
+        {center.x + half, center.y - half}, {center.x - half, center.y + half}, color, thickness);
+    return pressed;
 }
 
 } // namespace
@@ -207,10 +225,9 @@ bool render(bool visible) noexcept {
     ImGui::PushStyleVar(ImGuiStyleVar_Alpha, progress);
     const bool submitContents = ImGui::Begin("Sunrise", nullptr, kMainWindowFlags);
     if (submitContents) {
-        // The close action is one press of the configured toggle key, so both paths share the
-        // same visibility state. A surface already closing ignores it, or it would reopen.
-        if (draw_title() && visible) {
-            (void)runtime::toggle_for_key(runtime::snapshot().toggleVirtualKey);
+        // The close action only ever hides, so a surface already closing stays closed.
+        if (draw_title()) {
+            runtime::hide();
         }
         ImGui::Separator();
 

+ 7 - 0
Sunrise/src/core/ui/runtime/ui_visibility_runtime.cpp

@@ -63,4 +63,11 @@ bool toggle_for_key(UINT virtualKey) noexcept {
     return handled;
 }
 
+/** Closes the menu. A menu that is already closed or closing stays that way. */
+void hide() noexcept {
+    AcquireSRWLockExclusive(&g_visibilityLock);
+    g_state.visible = false;
+    ReleaseSRWLockExclusive(&g_visibilityLock);
+}
+
 } // namespace sunrise::core::ui::runtime

+ 3 - 0
Sunrise/src/core/ui/runtime/ui_visibility_runtime.h

@@ -35,4 +35,7 @@ void shutdown() noexcept;
  */
 [[nodiscard]] bool toggle_for_key(UINT virtualKey) noexcept;
 
+/** Closes the menu. A menu that is already closed or closing stays that way. */
+void hide() noexcept;
+
 } // namespace sunrise::core::ui::runtime