From 16e578a0f88aac392b33805a72df7b0b1076de2e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 31 Dec 2023 04:15:09 +0100 Subject: [PATCH] Implement NetStartWindow # Conflicts: # src/p_setup.cpp --- .../zwidget/widgets/textlabel/textlabel.h | 11 ++ .../src/widgets/textlabel/textlabel.cpp | 26 ++++- src/common/platform/win32/i_mainwindow.cpp | 7 +- src/common/widgets/netstartwindow.cpp | 108 +++++++++++++++++- src/common/widgets/netstartwindow.h | 36 +++++- 5 files changed, 182 insertions(+), 6 deletions(-) diff --git a/libraries/ZWidget/include/zwidget/widgets/textlabel/textlabel.h b/libraries/ZWidget/include/zwidget/widgets/textlabel/textlabel.h index b5eef01b6..32f250c6c 100644 --- a/libraries/ZWidget/include/zwidget/widgets/textlabel/textlabel.h +++ b/libraries/ZWidget/include/zwidget/widgets/textlabel/textlabel.h @@ -3,6 +3,13 @@ #include "../../core/widget.h" +enum TextLabelAlignment +{ + Left, + Center, + Right +}; + class TextLabel : public Widget { public: @@ -11,6 +18,9 @@ public: void SetText(const std::string& value); const std::string& GetText() const; + void SetTextAlignment(TextLabelAlignment alignment); + TextLabelAlignment GetTextAlignment() const; + double GetPreferredHeight() const; protected: @@ -18,4 +28,5 @@ protected: private: std::string text; + TextLabelAlignment textAlignment = TextLabelAlignment::Left; }; diff --git a/libraries/ZWidget/src/widgets/textlabel/textlabel.cpp b/libraries/ZWidget/src/widgets/textlabel/textlabel.cpp index 5f738db15..3c034ddb2 100644 --- a/libraries/ZWidget/src/widgets/textlabel/textlabel.cpp +++ b/libraries/ZWidget/src/widgets/textlabel/textlabel.cpp @@ -19,6 +19,20 @@ const std::string& TextLabel::GetText() const return text; } +void TextLabel::SetTextAlignment(TextLabelAlignment alignment) +{ + if (textAlignment != alignment) + { + textAlignment = alignment; + Update(); + } +} + +TextLabelAlignment TextLabel::GetTextAlignment() const +{ + return textAlignment; +} + double TextLabel::GetPreferredHeight() const { return 20.0; @@ -26,5 +40,15 @@ double TextLabel::GetPreferredHeight() const void TextLabel::OnPaint(Canvas* canvas) { - canvas->drawText(Point(0.0, GetHeight() - 5.0), Colorf::fromRgba8(255, 255, 255), text); + double x = 0.0; + if (textAlignment == TextLabelAlignment::Center) + { + x = (GetWidth() - canvas->measureText(text).width) * 0.5; + } + else if (textAlignment == TextLabelAlignment::Right) + { + x = GetWidth() - canvas->measureText(text).width; + } + + canvas->drawText(Point(x, GetHeight() - 5.0), Colorf::fromRgba8(255, 255, 255), text); } diff --git a/src/common/platform/win32/i_mainwindow.cpp b/src/common/platform/win32/i_mainwindow.cpp index c660d5e23..b96e556bd 100644 --- a/src/common/platform/win32/i_mainwindow.cpp +++ b/src/common/platform/win32/i_mainwindow.cpp @@ -120,21 +120,22 @@ void MainWindow::ShowErrorPane(const char* text) void MainWindow::ShowNetStartPane(const char* message, int maxpos) { + NetStartWindow::ShowNetStartPane(message, maxpos); } void MainWindow::HideNetStartPane() { + NetStartWindow::HideNetStartPane(); } void MainWindow::SetNetStartProgress(int pos) { + NetStartWindow::SetNetStartProgress(pos); } bool MainWindow::RunMessageLoop(bool (*timer_callback)(void*), void* userdata) { - // To do: pump messages while showing the netstart window and calling timer_callback every 500 ms - // To do: return true if timer_callback returns true and stop pumping. - return false; + return NetStartWindow::RunMessageLoop(timer_callback, userdata); } bool MainWindow::CheckForRestart() diff --git a/src/common/widgets/netstartwindow.cpp b/src/common/widgets/netstartwindow.cpp index 2dabccf33..00c93fc7c 100644 --- a/src/common/widgets/netstartwindow.cpp +++ b/src/common/widgets/netstartwindow.cpp @@ -1,12 +1,118 @@ #include "netstartwindow.h" #include "version.h" +#include +#include +#include -NetStartWindow::NetStartWindow() : Widget(nullptr, WidgetType::Window) +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(); +} + +void NetStartWindow::HideNetStartPane() +{ + delete Instance; + Instance = nullptr; +} + +void NetStartWindow::SetNetStartProgress(int pos) +{ + if (Instance) + Instance->SetProgress(pos); +} + +bool NetStartWindow::RunMessageLoop(bool (*newtimer_callback)(void*), void* newuserdata) +{ + if (!Instance) + return false; + + Instance->timer_callback = newtimer_callback; + Instance->userdata = newuserdata; + + DisplayWindow::RunLoop(); + + Instance->timer_callback = nullptr; + Instance->userdata = nullptr; + + return Instance->exitreason; +} + +NetStartWindow::NetStartWindow(const std::string& message, int maxpos) : Widget(nullptr, WidgetType::Window) { SetWindowBackground(Colorf::fromRgba8(51, 51, 51)); SetWindowBorderColor(Colorf::fromRgba8(51, 51, 51)); SetWindowCaptionColor(Colorf::fromRgba8(33, 33, 33)); SetWindowCaptionTextColor(Colorf::fromRgba8(226, 223, 219)); SetWindowTitle(GAMENAME); + + MessageLabel = new TextLabel(this); + ProgressLabel = new TextLabel(this); + AbortButton = new PushButton(this); + + MessageLabel->SetTextAlignment(TextLabelAlignment::Center); + ProgressLabel->SetTextAlignment(TextLabelAlignment::Center); + + AbortButton->OnClick = [=]() { OnClose(); }; + + AbortButton->SetText("Abort Network Game"); + MessageLabel->SetText(message); + + CallbackTimer = new Timer(this); + CallbackTimer->FuncExpired = [=]() { OnCallbackTimerExpired(); }; + CallbackTimer->Start(500); +} + +void NetStartWindow::SetProgress(int newpos) +{ + if (pos != newpos) + { + pos = newpos; + FString message; + message.Format("%d/%d", pos, maxpos); + ProgressLabel->SetText(message.GetChars()); + } +} + +void NetStartWindow::OnClose() +{ + exitreason = false; + DisplayWindow::ExitLoop(); +} + +void NetStartWindow::OnGeometryChanged() +{ + double w = GetWidth(); + double h = GetHeight(); + + double y = 15.0; + double labelheight = MessageLabel->GetPreferredHeight(); + MessageLabel->SetFrameGeometry(Rect::xywh(5.0, y, w - 10.0, labelheight)); + y += labelheight; + + labelheight = ProgressLabel->GetPreferredHeight(); + ProgressLabel->SetFrameGeometry(Rect::xywh(5.0, y, w - 10.0, labelheight)); + y += labelheight; + + y = GetHeight() - 15.0 - AbortButton->GetPreferredHeight(); + AbortButton->SetFrameGeometry((w - 200.0) * 0.5, y, 200.0, AbortButton->GetPreferredHeight()); +} + +void NetStartWindow::OnCallbackTimerExpired() +{ + if (timer_callback && timer_callback(userdata)) + { + exitreason = true; + DisplayWindow::ExitLoop(); + } } diff --git a/src/common/widgets/netstartwindow.h b/src/common/widgets/netstartwindow.h index 1814b8572..c02927f0e 100644 --- a/src/common/widgets/netstartwindow.h +++ b/src/common/widgets/netstartwindow.h @@ -2,8 +2,42 @@ #include +class TextLabel; +class PushButton; +class Timer; + class NetStartWindow : public Widget { public: - NetStartWindow(); + static void ShowNetStartPane(const char* message, int maxpos); + static void HideNetStartPane(); + static void SetNetStartProgress(int pos); + static bool RunMessageLoop(bool (*timer_callback)(void*), void* userdata); + +private: + NetStartWindow(const std::string& message, int maxpos); + + void SetProgress(int pos); + +protected: + void OnClose() override; + void OnGeometryChanged() override; + +private: + void OnCallbackTimerExpired(); + + TextLabel* MessageLabel = nullptr; + TextLabel* ProgressLabel = nullptr; + PushButton* AbortButton = nullptr; + + Timer* CallbackTimer = nullptr; + + int pos = 0; + int maxpos = 1; + bool (*timer_callback)(void*) = nullptr; + void* userdata = nullptr; + + bool exitreason = false; + + static NetStartWindow* Instance; };