Common: Add Win32ProgressCallback

This commit is contained in:
Connor McLaughlin 2020-08-06 19:33:08 +10:00
parent 7cafb8c515
commit 045e6dff61
5 changed files with 291 additions and 1 deletions

View file

@ -113,6 +113,8 @@ if(WIN32)
d3d11/texture.cpp
d3d11/texture.h
windows_headers.h
win32_progress_callback.cpp
win32_progress_callback.h
)
target_link_libraries(common PRIVATE d3dcompiler.lib)
endif()

View file

@ -91,6 +91,7 @@
<ClInclude Include="vulkan\texture.h" />
<ClInclude Include="vulkan\util.h" />
<ClInclude Include="wav_writer.h" />
<ClInclude Include="win32_progress_callback.h" />
<ClInclude Include="window_info.h" />
</ItemGroup>
<ItemGroup>
@ -143,6 +144,7 @@
<ClCompile Include="vulkan\texture.cpp" />
<ClCompile Include="vulkan\util.cpp" />
<ClCompile Include="wav_writer.cpp" />
<ClCompile Include="win32_progress_callback.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="bitfield.natvis" />

View file

@ -100,6 +100,7 @@
</ClInclude>
<ClInclude Include="image.h" />
<ClInclude Include="minizip_helpers.h" />
<ClInclude Include="win32_progress_callback.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="jit_code_buffer.cpp" />
@ -193,6 +194,7 @@
<ClCompile Include="image.cpp" />
<ClCompile Include="cd_image_memory.cpp" />
<ClCompile Include="minizip_helpers.cpp" />
<ClCompile Include="win32_progress_callback.cpp" />
</ItemGroup>
<ItemGroup>
<Natvis Include="bitfield.natvis" />

View file

