1269 lines
29 KiB
C++
1269 lines
29 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "common/system.h"
|
|
#include "common/queue.h"
|
|
#include "common/textconsole.h"
|
|
#include "bagel/mfc/afxwin.h"
|
|
#include "bagel/mfc/wingdi.h"
|
|
#include "bagel/mfc/win_hand.h"
|
|
#include "bagel/mfc/gfx/dialog_template.h"
|
|
|
|
namespace Bagel {
|
|
namespace MFC {
|
|
|
|
IMPLEMENT_DYNAMIC(CWnd, CCmdTarget)
|
|
BEGIN_MESSAGE_MAP(CWnd, CCmdTarget)
|
|
ON_WM_ACTIVATE()
|
|
ON_WM_CLOSE()
|
|
ON_WM_DESTROY()
|
|
ON_WM_NCDESTROY()
|
|
ON_WM_DRAWITEM()
|
|
ON_WM_SETFONT()
|
|
ON_WM_SETCURSOR()
|
|
ON_WM_SHOWWINDOW()
|
|
ON_WM_QUERYNEWPALETTE()
|
|
END_MESSAGE_MAP()
|
|
|
|
CWnd *CWnd::FromHandlePermanent(HWND hWnd) {
|
|
auto *pMap = AfxGetApp()->afxMapWnd();
|
|
assert(pMap);
|
|
return pMap->LookupPermanent(hWnd);
|
|
}
|
|
|
|
CWnd *CWnd::FromHandle(HWND hWnd) {
|
|
return FromHandlePermanent(hWnd);
|
|
}
|
|
|
|
CWnd::CWnd() : m_hWnd(this) {
|
|
CWinApp *app = AfxGetApp();
|
|
auto *pMap = app->afxMapWnd(true);
|
|
assert(pMap != nullptr);
|
|
|
|
pMap->SetPermanent(m_hWnd, this);
|
|
|
|
// Defaults
|
|
_hFont = app->getDefaultFont();
|
|
_hPen = app->getDefaultPen();
|
|
_hBrush = app->getDefaultBrush();
|
|
_hPalette = app->getSystemDefaultPalette();
|
|
}
|
|
|
|
CWnd::~CWnd() {
|
|
AfxGetApp()->afxUpdateWnds().remove(this);
|
|
|
|
// Although we check the flag here, currently it's
|
|
// hardcoded to be on for ScummVM
|
|
if ((m_nClassStyle & CS_OWNDC) && _pDC) {
|
|
_pDC->DeleteDC();
|
|
delete _pDC;
|
|
_pDC = nullptr;
|
|
}
|
|
|
|
DestroyWindow();
|
|
|
|
// Remove wnd from the map
|
|
auto *pMap = AfxGetApp()->afxMapWnd();
|
|
assert(pMap != nullptr);
|
|
pMap->RemoveHandle(m_hWnd);
|
|
}
|
|
|
|
bool CWnd::Create(const char *lpszClassName, const char *lpszWindowName,
|
|
uint32 dwStyle, const RECT &rect, CWnd *pParentWnd,
|
|
unsigned int nID, CCreateContext *pContext) {
|
|
m_pParentWnd = pParentWnd;
|
|
m_nStyle = dwStyle;
|
|
_controlId = nID;
|
|
|
|
// Set up create structure
|
|
CREATESTRUCT cs;
|
|
cs.x = rect.left;
|
|
cs.y = rect.top;
|
|
cs.cx = rect.right - rect.left;
|
|
cs.cy = rect.bottom - rect.top;
|
|
cs.style = dwStyle;
|
|
cs.lpCreateParams = pContext;
|
|
|
|
// Trigger pre-create event
|
|
if (!PreCreateWindow(cs))
|
|
return false;
|
|
|
|
// Create the actual window content
|
|
_windowRect.left = cs.x;
|
|
_windowRect.top = cs.y;
|
|
_windowRect.right = cs.x + cs.cx;
|
|
_windowRect.bottom = cs.y + cs.cy;
|
|
_windowText = lpszWindowName;
|
|
|
|
// Get the screen area
|
|
RECT screenRect;
|
|
screenRect.left = screenRect.top = 0;
|
|
screenRect.right = cs.cx;
|
|
screenRect.bottom = cs.cy;
|
|
ClientToScreen(&screenRect);
|
|
|
|
// Get the class details
|
|
WNDCLASS wc;
|
|
GetClassInfo(nullptr, lpszClassName, &wc);
|
|
m_nClassStyle = wc.style;
|
|
|
|
if (m_pParentWnd)
|
|
m_pParentWnd->_children[nID] = this;
|
|
|
|
SendMessage(WM_CREATE, 0, (LPARAM)&cs);
|
|
Invalidate();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CWnd::CreateEx(uint32 dwExStyle, const char *lpszClassName,
|
|
const char *lpszWindowName, uint32 dwStyle,
|
|
const RECT &rect, CWnd *pParentWnd, unsigned int nID,
|
|
void *lpParam /* = nullptr */) {
|
|
return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
|
|
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
|
|
pParentWnd->GetSafeHwnd(), nID, lpParam);
|
|
}
|
|
|
|
bool CWnd::CreateEx(uint32 dwExStyle, const char *lpszClassName,
|
|
const char *lpszWindowName, uint32 dwStyle,
|
|
int x, int y, int nWidth, int nHeight,
|
|
HWND hWndParent, LPARAM nIDorHMenu, void *lpParam) {
|
|
// Set up create structure
|
|
CREATESTRUCT cs;
|
|
cs.x = x;
|
|
cs.y = y;
|
|
cs.cx = nWidth;
|
|
cs.cy = nHeight;
|
|
cs.lpCreateParams = lpParam;
|
|
|
|
// Trigger pre-create event
|
|
if (!PreCreateWindow(cs))
|
|
return false;
|
|
|
|
// Create the actual window content
|
|
_windowRect.left = cs.x;
|
|
_windowRect.top = cs.y;
|
|
_windowRect.right = cs.x + cs.cx;
|
|
_windowRect.bottom = cs.y + cs.cy;
|
|
_windowText = lpszWindowName;
|
|
|
|
// Get the screen area
|
|
RECT screenRect;
|
|
screenRect.left = screenRect.top = 0;
|
|
screenRect.right = cs.cx;
|
|
screenRect.bottom = cs.cy;
|
|
ClientToScreen(&screenRect);
|
|
|
|
// Get the class details
|
|
WNDCLASS wc;
|
|
GetClassInfo(nullptr, lpszClassName, &wc);
|
|
m_nClassStyle = wc.style;
|
|
|
|
SendMessage(WM_CREATE, 0, (LPARAM)&cs);
|
|
Invalidate();
|
|
|
|
return true;
|
|
}
|
|
|
|
const MSG *CWnd::GetCurrentMessage() {
|
|
return &AfxGetApp()->_currentMessage;
|
|
}
|
|
|
|
CWnd *CWnd::GetParent() const {
|
|
return m_pParentWnd;
|
|
}
|
|
|
|
CWnd *CWnd::GetTopLevelFrame() {
|
|
CWnd *p = this;
|
|
while (p->GetParent() != nullptr)
|
|
p = p->GetParent();
|
|
return p;
|
|
}
|
|
|
|
Common::Array<const CWnd *> CWnd::GetSafeParents(bool includeSelf) const {
|
|
Common::Array<const CWnd *> results;
|
|
bool hasParentDialog = false;
|
|
|
|
for (const CWnd *wnd = includeSelf ? this : m_pParentWnd;
|
|
wnd; wnd = wnd->m_pParentWnd) {
|
|
if (dynamic_cast<const CDialog *>(wnd)) {
|
|
if (!hasParentDialog) {
|
|
hasParentDialog = true;
|
|
results.push_back(wnd);
|
|
}
|
|
} else {
|
|
results.push_back(wnd);
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
Common::Array<CWnd *> CWnd::GetSafeParents(bool includeSelf) {
|
|
Common::Array<CWnd *> results;
|
|
bool hasParentDialog = !includeSelf &&
|
|
dynamic_cast<CDialog *>(this) != nullptr;
|
|
|
|
for (CWnd *wnd = includeSelf ? this : m_pParentWnd;
|
|
wnd; wnd = wnd->m_pParentWnd) {
|
|
if (dynamic_cast<const CDialog *>(wnd)) {
|
|
if (!hasParentDialog) {
|
|
hasParentDialog = true;
|
|
results.push_back(wnd);
|
|
}
|
|
} else {
|
|
results.push_back(wnd);
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
HWND CWnd::GetSafeHwnd() const {
|
|
return m_hWnd;
|
|
}
|
|
|
|
void CWnd::ShowWindow(int nCmdShow) {
|
|
assert(nCmdShow == SW_SHOW || nCmdShow == SW_SHOWNORMAL ||
|
|
nCmdShow == SW_HIDE);
|
|
|
|
if (nCmdShow == SW_SHOW || nCmdShow == SW_SHOWNORMAL) {
|
|
m_nStyle |= WS_VISIBLE;
|
|
|
|
if (dynamic_cast<CFrameWnd *>(this) || dynamic_cast<CDialog *>(this))
|
|
SetActiveWindow();
|
|
} else {
|
|
m_nStyle &= ~WS_VISIBLE;
|
|
}
|
|
|
|
Invalidate(false);
|
|
SendMessage(WM_SHOWWINDOW, (m_nStyle & WS_VISIBLE) != 0);
|
|
}
|
|
|
|
bool CWnd::EnableWindow(bool bEnable) {
|
|
bool oldEnabled = (_itemState & ODS_DISABLED) == 0;
|
|
if (bEnable)
|
|
_itemState &= ~ODS_DISABLED;
|
|
else
|
|
_itemState |= ODS_DISABLED;
|
|
|
|
// Flag the control to be redrawn
|
|
Invalidate();
|
|
|
|
return oldEnabled;
|
|
}
|
|
|
|
void CWnd::UpdateWindow() {
|
|
// If there's a pending paint, do it now
|
|
MSG msg;
|
|
if (PeekMessage(&msg, m_hWnd, WM_PAINT, WM_PAINT, PM_REMOVE) ||
|
|
IsWindowDirty()) {
|
|
msg.hwnd = m_hWnd;
|
|
msg.message = WM_PAINT;
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
bool CWnd::RedrawWindow(LPCRECT lpRectUpdate,
|
|
CRgn *prgnUpdate, unsigned int flags) {
|
|
|
|
if (flags & RDW_INVALIDATE) {
|
|
// Invalidate the region or rectangle
|
|
if (prgnUpdate != nullptr) {
|
|
error("TODO: InvalidateRgn");
|
|
} else {
|
|
InvalidateRect(lpRectUpdate, !(flags & RDW_NOERASE));
|
|
}
|
|
}
|
|
|
|
if (flags & RDW_VALIDATE) {
|
|
// Optionally validate instead
|
|
if (prgnUpdate != nullptr) {
|
|
error("TODO: ValidateRgn");
|
|
} else {
|
|
ValidateRect(lpRectUpdate);
|
|
}
|
|
}
|
|
|
|
// Step 2: Invalidate overlapping children
|
|
if (flags & RDW_ALLCHILDREN) {
|
|
RECT rcUpdate = lpRectUpdate ? *lpRectUpdate : GetClientRect();
|
|
|
|
for (auto &node : _children) {
|
|
CWnd *pChild = node._value;
|
|
if (pChild->IsWindowVisible()) {
|
|
RECT rcChild = pChild->GetWindowRectInParentCoords();
|
|
|
|
if (RectsIntersect(rcUpdate, rcChild)) {
|
|
pChild->Invalidate();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flags & (RDW_UPDATENOW | RDW_ERASENOW)) {
|
|
// Send WM_PAINT immediately
|
|
UpdateWindow();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CWnd::SetActiveWindow() {
|
|
AfxGetApp()->SetActiveWindow(this);
|
|
}
|
|
|
|
void CWnd::SetFocus() {
|
|
AfxGetApp()->SetFocus(this);
|
|
}
|
|
|
|
CWnd *CWnd::GetFocus() const {
|
|
return AfxGetApp()->GetFocus();
|
|
}
|
|
|
|
void CWnd::OnActivate(unsigned int nState, CWnd *pWndOther, bool bMinimized) {
|
|
if (nState != WA_INACTIVE) {
|
|
// We're becoming active - ensure we repaint
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
void CWnd::OnClose() {
|
|
DestroyWindow();
|
|
}
|
|
|
|
void CWnd::DestroyWindow() {
|
|
// Lose focus if it currently has it
|
|
auto *app = AfxGetApp();
|
|
if (app->GetFocus() == this)
|
|
app->SetFocus(nullptr);
|
|
|
|
bool isActiveWindow = IsActiveWindow();
|
|
if (isActiveWindow)
|
|
SendMessage(WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, false), 0);
|
|
|
|
// Mark as not needed any repainting
|
|
Validate();
|
|
|
|
// Destroy and detach child controls
|
|
for (auto &node : _children) {
|
|
CWnd *child = node._value;
|
|
child->DestroyWindow();
|
|
}
|
|
_children.clear();
|
|
|
|
// Free any owned controls
|
|
for (CWnd *ctl : _ownedControls)
|
|
delete ctl;
|
|
_ownedControls.clear();
|
|
|
|
// If still attached to parent, remove from it
|
|
if (m_pParentWnd) {
|
|
m_pParentWnd->_ownedControls.remove(this);
|
|
m_pParentWnd->_children.erase(_controlId);
|
|
}
|
|
|
|
SendMessage(WM_DESTROY);
|
|
|
|
// Null the m_pParentWnd field, just in case
|
|
m_pParentWnd = nullptr;
|
|
|
|
// Send NCDESTROY. Warning: for at least view classes,
|
|
// the default PostNcDestroy deletes the view.
|
|
// So no class fields can be accessed beyond this point
|
|
SendMessage(WM_NCDESTROY);
|
|
|
|
// If it's the active window, pop it
|
|
if (isActiveWindow)
|
|
AfxGetApp()->PopActiveWindow();
|
|
}
|
|
|
|
int CWnd::GetWindowText(CString &rString) const {
|
|
rString = _windowText;
|
|
return rString.size();
|
|
}
|
|
|
|
int CWnd::GetWindowText(char *lpszStringBuf, int nMaxCount) const {
|
|
Common::strcpy_s(lpszStringBuf, nMaxCount, _windowText.c_str());
|
|
return strlen(lpszStringBuf);
|
|
}
|
|
|
|
bool CWnd::SetWindowText(const char *lpszString) {
|
|
_windowText = lpszString;
|
|
Invalidate();
|
|
return true;
|
|
}
|
|
|
|
unsigned int CWnd::GetState() const {
|
|
return _itemState;
|
|
}
|
|
|
|
void CWnd::SetStyle(uint32 nStyle) {
|
|
m_nStyle = nStyle;
|
|
Invalidate();
|
|
}
|
|
|
|
CDC *CWnd::GetDC() {
|
|
if (_pDC != nullptr) {
|
|
// Return persistent DC
|
|
return _pDC;
|
|
} else if (_windowRect.isEmpty()) {
|
|
// Window hasn't yet been created, so return
|
|
// a full screen DC
|
|
HDC hdc = MFC::GetDC(nullptr);
|
|
CDC *dc = new CDC();
|
|
dc->Attach(hdc);
|
|
return dc;
|
|
|
|
} else {
|
|
// Return a new DC for the window
|
|
CDC::Impl *hDC = new CDC::Impl(this);
|
|
hDC->Attach(_hFont);
|
|
hDC->Attach(_hPen);
|
|
hDC->Attach(_hBrush);
|
|
hDC->selectPalette(_hPalette, true);
|
|
|
|
RECT screenRect;
|
|
screenRect.left = screenRect.top = 0;
|
|
screenRect.right = _windowRect.width();
|
|
screenRect.bottom = _windowRect.height();
|
|
ClientToScreen(&screenRect);
|
|
hDC->setScreenRect(screenRect);
|
|
|
|
CDC *pDC = new CDC();
|
|
pDC->Attach(hDC);
|
|
|
|
if (m_nClassStyle & CS_OWNDC)
|
|
_pDC = pDC;
|
|
|
|
return pDC;
|
|
}
|
|
}
|
|
|
|
int CWnd::ReleaseDC(CDC *pDC) {
|
|
if (pDC && pDC == _pDC) {
|
|
// Wnd has persistent dc
|
|
assert(m_nClassStyle & CS_OWNDC);
|
|
|
|
} else {
|
|
delete pDC;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
bool CWnd::PostMessage(unsigned int message, WPARAM wParam, LPARAM lParam) {
|
|
return AfxGetApp()->PostMessage(m_hWnd, message, wParam, lParam);
|
|
}
|
|
|
|
LRESULT CWnd::SendMessage(unsigned int message, WPARAM wParam, LPARAM lParam) {
|
|
// Don't send messages to already destroyed windows
|
|
if (!m_hWnd)
|
|
return 0;
|
|
|
|
auto &msg = AfxGetApp()->_currentMessage;
|
|
msg.hwnd = m_hWnd;
|
|
msg.message = message;
|
|
msg.wParam = wParam;
|
|
msg.lParam = lParam;
|
|
|
|
LRESULT lResult = 0;
|
|
if (!OnWndMsg(message, wParam, lParam, &lResult))
|
|
lResult = DefWindowProc(message, wParam, lParam);
|
|
|
|
// FIXME: In a properly emulated control painting,
|
|
// painting a window background should exclude drawing on
|
|
// any area covered by child controls. Technically each
|
|
// control has it's own window, unlike here in ScummVM,
|
|
// where all the DCs are sharing the single physical screen.
|
|
// As a hack to fix issues with controls getting drawn over,
|
|
// any paint to a wnd will redraw any child controls
|
|
if (message == WM_PAINT) {
|
|
for (auto &child : _children)
|
|
child._value->RedrawWindow(nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW);
|
|
}
|
|
|
|
// Handle messages that get sent to child controls
|
|
if (isRecursiveMessage(message)) {
|
|
for (auto &ctl : _children)
|
|
ctl._value->SendMessage(message, wParam, lParam);
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
bool CWnd::isRecursiveMessage(unsigned int message) {
|
|
// TODO: Need to refactor these to use the
|
|
// SendMessageToDescendants instead of this
|
|
return message == WM_SHOWWINDOW ||
|
|
message == WM_ENABLE;
|
|
}
|
|
|
|
bool CWnd::OnWndMsg(unsigned int message, WPARAM wParam, LPARAM lParam, LRESULT *pResult) {
|
|
LRESULT lResult = 0;
|
|
const AFX_MSGMAP_ENTRY *lpEntry;
|
|
|
|
// Special case for commands
|
|
if (message == WM_COMMAND) {
|
|
if (OnCommand(wParam, lParam)) {
|
|
lResult = 1;
|
|
goto LReturnTrue;
|
|
}
|
|
|
|
return false;
|
|
} else if (message == WM_ACTIVATE) {
|
|
OnActivate(LOWORD(wParam), nullptr, false);
|
|
lResult = 1;
|
|
goto LReturnTrue;
|
|
}
|
|
|
|
// Ignoring messages to hidden controls
|
|
if (!IsWindowVisible()) {
|
|
static const uint16 MESSAGES[] = {
|
|
WM_PAINT, WM_ERASEBKGND, WM_LBUTTONDOWN,
|
|
WM_LBUTTONUP, WM_MOUSEMOVE, WM_SETFOCUS,
|
|
WM_KILLFOCUS, WM_KEYDOWN, WM_KEYUP, WM_CHAR,
|
|
WM_COMMAND, WM_TIMER, 0
|
|
};
|
|
for (const uint16 *msgP = MESSAGES; *msgP; ++msgP) {
|
|
if (message == *msgP)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Special cases we don't currently support
|
|
#define UNHANDLED(MSG) if (message == MSG) \
|
|
error(#MSG " not currently supported")
|
|
UNHANDLED(WM_NOTIFY);
|
|
UNHANDLED(WM_SETTINGCHANGE);
|
|
#undef UNHANDLED
|
|
|
|
// Look up the message in the message map
|
|
lpEntry = LookupMessage(message);
|
|
if (!lpEntry)
|
|
return false;
|
|
|
|
assert(message < 0xC000);
|
|
union MessageMapFunctions mmf;
|
|
mmf.pfn = lpEntry->pfn;
|
|
|
|
int nSig;
|
|
nSig = lpEntry->nSig;
|
|
|
|
switch (nSig) {
|
|
case AfxSig_bD:
|
|
lResult = (this->*mmf.pfn_bD)(CDC::FromHandle((HDC)wParam));
|
|
break;
|
|
|
|
case AfxSig_bb: // AfxSig_bb, AfxSig_bw, AfxSig_bh
|
|
lResult = (this->*mmf.pfn_bb)((bool)wParam);
|
|
break;
|
|
|
|
case AfxSig_bWww: // really AfxSig_bWiw
|
|
lResult = (this->*mmf.pfn_bWww)(CWnd::FromHandle((HWND)wParam),
|
|
(short)LOWORD(lParam), HIWORD(lParam));
|
|
break;
|
|
|
|
case AfxSig_bWCDS:
|
|
lResult = (this->*mmf.pfn_bWCDS)(CWnd::FromHandle((HWND)wParam),
|
|
(COPYDATASTRUCT *)lParam);
|
|
break;
|
|
|
|
case AfxSig_bHELPINFO:
|
|
lResult = (this->*mmf.pfn_bHELPINFO)((HELPINFO *)lParam);
|
|
break;
|
|
|
|
case AfxSig_hDWw:
|
|
// Special case for OnCtlColor to avoid too many temporary objects
|
|
error("Unsupported OnCtlColor");
|
|
break;
|
|
|
|
case AfxSig_hDw:
|
|
// Special case for CtlColor to avoid too many temporary objects
|
|
error("Unsupported WM_REFLECT_BASE");
|
|
break;
|
|
|
|
case AfxSig_iwWw:
|
|
lResult = (this->*mmf.pfn_iwWw)(LOWORD(wParam),
|
|
CWnd::FromHandle((HWND)lParam), HIWORD(wParam));
|
|
break;
|
|
|
|
case AfxSig_iww:
|
|
lResult = (this->*mmf.pfn_iww)(LOWORD(wParam), HIWORD(wParam));
|
|
break;
|
|
|
|
case AfxSig_iWww:
|
|
// Really AfxSig_iWiw
|
|
lResult = (this->*mmf.pfn_iWww)(CWnd::FromHandle((HWND)wParam),
|
|
(short)LOWORD(lParam), HIWORD(lParam));
|
|
break;
|
|
|
|
case AfxSig_is:
|
|
lResult = (this->*mmf.pfn_is)((uint16 *)lParam);
|
|
break;
|
|
|
|
case AfxSig_lwl:
|
|
lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
|
|
break;
|
|
|
|
case AfxSig_lwwM:
|
|
lResult = (this->*mmf.pfn_lwwM)((unsigned int)LOWORD(wParam),
|
|
(unsigned int)HIWORD(wParam), (CMenu *)CMenu::FromHandle((HMENU)lParam));
|
|
break;
|
|
|
|
case AfxSig_vv:
|
|
(this->*mmf.pfn_vv)();
|
|
break;
|
|
|
|
case AfxSig_vw: // AfxSig_vb, AfxSig_vh
|
|
(this->*mmf.pfn_vw)(wParam);
|
|
break;
|
|
|
|
case AfxSig_vww:
|
|
(this->*mmf.pfn_vww)((unsigned int)wParam, (unsigned int)lParam);
|
|
break;
|
|
|
|
case AfxSig_vvii:
|
|
(this->*mmf.pfn_vvii)((short)LOWORD(lParam), (short)HIWORD(lParam));
|
|
break;
|
|
|
|
case AfxSig_vwww:
|
|
(this->*mmf.pfn_vwww)(wParam, LOWORD(lParam), HIWORD(lParam));
|
|
break;
|
|
|
|
case AfxSig_vwii:
|
|
(this->*mmf.pfn_vwii)(wParam, LOWORD(lParam), HIWORD(lParam));
|
|
break;
|
|
|
|
case AfxSig_vwl:
|
|
(this->*mmf.pfn_vwl)(wParam, lParam);
|
|
break;
|
|
|
|
case AfxSig_vbWW:
|
|
(this->*mmf.pfn_vbWW)(m_hWnd == (HWND)lParam,
|
|
CWnd::FromHandle((HWND)lParam),
|
|
CWnd::FromHandle((HWND)wParam));
|
|
break;
|
|
|
|
case AfxSig_vD:
|
|
(this->*mmf.pfn_vD)(CDC::FromHandle((HDC)wParam));
|
|
break;
|
|
|
|
case AfxSig_vM:
|
|
(this->*mmf.pfn_vM)(CMenu::FromHandle((HMENU)wParam));
|
|
break;
|
|
|
|
case AfxSig_vMwb:
|
|
(this->*mmf.pfn_vMwb)(CMenu::FromHandle((HMENU)wParam),
|
|
LOWORD(lParam), (bool)HIWORD(lParam));
|
|
break;
|
|
|
|
case AfxSig_vW:
|
|
(this->*mmf.pfn_vW)(CWnd::FromHandle((HWND)wParam));
|
|
break;
|
|
|
|
case AfxSig_vW2:
|
|
(this->*mmf.pfn_vW)(CWnd::FromHandle((HWND)lParam));
|
|
break;
|
|
|
|
case AfxSig_vWww:
|
|
(this->*mmf.pfn_vWww)(CWnd::FromHandle((HWND)wParam), LOWORD(lParam),
|
|
HIWORD(lParam));
|
|
break;
|
|
|
|
case AfxSig_vWp:
|
|
{
|
|
CPoint point((uint32)lParam);
|
|
(this->*mmf.pfn_vWp)(CWnd::FromHandle((HWND)wParam), point);
|
|
}
|
|
break;
|
|
|
|
case AfxSig_vWh:
|
|
(this->*mmf.pfn_vWh)(CWnd::FromHandle((HWND)wParam),
|
|
(HANDLE)lParam);
|
|
break;
|
|
|
|
case AfxSig_vwW:
|
|
(this->*mmf.pfn_vwW)(wParam, CWnd::FromHandle((HWND)lParam));
|
|
break;
|
|
|
|
case AfxSig_vwWb:
|
|
(this->*mmf.pfn_vwWb)((unsigned int)(LOWORD(wParam)),
|
|
CWnd::FromHandle((HWND)lParam), (bool)HIWORD(wParam));
|
|
break;
|
|
|
|
case AfxSig_vwwW:
|
|
case AfxSig_vwwx:
|
|
{
|
|
// special case for WM_VSCROLL and WM_HSCROLL
|
|
ASSERT(message == WM_VSCROLL || message == WM_HSCROLL ||
|
|
message == WM_VSCROLL + WM_REFLECT_BASE || message == WM_HSCROLL + WM_REFLECT_BASE);
|
|
int nScrollCode = (short)LOWORD(wParam);
|
|
int nPos = (short)HIWORD(wParam);
|
|
if (lpEntry->nSig == AfxSig_vwwW)
|
|
(this->*mmf.pfn_vwwW)(nScrollCode, nPos,
|
|
CWnd::FromHandle((HWND)lParam));
|
|
else
|
|
(this->*mmf.pfn_vwwx)(nScrollCode, nPos);
|
|
}
|
|
break;
|
|
|
|
case AfxSig_vs:
|
|
(this->*mmf.pfn_vs)((uint16 *)lParam);
|
|
break;
|
|
|
|
case AfxSig_vws:
|
|
(this->*mmf.pfn_vws)((unsigned int)wParam, (const char *)lParam);
|
|
break;
|
|
|
|
case AfxSig_vOWNER:
|
|
(this->*mmf.pfn_vOWNER)((int)wParam, (uint16 *)lParam);
|
|
lResult = true;
|
|
break;
|
|
|
|
case AfxSig_iis:
|
|
lResult = (this->*mmf.pfn_iis)((int)wParam, (uint16 *)lParam);
|
|
break;
|
|
|
|
case AfxSig_wp:
|
|
{
|
|
CPoint point((uint32)lParam);
|
|
lResult = (this->*mmf.pfn_wp)(point);
|
|
}
|
|
break;
|
|
|
|
case AfxSig_bv:
|
|
lResult = (this->*mmf.pfn_bv)() ? 1 : 0;
|
|
break;
|
|
|
|
case AfxSig_wv:
|
|
lResult = (this->*mmf.pfn_wv)();
|
|
break;
|
|
|
|
case AfxSig_vCALC:
|
|
(this->*mmf.pfn_vCALC)((bool)wParam, (NCCALCSIZE_PARAMS *)lParam);
|
|
break;
|
|
|
|
case AfxSig_vPOS:
|
|
(this->*mmf.pfn_vPOS)((WINDOWPOS *)lParam);
|
|
break;
|
|
|
|
case AfxSig_vwwh:
|
|
(this->*mmf.pfn_vwwh)(LOWORD(wParam), HIWORD(wParam), (HANDLE)lParam);
|
|
break;
|
|
|
|
case AfxSig_vwp:
|
|
{
|
|
CPoint point((uint32)lParam);
|
|
(this->*mmf.pfn_vwp)(wParam, point);
|
|
break;
|
|
}
|
|
case AfxSig_vwSIZING:
|
|
(this->*mmf.pfn_vwl)(wParam, lParam);
|
|
lResult = true;
|
|
break;
|
|
|
|
case AfxSig_bwsp:
|
|
lResult = (this->*mmf.pfn_bwsp)(LOWORD(wParam), (short)HIWORD(wParam),
|
|
CPoint(LOWORD(lParam), HIWORD(lParam)));
|
|
if (!lResult)
|
|
return false;
|
|
break;
|
|
|
|
case AfxSig_vwpb:
|
|
(this->*mmf.pfn_vFb)((HFONT)wParam, (bool)lParam);
|
|
break;
|
|
|
|
default:
|
|
error("Unknown AFX signature");
|
|
break;
|
|
}
|
|
|
|
LReturnTrue:
|
|
if (pResult != nullptr)
|
|
*pResult = lResult;
|
|
return true;
|
|
}
|
|
|
|
bool CWnd::Validate() {
|
|
return ValidateRect(nullptr);
|
|
}
|
|
|
|
bool CWnd::ValidateRect(LPCRECT lpRect) {
|
|
if (!lpRect) {
|
|
// Remove entire area
|
|
_updateRect = Common::Rect();
|
|
|
|
} else {
|
|
if (_updateRect.isEmpty() || _updateRect.contains(*lpRect)) {
|
|
_updateRect = Common::Rect();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CWnd::Invalidate(bool bErase) {
|
|
CRect clientRect;
|
|
GetClientRect(&clientRect);
|
|
InvalidateRect(&clientRect, bErase);
|
|
}
|
|
|
|
bool CWnd::InvalidateRect(LPCRECT lpRect, bool bErase) {
|
|
if (lpRect)
|
|
_updateRect.extend(*lpRect);
|
|
else
|
|
_updateRect = Common::Rect(0, 0,
|
|
_windowRect.width(), _windowRect.height());
|
|
assert(_updateRect.left >= 0 && _updateRect.top >= 0 &&
|
|
_updateRect.right <= _windowRect.width() &&
|
|
_updateRect.bottom <= _windowRect.bottom);
|
|
|
|
// Add wnd to update list
|
|
AfxGetApp()->afxUpdateWnds().add(this);
|
|
|
|
return true;
|
|
}
|
|
|
|
void CWnd::GetWindowRect(LPRECT lpRect) const {
|
|
lpRect->left = _windowRect.left;
|
|
lpRect->top = _windowRect.top;
|
|
lpRect->right = _windowRect.right;
|
|
lpRect->bottom = _windowRect.bottom;
|
|
}
|
|
|
|
bool CWnd::GetUpdateRect(LPRECT lpRect, bool bErase) {
|
|
if (lpRect)
|
|
*lpRect = RectToRECT(_updateRect);
|
|
_updateErase = bErase;
|
|
|
|
return IsWindowDirty();
|
|
}
|
|
|
|
bool CWnd::GetClientRect(LPRECT lpRect) const {
|
|
lpRect->left = 0;
|
|
lpRect->top = 0;
|
|
lpRect->right = _windowRect.width();
|
|
lpRect->bottom = _windowRect.height();
|
|
|
|
return true;
|
|
}
|
|
|
|
RECT CWnd::GetClientRect() const {
|
|
RECT r;
|
|
GetClientRect(&r);
|
|
return r;
|
|
}
|
|
|
|
bool CWnd::PointInClientRect(const POINT &pt) const {
|
|
RECT clientRect;
|
|
GetClientRect(&clientRect);
|
|
|
|
return clientRect.contains(pt);
|
|
}
|
|
|
|
void CWnd::ClientToScreen(LPPOINT lpPoint) const {
|
|
for (const CWnd *wnd : GetSafeParents()) {
|
|
lpPoint->x += wnd->_windowRect.left;
|
|
lpPoint->y += wnd->_windowRect.top;
|
|
}
|
|
}
|
|
|
|
void CWnd::ClientToScreen(LPRECT lpRect) const {
|
|
for (const CWnd *wnd : GetSafeParents()) {
|
|
lpRect->left += wnd->_windowRect.left;
|
|
lpRect->top += wnd->_windowRect.top;
|
|
lpRect->right += wnd->_windowRect.left;
|
|
lpRect->bottom += wnd->_windowRect.top;
|
|
}
|
|
}
|
|
|
|
void CWnd::ScreenToClient(LPPOINT lpPoint) const {
|
|
for (const CWnd *wnd : GetSafeParents()) {
|
|
lpPoint->x -= wnd->_windowRect.left;
|
|
lpPoint->y -= wnd->_windowRect.top;
|
|
}
|
|
}
|
|
|
|
void CWnd::ScreenToClient(LPRECT lpRect) const {
|
|
for (const CWnd *wnd : GetSafeParents()) {
|
|
lpRect->left -= wnd->_windowRect.left;
|
|
lpRect->top -= wnd->_windowRect.top;
|
|
lpRect->right -= wnd->_windowRect.left;
|
|
lpRect->bottom -= wnd->_windowRect.top;
|
|
}
|
|
}
|
|
|
|
|
|
RECT CWnd::GetWindowRectInParentCoords() const {
|
|
RECT rc;
|
|
GetWindowRect(&rc);
|
|
|
|
// Convert to parent's client coordinates
|
|
CWnd *pParent = GetParent();
|
|
if (pParent != nullptr) {
|
|
pParent->ScreenToClient(&rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void CWnd::MoveWindow(LPCRECT lpRect, bool bRepaint) {
|
|
_windowRect = *lpRect;
|
|
ValidateRect(nullptr);
|
|
|
|
if (_pDC) {
|
|
// Get the screen area
|
|
RECT screenRect;
|
|
screenRect.left = screenRect.top = 0;
|
|
screenRect.right = _windowRect.width();
|
|
screenRect.bottom = _windowRect.height();
|
|
ClientToScreen(&screenRect);
|
|
_pDC->impl()->setScreenRect(screenRect);
|
|
}
|
|
|
|
// Iterate through all child controls. We won't
|
|
// change their relative position, but doing so will
|
|
// cause their screen surface area to be updated
|
|
for (auto &ctl : _children) {
|
|
const Common::Rect &r = ctl._value->_windowRect;
|
|
RECT ctlRect;
|
|
ctlRect.left = r.left;
|
|
ctlRect.top = r.top;
|
|
ctlRect.right = r.right;
|
|
ctlRect.bottom = r.bottom;
|
|
ctl._value->MoveWindow(&ctlRect, false);
|
|
}
|
|
|
|
if (bRepaint)
|
|
InvalidateRect(nullptr, true);
|
|
}
|
|
|
|
void CWnd::MoveWindow(int x, int y, int nWidth, int nHeight, bool bRepaint) {
|
|
RECT r;
|
|
r.left = x;
|
|
r.top = y;
|
|
r.right = x + nWidth;
|
|
r.bottom = y + nHeight;
|
|
MoveWindow(&r, bRepaint);
|
|
}
|
|
|
|
HDC CWnd::BeginPaint(LPPAINTSTRUCT lpPaint) {
|
|
CDC *dc = GetDC();
|
|
|
|
lpPaint->hdc = dc->m_hDC;
|
|
lpPaint->fErase = _updateErase;
|
|
lpPaint->rcPaint = RectToRECT(_updateRect);
|
|
lpPaint->fRestore = false;
|
|
lpPaint->fIncUpdate = false;
|
|
Common::fill(lpPaint->rgbReserved,
|
|
lpPaint->rgbReserved + 32, 0);
|
|
|
|
_updatingRect = _updateRect;
|
|
|
|
// Restrict drawing to the update area
|
|
dc->setClipRect(_updateRect);
|
|
|
|
if (_hFont)
|
|
SelectObject(lpPaint->hdc, _hFont);
|
|
|
|
return dc->m_hDC;
|
|
}
|
|
|
|
bool CWnd::EndPaint(const PAINTSTRUCT *lpPaint) {
|
|
_updateRect = Common::Rect();
|
|
AfxGetApp()->afxUpdateWnds().remove(this);
|
|
_updateErase = false;
|
|
|
|
// If it's a persistent dc for the window, reset clipping
|
|
if (_pDC)
|
|
_pDC->resetClipRect();
|
|
|
|
return true;
|
|
}
|
|
|
|
CWnd *CWnd::GetDlgItem(int nID) const {
|
|
return _children.contains(nID) ? _children[nID] : nullptr;
|
|
}
|
|
|
|
CWnd *CWnd::GetNextDlgGroupItem(CWnd *pWndCtl, bool bPrevious) const {
|
|
// First set up the children hash map as a straight array
|
|
// for easier iterating over
|
|
Common::Array<CWnd *> children;
|
|
for (auto &child : _children)
|
|
children.push_back(child._value);
|
|
|
|
// Get the starting index
|
|
int idStart = pWndCtl->GetDlgCtrlID();
|
|
int startIdx;
|
|
for (startIdx = 0; startIdx < (int)children.size() &&
|
|
children[startIdx]->GetDlgCtrlID() != idStart; ++startIdx) {
|
|
}
|
|
assert(startIdx != (int)children.size());
|
|
|
|
// Remove any items from the array from the next WS_GROUP onwards
|
|
const int style = WS_GROUP | WS_VISIBLE;
|
|
int idx = startIdx + 1;
|
|
for (; idx < (int)children.size(); ++idx) {
|
|
if ((children[idx]->GetStyle() & style) == style) {
|
|
// Found next group, remove remainder
|
|
while (idx < (int)children.size())
|
|
children.remove_at(idx);
|
|
}
|
|
}
|
|
|
|
// Remove any items before the start of the current group
|
|
idx = startIdx;
|
|
while (idx >= 0 && !(children[idx]->GetStyle() & WS_GROUP))
|
|
--idx;
|
|
for (; idx > 0; --idx, --startIdx)
|
|
children.remove_at(0);
|
|
assert(children[startIdx] == pWndCtl);
|
|
|
|
// Get the next item
|
|
if (bPrevious) {
|
|
if (--startIdx < 0)
|
|
startIdx = (int)children.size() - 1;
|
|
} else {
|
|
if (++startIdx == (int)children.size())
|
|
startIdx = 0;
|
|
}
|
|
|
|
return children[startIdx];
|
|
}
|
|
|
|
bool CWnd::GotoDlgCtrl(CWnd *pWndCtrl) {
|
|
if (pWndCtrl != nullptr) {
|
|
pWndCtrl->SetFocus(); // Give it focus
|
|
SendMessage(WM_NEXTDLGCTL, (WPARAM)pWndCtrl->m_hWnd, true); // Update focus info
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CWnd::SubclassDlgItem(unsigned int nID, CWnd *pParent) {
|
|
// Validate we're replacing the same kind of control
|
|
assert(pParent->_children.contains(nID));
|
|
CWnd *oldControl = pParent->_children[nID];
|
|
assert(IsKindOf(oldControl->GetRuntimeClass()));
|
|
|
|
// Remove the old control from the window
|
|
pParent->_ownedControls.remove(oldControl);
|
|
pParent->_children.erase(oldControl->_controlId);
|
|
|
|
// Add the new control to the parent
|
|
pParent->_children[nID] = this;
|
|
m_pParentWnd = pParent;
|
|
|
|
// Copy over the properties to the new control
|
|
_windowText = oldControl->_windowText;
|
|
_windowRect = oldControl->_windowRect;
|
|
_controlId = oldControl->_controlId;
|
|
m_nClassStyle = oldControl->m_nClassStyle;
|
|
m_nStyle = oldControl->m_nStyle;
|
|
_hFont = oldControl->_hFont;
|
|
|
|
RECT screenRect = RectToRECT(0, 0, _windowRect.width(), _windowRect.height());
|
|
ClientToScreen(&screenRect);
|
|
|
|
// Copy over the settings
|
|
_hFont = oldControl->_hFont;
|
|
_hPen = oldControl->_hPen;
|
|
_hBrush = oldControl->_hBrush;
|
|
_hPalette = oldControl->_hPalette;
|
|
|
|
// Mark the control for being drawn
|
|
AfxGetApp()->afxUpdateWnds().remove(oldControl);
|
|
Invalidate();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CWnd::SetDlgItemText(int nIDDlgItem, const char *lpString) {
|
|
CWnd *wnd = GetDlgItem(nIDDlgItem);
|
|
|
|
if (wnd) {
|
|
wnd->SetWindowText(lpString);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int CWnd::GetDlgCtrlID() const {
|
|
return _controlId;
|
|
}
|
|
|
|
void CWnd::CheckDlgButton(int nIDButton, unsigned int nCheck) {
|
|
CWnd *btn = GetDlgItem(nIDButton);
|
|
assert(btn);
|
|
btn->SendMessage(BM_SETCHECK, nCheck);
|
|
}
|
|
|
|
LRESULT CWnd::SendDlgItemMessage(int nID, unsigned int message,
|
|
WPARAM wParam, LPARAM lParam) const {
|
|
CWnd *ctl = GetDlgItem(nID);
|
|
assert(ctl);
|
|
return ctl->SendMessage(message, wParam, lParam);
|
|
}
|
|
|
|
uintptr CWnd::SetTimer(uintptr nIDEvent, unsigned int nElapse,
|
|
void (CALLBACK *lpfnTimer)(HWND, unsigned int, uintptr, uint32)) {
|
|
return MFC::SetTimer(m_hWnd, nIDEvent, nElapse, lpfnTimer);
|
|
}
|
|
|
|
bool CWnd::KillTimer(uintptr nIDEvent) {
|
|
return MFC::KillTimer(m_hWnd, nIDEvent);
|
|
}
|
|
|
|
void CWnd::createDialogIndirect(LPCDLGTEMPLATE dlgTemplate) {
|
|
CDialog *dialog = dynamic_cast<CDialog *>(this);
|
|
assert(dialog);
|
|
|
|
// Parse the template and use it to load controls
|
|
Gfx::CDialogTemplate dt(dlgTemplate);
|
|
dt.loadTemplate(dialog);
|
|
|
|
SendMessage(WM_INITDIALOG);
|
|
ShowWindow(SW_SHOWNORMAL);
|
|
}
|
|
|
|
void CWnd::SetCapture() {
|
|
AfxGetApp()->SetCapture(m_hWnd);
|
|
}
|
|
|
|
void CWnd::ReleaseCapture() {
|
|
AfxGetApp()->ReleaseCapture();
|
|
}
|
|
|
|
void CWnd::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) {
|
|
CWnd *pControl = GetDlgItem(nIDCtl);
|
|
if (pControl)
|
|
pControl->DrawItem(lpDrawItemStruct);
|
|
}
|
|
|
|
bool CWnd::OnCommand(WPARAM wParam, LPARAM lParam) {
|
|
unsigned int nID = LOWORD(wParam);
|
|
int nCode = HIWORD(wParam);
|
|
|
|
// TODO: Original does some stuff with reflecting
|
|
// the previous message to child control by default
|
|
|
|
return OnCmdMsg(nID, nCode, nullptr, nullptr);
|
|
}
|
|
|
|
void CWnd::OnSetFont(HFONT hFont, bool bRedraw) {
|
|
_hFont = hFont;
|
|
|
|
if (bRedraw)
|
|
Invalidate();
|
|
}
|
|
|
|
bool CWnd::OnSetCursor(CWnd *pWnd, unsigned int nHitTest, unsigned int message) {
|
|
MFC::SetCursor(MFC::LoadCursor(nullptr, IDC_ARROW));
|
|
return true;
|
|
}
|
|
|
|
void CWnd::SendMessageToDescendants(unsigned int message,
|
|
WPARAM wParam, LPARAM lParam,
|
|
bool bDeep, bool) {
|
|
// Note: since in ScummVM the m_hWnd points
|
|
// to the CWnd itself, all controls are currently
|
|
// "permanent", hence the original bPermanent
|
|
// param is meaningless
|
|
Common::Queue<CWnd *> queue;
|
|
|
|
// Add immediate children
|
|
for (auto &node : _children)
|
|
queue.push(node._value);
|
|
|
|
// Iterate through handling each child, and adding
|
|
// in any child they have if doing a deep send
|
|
while (!queue.empty()) {
|
|
CWnd *wnd = queue.pop();
|
|
|
|
// If the control has any children,
|
|
// add them if deep mode is flagged
|
|
if (bDeep) {
|
|
for (auto &node : wnd->_children)
|
|
queue.push(node._value);
|
|
}
|
|
|
|
// Send the message to the control
|
|
wnd->SendMessage(message, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
void CWnd::SendMessageToDescendants(HWND hWnd, unsigned int message,
|
|
WPARAM wParam, LPARAM lParam, bool bDeep, bool bOnlyPerm) {
|
|
CWnd *wnd = CWnd::FromHandle(hWnd);
|
|
wnd->SendMessageToDescendants(message,
|
|
wParam, lParam, bDeep, bOnlyPerm);
|
|
}
|
|
|
|
bool CWnd::IsActiveWindow() const {
|
|
return AfxGetApp()->GetActiveWindow() == this;
|
|
}
|
|
|
|
void CWnd::SetFont(CFont *pFont, bool bRedraw) {
|
|
SendMessage(WM_SETFONT, (WPARAM)pFont->m_hObject, bRedraw);
|
|
}
|
|
|
|
void CWnd::pause() {
|
|
AfxGetApp()->pause();
|
|
}
|
|
|
|
void CWnd::OnShowWindow(bool bShow, unsigned int nStatus) {
|
|
if (bShow) {
|
|
// Invalidate this window
|
|
Invalidate();
|
|
|
|
// Invalidate all descendants
|
|
SendMessageToDescendants(WM_SETREDRAW, true);
|
|
}
|
|
}
|
|
|
|
void CWnd::OnNcDestroy() {
|
|
Detach();
|
|
ASSERT(m_hWnd == nullptr);
|
|
}
|
|
|
|
HWND CWnd::Detach() {
|
|
HWND hWnd = m_hWnd;
|
|
|
|
auto *pMap = AfxGetApp()->afxMapWnd();
|
|
assert(pMap);
|
|
pMap->RemoveHandle(m_hWnd);
|
|
|
|
m_hWnd = nullptr;
|
|
return hWnd;
|
|
}
|
|
|
|
bool CWnd::OnQueryNewPalette() {
|
|
return true;
|
|
}
|
|
|
|
} // namespace MFC
|
|
} // namespace Bagel
|