diff --git a/libraries/ZWidget/include/zwidget/core/widget.h b/libraries/ZWidget/include/zwidget/core/widget.h index 4eb434aa9..50756bcad 100644 --- a/libraries/ZWidget/include/zwidget/core/widget.h +++ b/libraries/ZWidget/include/zwidget/core/widget.h @@ -104,6 +104,8 @@ public: Point MapToGlobal(const Point& pos) const; Point MapToParent(const Point& pos) const { return MapTo(Parent(), pos); } + static Size GetScreenSize(); + protected: virtual void OnPaintFrame(Canvas* canvas) { } virtual void OnPaint(Canvas* canvas) { } diff --git a/libraries/ZWidget/include/zwidget/window/window.h b/libraries/ZWidget/include/zwidget/window/window.h index 2c084cfcd..63c65ff37 100644 --- a/libraries/ZWidget/include/zwidget/window/window.h +++ b/libraries/ZWidget/include/zwidget/window/window.h @@ -141,6 +141,8 @@ public: static void RunLoop(); static void ExitLoop(); + static Size GetScreenSize(); + virtual ~DisplayWindow() = default; virtual void SetWindowTitle(const std::string& text) = 0; diff --git a/libraries/ZWidget/src/core/widget.cpp b/libraries/ZWidget/src/core/widget.cpp index d6647fce7..4d22c0607 100644 --- a/libraries/ZWidget/src/core/widget.cpp +++ b/libraries/ZWidget/src/core/widget.cpp @@ -592,3 +592,8 @@ void Widget::OnWindowDeactivated() void Widget::OnWindowDpiScaleChanged() { } + +Size Widget::GetScreenSize() +{ + return DisplayWindow::GetScreenSize(); +} diff --git a/libraries/ZWidget/src/widgets/textedit/textedit.cpp b/libraries/ZWidget/src/widgets/textedit/textedit.cpp index 7314b0e68..9ddb5fba4 100644 --- a/libraries/ZWidget/src/widgets/textedit/textedit.cpp +++ b/libraries/ZWidget/src/widgets/textedit/textedit.cpp @@ -966,9 +966,9 @@ void TextEdit::LayoutLines(Canvas* canvas) { line.layout.Clear(); if (!line.text.empty()) - line.layout.AddText(line.text, font, Colorf()); + line.layout.AddText(line.text, font, Colorf::fromRgba8(255, 255, 255)); else - line.layout.AddText(" ", font, Colorf()); // Draw one space character to get the correct height + line.layout.AddText(" ", font, Colorf::fromRgba8(255, 255, 255)); // Draw one space character to get the correct height line.layout.Layout(canvas, GetWidth()); line.box = Rect(draw_pos, line.layout.GetSize()); line.invalidated = false; @@ -989,6 +989,7 @@ void TextEdit::LayoutLines(Canvas* canvas) if (cursor_blink_visible && cursor_pos.y == i) { line.layout.SetCursorPos(cursor_pos.x); + line.layout.SetCursorColor(Colorf::fromRgba8(255, 255, 255)); line.layout.ShowCursor(); } } @@ -1006,8 +1007,8 @@ void TextEdit::OnPaintFrame(Canvas* canvas) { double w = GetFrameGeometry().width; double h = GetFrameGeometry().height; - Colorf bordercolor(200 / 255.0f, 200 / 255.0f, 200 / 255.0f); - canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(255, 255, 255)); + Colorf bordercolor = Colorf::fromRgba8(100, 100, 100); + canvas->fillRect(Rect::xywh(0.0, 0.0, w, h), Colorf::fromRgba8(38, 38, 38)); canvas->fillRect(Rect::xywh(0.0, 0.0, w, 1.0), bordercolor); canvas->fillRect(Rect::xywh(0.0, h - 1.0, w, 1.0), bordercolor); canvas->fillRect(Rect::xywh(0.0, 0.0, 1.0, h - 0.0), bordercolor); diff --git a/libraries/ZWidget/src/window/win32/win32window.cpp b/libraries/ZWidget/src/window/win32/win32window.cpp index 009d9f4cc..3a9b54c48 100644 --- a/libraries/ZWidget/src/window/win32/win32window.cpp +++ b/libraries/ZWidget/src/window/win32/win32window.cpp @@ -481,5 +481,16 @@ void Win32Window::ExitLoop() ExitRunLoop = true; } +Size Win32Window::GetScreenSize() +{ + HDC screenDC = GetDC(0); + int screenWidth = GetDeviceCaps(screenDC, HORZRES); + int screenHeight = GetDeviceCaps(screenDC, VERTRES); + double dpiScale = GetDeviceCaps(screenDC, LOGPIXELSX) / 96.0; + ReleaseDC(0, screenDC); + + return Size(screenWidth / dpiScale, screenHeight / dpiScale); +} + std::list Win32Window::Windows; bool Win32Window::ExitRunLoop; diff --git a/libraries/ZWidget/src/window/win32/win32window.h b/libraries/ZWidget/src/window/win32/win32window.h index 8ecb21538..316e228cd 100644 --- a/libraries/ZWidget/src/window/win32/win32window.h +++ b/libraries/ZWidget/src/window/win32/win32window.h @@ -49,6 +49,7 @@ public: static void ProcessEvents(); static void RunLoop(); static void ExitLoop(); + static Size GetScreenSize(); static bool ExitRunLoop; static std::list Windows; diff --git a/libraries/ZWidget/src/window/window.cpp b/libraries/ZWidget/src/window/window.cpp index e6f82ac3c..9f07eb801 100644 --- a/libraries/ZWidget/src/window/window.cpp +++ b/libraries/ZWidget/src/window/window.cpp @@ -25,6 +25,11 @@ void DisplayWindow::ExitLoop() Win32Window::ExitLoop(); } +Size DisplayWindow::GetScreenSize() +{ + return Win32Window::GetScreenSize(); +} + #else std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost) @@ -47,4 +52,9 @@ void DisplayWindow::ExitLoop() throw std::runtime_error("DisplayWindow::ExitLoop not implemented"); } +Size DisplayWindow::GetScreenSize() +{ + throw std::runtime_error("DisplayWindow::GetScreenSize not implemented"); +} + #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index be4dabe8b..afc3a91f3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -979,6 +979,9 @@ set (PCH_SOURCES common/startscreen/startscreen_generic.cpp common/startscreen/endoom.cpp common/widgets/launcherwindow.cpp + common/widgets/errorwindow.cpp + common/widgets/netstartwindow.cpp + common/widgets/widgetresourcedata.cpp common/fonts/singlelumpfont.cpp common/fonts/singlepicfont.cpp common/fonts/specialfont.cpp diff --git a/src/common/engine/st_start.h b/src/common/engine/st_start.h index 8e02987d6..a8b78aaa8 100644 --- a/src/common/engine/st_start.h +++ b/src/common/engine/st_start.h @@ -39,7 +39,7 @@ class FStartupScreen { public: - static FStartupScreen *CreateInstance(int max_progress, bool showprogress); + static FStartupScreen *CreateInstance(int max_progress); FStartupScreen(int max_progress) { @@ -66,7 +66,7 @@ protected: class FBasicStartupScreen : public FStartupScreen { public: - FBasicStartupScreen(int max_progress, bool show_bar); + FBasicStartupScreen(int max_progress); ~FBasicStartupScreen(); void Progress(); diff --git a/src/common/platform/posix/cocoa/st_start.mm b/src/common/platform/posix/cocoa/st_start.mm index 8e4ae4bf9..ee6ea2627 100644 --- a/src/common/platform/posix/cocoa/st_start.mm +++ b/src/common/platform/posix/cocoa/st_start.mm @@ -45,7 +45,7 @@ // --------------------------------------------------------------------------- -FBasicStartupScreen::FBasicStartupScreen(int maxProgress, bool showBar) +FBasicStartupScreen::FBasicStartupScreen(int maxProgress) : FStartupScreen(maxProgress) { FConsoleWindow& consoleWindow = FConsoleWindow::GetInstance(); @@ -132,7 +132,7 @@ bool FBasicStartupScreen::NetLoop(bool (*timerCallback)(void*), void* const user // --------------------------------------------------------------------------- -FStartupScreen *FStartupScreen::CreateInstance(const int maxProgress, bool showprogress) +FStartupScreen *FStartupScreen::CreateInstance(const int maxProgress) { - return new FBasicStartupScreen(maxProgress, showprogress); + return new FBasicStartupScreen(maxProgress); } diff --git a/src/common/platform/posix/sdl/st_start.cpp b/src/common/platform/posix/sdl/st_start.cpp index c068e682a..019a66122 100644 --- a/src/common/platform/posix/sdl/st_start.cpp +++ b/src/common/platform/posix/sdl/st_start.cpp @@ -85,7 +85,7 @@ static const char SpinnyProgressChars[4] = { '|', '/', '-', '\\' }; // //========================================================================== -FStartupScreen *FStartupScreen::CreateInstance(int max_progress, bool) +FStartupScreen *FStartupScreen::CreateInstance(int max_progress) { return new FTTYStartupScreen(max_progress); } diff --git a/src/common/platform/win32/i_main.cpp b/src/common/platform/win32/i_main.cpp index c28a3ff4b..d1f82e59a 100644 --- a/src/common/platform/win32/i_main.cpp +++ b/src/common/platform/win32/i_main.cpp @@ -132,8 +132,6 @@ bool FancyStdOut, AttachedStdOut; void I_SetIWADInfo() { - // Make the startup banner show itself - mainwindow.UpdateLayout(); } //========================================================================== @@ -266,7 +264,14 @@ int DoMain (HINSTANCE hInstance) atexit ([](){ CoUninitialize(); }); // beware of calling convention. int ret = GameMain (); - mainwindow.CheckForRestart(); + + if (mainwindow.CheckForRestart()) + { + HMODULE hModule = GetModuleHandleW(NULL); + WCHAR path[MAX_PATH]; + GetModuleFileNameW(hModule, path, MAX_PATH); + ShellExecuteW(NULL, L"open", path, GetCommandLineW(), NULL, SW_SHOWNORMAL); + } DestroyCustomCursor(); if (ret == 1337) // special exit code for 'norun'. diff --git a/src/common/platform/win32/i_mainwindow.cpp b/src/common/platform/win32/i_mainwindow.cpp index c97f4e88c..27dac7c60 100644 --- a/src/common/platform/win32/i_mainwindow.cpp +++ b/src/common/platform/win32/i_mainwindow.cpp @@ -11,6 +11,8 @@ #include "v_font.h" #include "i_net.h" #include "engineerrors.h" +#include "common/widgets/errorwindow.h" +#include "common/widgets/netstartwindow.h" #include #include #include @@ -18,14 +20,6 @@ #pragma comment(lib, "dwmapi.lib") -#ifdef _M_X64 -#define X64 " 64-bit" -#elif _M_ARM64 -#define X64 " ARM-64" -#else -#define X64 "" -#endif - MainWindow mainwindow; void MainWindow::Create(const FString& caption, int x, int y, int width, int height) @@ -81,29 +75,6 @@ void MainWindow::Create(const FString& caption, int x, int y, int width, int hei DwmSetWindowAttribute(Window, 36/*DWMWA_TEXT_COLOR*/, &textcolor, sizeof(uint32_t)); } -void MainWindow::HideGameTitleWindow() -{ - if (GameTitleWindow != 0) - { - DestroyWindow(GameTitleWindow); - GameTitleWindow = 0; - } -} - -int MainWindow::GetGameTitleWindowHeight() -{ - if (GameTitleWindow != 0) - { - RECT rect; - GetClientRect(GameTitleWindow, &rect); - return rect.bottom; - } - else - { - return 0; - } -} - // Sets the main WndProc, hides all the child windows, and starts up in-game input. void MainWindow::ShowGameView() { @@ -111,10 +82,6 @@ void MainWindow::ShowGameView() { SetWindowLongPtr(Window, GWLP_USERDATA, 1); SetWindowLongPtr(Window, GWLP_WNDPROC, (LONG_PTR)WndProc); - ShowWindow(ConWindow, SW_HIDE); - ShowWindow(ProgressBar, SW_HIDE); - ConWindowHidden = true; - ShowWindow(GameTitleWindow, SW_HIDE); I_InitInput(Window); } } @@ -122,766 +89,87 @@ void MainWindow::ShowGameView() // Returns the main window to its startup state. void MainWindow::RestoreConView() { - HDC screenDC = GetDC(0); - int dpi = GetDeviceCaps(screenDC, LOGPIXELSX); - ReleaseDC(0, screenDC); - int width = (512 * dpi + 96 / 2) / 96; - int height = (384 * dpi + 96 / 2) / 96; - - // Make sure the window has a frame in case it was fullscreened. - SetWindowLongPtr(Window, GWL_STYLE, WS_VISIBLE | WS_OVERLAPPEDWINDOW); - if (GetWindowLong(Window, GWL_EXSTYLE) & WS_EX_TOPMOST) - { - SetWindowPos(Window, HWND_BOTTOM, 0, 0, width, height, SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_NOMOVE); - SetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE); - } - else - { - SetWindowPos(Window, NULL, 0, 0, width, height, SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER); - } - - SetWindowLongPtr(Window, GWLP_WNDPROC, (LONG_PTR)LConProc); - ShowWindow(ConWindow, SW_SHOW); - ConWindowHidden = false; - ShowWindow(GameTitleWindow, SW_SHOW); I_ShutdownInput(); // Make sure the mouse pointer is available. + ShowWindow(Window, SW_HIDE); + // Make sure the progress bar isn't visible. DeleteStartupScreen(); - - FlushBufferedConsoleStuff(); } // Shows an error message, preferably in the main window, but it can use a normal message box too. void MainWindow::ShowErrorPane(const char* text) { - auto widetext = WideString(text); - if (Window == nullptr || ConWindow == nullptr) - { - if (text != NULL) - { - FStringf caption("Fatal Error - " GAMENAME " %s " X64 " (%s)", GetVersionString(), GetGitTime()); - MessageBoxW(Window, widetext.c_str(),caption.WideString().c_str(), MB_OK | MB_ICONSTOP | MB_TASKMODAL); - } - return; - } - - if (StartWindow != NULL) // Ensure that the network pane is hidden. + if (StartWindow) // Ensure that the network pane is hidden. { I_NetDone(); } - if (text != NULL) - { - FStringf caption("Fatal Error - " GAMENAME " %s " X64 " (%s)", GetVersionString(), GetGitTime()); - auto wcaption = caption.WideString(); - SetWindowTextW(Window, wcaption.c_str()); - ErrorIcon = CreateWindowExW(WS_EX_NOPARENTNOTIFY, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_OWNERDRAW, 0, 0, 0, 0, Window, NULL, GetModuleHandle(0), NULL); - if (ErrorIcon != NULL) - { - SetWindowLong(ErrorIcon, GWL_ID, IDC_ICONPIC); - } - } - ErrorPane = CreateDialogParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_ERRORPANE), Window, ErrorPaneProc, (LONG_PTR)NULL); - if (text != NULL) - { - CHARRANGE end; - CHARFORMAT2 oldformat, newformat; - PARAFORMAT2 paraformat; + PrintStr(text); - // Append the error message to the log. - end.cpMax = end.cpMin = GetWindowTextLength(ConWindow); - SendMessage(ConWindow, EM_EXSETSEL, 0, (LPARAM)&end); + size_t totalsize = 0; + for (const FString& line : bufferedConsoleStuff) + totalsize += line.Len(); - // Remember current charformat. - oldformat.cbSize = sizeof(oldformat); - SendMessage(ConWindow, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&oldformat); + std::string alltext; + alltext.reserve(totalsize); + for (const FString& line : bufferedConsoleStuff) + alltext.append(line.GetChars(), line.Len()); - // Use bigger font and standout colors. - newformat.cbSize = sizeof(newformat); - newformat.dwMask = CFM_BOLD | CFM_COLOR | CFM_SIZE; - newformat.dwEffects = CFE_BOLD; - newformat.yHeight = oldformat.yHeight * 5 / 4; - newformat.crTextColor = RGB(255, 170, 170); - SendMessage(ConWindow, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&newformat); - - // Indent the rest of the text to make the error message stand out a little more. - paraformat.cbSize = sizeof(paraformat); - paraformat.dwMask = PFM_STARTINDENT | PFM_OFFSETINDENT | PFM_RIGHTINDENT; - paraformat.dxStartIndent = paraformat.dxOffset = paraformat.dxRightIndent = 120; - SendMessage(ConWindow, EM_SETPARAFORMAT, 0, (LPARAM)¶format); - SendMessageW(ConWindow, EM_REPLACESEL, FALSE, (LPARAM)L"\n"); - - // Find out where the error lines start for the error icon display control. - SendMessage(ConWindow, EM_EXGETSEL, 0, (LPARAM)&end); - ErrorIconChar = end.cpMax; - - // Now start adding the actual error message. - SendMessageW(ConWindow, EM_REPLACESEL, FALSE, (LPARAM)L"Execution could not continue.\n\n"); - - // Restore old charformat but with light yellow text. - oldformat.crTextColor = RGB(255, 255, 170); - SendMessage(ConWindow, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&oldformat); - - // Add the error text. - SendMessageW(ConWindow, EM_REPLACESEL, FALSE, (LPARAM)widetext.c_str()); - - // Make sure the error text is not scrolled below the window. - SendMessage(ConWindow, EM_LINESCROLL, 0, SendMessage(ConWindow, EM_GETLINECOUNT, 0, 0)); - // The above line scrolled everything off the screen, so pretend to move the scroll - // bar thumb, which clamps to not show any extra lines if it doesn't need to. - SendMessage(ConWindow, EM_SCROLL, SB_PAGEDOWN, 0); - } - - BOOL bRet; - MSG msg; - - while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) - { - if (bRet == -1) - { - MessageBoxW(Window, widetext.c_str(), WGAMENAME " Fatal Error", MB_OK | MB_ICONSTOP | MB_TASKMODAL); - return; - } - else if (!IsDialogMessage(ErrorPane, &msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } -} - -void MainWindow::ShowProgressBar(int maxpos) -{ - if (ProgressBar == 0) - ProgressBar = CreateWindowEx(0, PROGRESS_CLASS, 0, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, 0, 0, 0, 0, Window, 0, GetModuleHandle(0), 0); - SendMessage(ProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, maxpos)); - LayoutMainWindow(Window, 0); -} - -void MainWindow::HideProgressBar() -{ - if (ProgressBar != 0) - { - DestroyWindow(ProgressBar); - ProgressBar = 0; - LayoutMainWindow(Window, 0); - } -} - -void MainWindow::SetProgressPos(int pos) -{ - if (ProgressBar != 0) - SendMessage(ProgressBar, PBM_SETPOS, pos, 0); -} - -// DialogProc for the network startup pane. It just waits for somebody to click a button, and the only button available is the abort one. -static INT_PTR CALLBACK NetStartPaneProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_COMMAND && HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDCANCEL) - { - PostMessage(hDlg, WM_COMMAND, 1337, 1337); - return TRUE; - } - return FALSE; + ErrorWindow::ExecModal(alltext); } void MainWindow::ShowNetStartPane(const char* message, int maxpos) { - // Create the dialog child window - if (NetStartPane == NULL) - { - NetStartPane = CreateDialogParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_NETSTARTPANE), Window, NetStartPaneProc, 0); - if (ProgressBar != 0) - { - DestroyWindow(ProgressBar); - ProgressBar = 0; - } - RECT winrect; - GetWindowRect(Window, &winrect); - SetWindowPos(Window, NULL, 0, 0, - winrect.right - winrect.left, winrect.bottom - winrect.top + LayoutNetStartPane(NetStartPane, 0), - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER); - LayoutMainWindow(Window, NULL); - SetFocus(NetStartPane); - } - - // Set the message text - std::wstring wmessage = WideString(message); - SetDlgItemTextW(NetStartPane, IDC_NETSTARTMESSAGE, wmessage.c_str()); - - // Set the progress bar range - NetStartMaxPos = maxpos; - HWND ctl = GetDlgItem(NetStartPane, IDC_NETSTARTPROGRESS); - if (maxpos == 0) - { - SendMessage(ctl, PBM_SETMARQUEE, TRUE, 100); - SetWindowLong(ctl, GWL_STYLE, GetWindowLong(ctl, GWL_STYLE) | PBS_MARQUEE); - SetDlgItemTextW(NetStartPane, IDC_NETSTARTCOUNT, L""); - } - else - { - SendMessage(ctl, PBM_SETMARQUEE, FALSE, 0); - SetWindowLong(ctl, GWL_STYLE, GetWindowLong(ctl, GWL_STYLE) & (~PBS_MARQUEE)); - - SendMessage(ctl, PBM_SETRANGE, 0, MAKELPARAM(0, maxpos)); - if (maxpos == 1) - { - SendMessage(ctl, PBM_SETPOS, 1, 0); - SetDlgItemTextW(NetStartPane, IDC_NETSTARTCOUNT, L""); - } - } } void MainWindow::HideNetStartPane() { - if (NetStartPane != 0) - { - DestroyWindow(NetStartPane); - NetStartPane = 0; - LayoutMainWindow(Window, 0); - } } void MainWindow::SetNetStartProgress(int pos) { - if (NetStartPane != 0 && NetStartMaxPos > 1) - { - char buf[16]; - mysnprintf(buf, sizeof(buf), "%d/%d", pos, NetStartMaxPos); - SetDlgItemTextA(NetStartPane, IDC_NETSTARTCOUNT, buf); - SendDlgItemMessage(NetStartPane, IDC_NETSTARTPROGRESS, PBM_SETPOS, min(pos, NetStartMaxPos), 0); - } } bool MainWindow::RunMessageLoop(bool (*timer_callback)(void*), void* userdata) { - BOOL bRet; - MSG msg; - - if (SetTimer(Window, 1337, 500, NULL) == 0) - { - I_FatalError("Could not set network synchronization timer."); - } - - while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) - { - if (bRet == -1) - { - KillTimer(Window, 1337); - return false; - } - else - { - // This must be outside the window function so that the exception does not cross DLL boundaries. - if (msg.message == WM_COMMAND && msg.wParam == 1337 && msg.lParam == 1337) - { - throw CExitEvent(0); - } - if (msg.message == WM_TIMER && msg.hwnd == Window && msg.wParam == 1337) - { - if (timer_callback(userdata)) - { - KillTimer(Window, 1337); - return true; - } - } - if (!IsDialogMessage(NetStartPane, &msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - } - KillTimer(Window, 1337); + // 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; } -void MainWindow::UpdateLayout() +bool MainWindow::CheckForRestart() { - LayoutMainWindow(Window, 0); -} - -// Lays out the main window with the game title and log controls and possibly the error pane and progress bar. -void MainWindow::LayoutMainWindow(HWND hWnd, HWND pane) -{ - RECT rect; - int errorpaneheight = 0; - int bannerheight = 0; - int progressheight = 0; - int netpaneheight = 0; - int leftside = 0; - int w, h; - - GetClientRect(hWnd, &rect); - w = rect.right; - h = rect.bottom; - - if (GameStartupInfo.Name.IsNotEmpty() && GameTitleWindow != NULL) - { - bannerheight = GameTitleFontHeight + 5; - MoveWindow(GameTitleWindow, 0, 0, w, bannerheight, TRUE); - InvalidateRect(GameTitleWindow, NULL, FALSE); - } - if (ProgressBar != NULL) - { - // Base the height of the progress bar on the height of a scroll bar - // arrow, just as in the progress bar example. - progressheight = GetSystemMetrics(SM_CYVSCROLL); - MoveWindow(ProgressBar, 0, h - progressheight, w, progressheight, TRUE); - } - if (NetStartPane != NULL) - { - netpaneheight = LayoutNetStartPane(NetStartPane, w); - SetWindowPos(NetStartPane, HWND_TOP, 0, h - progressheight - netpaneheight, w, netpaneheight, SWP_SHOWWINDOW); - } - if (pane != NULL) - { - errorpaneheight = LayoutErrorPane(pane, w); - SetWindowPos(pane, HWND_TOP, 0, h - progressheight - netpaneheight - errorpaneheight, w, errorpaneheight, 0); - } - if (ErrorIcon != NULL) - { - leftside = GetSystemMetrics(SM_CXICON) + 6; - MoveWindow(ErrorIcon, 0, bannerheight, leftside, h - bannerheight - errorpaneheight - progressheight - netpaneheight, TRUE); - } - // The log window uses whatever space is left. - MoveWindow(ConWindow, leftside, bannerheight, w - leftside, h - bannerheight - errorpaneheight - progressheight - netpaneheight, TRUE); -} - -// Lays out the error pane to the desired width, returning the required height. -int MainWindow::LayoutErrorPane(HWND pane, int w) -{ - HWND ctl, ctl_two; - RECT rectc, rectc_two; - - // Right-align the Quit button. - ctl = GetDlgItem(pane, IDOK); - GetClientRect(ctl, &rectc); // Find out how big it is. - MoveWindow(ctl, w - rectc.right - 1, 1, rectc.right, rectc.bottom, TRUE); - - // Second-right-align the Restart button - ctl_two = GetDlgItem(pane, IDC_BUTTON1); - GetClientRect(ctl_two, &rectc_two); // Find out how big it is. - MoveWindow(ctl_two, w - rectc.right - rectc_two.right - 2, 1, rectc.right, rectc.bottom, TRUE); - - InvalidateRect(ctl, NULL, TRUE); - InvalidateRect(ctl_two, NULL, TRUE); - - // Return the needed height for this layout - return rectc.bottom + 2; -} - -// Lays out the network startup pane to the specified width, returning its required height. -int MainWindow::LayoutNetStartPane(HWND pane, int w) -{ - HWND ctl; - RECT margin, rectc; - int staticheight, barheight; - - // Determine margin sizes. - SetRect(&margin, 7, 7, 0, 0); - MapDialogRect(pane, &margin); - - // Stick the message text in the upper left corner. - ctl = GetDlgItem(pane, IDC_NETSTARTMESSAGE); - GetClientRect(ctl, &rectc); - MoveWindow(ctl, margin.left, margin.top, rectc.right, rectc.bottom, TRUE); - - // Stick the count text in the upper right corner. - ctl = GetDlgItem(pane, IDC_NETSTARTCOUNT); - GetClientRect(ctl, &rectc); - MoveWindow(ctl, w - rectc.right - margin.left, margin.top, rectc.right, rectc.bottom, TRUE); - staticheight = rectc.bottom; - - // Stretch the progress bar to fill the entire width. - ctl = GetDlgItem(pane, IDC_NETSTARTPROGRESS); - barheight = GetSystemMetrics(SM_CYVSCROLL); - MoveWindow(ctl, margin.left, margin.top * 2 + staticheight, w - margin.left * 2, barheight, TRUE); - - // Center the abort button underneath the progress bar. - ctl = GetDlgItem(pane, IDCANCEL); - GetClientRect(ctl, &rectc); - MoveWindow(ctl, (w - rectc.right) / 2, margin.top * 3 + staticheight + barheight, rectc.right, rectc.bottom, TRUE); - - return margin.top * 4 + staticheight + barheight + rectc.bottom; -} - -void MainWindow::CheckForRestart() -{ - if (restartrequest) - { - HMODULE hModule = GetModuleHandleW(NULL); - WCHAR path[MAX_PATH]; - GetModuleFileNameW(hModule, path, MAX_PATH); - ShellExecuteW(NULL, L"open", path, GetCommandLineW(), NULL, SW_SHOWNORMAL); - } + bool result = restartrequest; restartrequest = false; + return result; } // The main window's WndProc during startup. During gameplay, the WndProc in i_input.cpp is used instead. LRESULT MainWindow::LConProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - return mainwindow.OnMessage(hWnd, msg, wParam, lParam); -} - -INT_PTR MainWindow::ErrorPaneProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_INITDIALOG: - // Appear in the main window. - mainwindow.LayoutMainWindow(GetParent(hDlg), hDlg); - return TRUE; - - case WM_COMMAND: - if (HIWORD(wParam) == BN_CLICKED) - { - if (LOWORD(wParam) == IDC_BUTTON1) // we pressed the restart button, so run GZDoom again - { - mainwindow.restartrequest = true; - } - PostQuitMessage(0); - return TRUE; - } - break; - } - return FALSE; -} - -LRESULT MainWindow::OnMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_CREATE: return OnCreate(hWnd, msg, wParam, lParam); - case WM_SIZE: return OnSize(hWnd, msg, wParam, lParam); - case WM_DRAWITEM: return OnDrawItem(hWnd, msg, wParam, lParam); - case WM_COMMAND: return OnCommand(hWnd, msg, wParam, lParam); - case WM_CLOSE: return OnClose(hWnd, msg, wParam, lParam); - case WM_DESTROY: return OnDestroy(hWnd, msg, wParam, lParam); - default: return DefWindowProc(hWnd, msg, wParam, lParam); - } -} - -LRESULT MainWindow::OnCreate(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - HWND view; - HDC hdc; - HGDIOBJ oldfont; - LOGFONT lf; - TEXTMETRIC tm; - CHARFORMAT2W format; - - HINSTANCE inst = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hWnd, GWLP_HINSTANCE); - - // Create game title static control - memset(&lf, 0, sizeof(lf)); - hdc = GetDC(hWnd); - lf.lfHeight = -MulDiv(12, GetDeviceCaps(hdc, LOGPIXELSY), 72); - lf.lfCharSet = ANSI_CHARSET; - lf.lfWeight = FW_BOLD; - lf.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN; - wcscpy(lf.lfFaceName, L"Trebuchet MS"); - GameTitleFont = CreateFontIndirect(&lf); - - oldfont = SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); - GetTextMetrics(hdc, &tm); - DefaultGUIFontHeight = tm.tmHeight; - if (GameTitleFont == NULL) - { - GameTitleFontHeight = DefaultGUIFontHeight; - } - else - { - SelectObject(hdc, GameTitleFont); - GetTextMetrics(hdc, &tm); - GameTitleFontHeight = tm.tmHeight; - } - SelectObject(hdc, oldfont); - - // Create log read-only edit control - view = CreateWindowExW(WS_EX_NOPARENTNOTIFY, L"RichEdit20W", nullptr, - WS_CHILD | WS_VISIBLE | WS_VSCROLL | - ES_LEFT | ES_MULTILINE | WS_CLIPSIBLINGS, - 0, 0, 0, 0, - hWnd, NULL, inst, NULL); - HRESULT hr; - hr = GetLastError(); - if (view == NULL) - { - ReleaseDC(hWnd, hdc); - return -1; - } - SendMessage(view, EM_SETREADONLY, TRUE, 0); - SendMessage(view, EM_EXLIMITTEXT, 0, 0x7FFFFFFE); - SendMessage(view, EM_SETBKGNDCOLOR, 0, RGB(70, 70, 70)); - // Setup default font for the log. - //SendMessage (view, WM_SETFONT, (WPARAM)GetStockObject (DEFAULT_GUI_FONT), FALSE); - format.cbSize = sizeof(format); - format.dwMask = CFM_BOLD | CFM_COLOR | CFM_FACE | CFM_SIZE | CFM_CHARSET; - format.dwEffects = 0; - format.yHeight = 200; - format.crTextColor = RGB(223, 223, 223); - format.bCharSet = ANSI_CHARSET; - format.bPitchAndFamily = FF_SWISS | VARIABLE_PITCH; - wcscpy(format.szFaceName, L"DejaVu Sans"); // At least I have it. :p - SendMessageW(view, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&format); - - ConWindow = view; - ReleaseDC(hWnd, hdc); - - view = CreateWindowExW(WS_EX_NOPARENTNOTIFY, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SS_OWNERDRAW, 0, 0, 0, 0, hWnd, nullptr, inst, nullptr); - if (view == nullptr) - { - return -1; - } - SetWindowLong(view, GWL_ID, IDC_STATIC_TITLE); - GameTitleWindow = view; - - return 0; -} - -LRESULT MainWindow::OnSize(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (wParam != SIZE_MAXHIDE && wParam != SIZE_MAXSHOW) - { - LayoutMainWindow(hWnd, ErrorPane); - } - return 0; -} - -LRESULT MainWindow::OnDrawItem(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - HGDIOBJ oldfont; - HBRUSH hbr; - DRAWITEMSTRUCT* drawitem; - RECT rect; - SIZE size; - - // Draw title banner. - if (wParam == IDC_STATIC_TITLE && GameStartupInfo.Name.IsNotEmpty()) - { - const PalEntry* c; - - // Draw the game title strip at the top of the window. - drawitem = (LPDRAWITEMSTRUCT)lParam; - - // Draw the background. - rect = drawitem->rcItem; - rect.bottom -= 1; - c = (const PalEntry*)&GameStartupInfo.BkColor; - hbr = CreateSolidBrush(RGB(c->r, c->g, c->b)); - FillRect(drawitem->hDC, &drawitem->rcItem, hbr); - DeleteObject(hbr); - - // Calculate width of the title string. - SetTextAlign(drawitem->hDC, TA_TOP); - oldfont = SelectObject(drawitem->hDC, GameTitleFont != NULL ? GameTitleFont : (HFONT)GetStockObject(DEFAULT_GUI_FONT)); - auto widename = GameStartupInfo.Name.WideString(); - GetTextExtentPoint32W(drawitem->hDC, widename.c_str(), (int)widename.length(), &size); - - // Draw the title. - c = (const PalEntry*)&GameStartupInfo.FgColor; - SetTextColor(drawitem->hDC, RGB(c->r, c->g, c->b)); - SetBkMode(drawitem->hDC, TRANSPARENT); - TextOutW(drawitem->hDC, rect.left + (rect.right - rect.left - size.cx) / 2, 2, widename.c_str(), (int)widename.length()); - SelectObject(drawitem->hDC, oldfont); - return TRUE; - } - // Draw stop icon. - else if (wParam == IDC_ICONPIC) - { - HICON icon; - POINTL char_pos; - drawitem = (LPDRAWITEMSTRUCT)lParam; - - // This background color should match the edit control's. - hbr = CreateSolidBrush(RGB(70, 70, 70)); - FillRect(drawitem->hDC, &drawitem->rcItem, hbr); - DeleteObject(hbr); - - // Draw the icon aligned with the first line of error text. - SendMessage(ConWindow, EM_POSFROMCHAR, (WPARAM)&char_pos, ErrorIconChar); - icon = (HICON)LoadImage(0, IDI_ERROR, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); - DrawIcon(drawitem->hDC, 6, char_pos.y, icon); - return TRUE; - } - return FALSE; -} - -LRESULT MainWindow::OnCommand(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (ErrorIcon != NULL && (HWND)lParam == ConWindow && HIWORD(wParam) == EN_UPDATE) - { - // Be sure to redraw the error icon if the edit control changes. - InvalidateRect(ErrorIcon, NULL, TRUE); - return 0; - } - return DefWindowProc(hWnd, msg, wParam, lParam); -} - -LRESULT MainWindow::OnClose(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - PostQuitMessage(0); - return DefWindowProc(hWnd, msg, wParam, lParam); -} - -LRESULT MainWindow::OnDestroy(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (GameTitleFont != NULL) - { - DeleteObject(GameTitleFont); - } return DefWindowProc(hWnd, msg, wParam, lParam); } void MainWindow::PrintStr(const char* cp) { - if (ConWindowHidden) - { - bufferedConsoleStuff.Push(cp); - } - else - { - DoPrintStr(cp); - } -} - -void MainWindow::FlushBufferedConsoleStuff() -{ - for (unsigned i = 0; i < bufferedConsoleStuff.Size(); i++) - { - DoPrintStr(bufferedConsoleStuff[i].GetChars()); - } - bufferedConsoleStuff.Clear(); -} - -void MainWindow::DoPrintStr(const char* cpt) -{ - wchar_t wbuf[256]; - int bpos = 0; - CHARRANGE selection = {}; - CHARRANGE endselection = {}; - LONG lines_before = 0, lines_after = 0; - - // Store the current selection and set it to the end so we can append text. - SendMessage(ConWindow, EM_EXGETSEL, 0, (LPARAM)&selection); - endselection.cpMax = endselection.cpMin = GetWindowTextLength(ConWindow); - SendMessage(ConWindow, EM_EXSETSEL, 0, (LPARAM)&endselection); - - // GetWindowTextLength and EM_EXSETSEL can disagree on where the end of - // the text is. Find out what EM_EXSETSEL thought it was and use that later. - SendMessage(ConWindow, EM_EXGETSEL, 0, (LPARAM)&endselection); - - // Remember how many lines there were before we added text. - lines_before = (LONG)SendMessage(ConWindow, EM_GETLINECOUNT, 0, 0); - - const uint8_t* cptr = (const uint8_t*)cpt; - - auto outputIt = [&]() - { - wbuf[bpos] = 0; - SendMessageW(ConWindow, EM_REPLACESEL, FALSE, (LPARAM)wbuf); - bpos = 0; - }; - - while (int chr = GetCharFromString(cptr)) - { - if ((chr == TEXTCOLOR_ESCAPE && bpos != 0) || bpos == 255) - { - outputIt(); - } - if (chr != TEXTCOLOR_ESCAPE) - { - if (chr >= 0x1D && chr <= 0x1F) - { // The bar characters, most commonly used to indicate map changes - chr = 0x2550; // Box Drawings Double Horizontal - } - wbuf[bpos++] = chr; - } - else - { - EColorRange range = V_ParseFontColor(cptr, CR_UNTRANSLATED, CR_YELLOW); - - if (range != CR_UNDEFINED) - { - // Change the color of future text added to the control. - PalEntry color = V_LogColorFromColorRange(range); - - // Change the color. - CHARFORMAT format; - format.cbSize = sizeof(format); - format.dwMask = CFM_COLOR; - format.dwEffects = 0; - format.crTextColor = RGB(color.r, color.g, color.b); - SendMessage(ConWindow, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format); - } - } - } - if (bpos != 0) - { - outputIt(); - } - - // If the old selection was at the end of the text, keep it at the end and - // scroll. Don't scroll if the selection is anywhere else. - if (selection.cpMin == endselection.cpMin && selection.cpMax == endselection.cpMax) - { - selection.cpMax = selection.cpMin = GetWindowTextLength(ConWindow); - lines_after = (LONG)SendMessage(ConWindow, EM_GETLINECOUNT, 0, 0); - if (lines_after > lines_before) - { - SendMessage(ConWindow, EM_LINESCROLL, 0, lines_after - lines_before); - } - } - // Restore the previous selection. - SendMessage(ConWindow, EM_EXSETSEL, 0, (LPARAM)&selection); - // Give the edit control a chance to redraw itself. - I_GetEvent(); -} - -static DWORD CALLBACK WriteLogFileStreamer(DWORD_PTR cookie, LPBYTE buffer, LONG cb, LONG* pcb) -{ - uint32_t didwrite; - LONG p, pp; - - // Replace gray foreground color with black. - static const char* badfg = "\\red223\\green223\\blue223;"; - // 4321098 765432109 876543210 - // 2 1 0 - for (p = pp = 0; p < cb; ++p) - { - if (buffer[p] == badfg[pp]) - { - ++pp; - if (pp == 25) - { - buffer[p - 1] = buffer[p - 2] = buffer[p - 3] = - buffer[p - 9] = buffer[p - 10] = buffer[p - 11] = - buffer[p - 18] = buffer[p - 19] = buffer[p - 20] = '0'; - break; - } - } - else - { - pp = 0; - } - } - - auto& writeData = *reinterpret_cast*>(cookie); - if (!writeData((const void*)buffer, cb, didwrite)) - { - return 1; - } - *pcb = didwrite; - return 0; + bufferedConsoleStuff.Push(cp); } void MainWindow::GetLog(std::function writeData) { - FlushBufferedConsoleStuff(); - - EDITSTREAM streamer = { (DWORD_PTR)&writeData, 0, WriteLogFileStreamer }; - SendMessage(ConWindow, EM_STREAMOUT, SF_RTF, (LPARAM)&streamer); + for (const FString& line : bufferedConsoleStuff) + { + size_t pos = 0; + size_t len = line.Len(); + while (pos < len) + { + uint32_t size = (uint32_t)std::min(len - pos, 0x0fffffffULL); + uint32_t written = 0; + if (!writeData(&line[pos], size, written)) + return; + pos += written; + } + } } // each platform has its own specific version of this function. @@ -890,7 +178,7 @@ void MainWindow::SetWindowTitle(const char* caption) std::wstring widecaption; if (!caption) { - FStringf default_caption("" GAMENAME " %s " X64 " (%s)", GetVersionString(), GetGitTime()); + FStringf default_caption("" GAMENAME " %s (%s)", GetVersionString(), GetGitTime()); widecaption = default_caption.WideString(); } else diff --git a/src/common/platform/win32/i_mainwindow.h b/src/common/platform/win32/i_mainwindow.h index 2adea7bfa..3c0c7e55d 100644 --- a/src/common/platform/win32/i_mainwindow.h +++ b/src/common/platform/win32/i_mainwindow.h @@ -20,20 +20,11 @@ public: void RestoreConView(); void ShowErrorPane(const char* text); - void CheckForRestart(); - - void HideGameTitleWindow(); - int GetGameTitleWindowHeight(); + bool CheckForRestart(); void PrintStr(const char* cp); void GetLog(std::function writeFile); - void UpdateLayout(); - - void ShowProgressBar(int maxpos); - void HideProgressBar(); - void SetProgressPos(int pos); - void ShowNetStartPane(const char* message, int maxpos); void SetNetStartProgress(int pos); bool RunMessageLoop(bool (*timer_callback)(void*), void* userdata); @@ -44,47 +35,11 @@ public: HWND GetHandle() { return Window; } private: - void LayoutMainWindow(HWND hWnd, HWND pane); - int LayoutErrorPane(HWND pane, int w); - int LayoutNetStartPane(HWND pane, int w); - - void DoPrintStr(const char* cpt); - void FlushBufferedConsoleStuff(); - - LRESULT OnMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - LRESULT OnCreate(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - LRESULT OnSize(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - LRESULT OnDrawItem(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - LRESULT OnCommand(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - LRESULT OnClose(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - LRESULT OnDestroy(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - static LRESULT CALLBACK LConProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - static INT_PTR CALLBACK ErrorPaneProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); HWND Window = 0; - - HFONT GameTitleFont = 0; - LONG GameTitleFontHeight = 0; - LONG DefaultGUIFontHeight = 0; - LONG ErrorIconChar = 0; - bool restartrequest = false; - - HWND GameTitleWindow = 0; - HWND ErrorPane = 0; - HWND ErrorIcon = 0; - - bool ConWindowHidden = false; - HWND ConWindow = 0; TArray bufferedConsoleStuff; - - HWND ProgressBar = 0; - - HWND NetStartPane = 0; - int NetStartMaxPos = 0; - - HWND StartupScreen = 0; }; extern MainWindow mainwindow; diff --git a/src/common/platform/win32/st_start.cpp b/src/common/platform/win32/st_start.cpp index 07039add2..8bc48d26e 100644 --- a/src/common/platform/win32/st_start.cpp +++ b/src/common/platform/win32/st_start.cpp @@ -76,9 +76,9 @@ extern HINSTANCE g_hInst; // //========================================================================== -FStartupScreen *FStartupScreen::CreateInstance(int max_progress, bool showprogress) +FStartupScreen *FStartupScreen::CreateInstance(int max_progress) { - return new FBasicStartupScreen(max_progress, showprogress); + return new FBasicStartupScreen(max_progress); } //========================================================================== @@ -89,13 +89,9 @@ FStartupScreen *FStartupScreen::CreateInstance(int max_progress, bool showprogre // //========================================================================== -FBasicStartupScreen::FBasicStartupScreen(int max_progress, bool show_bar) +FBasicStartupScreen::FBasicStartupScreen(int max_progress) : FStartupScreen(max_progress) { - if (show_bar) - { - mainwindow.ShowProgressBar(MaxPos); - } NetMaxPos = 0; NetCurPos = 0; } @@ -111,8 +107,6 @@ FBasicStartupScreen::FBasicStartupScreen(int max_progress, bool show_bar) FBasicStartupScreen::~FBasicStartupScreen() { - mainwindow.HideProgressBar(); - KillTimer(mainwindow.GetHandle(), 1337); } //========================================================================== @@ -128,7 +122,6 @@ void FBasicStartupScreen::Progress() if (CurPos < MaxPos) { CurPos++; - mainwindow.SetProgressPos(CurPos); } } diff --git a/src/common/widgets/errorwindow.cpp b/src/common/widgets/errorwindow.cpp new file mode 100644 index 000000000..30fc60a5b --- /dev/null +++ b/src/common/widgets/errorwindow.cpp @@ -0,0 +1,44 @@ + +#include "errorwindow.h" +#include "version.h" +#include + +void ErrorWindow::ExecModal(const std::string& text) +{ + Size screenSize = GetScreenSize(); + double windowWidth = 1200.0; + double windowHeight = 700.0; + + auto window = new ErrorWindow(); + window->SetText(text); + window->SetFrameGeometry((screenSize.width - windowWidth) * 0.5, (screenSize.height - windowHeight) * 0.5, windowWidth, windowHeight); + window->Show(); + + DisplayWindow::RunLoop(); +} + +ErrorWindow::ErrorWindow() : Widget(nullptr, WidgetType::Window) +{ + FStringf caption("Fatal Error - " GAMENAME " %s (%s)", GetVersionString(), GetGitTime()); + SetWindowTitle(caption.GetChars()); + SetWindowBackground(Colorf::fromRgba8(51, 51, 51)); + SetWindowBorderColor(Colorf::fromRgba8(51, 51, 51)); + SetWindowCaptionColor(Colorf::fromRgba8(33, 33, 33)); + SetWindowCaptionTextColor(Colorf::fromRgba8(226, 223, 219)); + + LogView = new TextEdit(this); + + LogView->SetFocus(); +} + +void ErrorWindow::SetText(const std::string& text) +{ + LogView->SetText(text); +} + +void ErrorWindow::OnGeometryChanged() +{ + double w = GetWidth(); + double h = GetHeight(); + LogView->SetFrameGeometry(Rect::xywh(20.0, 20.0, w - 40.0, h - 40.0)); +} diff --git a/src/common/widgets/errorwindow.h b/src/common/widgets/errorwindow.h new file mode 100644 index 000000000..11cfbf6ed --- /dev/null +++ b/src/common/widgets/errorwindow.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +class TextEdit; + +class ErrorWindow : public Widget +{ +public: + static void ExecModal(const std::string& text); + +protected: + void OnGeometryChanged() override; + +private: + ErrorWindow(); + + void SetText(const std::string& text); + + TextEdit* LogView = nullptr; +}; diff --git a/src/common/widgets/launcherwindow.cpp b/src/common/widgets/launcherwindow.cpp index 935504295..e3fb482b4 100644 --- a/src/common/widgets/launcherwindow.cpp +++ b/src/common/widgets/launcherwindow.cpp @@ -3,7 +3,6 @@ #include "v_video.h" #include "version.h" #include "i_interface.h" -#include #include #include #include @@ -160,74 +159,3 @@ void LauncherWindow::OnGeometryChanged() double listViewBottom = y - 10.0; GamesList->SetFrameGeometry(20.0, listViewTop, GetWidth() - 40.0, std::max(listViewBottom - listViewTop, 0.0)); } - - -// To do: clean this up -#ifdef WIN32 -#include -#include -static std::wstring to_utf16(const std::string& str) -{ - if (str.empty()) return {}; - int needed = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0); - if (needed == 0) - throw std::runtime_error("MultiByteToWideChar failed"); - std::wstring result; - result.resize(needed); - needed = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &result[0], (int)result.size()); - if (needed == 0) - throw std::runtime_error("MultiByteToWideChar failed"); - return result; -} - -static std::vector ReadAllBytes(const std::string& filename) -{ - HANDLE handle = CreateFile(to_utf16(filename).c_str(), 0x0001/*FILE_READ_ACCESS*/, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if (handle == INVALID_HANDLE_VALUE) - throw std::runtime_error("Could not open " + filename); - - LARGE_INTEGER fileSize; - BOOL result = GetFileSizeEx(handle, &fileSize); - if (result == FALSE) - { - CloseHandle(handle); - throw std::runtime_error("GetFileSizeEx failed"); - } - - std::vector buffer(fileSize.QuadPart); - - DWORD bytesRead = 0; - result = ReadFile(handle, buffer.data(), (DWORD)buffer.size(), &bytesRead, nullptr); - if (result == FALSE || bytesRead != buffer.size()) - { - CloseHandle(handle); - throw std::runtime_error("ReadFile failed"); - } - - CloseHandle(handle); - - return buffer; -} - -std::vector LoadWidgetFontData(const std::string& name) -{ - return ReadAllBytes("C:\\Windows\\Fonts\\segoeui.ttf"); -} - -Size LauncherWindow::GetScreenSize() -{ - HDC screenDC = GetDC(0); - int screenWidth = GetDeviceCaps(screenDC, HORZRES); - int screenHeight = GetDeviceCaps(screenDC, VERTRES); - double dpiScale = GetDeviceCaps(screenDC, LOGPIXELSX) / 96.0; - ReleaseDC(0, screenDC); - - return Size(screenWidth / dpiScale, screenHeight / dpiScale); -} - -#else -std::vector LoadWidgetFontData(const std::string& name) -{ - return {}; -} -#endif diff --git a/src/common/widgets/launcherwindow.h b/src/common/widgets/launcherwindow.h index daad2df8c..4ca127902 100644 --- a/src/common/widgets/launcherwindow.h +++ b/src/common/widgets/launcherwindow.h @@ -34,6 +34,4 @@ private: PushButton* PlayButton = nullptr; PushButton* ExitButton = nullptr; ListView* GamesList = nullptr; - - static Size GetScreenSize(); }; diff --git a/src/common/widgets/netstartwindow.cpp b/src/common/widgets/netstartwindow.cpp new file mode 100644 index 000000000..2dabccf33 --- /dev/null +++ b/src/common/widgets/netstartwindow.cpp @@ -0,0 +1,12 @@ + +#include "netstartwindow.h" +#include "version.h" + +NetStartWindow::NetStartWindow() : 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); +} diff --git a/src/common/widgets/netstartwindow.h b/src/common/widgets/netstartwindow.h new file mode 100644 index 000000000..1814b8572 --- /dev/null +++ b/src/common/widgets/netstartwindow.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +class NetStartWindow : public Widget +{ +public: + NetStartWindow(); +}; diff --git a/src/common/widgets/widgetresourcedata.cpp b/src/common/widgets/widgetresourcedata.cpp new file mode 100644 index 000000000..984ce8b74 --- /dev/null +++ b/src/common/widgets/widgetresourcedata.cpp @@ -0,0 +1,62 @@ + +#include + +// To do: this should load data from lumps + +#ifdef WIN32 +#include +#include +static std::wstring to_utf16(const std::string& str) +{ + if (str.empty()) return {}; + int needed = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0); + if (needed == 0) + throw std::runtime_error("MultiByteToWideChar failed"); + std::wstring result; + result.resize(needed); + needed = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &result[0], (int)result.size()); + if (needed == 0) + throw std::runtime_error("MultiByteToWideChar failed"); + return result; +} + +static std::vector ReadAllBytes(const std::string& filename) +{ + HANDLE handle = CreateFile(to_utf16(filename).c_str(), 0x0001/*FILE_READ_ACCESS*/, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (handle == INVALID_HANDLE_VALUE) + throw std::runtime_error("Could not open " + filename); + + LARGE_INTEGER fileSize; + BOOL result = GetFileSizeEx(handle, &fileSize); + if (result == FALSE) + { + CloseHandle(handle); + throw std::runtime_error("GetFileSizeEx failed"); + } + + std::vector buffer(fileSize.QuadPart); + + DWORD bytesRead = 0; + result = ReadFile(handle, buffer.data(), (DWORD)buffer.size(), &bytesRead, nullptr); + if (result == FALSE || bytesRead != buffer.size()) + { + CloseHandle(handle); + throw std::runtime_error("ReadFile failed"); + } + + CloseHandle(handle); + + return buffer; +} + +std::vector LoadWidgetFontData(const std::string& name) +{ + return ReadAllBytes("C:\\Windows\\Fonts\\segoeui.ttf"); +} + +#else +std::vector LoadWidgetFontData(const std::string& name) +{ + return {}; +} +#endif diff --git a/src/d_main.cpp b/src/d_main.cpp index 143bcaf32..d9d0ce6d3 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -3288,7 +3288,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, std::vector& allw if (!batchrun) Printf ("ST_Init: Init startup screen.\n"); if (!restart) { - StartWindow = FStartupScreen::CreateInstance (TexMan.GuesstimateNumTextures() + 5, StartScreen == nullptr); + StartWindow = FStartupScreen::CreateInstance (TexMan.GuesstimateNumTextures() + 5); } else {