@ -0,0 +1,233 @@
#include "win32_progress_callback.h"
#include "common/log.h"
#include <CommCtrl.h>
#pragma comment(lib, "Comctl32.lib")
Log_SetChannel(Win32ProgressCallback);
Win32ProgressCallback::Win32ProgressCallback() : BaseProgressCallback()
{
Create();
}
void Win32ProgressCallback::PushState()
{
BaseProgressCallback::PushState();
}
void Win32ProgressCallback::PopState()
{
BaseProgressCallback::PopState();
Redraw(true);
}
void Win32ProgressCallback::SetCancellable(bool cancellable)
{
BaseProgressCallback::SetCancellable(cancellable);
Redraw(true);
}
void Win32ProgressCallback::SetTitle(const char* title)
{
SetWindowTextA(m_window_hwnd, title);
}
void Win32ProgressCallback::SetStatusText(const char* text)
{
BaseProgressCallback::SetStatusText(text);
Redraw(true);
}
void Win32ProgressCallback::SetProgressRange(u32 range)
{
BaseProgressCallback::SetProgressRange(range);
Redraw(false);
}
void Win32ProgressCallback::SetProgressValue(u32 value)
{
BaseProgressCallback::SetProgressValue(value);
Redraw(false);
}
bool Win32ProgressCallback::Create()
{
static const char* CLASS_NAME = "DSWin32ProgressCallbackWindow";
static bool class_registered = false;
if (!class_registered)
{
InitCommonControls();
WNDCLASSEX wc = {};
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WndProcThunk;
wc.hInstance = GetModuleHandle(nullptr);
// wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
// wc.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
wc.hCursor = LoadCursor(NULL, IDC_WAIT);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = CLASS_NAME;
if (!RegisterClassExA(&wc))
{
Log_ErrorPrint("Failed to register window class");
return false;
}
class_registered = true;
}
m_window_hwnd =
CreateWindowExA(WS_EX_CLIENTEDGE, CLASS_NAME, "Win32ProgressCallback", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, nullptr, nullptr, GetModuleHandle(nullptr), this);
if (!m_window_hwnd)
{
Log_ErrorPrint("Failed to create window");
return false;
}
SetWindowLongPtr(m_window_hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
ShowWindow(m_window_hwnd, SW_SHOW);
PumpMessages();
return true;
}
void Win32ProgressCallback::Destroy()
{
if (!m_window_hwnd)
return;
DestroyWindow(m_window_hwnd);
m_window_hwnd = {};
m_text_hwnd = {};
m_progress_hwnd = {};
}
void Win32ProgressCallback::PumpMessages()
{
MSG msg;
while (PeekMessageA(&msg, m_window_hwnd, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
}
void Win32ProgressCallback::Redraw(bool force)
{
const int percent =
static_cast<int>((static_cast<float>(m_progress_value) / static_cast<float>(m_progress_range)) * 100.0f);
if (percent == m_last_progress_percent && !force)
{
PumpMessages();
return;
}
m_last_progress_percent = percent;
SendMessageA(m_progress_hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, m_progress_range));
SendMessageA(m_progress_hwnd, PBM_SETPOS, static_cast<WPARAM>(m_progress_value), 0);
SetWindowTextA(m_text_hwnd, m_status_text);
RedrawWindow(m_text_hwnd, nullptr, nullptr, RDW_INVALIDATE);
PumpMessages();
}
LRESULT CALLBACK Win32ProgressCallback::WndProcThunk(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
Win32ProgressCallback* cb;
if (msg == WM_CREATE)
{
const CREATESTRUCTA* cs = reinterpret_cast<CREATESTRUCTA*>(lparam);
cb = static_cast<Win32ProgressCallback*>(cs->lpCreateParams);
}
else
{
cb = reinterpret_cast<Win32ProgressCallback*>(GetWindowLongPtrA(hwnd, GWLP_USERDATA));
}
return cb->WndProc(hwnd, msg, wparam, lparam);
}
LRESULT CALLBACK Win32ProgressCallback::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CREATE:
{
const CREATESTRUCTA* cs = reinterpret_cast<CREATESTRUCTA*>(lparam);
HFONT default_font = reinterpret_cast<HFONT>(GetStockObject(ANSI_VAR_FONT));
SendMessageA(hwnd, WM_SETFONT, WPARAM(default_font), TRUE);
int y = WINDOW_MARGIN;
m_text_hwnd = CreateWindowExA(0, "Static", nullptr, WS_VISIBLE | WS_CHILD, WINDOW_MARGIN, y, SUBWINDOW_WIDTH, 16,
hwnd, nullptr, cs->hInstance, nullptr);
SendMessageA(m_text_hwnd, WM_SETFONT, WPARAM(default_font), TRUE);
y += 16 + WINDOW_MARGIN;
m_progress_hwnd = CreateWindowExA(0, PROGRESS_CLASSA, nullptr, WS_VISIBLE | WS_CHILD, WINDOW_MARGIN, y,
SUBWINDOW_WIDTH, 32, hwnd, nullptr, cs->hInstance, nullptr);
y += 32 + WINDOW_MARGIN;
m_list_box_hwnd =
CreateWindowExA(0, "LISTBOX", nullptr, WS_VISIBLE | WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_BORDER | LBS_NOSEL,
WINDOW_MARGIN, y, SUBWINDOW_WIDTH, 170, hwnd, nullptr, cs->hInstance, nullptr);
SendMessageA(m_list_box_hwnd, WM_SETFONT, WPARAM(default_font), TRUE);
y += 170;
}
break;
default:
return DefWindowProcA(hwnd, msg, wparam, lparam);
}
return 0;
}
void Win32ProgressCallback::DisplayError(const char* message)
{
Log_ErrorPrint(message);
SendMessageA(m_list_box_hwnd, LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(message));
SendMessageA(m_list_box_hwnd, WM_VSCROLL, SB_BOTTOM, 0);
PumpMessages();
}
void Win32ProgressCallback::DisplayWarning(const char* message)
{
Log_WarningPrint(message);
SendMessageA(m_list_box_hwnd, LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(message));
SendMessageA(m_list_box_hwnd, WM_VSCROLL, SB_BOTTOM, 0);
PumpMessages();
}
void Win32ProgressCallback::DisplayInformation(const char* message)
{
Log_InfoPrint(message);
SendMessageA(m_list_box_hwnd, LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(message));
SendMessageA(m_list_box_hwnd, WM_VSCROLL, SB_BOTTOM, 0);
PumpMessages();
}
void Win32ProgressCallback::DisplayDebugMessage(const char* message)
{
Log_DevPrint(message);
}
void Win32ProgressCallback::ModalError(const char* message)
{
PumpMessages();
MessageBoxA(m_window_hwnd, message, "Error", MB_ICONERROR | MB_OK);
PumpMessages();
}
bool Win32ProgressCallback::ModalConfirmation(const char* message)
{
PumpMessages();
bool result = MessageBoxA(m_window_hwnd, message, "Confirmation", MB_ICONQUESTION | MB_YESNO) == IDYES;
PumpMessages();
return result;
}
void Win32ProgressCallback::ModalInformation(const char* message)
{
MessageBoxA(m_window_hwnd, message, "Information", MB_ICONINFORMATION | MB_OK);
}

View file

@ -0,0 +1,51 @@
#pragma once
#include "common/progress_callback.h"
#include "windows_headers.h"
class Win32ProgressCallback final : public BaseProgressCallback
{
public:
Win32ProgressCallback();
void PushState() override;
void PopState() override;
void SetCancellable(bool cancellable) override;
void SetTitle(const char* title) override;
void SetStatusText(const char* text) override;
void SetProgressRange(u32 range) override;
void SetProgressValue(u32 value) override;
void DisplayError(const char* message) override;
void DisplayWarning(const char* message) override;
void DisplayInformation(const char* message) override;
void DisplayDebugMessage(const char* message) override;
void ModalError(const char* message) override;
bool ModalConfirmation(const char* message) override;
void ModalInformation(const char* message) override;
private:
enum : int
{
WINDOW_WIDTH = 600,
WINDOW_HEIGHT = 300,
WINDOW_MARGIN = 10,
SUBWINDOW_WIDTH = WINDOW_WIDTH - 20 - WINDOW_MARGIN - WINDOW_MARGIN,
};
bool Create();
void Destroy();
void Redraw(bool force);
void PumpMessages();
static LRESULT CALLBACK WndProcThunk(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
HWND m_window_hwnd{};
HWND m_text_hwnd{};
HWND m_progress_hwnd{};
HWND m_list_box_hwnd{};
int m_last_progress_percent = -1;
};