From 426837e7d4c564028b1c0ce17bb7c430f4615b4c Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 31 Dec 2023 06:36:26 +0100 Subject: [PATCH] Implement the timer class Support calling ShowNetStartPane multiple times --- .../ZWidget/include/zwidget/core/timer.h | 2 ++ .../ZWidget/include/zwidget/window/window.h | 4 +++ libraries/ZWidget/src/core/timer.cpp | 14 +++++++++ .../ZWidget/src/window/win32/win32window.cpp | 30 +++++++++++++++++++ .../ZWidget/src/window/win32/win32window.h | 6 ++++ libraries/ZWidget/src/window/window.cpp | 20 +++++++++++++ src/common/widgets/netstartwindow.cpp | 22 +++++++++----- src/common/widgets/netstartwindow.h | 3 +- 8 files changed, 93 insertions(+), 8 deletions(-) diff --git a/libraries/ZWidget/include/zwidget/core/timer.h b/libraries/ZWidget/include/zwidget/core/timer.h index 0cbfc8dc89..25e6fb3461 100644 --- a/libraries/ZWidget/include/zwidget/core/timer.h +++ b/libraries/ZWidget/include/zwidget/core/timer.h @@ -20,5 +20,7 @@ private: Timer* PrevTimerObj = nullptr; Timer* NextTimerObj = nullptr; + void* TimerId = nullptr; + friend class Widget; }; diff --git a/libraries/ZWidget/include/zwidget/window/window.h b/libraries/ZWidget/include/zwidget/window/window.h index df852d2b87..5798e787cd 100644 --- a/libraries/ZWidget/include/zwidget/window/window.h +++ b/libraries/ZWidget/include/zwidget/window/window.h @@ -2,6 +2,7 @@ #include #include +#include #include "../core/rect.h" class Engine; @@ -141,6 +142,9 @@ public: static void RunLoop(); static void ExitLoop(); + static void* StartTimer(int timeoutMilliseconds, std::function onTimer); + static void StopTimer(void* timerID); + static Size GetScreenSize(); virtual ~DisplayWindow() = default; diff --git a/libraries/ZWidget/src/core/timer.cpp b/libraries/ZWidget/src/core/timer.cpp index 9e575511c8..4c748561b7 100644 --- a/libraries/ZWidget/src/core/timer.cpp +++ b/libraries/ZWidget/src/core/timer.cpp @@ -1,6 +1,7 @@ #include "core/timer.h" #include "core/widget.h" +#include "window/window.h" Timer::Timer(Widget* owner) : OwnerObj(owner) { @@ -22,8 +23,21 @@ Timer::~Timer() void Timer::Start(int timeoutMilliseconds, bool repeat) { + Stop(); + + TimerId = DisplayWindow::StartTimer(timeoutMilliseconds, [=]() { + if (!repeat) + Stop(); + if (FuncExpired) + FuncExpired(); + }); } void Timer::Stop() { + if (TimerId != 0) + { + DisplayWindow::StopTimer(TimerId); + TimerId = 0; + } } diff --git a/libraries/ZWidget/src/window/win32/win32window.cpp b/libraries/ZWidget/src/window/win32/win32window.cpp index 6ece5f8db4..58a2c9214b 100644 --- a/libraries/ZWidget/src/window/win32/win32window.cpp +++ b/libraries/ZWidget/src/window/win32/win32window.cpp @@ -568,5 +568,35 @@ Size Win32Window::GetScreenSize() return Size(screenWidth / dpiScale, screenHeight / dpiScale); } +static void CALLBACK Win32TimerCallback(HWND handle, UINT message, UINT_PTR timerID, DWORD timestamp) +{ + auto it = Win32Window::Timers.find(timerID); + if (it != Win32Window::Timers.end()) + { + it->second(); + } +} + +void* Win32Window::StartTimer(int timeoutMilliseconds, std::function onTimer) +{ + UINT_PTR result = SetTimer(0, 0, timeoutMilliseconds, Win32TimerCallback); + if (result == 0) + throw std::runtime_error("Could not create timer"); + Timers[result] = std::move(onTimer); + return (void*)result; +} + +void Win32Window::StopTimer(void* timerID) +{ + auto it = Timers.find((UINT_PTR)timerID); + if (it != Timers.end()) + { + Timers.erase(it); + KillTimer(0, (UINT_PTR)timerID); + } +} + std::list Win32Window::Windows; bool Win32Window::ExitRunLoop; + +std::unordered_map> Win32Window::Timers; diff --git a/libraries/ZWidget/src/window/win32/win32window.h b/libraries/ZWidget/src/window/win32/win32window.h index 2db141210e..74f56f18e2 100644 --- a/libraries/ZWidget/src/window/win32/win32window.h +++ b/libraries/ZWidget/src/window/win32/win32window.h @@ -8,6 +8,7 @@ #include #include +#include #include class Win32Window : public DisplayWindow @@ -54,10 +55,15 @@ public: static void ExitLoop(); static Size GetScreenSize(); + static void* StartTimer(int timeoutMilliseconds, std::function onTimer); + static void StopTimer(void* timerID); + static bool ExitRunLoop; static std::list Windows; std::list::iterator WindowsIterator; + static std::unordered_map> Timers; + LRESULT OnWindowMessage(UINT msg, WPARAM wparam, LPARAM lparam); static LRESULT CALLBACK WndProc(HWND windowhandle, UINT msg, WPARAM wparam, LPARAM lparam); diff --git a/libraries/ZWidget/src/window/window.cpp b/libraries/ZWidget/src/window/window.cpp index 9f07eb8019..e32932d652 100644 --- a/libraries/ZWidget/src/window/window.cpp +++ b/libraries/ZWidget/src/window/window.cpp @@ -30,6 +30,16 @@ Size DisplayWindow::GetScreenSize() return Win32Window::GetScreenSize(); } +void* DisplayWindow::StartTimer(int timeoutMilliseconds, std::function onTimer) +{ + return Win32Window::StartTimer(timeoutMilliseconds, std::move(onTimer)); +} + +void DisplayWindow::StopTimer(void* timerID) +{ + Win32Window::StopTimer(timerID); +} + #else std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost) @@ -57,4 +67,14 @@ Size DisplayWindow::GetScreenSize() throw std::runtime_error("DisplayWindow::GetScreenSize not implemented"); } +int DisplayWindow::StartTimer(int timeoutMilliseconds, std::function onTimer) +{ + throw std::runtime_error("DisplayWindow::StartTimer not implemented"); +} + +void DisplayWindow::StopTimer(int timerID) +{ + throw std::runtime_error("DisplayWindow::StopTimer not implemented"); +} + #endif diff --git a/src/common/widgets/netstartwindow.cpp b/src/common/widgets/netstartwindow.cpp index ee6f76fe12..c45f300988 100644 --- a/src/common/widgets/netstartwindow.cpp +++ b/src/common/widgets/netstartwindow.cpp @@ -10,15 +10,18 @@ NetStartWindow* NetStartWindow::Instance = nullptr; void NetStartWindow::ShowNetStartPane(const char* message, int maxpos) { - HideNetStartPane(); - Size screenSize = GetScreenSize(); double windowWidth = 300.0; double windowHeight = 150.0; - Instance = new NetStartWindow(message, maxpos); - Instance->SetFrameGeometry((screenSize.width - windowWidth) * 0.5, (screenSize.height - windowHeight) * 0.5, windowWidth, windowHeight); - Instance->Show(); + if (!Instance) + { + Instance = new NetStartWindow(); + Instance->SetFrameGeometry((screenSize.width - windowWidth) * 0.5, (screenSize.height - windowHeight) * 0.5, windowWidth, windowHeight); + Instance->Show(); + } + + Instance->SetMessage(message, maxpos); } void NetStartWindow::HideNetStartPane() @@ -60,7 +63,7 @@ bool NetStartWindow::RunMessageLoop(bool (*newtimer_callback)(void*), void* newu return Instance->exitreason; } -NetStartWindow::NetStartWindow(const std::string& message, int maxpos) : Widget(nullptr, WidgetType::Window) +NetStartWindow::NetStartWindow() : Widget(nullptr, WidgetType::Window) { SetWindowBackground(Colorf::fromRgba8(51, 51, 51)); SetWindowBorderColor(Colorf::fromRgba8(51, 51, 51)); @@ -78,13 +81,18 @@ NetStartWindow::NetStartWindow(const std::string& message, int maxpos) : Widget( AbortButton->OnClick = [=]() { OnClose(); }; AbortButton->SetText("Abort Network Game"); - MessageLabel->SetText(message); CallbackTimer = new Timer(this); CallbackTimer->FuncExpired = [=]() { OnCallbackTimerExpired(); }; CallbackTimer->Start(500); } +void NetStartWindow::SetMessage(const std::string& message, int newmaxpos) +{ + MessageLabel->SetText(message); + maxpos = newmaxpos; +} + void NetStartWindow::SetProgress(int newpos) { if (pos != newpos && maxpos > 1) diff --git a/src/common/widgets/netstartwindow.h b/src/common/widgets/netstartwindow.h index 8dffa4d709..5d27b8ebfc 100644 --- a/src/common/widgets/netstartwindow.h +++ b/src/common/widgets/netstartwindow.h @@ -16,8 +16,9 @@ public: static bool RunMessageLoop(bool (*timer_callback)(void*), void* userdata); private: - NetStartWindow(const std::string& message, int maxpos); + NetStartWindow(); + void SetMessage(const std::string& message, int maxpos); void SetProgress(int pos); protected: