Skip to content

Commit 8366ded

Browse files
committed
feat: Update assets for new Millennium version, and fix some UX issues
1 parent 24ff23e commit 8366ded

6 files changed

Lines changed: 2600 additions & 1783 deletions

File tree

src/animate.cc

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <imgui.h>
3838
#include <memory>
3939
#include <dpi.h>
40+
#include <mutex>
4041

4142
/** Based on https://stackoverflow.com/questions/13462001/ease-in-and-ease-out-animation-formula */
4243
float EaseInOut(float t)
@@ -46,7 +47,7 @@ float EaseInOut(float t)
4647

4748
float EaseInOutFloat(const std::string& id, float lowerBound, float upperBound, bool currentState, float duration)
4849
{
49-
struct AnimationState
50+
struct FloatAnimationState
5051
{
5152
bool wasHovered = false;
5253
bool isAnimating = false;
@@ -59,23 +60,26 @@ float EaseInOutFloat(const std::string& id, float lowerBound, float upperBound,
5960

6061
float lastXDPI = XDPI, lastYDPI = YDPI;
6162

62-
AnimationState() = default;
63-
AnimationState(float lower, float upper)
63+
FloatAnimationState() = default;
64+
FloatAnimationState(float lower, float upper)
6465
: wasHovered(false), isAnimating(false), isReversing(false), elapsedTime(0.0f), currentValue(lower), minValue(lower), maxValue(upper)
6566
{
6667
}
6768
};
6869

69-
static std::unordered_map<std::string, AnimationState> animations;
70+
static std::unordered_map<std::string, FloatAnimationState> animations;
71+
static std::mutex animationsMutex;
72+
73+
std::lock_guard<std::mutex> lock(animationsMutex);
7074

7175
auto it = animations.find(id);
7276
if (it == animations.end()) {
73-
animations[id] = AnimationState(lowerBound, upperBound);
77+
animations[id] = FloatAnimationState(lowerBound, upperBound);
7478
animations[id].currentValue = currentState ? upperBound : lowerBound;
7579
animations[id].wasHovered = currentState;
7680
}
7781

78-
AnimationState& state = animations[id];
82+
FloatAnimationState& state = animations[id];
7983

8084
float deltaTime = ImGui::GetIO().DeltaTime;
8185

@@ -119,6 +123,9 @@ float EaseInOutFloat(const std::string& id, float lowerBound, float upperBound,
119123
float SmoothFloat(const std::string& id, float targetOffset, bool currentState, float displacement, float duration, std::tuple<float, float> colorTransition)
120124
{
121125
static std::unordered_map<std::string, AnimationState> animations;
126+
static std::mutex animationsMutex;
127+
128+
std::lock_guard<std::mutex> lock(animationsMutex);
122129

123130
const auto [lowerBound, upperBound] = colorTransition;
124131
AnimationState& state = animations[id];

src/components/message.cc

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ void ShowMessageBox(std::string title, std::string body, MessageLevel level)
6363
*/
6464
void RenderMessageBoxes()
6565
{
66+
static bool isClosing = false;
67+
6668
if (messageBoxQueue.size() <= 0) {
69+
isClosing = false;
6770
return;
6871
}
6972

@@ -81,15 +84,25 @@ void RenderMessageBoxes()
8184
static const float scrollFriction = 0.95f;
8285
static const float minVelocityThreshold = 0.01f;
8386

84-
float opacityAnimation = EaseInOutFloat("MessageAlertPopupAnimation", 0.f, 1.f, true, 0.3f);
87+
float opacityAnimation = EaseInOutFloat("MessageAlertPopupAnimation", 0.f, 1.f, !isClosing, 0.3f);
88+
89+
// When fade-out animation completes, actually close the popup
90+
if (isClosing && opacityAnimation <= 0.01f) {
91+
CloseCurrentPopup();
92+
messageBoxQueue.pop();
93+
isClosing = false;
94+
hasSkippedFirstFrame = false;
95+
scrollPosition = 0.0f;
96+
scrollVelocity = 0.0f;
97+
}
8598

86-
PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.098f, 0.102f, 0.11f, 1.0f));
87-
PushStyleColor(ImGuiCol_Border, ImVec4(0.48f, 0.484f, 0.492f, 0.5f));
99+
PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.067f, 0.071f, 0.078f, 1.0f));
100+
PushStyleColor(ImGuiCol_Border, ImVec4(0.48f, 0.484f, 0.492f, 0.3f));
88101
PushStyleVar(ImGuiStyleVar_Alpha, opacityAnimation);
89102
PushStyleVar(ImGuiStyleVar_WindowRounding, ScaleX(10.0f));
90103
PushStyleVar(ImGuiStyleVar_WindowBorderSize, ScaleX(1.0f));
91104

92-
SetNextWindowSizeConstraints(ImVec2(ScaleX(500), 0), ImVec2(ScaleX(700), FLT_MAX));
105+
SetNextWindowSizeConstraints(ImVec2(ScaleX(650), 0), ImVec2(ScaleX(900), FLT_MAX));
93106

94107
if (BeginPopupModal("MessageAlertPopup", nullptr,
95108
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove |
@@ -120,9 +133,7 @@ void RenderMessageBoxes()
120133

121134
TextWrapped(currentBox.title.c_str());
122135
PopFont();
123-
SetCursorPosY(GetCursorPosY() + ScaleY(15));
124-
Separator();
125-
SetCursorPosY(GetCursorPosY() + ScaleY(20));
136+
SetCursorPosY(GetCursorPosY() + ScaleY(25));
126137

127138
TextWrapped(currentBox.body.c_str());
128139

@@ -134,25 +145,28 @@ void RenderMessageBoxes()
134145

135146
SetScrollY(scrollPosition);
136147
if (hasSkippedFirstFrame && !ImGui::IsWindowHovered() && ImGui::IsMouseClicked(0)) {
137-
CloseCurrentPopup();
138-
messageBoxQueue.pop();
148+
isClosing = true;
139149
}
140150
hasSkippedFirstFrame = true;
141151

142152
SetCursorPosY(GetCursorPosY() + ScaleY(40));
143153

144154
PushStyleColor(ImGuiCol_Button, ImVec4(1.f, 1.f, 1.f, 1.f));
145155
PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.f, 1.f, 1.f, 1.f));
156+
PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.9f, 0.9f, 0.9f, 1.f));
146157
PushStyleColor(ImGuiCol_Text, ImVec4(0.f, 0.f, 0.f, 1.f));
147158

