Fixed up the wait dialog.

This commit is contained in:
Justin Marshall
2026-05-06 23:43:11 -07:00
parent f238db4a34
commit 1a6bc0c447
2 changed files with 645 additions and 96 deletions
+576 -62
View File
@@ -2,9 +2,9 @@
===========================================================================
IceTech GPL Source Code
Copyright (C) 2026 Justin Marshall
Copyright (C) 2026 Justin Marshall
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
IceTech Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -38,101 +38,615 @@ If you have questions concerning this license or the applicable additional terms
static char THIS_FILE[] = __FILE__;
#endif
#define WAITDLG_TIMER_ANIMATE 1001
#define WAITDLG_TIMER_MS 33
// Runtime size. This makes the old tiny resource dialog larger without
// needing to edit the .rc file.
#define WAITDLG_WIDTH 560
#define WAITDLG_HEIGHT 260
/////////////////////////////////////////////////////////////////////////////
// CWaitDlg dialog
CWaitDlg::CWaitDlg(CWnd* pParent, const char* msg)
: CDialog(CWaitDlg::IDD, pParent) {
waitStr = msg ? msg : "Wait...";
text = waitStr;
titleStr = "IceTech Radiant";
CWaitDlg::CWaitDlg(CWnd* pParent, const char *msg)
: CDialog(CWaitDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CWaitDlg)
waitStr = msg;
//}}AFX_DATA_INIT
cancelPressed = false;
Create(CWaitDlg::IDD);
//g_pParentWnd->SetBusy(true);
cancelAllowed = false;
progressPercent = -1;
marqueeOffset = 0;
pulseFrame = 0;
colorBackTop = RGB(13, 17, 26);
colorBackBottom = RGB(24, 30, 45);
colorPanel = RGB(28, 35, 52);
colorPanelBorder = RGB(62, 78, 112);
colorText = RGB(236, 242, 255);
colorMutedText = RGB(148, 162, 190);
colorAccent = RGB(83, 169, 255);
colorAccent2 = RGB(127, 96, 255);
colorProgressBack = RGB(15, 20, 31);
colorDanger = RGB(255, 92, 112);
InitModernResources();
Create(CWaitDlg::IDD, pParent);
}
CWaitDlg::~CWaitDlg() {
g_pParentWnd->SetBusy(false);
KillTimer(WAITDLG_TIMER_ANIMATE);
FreeModernResources();
if (g_pParentWnd) {
g_pParentWnd->SetBusy(false);
}
}
void CWaitDlg::DoDataExchange(CDataExchange* pDX)
{
void CWaitDlg::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CWaitDlg)
DDX_Text(pDX, IDC_WAITSTR, waitStr);
//}}AFX_DATA_MAP
}
// Keep the original DDX mapping alive for old resource compatibility.
DDX_Text(pDX, IDC_WAITSTR, waitStr);
}
BEGIN_MESSAGE_MAP(CWaitDlg, CDialog)
//{{AFX_MSG_MAP(CWaitDlg)
//}}AFX_MSG_MAP
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_WM_TIMER()
ON_WM_SIZE()
ON_WM_CTLCOLOR()
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CWaitDlg message handlers
// Modern resources
BOOL CWaitDlg::OnInitDialog()
{
void CWaitDlg::InitModernResources(void) {
LOGFONT lf;
memset(&lf, 0, sizeof(lf));
lf.lfHeight = -23;
lf.lfWeight = FW_SEMIBOLD;
lf.lfQuality = CLEARTYPE_QUALITY;
strcpy(lf.lfFaceName, "Segoe UI");
titleFont.CreateFontIndirect(&lf);
memset(&lf, 0, sizeof(lf));
lf.lfHeight = -15;
lf.lfWeight = FW_NORMAL;
lf.lfQuality = CLEARTYPE_QUALITY;
strcpy(lf.lfFaceName, "Segoe UI");
messageFont.CreateFontIndirect(&lf);
memset(&lf, 0, sizeof(lf));
lf.lfHeight = -12;
lf.lfWeight = FW_NORMAL;
lf.lfQuality = CLEARTYPE_QUALITY;
strcpy(lf.lfFaceName, "Segoe UI");
smallFont.CreateFontIndirect(&lf);
transparentBrush.CreateStockObject(NULL_BRUSH);
}
void CWaitDlg::FreeModernResources(void) {
if (titleFont.GetSafeHandle()) {
titleFont.DeleteObject();
}
if (messageFont.GetSafeHandle()) {
messageFont.DeleteObject();
}
if (smallFont.GetSafeHandle()) {
smallFont.DeleteObject();
}
if (transparentBrush.GetSafeHandle()) {
transparentBrush.DeleteObject();
}
}
/////////////////////////////////////////////////////////////////////////////
// Dialog init
BOOL CWaitDlg::OnInitDialog() {
CDialog::OnInitDialog();
//GetDlgItem(IDC_WAITSTR)->SetWindowText(waitStr);
GetDlgItem(IDC_WAITSTR)->SetFocus();
ModifyStyleEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, 0);
ModifyStyle(WS_THICKFRAME, 0);
SetWindowText("Please wait");
ResizeAndCenterDialog();
CWnd* pWaitText = GetDlgItem(IDC_WAITSTR);
if (pWaitText && pWaitText->GetSafeHwnd()) {
pWaitText->ShowWindow(SW_HIDE);
}
CWnd* pCancelButton = GetDlgItem(IDCANCEL);
if (pCancelButton && pCancelButton->GetSafeHwnd()) {
pCancelButton->SetFont(&messageFont);
pCancelButton->SetWindowText("Cancel");
}
UpdateData(FALSE);
AllowCancel(false);
LayoutModernControls();
SetTimer(WAITDLG_TIMER_ANIMATE, WAITDLG_TIMER_MS, NULL);
ShowWindow(SW_SHOW);
// cancel disabled by default
AllowCancel( false );
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CWaitDlg::SetText(const char *msg, bool append) {
if (append) {
waitStr = text;
waitStr += "\r\n";
waitStr += msg;
} else {
waitStr = msg;
text = msg;
}
UpdateData(FALSE);
Invalidate();
Invalidate(FALSE);
UpdateWindow();
ShowWindow (SW_SHOWNORMAL);
return TRUE;
}
void CWaitDlg::AllowCancel( bool enable ) {
// this shows or hides the Cancel button
CWnd* pCancelButton = GetDlgItem (IDCANCEL);
ASSERT (pCancelButton);
if ( enable ) {
pCancelButton->ShowWindow (SW_NORMAL);
} else {
pCancelButton->ShowWindow (SW_HIDE);
void CWaitDlg::ResizeAndCenterDialog(void) {
CRect rcWindow;
GetWindowRect(&rcWindow);
int width = WAITDLG_WIDTH;
int height = WAITDLG_HEIGHT;
CWnd* pParent = GetParent();
CRect rcParent;
if (pParent && pParent->GetSafeHwnd()) {
pParent->GetWindowRect(&rcParent);
}
else {
SystemParametersInfo(SPI_GETWORKAREA, 0, &rcParent, 0);
}
int x = rcParent.left + ((rcParent.Width() - width) / 2);
int y = rcParent.top + ((rcParent.Height() - height) / 2);
SetWindowPos(NULL, x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE);
}
bool CWaitDlg::CancelPressed( void ) {
/////////////////////////////////////////////////////////////////////////////
// Public API
void CWaitDlg::SetText(const char* msg, bool append) {
if (append) {
waitStr = text.c_str();
waitStr += "\r\n";
waitStr += msg ? msg : "";
text = waitStr;
}
else {
waitStr = msg ? msg : "";
text = waitStr;
}
UpdateData(FALSE);
Invalidate(FALSE);
UpdateWindow();
ShowWindow(SW_SHOWNORMAL);
}
void CWaitDlg::SetTitleText(const char* title) {
titleStr = title ? title : "";
Invalidate(FALSE);
UpdateWindow();
}
void CWaitDlg::SetProgress(int percent) {
if (percent < 0) {
progressPercent = -1;
}
else {
if (percent > 100) {
percent = 100;
}
progressPercent = percent;
}
Invalidate(FALSE);
UpdateWindow();
}
void CWaitDlg::StepProgress(int amount) {
if (progressPercent < 0) {
progressPercent = 0;
}
progressPercent += amount;
if (progressPercent < 0) {
progressPercent = 0;
}
if (progressPercent > 100) {
progressPercent = 100;
}
Invalidate(FALSE);
UpdateWindow();
}
int CWaitDlg::GetProgress(void) const {
return progressPercent;
}
void CWaitDlg::AllowCancel(bool enable) {
cancelAllowed = enable;
CWnd* pCancelButton = GetDlgItem(IDCANCEL);
ASSERT(pCancelButton);
if (pCancelButton && pCancelButton->GetSafeHwnd()) {
pCancelButton->ShowWindow(enable ? SW_SHOW : SW_HIDE);
}
LayoutModernControls();
Invalidate(FALSE);
}
bool CWaitDlg::CancelPressed(void) {
PumpMessages();
return cancelPressed;
}
void CWaitDlg::PumpMessages(void) {
#if _MSC_VER >= 1300
MSG *msg = AfxGetCurrentMessage(); // TODO Robert fix me!!
MSG* msg = AfxGetCurrentMessage();
#else
MSG *msg = &m_msgCur;
MSG* msg = &m_msgCur;
#endif
while( ::PeekMessage(msg, NULL, NULL, NULL, PM_NOREMOVE) ) {
// pump message
if ( !AfxGetApp()->PumpMessage() ) {
while (::PeekMessage(msg, NULL, 0, 0, PM_NOREMOVE)) {
if (!AfxGetApp()->PumpMessage()) {
break;
}
}
return cancelPressed;
}
void CWaitDlg::OnCancel() {
cancelPressed = true;
}
/////////////////////////////////////////////////////////////////////////////
// Layout
void CWaitDlg::OnSize(UINT nType, int cx, int cy) {
CDialog::OnSize(nType, cx, cy);
LayoutModernControls();
Invalidate(FALSE);
}
void CWaitDlg::LayoutModernControls(void) {
if (!GetSafeHwnd()) {
return;
}
CRect rcClient;
GetClientRect(&rcClient);
CWnd* pCancelButton = GetDlgItem(IDCANCEL);
if (pCancelButton && pCancelButton->GetSafeHwnd()) {
const int buttonW = 112;
const int buttonH = 32;
const int margin = 26;
CRect rcButton;
rcButton.left = rcClient.right - margin - buttonW;
rcButton.top = rcClient.bottom - margin - buttonH;
rcButton.right = rcButton.left + buttonW;
rcButton.bottom = rcButton.top + buttonH;
pCancelButton->MoveWindow(rcButton);
}
}
/////////////////////////////////////////////////////////////////////////////
// Paint
BOOL CWaitDlg::OnEraseBkgnd(CDC* pDC) {
return TRUE;
}
HBRUSH CWaitDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(colorText);
return (HBRUSH)transparentBrush.GetSafeHandle();
}
void CWaitDlg::OnTimer(UINT_PTR nIDEvent) {
if (nIDEvent == WAITDLG_TIMER_ANIMATE) {
pulseFrame++;
marqueeOffset += 5;
if (marqueeOffset > 10000) {
marqueeOffset = 0;
}
Invalidate(FALSE);
return;
}
CDialog::OnTimer(nIDEvent);
}
void CWaitDlg::OnPaint() {
CPaintDC dcPaint(this);
CRect rcClient;
GetClientRect(&rcClient);
CDC memDC;
CBitmap memBmp;
CBitmap* oldBmp = NULL;
memDC.CreateCompatibleDC(&dcPaint);
memBmp.CreateCompatibleBitmap(&dcPaint, rcClient.Width(), rcClient.Height());
oldBmp = memDC.SelectObject(&memBmp);
DrawModernBackground(memDC, rcClient);
DrawHeader(memDC, rcClient);
DrawMessage(memDC, rcClient);
DrawProgress(memDC, rcClient);
dcPaint.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &memDC, 0, 0, SRCCOPY);
if (oldBmp) {
memDC.SelectObject(oldBmp);
}
}
void CWaitDlg::DrawModernBackground(CDC& dc, const CRect& rcClient) {
TRIVERTEX vertex[2];
vertex[0].x = rcClient.left;
vertex[0].y = rcClient.top;
vertex[0].Red = GetRValue(colorBackTop) << 8;
vertex[0].Green = GetGValue(colorBackTop) << 8;
vertex[0].Blue = GetBValue(colorBackTop) << 8;
vertex[0].Alpha = 0x0000;
vertex[1].x = rcClient.right;
vertex[1].y = rcClient.bottom;
vertex[1].Red = GetRValue(colorBackBottom) << 8;
vertex[1].Green = GetGValue(colorBackBottom) << 8;
vertex[1].Blue = GetBValue(colorBackBottom) << 8;
vertex[1].Alpha = 0x0000;
GRADIENT_RECT gRect;
gRect.UpperLeft = 0;
gRect.LowerRight = 1;
dc.GradientFill(vertex, 2, &gRect, 1, GRADIENT_FILL_RECT_V);
CRect panel = rcClient;
panel.DeflateRect(14, 14, 14, 14);
DrawRoundedRect(dc, panel, colorPanel, colorPanelBorder, 18);
// Top glass sheen.
CRect sheen = panel;
sheen.bottom = sheen.top + 70;
TRIVERTEX sheenVertex[2];
sheenVertex[0].x = sheen.left;
sheenVertex[0].y = sheen.top;
sheenVertex[0].Red = 60 << 8;
sheenVertex[0].Green = 78 << 8;
sheenVertex[0].Blue = 118 << 8;
sheenVertex[0].Alpha = 0x0000;
sheenVertex[1].x = sheen.right;
sheenVertex[1].y = sheen.bottom;
sheenVertex[1].Red = GetRValue(colorPanel) << 8;
sheenVertex[1].Green = GetGValue(colorPanel) << 8;
sheenVertex[1].Blue = GetBValue(colorPanel) << 8;
sheenVertex[1].Alpha = 0x0000;
dc.GradientFill(sheenVertex, 2, &gRect, 1, GRADIENT_FILL_RECT_V);
// Header separator.
CRect accent = panel;
accent.left += 24;
accent.right -= 24;
accent.top += 66;
accent.bottom = accent.top + 1;
CPen accentPen(PS_SOLID, 1, RGB(72, 91, 130));
CPen* oldPen = dc.SelectObject(&accentPen);
dc.MoveTo(accent.left, accent.top);
dc.LineTo(accent.right, accent.top);
dc.SelectObject(oldPen);
}
void CWaitDlg::DrawHeader(CDC& dc, const CRect& rcClient) {
CRect panel = rcClient;
panel.DeflateRect(14, 14, 14, 14);
CRect iconRc;
iconRc.left = panel.left + 26;
iconRc.top = panel.top + 20;
iconRc.right = iconRc.left + 30;
iconRc.bottom = iconRc.top + 30;
int glow = 20 + (pulseFrame % 50);
if (glow > 45) {
glow = 70 - glow;
}
COLORREF coreColor = RGB(
min(255, GetRValue(colorAccent) + glow),
min(255, GetGValue(colorAccent) + glow / 2),
min(255, GetBValue(colorAccent))
);
DrawRoundedRect(dc, iconRc, coreColor, RGB(155, 205, 255), 8);
CRect inner = iconRc;
inner.DeflateRect(7, 7, 7, 7);
DrawRoundedRect(dc, inner, RGB(18, 25, 38), RGB(150, 220, 255), 4);
CFont* oldFont = dc.SelectObject(&titleFont);
dc.SetBkMode(TRANSPARENT);
dc.SetTextColor(colorText);
CRect titleRc;
titleRc.left = iconRc.right + 14;
titleRc.top = panel.top + 17;
titleRc.right = panel.right - 26;
titleRc.bottom = titleRc.top + 30;
dc.DrawText(titleStr, &titleRc, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
dc.SelectObject(&smallFont);
dc.SetTextColor(colorMutedText);
CRect subRc = titleRc;
subRc.top += 28;
subRc.bottom = subRc.top + 20;
CString subText = "Working on the current Radiant task";
dc.DrawText(subText, &subRc, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
dc.SelectObject(oldFont);
}
void CWaitDlg::DrawMessage(CDC& dc, const CRect& rcClient) {
CRect panel = rcClient;
panel.DeflateRect(14, 14, 14, 14);
// Move status text higher and reserve a larger footer.
const int headerBottom = panel.top + 70;
const int footerHeight = cancelAllowed ? 138 : 108;
CRect textRc;
textRc.left = panel.left + 28;
textRc.top = headerBottom + 6;
textRc.right = panel.right - 28;
textRc.bottom = panel.bottom - footerHeight;
if (textRc.bottom < textRc.top + 26) {
textRc.bottom = textRc.top + 26;
}
CFont* oldFont = dc.SelectObject(&messageFont);
dc.SetBkMode(TRANSPARENT);
dc.SetTextColor(colorText);
CString drawText = waitStr;
if (drawText.IsEmpty()) {
drawText = "Please wait...";
}
dc.DrawText(drawText, &textRc, DT_LEFT | DT_TOP | DT_WORDBREAK | DT_END_ELLIPSIS);
dc.SelectObject(oldFont);
}
void CWaitDlg::DrawProgress(CDC& dc, const CRect& rcClient) {
CRect panel = rcClient;
panel.DeflateRect(14, 14, 14, 14);
// Push progress lower so it never overlaps the status text.
CRect barRc;
barRc.left = panel.left + 28;
barRc.right = panel.right - 28;
if (cancelAllowed) {
barRc.bottom = panel.bottom - 54;
}
else {
barRc.bottom = panel.bottom - 28;
}
barRc.top = barRc.bottom - 18;
DrawRoundedRect(dc, barRc, colorProgressBack, RGB(54, 68, 96), 9);
CRect fillRc = barRc;
fillRc.DeflateRect(2, 2, 2, 2);
if (progressPercent >= 0) {
int fillW = MulDiv(fillRc.Width(), progressPercent, 100);
CRect filled = fillRc;
filled.right = filled.left + fillW;
if (filled.Width() > 0) {
DrawRoundedRect(dc, filled, colorAccent, RGB(125, 205, 255), 8);
}
CString percentText;
percentText.Format("%d%%", progressPercent);
CFont* oldFont = dc.SelectObject(&smallFont);
dc.SetBkMode(TRANSPARENT);
dc.SetTextColor(colorMutedText);
CRect labelRc = barRc;
labelRc.top = barRc.bottom + 6;
labelRc.bottom = labelRc.top + 18;
dc.DrawText(percentText, &labelRc, DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
dc.SelectObject(oldFont);
}
else {
const int chunkW = max(64, fillRc.Width() / 4);
const int travelW = fillRc.Width() + chunkW;
const int x = fillRc.left - chunkW + (marqueeOffset % travelW);
CRect chunk;
chunk.left = x;
chunk.right = x + chunkW;
chunk.top = fillRc.top;
chunk.bottom = fillRc.bottom;
CRect clipped;
clipped.IntersectRect(&chunk, &fillRc);
if (!clipped.IsRectEmpty()) {
DrawRoundedRect(dc, clipped, colorAccent, RGB(125, 205, 255), 8);
}
CRect glowChunk = chunk;
glowChunk.OffsetRect(-chunkW / 2, 0);
CRect glowClip;
glowClip.IntersectRect(&glowChunk, &fillRc);
if (!glowClip.IsRectEmpty()) {
DrawRoundedRect(dc, glowClip, colorAccent2, RGB(140, 120, 255), 8);
}
CFont* oldFont = dc.SelectObject(&smallFont);
dc.SetBkMode(TRANSPARENT);
dc.SetTextColor(colorMutedText);
CRect labelRc = barRc;
labelRc.top = barRc.bottom + 6;
labelRc.bottom = labelRc.top + 18;
CString label = "Processing...";
dc.DrawText(label, &labelRc, DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
dc.SelectObject(oldFont);
}
}
void CWaitDlg::DrawRoundedRect(CDC& dc, const CRect& rc, COLORREF fill, COLORREF outline, int radius) {
CBrush brush(fill);
CPen pen(PS_SOLID, 1, outline);
CBrush* oldBrush = dc.SelectObject(&brush);
CPen* oldPen = dc.SelectObject(&pen);
dc.RoundRect(&rc, CPoint(radius, radius));
dc.SelectObject(oldBrush);
dc.SelectObject(oldPen);
}