duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

win32_progress_callback.cpp (7135B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #include "win32_progress_callback.h"
      5 
      6 #include "common/log.h"
      7 #include "common/string_util.h"
      8 
      9 #include <CommCtrl.h>
     10 
     11 Log_SetChannel(Win32ProgressCallback);
     12 
     13 Win32ProgressCallback::Win32ProgressCallback() : ProgressCallback()
     14 {
     15   Create();
     16 }
     17 
     18 void Win32ProgressCallback::PushState()
     19 {
     20   ProgressCallback::PushState();
     21 }
     22 
     23 void Win32ProgressCallback::PopState()
     24 {
     25   ProgressCallback::PopState();
     26   Redraw(true);
     27 }
     28 
     29 void Win32ProgressCallback::SetCancellable(bool cancellable)
     30 {
     31   ProgressCallback::SetCancellable(cancellable);
     32   Redraw(true);
     33 }
     34 
     35 void Win32ProgressCallback::SetTitle(const std::string_view title)
     36 {
     37   SetWindowTextW(m_window_hwnd, StringUtil::UTF8StringToWideString(title).c_str());
     38 }
     39 
     40 void Win32ProgressCallback::SetStatusText(const std::string_view text)
     41 {
     42   ProgressCallback::SetStatusText(text);
     43   Redraw(true);
     44 }
     45 
     46 void Win32ProgressCallback::SetProgressRange(u32 range)
     47 {
     48   ProgressCallback::SetProgressRange(range);
     49   Redraw(false);
     50 }
     51 
     52 void Win32ProgressCallback::SetProgressValue(u32 value)
     53 {
     54   ProgressCallback::SetProgressValue(value);
     55   Redraw(false);
     56 }
     57 
     58 bool Win32ProgressCallback::Create()
     59 {
     60   static const char* CLASS_NAME = "DSWin32ProgressCallbackWindow";
     61   static bool class_registered = false;
     62 
     63   if (!class_registered)
     64   {
     65     InitCommonControls();
     66 
     67     WNDCLASSEX wc = {};
     68     wc.cbSize = sizeof(WNDCLASSEX);
     69     wc.lpfnWndProc = WndProcThunk;
     70     wc.hInstance = GetModuleHandle(nullptr);
     71     // wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
     72     // wc.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
     73     wc.hCursor = LoadCursor(NULL, IDC_WAIT);
     74     wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
     75     wc.lpszClassName = CLASS_NAME;
     76     if (!RegisterClassExA(&wc))
     77     {
     78       ERROR_LOG("Failed to register window class");
     79       return false;
     80     }
     81 
     82     class_registered = true;
     83   }
     84 
     85   m_window_hwnd =
     86     CreateWindowExA(WS_EX_CLIENTEDGE, CLASS_NAME, "Win32ProgressCallback", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
     87                     CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, nullptr, nullptr, GetModuleHandle(nullptr), this);
     88   if (!m_window_hwnd)
     89   {
     90     ERROR_LOG("Failed to create window");
     91     return false;
     92   }
     93 
     94   SetWindowLongPtr(m_window_hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
     95   ShowWindow(m_window_hwnd, SW_SHOW);
     96   PumpMessages();
     97   return true;
     98 }
     99 
    100 void Win32ProgressCallback::Destroy()
    101 {
    102   if (!m_window_hwnd)
    103     return;
    104 
    105   DestroyWindow(m_window_hwnd);
    106   m_window_hwnd = {};
    107   m_text_hwnd = {};
    108   m_progress_hwnd = {};
    109 }
    110 
    111 void Win32ProgressCallback::PumpMessages()
    112 {
    113   MSG msg;
    114   while (PeekMessageA(&msg, m_window_hwnd, 0, 0, PM_REMOVE))
    115   {
    116     TranslateMessage(&msg);
    117     DispatchMessageA(&msg);
    118   }
    119 }
    120 
    121 void Win32ProgressCallback::Redraw(bool force)
    122 {
    123   const int percent =
    124     static_cast<int>((static_cast<float>(m_progress_value) / static_cast<float>(m_progress_range)) * 100.0f);
    125   if (percent == m_last_progress_percent && !force)
    126   {
    127     PumpMessages();
    128     return;
    129   }
    130 
    131   m_last_progress_percent = percent;
    132 
    133   SendMessageA(m_progress_hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, m_progress_range));
    134   SendMessageA(m_progress_hwnd, PBM_SETPOS, static_cast<WPARAM>(m_progress_value), 0);
    135   SetWindowTextA(m_text_hwnd, m_status_text.c_str());
    136   RedrawWindow(m_text_hwnd, nullptr, nullptr, RDW_INVALIDATE);
    137   PumpMessages();
    138 }
    139 
    140 LRESULT CALLBACK Win32ProgressCallback::WndProcThunk(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
    141 {
    142   Win32ProgressCallback* cb;
    143   if (msg == WM_CREATE)
    144   {
    145     const CREATESTRUCTA* cs = reinterpret_cast<CREATESTRUCTA*>(lparam);
    146     cb = static_cast<Win32ProgressCallback*>(cs->lpCreateParams);
    147   }
    148   else
    149   {
    150     cb = reinterpret_cast<Win32ProgressCallback*>(GetWindowLongPtrA(hwnd, GWLP_USERDATA));
    151   }
    152 
    153   return cb->WndProc(hwnd, msg, wparam, lparam);
    154 }
    155 
    156 LRESULT CALLBACK Win32ProgressCallback::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
    157 {
    158   switch (msg)
    159   {
    160     case WM_CREATE:
    161     {
    162       const CREATESTRUCTA* cs = reinterpret_cast<CREATESTRUCTA*>(lparam);
    163       HFONT default_font = reinterpret_cast<HFONT>(GetStockObject(ANSI_VAR_FONT));
    164       SendMessageA(hwnd, WM_SETFONT, WPARAM(default_font), TRUE);
    165 
    166       int y = WINDOW_MARGIN;
    167 
    168       m_text_hwnd = CreateWindowExA(0, "Static", nullptr, WS_VISIBLE | WS_CHILD, WINDOW_MARGIN, y, SUBWINDOW_WIDTH, 16,
    169                                     hwnd, nullptr, cs->hInstance, nullptr);
    170       SendMessageA(m_text_hwnd, WM_SETFONT, WPARAM(default_font), TRUE);
    171       y += 16 + WINDOW_MARGIN;
    172 
    173       m_progress_hwnd = CreateWindowExA(0, PROGRESS_CLASSA, nullptr, WS_VISIBLE | WS_CHILD, WINDOW_MARGIN, y,
    174                                         SUBWINDOW_WIDTH, 32, hwnd, nullptr, cs->hInstance, nullptr);
    175       y += 32 + WINDOW_MARGIN;
    176 
    177       m_list_box_hwnd =
    178         CreateWindowExA(0, "LISTBOX", nullptr, WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_BORDER | LBS_NOSEL,
    179                         WINDOW_MARGIN, y, SUBWINDOW_WIDTH, 170, hwnd, nullptr, cs->hInstance, nullptr);
    180       SendMessageA(m_list_box_hwnd, WM_SETFONT, WPARAM(default_font), TRUE);
    181       y += 170;
    182     }
    183     break;
    184 
    185     default:
    186       return DefWindowProcA(hwnd, msg, wparam, lparam);
    187   }
    188 
    189   return 0;
    190 }
    191 
    192 void Win32ProgressCallback::DisplayError(const std::string_view message)
    193 {
    194   ERROR_LOG(message);
    195   SendMessageW(m_list_box_hwnd, LB_ADDSTRING, 0,
    196                reinterpret_cast<LPARAM>(StringUtil::UTF8StringToWideString(message).c_str()));
    197   SendMessageW(m_list_box_hwnd, WM_VSCROLL, SB_BOTTOM, 0);
    198   PumpMessages();
    199 }
    200 
    201 void Win32ProgressCallback::DisplayWarning(const std::string_view message)
    202 {
    203   WARNING_LOG(message);
    204   SendMessageW(m_list_box_hwnd, LB_ADDSTRING, 0,
    205                reinterpret_cast<LPARAM>(StringUtil::UTF8StringToWideString(message).c_str()));
    206   SendMessageW(m_list_box_hwnd, WM_VSCROLL, SB_BOTTOM, 0);
    207   PumpMessages();
    208 }
    209 
    210 void Win32ProgressCallback::DisplayInformation(const std::string_view message)
    211 {
    212   INFO_LOG(message);
    213   SendMessageW(m_list_box_hwnd, LB_ADDSTRING, 0,
    214                reinterpret_cast<LPARAM>(StringUtil::UTF8StringToWideString(message).c_str()));
    215   SendMessageW(m_list_box_hwnd, WM_VSCROLL, SB_BOTTOM, 0);
    216   PumpMessages();
    217 }
    218 
    219 void Win32ProgressCallback::DisplayDebugMessage(const std::string_view message)
    220 {
    221   DEV_LOG(message);
    222 }
    223 
    224 void Win32ProgressCallback::ModalError(const std::string_view message)
    225 {
    226   PumpMessages();
    227   MessageBoxW(m_window_hwnd, StringUtil::UTF8StringToWideString(message).c_str(), L"Error", MB_ICONERROR | MB_OK);
    228   PumpMessages();
    229 }
    230 
    231 bool Win32ProgressCallback::ModalConfirmation(const std::string_view message)
    232 {
    233   PumpMessages();
    234   bool result = MessageBoxW(m_window_hwnd, StringUtil::UTF8StringToWideString(message).c_str(), L"Confirmation",
    235                             MB_ICONQUESTION | MB_YESNO) == IDYES;
    236   PumpMessages();
    237   return result;
    238 }
    239 
    240 void Win32ProgressCallback::ModalInformation(const std::string_view message)
    241 {
    242   MessageBoxW(m_window_hwnd, StringUtil::UTF8StringToWideString(message).c_str(), L"Information",
    243               MB_ICONINFORMATION | MB_OK);
    244 }