148159
SetCursorPosX(GetCursorPosX() + GetContentRegionAvail().x - ScaleX(140));
149160

150161
if (Button("Continue", ImVec2(ScaleX(140), ScaleY(50)))) {
151-
CloseCurrentPopup();
152-
messageBoxQueue.pop();
162+
isClosing = true;
163+
}
164+
165+
if (IsItemHovered()) {
166+
SetMouseCursor(ImGuiMouseCursor_Hand);
153167
}
154168

155-
PopStyleColor(3);
169+
PopStyleColor(4);
156170
EndPopup();
157171
}
158172

src/renderer.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ void RenderImGui(GLFWwindow* window, std::shared_ptr<RouterNav> router)
6969
SameLine();
7070
currentPanel(router, xOffsetCurrent);
7171

72-
// if (IsKeyPressed(ImGuiKey_MouseX1)) {
73-
// if (router->canGoBack())
74-
// router->navigateBack();
75-
// }
72+
if (IsKeyPressed(ImGuiKey_MouseX1)) {
73+
if (router->canGoBack())
74+
router->navigateBack();
75+
}
7676
// if (IsKeyPressed(ImGuiKey_MouseX2)) {
7777
// if (router->canGoForward())
7878
// router->navigateNext();

src/routes/installer.cc

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ const void RenderInstaller(std::shared_ptr<RouterNav> router, float xPos)
282282
static float currentY = startY;
283283
static bool shouldAnimate = false;
284284
static bool shouldRenderCompleteModal = false;
285+
static bool isWaitingForProgressComplete = false;
286+
static auto progressCompleteTime = std::chrono::steady_clock::now();
285287

286288
static auto animationStartTime = std::chrono::steady_clock::now();
287289

@@ -338,14 +340,33 @@ const void RenderInstaller(std::shared_ptr<RouterNav> router, float xPos)
338340
}
339341

340342
if (hasTaskSchedulerFinished.load()) {
341-
shouldAnimate = true;
342-
shouldRenderCompleteModal = true;
343-
animationStartTime = std::chrono::steady_clock::now();
344-
345-
/** Reset the flag so it doesn't restart the animation each frame */
343+
isWaitingForProgressComplete = true;
344+
/** Reset the flag so it doesn't restart each frame */
346345
hasTaskSchedulerFinished.store(false);
347346
}
348347

348+
/** Wait for progress bar animation to complete, then wait 0.5 seconds before showing the complete modal */
349+
if (isWaitingForProgressComplete && !shouldRenderCompleteModal) {
350+
if (easedProgress >= 0.99f) {
351+
static bool timerStarted = false;
352+
if (!timerStarted) {
353+
progressCompleteTime = std::chrono::steady_clock::now();
354+
timerStarted = true;
355+
}
356+
357+
auto now = std::chrono::steady_clock::now();
358+
float elapsedTime = std::chrono::duration<float>(now - progressCompleteTime).count();
359+
360+
if (elapsedTime >= 0.5f) {
361+
shouldAnimate = true;
362+
shouldRenderCompleteModal = true;
363+
animationStartTime = std::chrono::steady_clock::now();
364+
isWaitingForProgressComplete = false;
365+
timerStarted = false;
366+
}
367+
}
368+
}
369+
349370
static const float ANIMATION_DURATION = 0.3f;
350371

351372
if (shouldAnimate) {

src/routes/uninstall_select.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ void InitializeUninstaller()
122122
steamPath / "version.dll",
123123
steamPath / "ext" / "compat32" / "millennium_x86.dll",
124124
steamPath / "ext" / "compat32" / "python311.dll",
125+
steamPath / "ext" / "compat64" / "millennium_x64.dll",
126+
steamPath / "ext" / "compat64" / "python311.dll",
125127
steamPath / "millennium.hhx64.dll",
126128
steamPath / "millennium.dll",
127129
steamPath / "python311.dll"
@@ -139,6 +141,9 @@ void InitializeUninstaller()
139141

140142
void StartUninstall()
141143
{
144+
/** Kill Steam before uninstalling */
145+
KillSteamProcess();
146+
142147
/** Render all selected components as uninstalling */
143148
std::for_each(uninstallComponents.begin(), uninstallComponents.end(), [](auto& pair)
144149
{
@@ -152,6 +157,12 @@ void StartUninstall()
152157
if (state.isSelected) {
153158
std::this_thread::sleep_for(std::chrono::milliseconds(300));
154159

160+
/** If the path list is empty, the component is already uninstalled */
161+
if (props.pathList.empty()) {
162+
state.uninstallState.state = ComponentState::UninstallState::Success;
163+
continue;
164+
}
165+
155166
for (const auto& path : props.pathList) {
156167
std::error_code ec;
157168
std::filesystem::remove_all(path, ec); // Remove the path

0 commit comments

Comments
 (0)