1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00
Beef/BeefySysLib/platform/win/WinBFApp.cpp
2019-08-23 11:56:54 -07:00

1691 lines
40 KiB
C++

#include "WinBFApp.h"
#include "DXRenderDevice.h"
#include <signal.h>
#include "../../util/BeefPerf.h"
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
#include "util/AllocDebug.h"
USING_NS_BF;
int Beefy::WinBFMenu::mMenuCount = 0;
int PrintStuff()
{
OutputDebugStringA("Hey!\n");
return 123;
}
WinBFMenu::WinBFMenu()
{
mIsPlaceholder = false;
mMenu = NULL;
mParent = NULL;
mMenuId = 0;
}
///
static HICON gMainIcon = NULL;
static BOOL CALLBACK BFEnumResNameProc(
HMODULE hModule,
LPCWSTR lpszType,
LPWSTR lpszName,
LONG_PTR lParam
)
{
gMainIcon = ::LoadIconW(hModule, lpszName);
return FALSE;
}
WinBFWindow::WinBFWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags)
{
HINSTANCE hInstance = GetModuleHandle(NULL);
mMinWidth = 128;
mMinHeight = 128;
WNDCLASSW wc;
wc.style = CS_DBLCLKS;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = NULL;
//wc.hbrBackground = ::CreateSolidBrush(::GetSysColor(COLOR_BTNFACE));
wc.hCursor = NULL;
//wc.hIcon = (HICON) ::LoadImageA(hInstance, "MainIcon", IMAGE_ICON, 0, 0, 0);
//wc.hIcon = (HICON) ::LoadImageA(hInstance, MAKEINTRESOURCEA(32512), IMAGE_ICON, 0, 0, 0);
if (gMainIcon != NULL)
{
wc.hIcon = gMainIcon;
}
else
{
wc.hIcon = (HICON) ::LoadIconA(hInstance, "MainIcon");
if (wc.hIcon == NULL)
{
EnumResourceNamesW(hInstance, (LPCWSTR)RT_GROUP_ICON, BFEnumResNameProc, 0);
wc.hIcon = gMainIcon;
}
}
wc.hInstance = hInstance;
wc.lpfnWndProc = WindowProcStub;
wc.lpszClassName = L"BFWindow";
wc.lpszMenuName = NULL;
RegisterClassW(&wc);
int requestedX = x;
int requestedY = y;
int aWindowFlags = 0;
bool hasDestAlpha = (windowFlags & BFWINDOW_DEST_ALPHA) != 0;
if (windowFlags & BFWINDOW_MENU)
{
WinBFMenu* aMenu = new WinBFMenu();
aMenu->mMenu = ::CreateMenu();
mHMenuMap[aMenu->mMenu] = aMenu;
mMenu = aMenu;
}
int windowFlagsEx = /*WS_EX_COMPOSITED |*/ WS_EX_LAYERED;
if (windowFlags & BFWINDOW_TOOLWINDOW)
windowFlagsEx |= WS_EX_TOOLWINDOW;
if (windowFlags & BFWINDOW_BORDER)
aWindowFlags |= WS_BORDER;
if (windowFlags & BFWINDOW_THICKFRAME)
aWindowFlags |= WS_THICKFRAME;
if ((windowFlags & BFWINDOW_RESIZABLE) && (!hasDestAlpha))
aWindowFlags |= WS_SIZEBOX;
if (windowFlags & BFWINDOW_SYSMENU)
aWindowFlags |= WS_SYSMENU;
if (windowFlags & BFWINDOW_CAPTION)
aWindowFlags |= WS_CAPTION;
else
aWindowFlags |= WS_POPUP;
if (windowFlags & BFWINDOW_MINIMIZE)
aWindowFlags |= WS_MINIMIZEBOX;
if (windowFlags & BFWINDOW_MAXIMIZE)
aWindowFlags |= WS_MAXIMIZEBOX;
if ((windowFlags & BFWINDOW_TOPMOST) && (parent == NULL))
windowFlagsEx |= WS_EX_TOPMOST;
if (windowFlags & BFWINDOW_CLIENT_SIZED)
{
RECT rect = {0, 0, width, height};
AdjustWindowRectEx(&rect, aWindowFlags, mMenu != NULL, windowFlagsEx);
x += rect.left;
y += rect.top;
width = rect.right - rect.left;
height = rect.bottom - rect.top;
}
if (windowFlags & BFWINDOW_POPUP_POSITION)
{
RECT desktopRect;
::SystemParametersInfo(SPI_GETWORKAREA, NULL, &desktopRect, NULL);
if (x + width >= desktopRect.right)
x = std::max((int)desktopRect.left, requestedX - width);
if (y + height >= desktopRect.bottom)
y = std::max((int)desktopRect.top, requestedY - height);
}
mFlags = windowFlags;
mMouseVisible = true;
mParent = parent;
HWND parentHWnd = NULL;
if (parent != NULL)
parentHWnd = ((WinBFWindow*) parent)->mHWnd;
if (mMenu != NULL)
{
WinBFMenu* placeholderMenu = (WinBFMenu*) AddMenuItem(mMenu, 0, ": Placeholder Menu Item :", NULL, NULL, false, -1, false);
placeholderMenu->mIsPlaceholder = true;
}
mHWnd = CreateWindowExW(windowFlagsEx, L"BFWindow", UTF8Decode(title).c_str(),
aWindowFlags,
x, y,
width,
height,
parentHWnd,
(mMenu != NULL) ? ((WinBFMenu*) mMenu)->mMenu : NULL,
hInstance,
0);
if ((windowFlags & BFWINDOW_ALPHA_MASK) == 0)
SetLayeredWindowAttributes(mHWnd, 0, 255, 0);
HWND relativeWindow = NULL;
if ((windowFlags & BFWINDOW_TOPMOST) && (parent == NULL))
relativeWindow = HWND_TOP;
int showFlags = SWP_SHOWWINDOW;
mHasFocus = true;
mSoftHasFocus = true;
if (windowFlags & BFWINDOW_FAKEFOCUS)
{
showFlags |= SWP_NOACTIVATE;
if (windowFlags & BFWINDOW_NO_ACTIVATE)
{
mHasFocus = false;
mSoftHasFocus = false;
}
}
else if (windowFlags & BFWINDOW_NO_ACTIVATE)
{
showFlags |= SWP_NOACTIVATE;
mHasFocus = false;
mSoftHasFocus = false;
}
SetWindowPos(mHWnd, relativeWindow, x, y, width, height, showFlags);
SetTimer(mHWnd, 0, 10, NULL);
mIsMouseInside = false;
mRenderWindow = new DXRenderWindow((DXRenderDevice*) gBFApp->mRenderDevice, mHWnd, (windowFlags & BFWINDOW_FULLSCREEN) == 0);
mRenderWindow->mWindow = this;
gBFApp->mRenderDevice->AddRenderWindow(mRenderWindow);
SetWindowLongPtr(mHWnd, GWLP_USERDATA, (LONG_PTR)this);
mIsMenuKeyHandled = false;
mAlphaMaskBitmap = NULL;
mAlphaMaskDC = NULL;
mAlphaMaskPixels = NULL;
mAlphaMaskWidth = 0;
mAlphaMaskHeight = 0;
mNeedsStateReset = false;
if (windowFlags & BFWINDOW_DEST_ALPHA)
{
MARGINS dWMMargins = {-1, -1, -1, -1};
DwmExtendFrameIntoClientArea(mHWnd, &dWMMargins);
}
if (windowFlags & BFWINDOW_MODAL)
{
EnableWindow(parentHWnd, FALSE);
}
if (parent != NULL)
{
auto winParent = (WinBFWindow*)parent;
BF_ASSERT(winParent->mHWnd);
parent->mChildren.push_back(this);
}
}
WinBFWindow::~WinBFWindow()
{
for (auto child : mChildren)
{
NOP;
}
if (mHWnd != NULL)
Destroy();
}
void* WinBFWindow::GetUnderlying()
{
return mHWnd;
}
void WinBFWindow::Destroy()
{
if (mAlphaMaskDC != NULL)
DeleteDC(mAlphaMaskDC);
mAlphaMaskDC = NULL;
if (mAlphaMaskBitmap != NULL)
DeleteObject(mAlphaMaskBitmap);
mAlphaMaskBitmap = NULL;
for (auto& menu : mMenuIDMap)
{
delete menu.mValue;
}
mMenuIDMap.Clear();
::DestroyWindow(mHWnd);
BF_ASSERT(mHWnd == NULL);
}
bool WinBFWindow::TryClose()
{
SendMessage(mHWnd, WM_CLOSE, 0, 0);
return mHWnd == NULL;
}
void WinBFWindow::SetTitle(const char* title)
{
SetWindowTextA(mHWnd, title);
}
void WinBFWindow::LostFocus(BFWindow* newFocus)
{
WinBFWindow* bfNewFocus = (WinBFWindow*)newFocus;
mSoftHasFocus = false;
for (int i = 0; i < KEYCODE_MAX; i++)
{
// Only transfer mode keys
if (mIsKeyDown[i])
{
mIsKeyDown[i] = false;
mKeyUpFunc(this, i);
if ((newFocus != NULL) &&
((i == VK_SHIFT) || (i == VK_CONTROL) || (i == VK_MENU)))
{
newFocus->mIsKeyDown[i] = true;
newFocus->mKeyDownFunc(newFocus, i, 0);
}
}
}
}
void WinBFWindow::SetForeground()
{
if (mFlags & BFWINDOW_FAKEFOCUS)
{
mHasFocus = true;
mSoftHasFocus = true;
return;
}
::SetFocus(mHWnd);
::SetForegroundWindow(mHWnd);
//OutputDebugStrF("SetForeground %p\n", mHWnd);
}
static POINT gLastScreenMouseCoords = { -1, -1 };
void WinBFWindow::RehupMouseOver(bool isMouseOver)
{
if ((!mIsMouseInside) && (isMouseOver))
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = mHWnd;
TrackMouseEvent(&tme);
mIsMouseInside = true;
}
if ((mIsMouseInside) && (!isMouseOver))
{
mIsMouseInside = false;
mMouseLeaveFunc(this);
}
}
LRESULT WinBFWindow::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WinBFApp* app = (WinBFApp*) gBFApp;
if (app == NULL)
{
PrintStuff();
}
switch (uMsg)
{
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_CHAR:
for (auto child : mChildren)
{
auto childWindow = (WinBFWindow*)child;
if ((childWindow->mSoftHasFocus) && (childWindow->mFlags & BFWINDOW_FAKEFOCUS))
{
return childWindow->WindowProc(hWnd, uMsg, wParam, lParam);
}
}
break;
}
switch (uMsg)
{
case WM_CLOSE:
{
//OutputDebugStrF("WM_CLOSE %08X NewFocus:%08X\n", hWnd, GetFocus());
if (mCloseQueryFunc(this) != 0)
gBFApp->RemoveWindow(this);
HWND newFocus = GetFocus();
for (auto window : gBFApp->mWindowList)
{
WinBFWindow* winWindow = (WinBFWindow*)window;
if (winWindow->mHWnd == newFocus)
{
while (true)
{
WinBFWindow* altFocusWindow = NULL;
for (auto checkChild : winWindow->mChildren)
{
auto checkWinChild = (WinBFWindow*)checkChild;
if (checkWinChild->mFlags & BFWINDOW_FAKEFOCUS)
altFocusWindow = checkWinChild;
}
if (altFocusWindow == NULL)
break;
winWindow = altFocusWindow;
}
winWindow->mHasFocus = true;
winWindow->mSoftHasFocus = true;
winWindow->mGotFocusFunc(winWindow);
}
}
return 0;
}
break;
case WM_DESTROY:
/*if (mFlags & BFWINDOW_QUIT_ON_CLOSE)
{
gBFApp->mRunning = false;
}*/
SetWindowLongPtr(mHWnd, GWLP_USERDATA, (LONG_PTR)0);
mHWnd = NULL;
if (!mChildren.IsEmpty())
{
NOP;
}
break;
}
LRESULT result = 0;
bool doResult = false;
if (!app->mInMsgProc)
{
if (mNeedsStateReset)
{
for (int i = 0; i < KEYCODE_MAX; i++)
{
if (mIsKeyDown[i])
{
mIsKeyDown[i] = false;
mKeyUpFunc(this, i);
}
}
POINT mousePoint;
::GetCursorPos(&mousePoint);
::ScreenToClient(hWnd, &mousePoint);
for (int i = 0; i < MOUSEBUTTON_MAX; i++)
{
if (mIsMouseDown[i])
{
mMouseUpFunc(this, mousePoint.x, mousePoint.y, i);
mIsMouseDown[i] = false;
}
}
//OutputDebugStrF("Rehup ReleaseCapture()\n");
ReleaseCapture();
mNeedsStateReset = false;
mIsMouseInside = false;
}
WinBFWindow* menuTarget = this;
if (mFlags & BFWINDOW_USE_PARENT_MENU)
menuTarget = ((WinBFWindow*)mParent);
auto* menuIDMap = &menuTarget->mMenuIDMap;
auto* hMenuMap = &menuTarget->mHMenuMap;
app->mInMsgProc = true;
switch (uMsg)
{
case WM_SIZE:
mRenderWindow->Resized();
if (mMovedFunc != NULL)
mMovedFunc(this);
break;
case WM_PAINT:
break;
case WM_NCHITTEST:
{
//OutputDebugStrF("WM_NCHITTEST %X\n", mHWnd);
int x = (short)LOWORD(lParam);
int y = (short)HIWORD(lParam);
result = mHitTestFunc(this, x, y);
doResult = (result != -3);
}
break;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
case WM_MOUSEWHEEL:
case WM_MOUSEMOVE:
{
int x = (short)LOWORD(lParam);
int y = (short)HIWORD(lParam);
bool releaseCapture = false;
POINT point = {x, y};
if (uMsg != WM_MOUSEWHEEL)
::ClientToScreen(hWnd, &point);
if ((uMsg == WM_MOUSEMOVE) && (point.x == gLastScreenMouseCoords.x) && (point.y == gLastScreenMouseCoords.y))
{
// Don't process a WM_MOUSEMOVE if it's at the same point at the last mouse event
// This keeps us from getting a WM_MOUSEMOVE when we popup a window under the current cursor location.
// This is important for keyboard cursor control - so the first down arrow keypress selects the first item in the list
// irregardless of the mouse cursor position.
break;
}
gLastScreenMouseCoords.x = point.x;
gLastScreenMouseCoords.y = point.y;
HWND windowAtPoint = ::WindowFromPoint(point);
bool isMouseOver = windowAtPoint == hWnd;
RehupMouseOver(isMouseOver);
//OutputDebugStrF("HWnd: %X Focus Window: %X Capture: %X\n", hWnd, windowAtPoint, ::GetCapture());
bool checkNonTransparentMousePosition = mNonExclusiveMouseCapture;
switch (uMsg)
{
case WM_LBUTTONDOWN:
//OutputDebugStrF("WM_LBUTTONDOWN Capture HWnd: %X\n", hWnd);
SetCapture(hWnd);
mIsMouseDown[0] = true;
mMouseDownFunc(this, x, y, 0, 1);
break;
case WM_RBUTTONDOWN:
//OutputDebugStrF("WM_RBUTTONDOWN Capture HWnd: %X\n", hWnd);
SetCapture(hWnd);
mIsMouseDown[1] = true;
mMouseDownFunc(this, x, y, 1, 1);
break;
case WM_MBUTTONDOWN:
SetCapture(hWnd);
mIsMouseDown[2] = true;
mMouseDownFunc(this, x, y, 2, 1);
break;
case WM_LBUTTONDBLCLK:
SetCapture(hWnd);
mMouseDownFunc(this, x, y, 0, 2);
break;
case WM_RBUTTONDBLCLK:
SetCapture(hWnd);
mMouseDownFunc(this, x, y, 1, 2);
break;
case WM_MBUTTONDBLCLK:
SetCapture(hWnd);
mMouseDownFunc(this, x, y, 2, 2);
break;
case WM_LBUTTONUP:
releaseCapture = true;
mIsMouseDown[0] = false;
mMouseUpFunc(this, x, y, 0);
break;
case WM_RBUTTONUP:
releaseCapture = true;
mIsMouseDown[1] = false;
mMouseUpFunc(this, x, y, 1);
break;
case WM_MBUTTONUP:
releaseCapture = true;
mIsMouseDown[2] = false;
mMouseUpFunc(this, x, y, 2);
break;
case WM_MOUSEWHEEL:
{
WinBFWindow* cursorWindow = this;
if ((gBFApp->mWindowList.size() > 1) && (GetCapture() == NULL))
{
// See if our mouse is down and has entered into another window's space
POINT point = { x, y };
HWND windowAtPoint = ::WindowFromPoint(point);
BFWindowList::iterator itr = gBFApp->mWindowList.begin();
while (itr != gBFApp->mWindowList.end())
{
WinBFWindow* aWindow = (WinBFWindow*) *itr;
LONG targetStyle = ::GetWindowLong(aWindow->mHWnd, GWL_EXSTYLE);
if ((::IsWindowEnabled(aWindow->mHWnd)) && ((targetStyle & WS_EX_TRANSPARENT) == 0))
{
if (aWindow->mHWnd == windowAtPoint)
{
aWindow->mIsMouseInside = true;
cursorWindow = aWindow;
}
}
++itr;
}
}
if ((cursorWindow != this) && (mIsMouseInside))
{
mMouseLeaveFunc(this);
mIsMouseInside = false;
}
POINT pt = {x, y};
ScreenToClient(cursorWindow->mHWnd, &pt);
int delta = ((int16)HIWORD(wParam)) / 120;
mMouseWheelFunc(cursorWindow, pt.x, pt.y, delta);
}
break;
case WM_MOUSEMOVE:
{
//OutputDebugStrF("WM_MOUSEMOVE %d\n", hWnd);
mMouseMoveFunc(this, x, y);
// If we are dragging a transparent window then check for mouse positions under cursor
HWND captureWindow = GetCapture();
if (captureWindow != NULL)
{
LONG captureStyle = ::GetWindowLong(captureWindow, GWL_EXSTYLE);
if ((captureStyle & WS_EX_TRANSPARENT) != 0)
checkNonTransparentMousePosition = true;
}
}
break;
}
if ((checkNonTransparentMousePosition) && (gBFApp->mWindowList.size() > 1))
{
// See if our mouse is down and has entered into another window's space
POINT point = { x, y };
::ClientToScreen(hWnd, &point);
HWND windowAtPoint = ::WindowFromPoint(point);
BFWindowList::iterator itr = gBFApp->mWindowList.begin();
while (itr != gBFApp->mWindowList.end())
{
WinBFWindow* aWindow = (WinBFWindow*) *itr;
if (aWindow != this)
{
LONG myStyle = ::GetWindowLong(mHWnd, GWL_EXSTYLE);
LONG targetStyle = ::GetWindowLong(aWindow->mHWnd, GWL_EXSTYLE);
if ((targetStyle & WS_EX_TRANSPARENT) == 0)
{
if (aWindow->mHWnd == windowAtPoint)
{
POINT clientPt = point;
::ScreenToClient(aWindow->mHWnd, &clientPt);
aWindow->mMouseProxyMoveFunc(aWindow, clientPt.x, clientPt.y);
aWindow->mIsMouseInside = true;
}
else if (aWindow->mIsMouseInside)
{
aWindow->mMouseLeaveFunc(aWindow);
aWindow->mIsMouseInside = false;
}
}
}
++itr;
}
}
if (releaseCapture)
{
for (int i = 0; i < MOUSEBUTTON_MAX; i++)
if (mIsMouseDown[i])
releaseCapture = false;
}
if (releaseCapture)
{
//OutputDebugStrF("ReleaseCapture\n");
ReleaseCapture();
BFWindowList::iterator itr = gBFApp->mWindowList.begin();
while (itr != gBFApp->mWindowList.end())
{
WinBFWindow* aWindow = (WinBFWindow*) *itr;
if ((aWindow != this) && (aWindow->mIsMouseInside))
{
aWindow->mMouseLeaveFunc(aWindow);
aWindow->mIsMouseInside = false;
}
++itr;
}
}
}
break;
case WM_COMMAND:
{
WinBFMenu* aMenu = (*menuIDMap)[(uint32)wParam];
if (aMenu != NULL)
menuTarget->mMenuItemSelectedFunc(menuTarget, aMenu);
}
break;
case WM_APPCOMMAND:
{
if ((mFlags & BFWINDOW_CAPTURE_MEDIA_KEYS) != 0)
{
int cmd = GET_APPCOMMAND_LPARAM(lParam);
int uDevice = GET_DEVICE_LPARAM(lParam);
int dwKeys = GET_KEYSTATE_LPARAM(lParam);
int key = cmd | 0x1000;
mKeyDownFunc(this, key, false);
result = TRUE;
doResult = true;
}
}
break;
case WM_INITMENUPOPUP:
{
if (mIsKeyDown[VK_MENU])
{
mKeyUpFunc(this, (int)VK_MENU);
mIsKeyDown[VK_MENU] = false;
}
HMENU hMenu = (HMENU) wParam;
WinBFMenu* aMenu = (*hMenuMap)[hMenu];
if (aMenu != NULL)
menuTarget->mMenuItemSelectedFunc(menuTarget, aMenu);
}
break;
case WM_MOUSEACTIVATE:
if (mFlags & BFWINDOW_NO_MOUSE_ACTIVATE)
{
doResult = true;
result = MA_NOACTIVATE;
}
else if (mFlags & BFWINDOW_FAKEFOCUS)
{
doResult = true;
result = MA_NOACTIVATE;
SetForeground();
}
break;
case WM_ACTIVATE:
//OutputDebugStrF("WM_ACTIVATE %p\n", hWnd);
break;
case WM_KILLFOCUS:
//OutputDebugStrF("WM_KILLFOCUS %p\n", hWnd);
mHasFocus = false;
mSoftHasFocus = false;
LostFocus(NULL);
mLostFocusFunc(this);
break;
case WM_SETFOCUS:
//OutputDebugStrF("WM_SETFOCUS %p\n", hWnd);
mHasFocus = true;
mSoftHasFocus = true;
mGotFocusFunc(this);
break;
case WM_ENTERMENULOOP:
//OutputDebugStrF("WM_ENTERMENULOOP %08X\n", hWnd);
if (mMenu != NULL)
mNeedsStateReset = true;
break;
case WM_EXITMENULOOP:
//OutputDebugStrF("WM_EXITMENULOOP %08X\n", hWnd);
if (mMenu != NULL)
mNeedsStateReset = true;
break;
case WM_NCMOUSELEAVE:
mIsMouseInside = false;
mMouseLeaveFunc(this);
break;
case WM_CHAR:
{
/*if (wParam == 'z')
{
ID3D11Debug* pD3DDebug = NULL;
HRESULT hr = ((DXRenderDevice*)mRenderWindow->mRenderDevice)->mD3DDevice->QueryInterface(__uuidof(ID3D11Debug), (void**)&pD3DDebug);
if (pD3DDebug != NULL)
{
pD3DDebug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
pD3DDebug->Release();
}
}*/
if ((!mIsKeyDown[VK_MENU]) && (!mIsKeyDown[VK_CONTROL]))
{
for (int i = 0; i < (lParam & 0x7FFF); i++)
mKeyCharFunc(this, (WCHAR)wParam);
}
}
break;
case WM_MENUCHAR:
if (mIsMenuKeyHandled)
{
result = MNC_CLOSE << 16;
doResult = true;
}
break;
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
{
mIsMenuKeyHandled = false;
int keyCode = (int) wParam;
if (keyCode == VK_APPS)
break; // This is handled in WM_CONTEXTMENU
mIsKeyDown[keyCode] = true;
for (auto kv : *menuIDMap)
{
WinBFMenu* aMenu = kv.mValue;
if ((aMenu->mKeyCode == keyCode) &&
(aMenu->mKeyShift == mIsKeyDown[VK_SHIFT]) &&
(aMenu->mKeyCtrl == mIsKeyDown[VK_CONTROL]) &&
(aMenu->mKeyAlt == mIsKeyDown[VK_MENU]))
{
mIsMenuKeyHandled = true;
menuTarget->mMenuItemSelectedFunc(menuTarget, aMenu);
doResult = true;
break;
}
}
if (!mIsMenuKeyHandled)
{
if (mKeyDownFunc(this, (int) wParam, (lParam & 0x7FFF) != 0))
{
mIsMenuKeyHandled = true;
doResult = true;
}
}
}
break;
case WM_SYSCHAR:
{
int keyCode = toupper((int) wParam);
for (auto& menuKV : *menuIDMap)
{
WinBFMenu* aMenu = menuKV.mValue;
if ((aMenu->mKeyCode == keyCode) &&
(aMenu->mKeyShift == mIsKeyDown[VK_SHIFT]) &&
(aMenu->mKeyCtrl == mIsKeyDown[VK_CONTROL]) &&
(aMenu->mKeyAlt == mIsKeyDown[VK_MENU]))
{
doResult = true;
break;
}
}
if (!mIsKeyDown[VK_MENU])
{
// If we don't have the alt key down then we assume we must have
// had keyups forced by losing focus from the mMenuItemSelectedFunc
doResult = true;
}
}
break;
case WM_SYSKEYUP:
case WM_KEYUP:
{
int keyCode = (int) wParam;
if (mIsKeyDown[keyCode])
{
mKeyUpFunc(this, (int) wParam);
mIsKeyDown[keyCode] = false;
}
}
break;
case WM_SYSCOMMAND:
// Ignore F10
if ((wParam == SC_KEYMENU) && (lParam == 0))
{
doResult = true;
result = 0;
}
break;
case WM_CONTEXTMENU:
{
int x = (short)LOWORD(lParam);
int y = (short)HIWORD(lParam);
if ((x == -1) && (y == -1))
{
mKeyDownFunc(this, VK_APPS, false);
mKeyUpFunc(this, VK_APPS);
}
}
break;
case WM_TIMER:
if (gBFApp->mSysDialogCnt == 0)
{
auto checkNonFake = this;
while (checkNonFake->mFlags & BFWINDOW_FAKEFOCUS)
{
checkNonFake = (WinBFWindow*)checkNonFake->mParent;
}
bool isFocused = GetForegroundWindow() == checkNonFake->mHWnd;
if ((!isFocused) && (mHasFocus))
{
mSoftHasFocus = false;
mHasFocus = false;
LostFocus(NULL);
mLostFocusFunc(this);
//OutputDebugStrF("Timer detected lost focus %p\r\n", hWnd);
}
else if ((isFocused) && (!mHasFocus) && (checkNonFake == this))
{
mHasFocus = true;
mSoftHasFocus = true;
mGotFocusFunc(this);
//OutputDebugStrF("Timer detected got focus %p\r\n", hWnd);
}
mSoftHasFocus = mHasFocus;
gBFApp->Process();
// Don't do anything with 'this' after Process, we may be deleted now
doResult = true;
result = 0;
}
break;
case WM_SETCURSOR:
gBFApp->PhysSetCursor();
break;
case WM_GETMINMAXINFO:
{
MINMAXINFO* minMaxInfo = (MINMAXINFO*)lParam;
minMaxInfo->ptMinTrackSize.x = mMinWidth;
minMaxInfo->ptMinTrackSize.y = mMinHeight;
result = 0;
doResult = true;
}
break;
case WM_MOVE:
case WM_MOVING:
if (mMovedFunc != NULL)
mMovedFunc(this);
break;
case WM_SIZING:
mRenderWindow->Resized();
if (mMovedFunc != NULL)
mMovedFunc(this);
if (gBFApp->mSysDialogCnt == 0)
gBFApp->Process();
break;
}
app->mInMsgProc = false;
}
else
{
// We got messages we couldn't process (due to reentrancy)
switch (uMsg)
{
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
case WM_MOUSEMOVE:
case WM_KEYUP:
case WM_MOUSELEAVE:
mNeedsStateReset = true;
break;
}
}
if (doResult)
return result;
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK WinBFWindow::WindowProcStub(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
WinBFWindow* aWindow = (WinBFWindow*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (aWindow != NULL)
return aWindow->WindowProc(hWnd, Msg, wParam, lParam);
else
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
//
static int WinBFReportHook( int reportType, char *message, int *returnValue )
{
if (reportType == 0)
return 0;
//__crtMessageWindowW(nRptType, szFile, (nLine ? szLineMessage : NULL), szModule, szUserMessage);;
if (gBFApp)
((WinBFApp*) gBFApp)->mInMsgProc = true;
int nCode = ::MessageBoxA(NULL, message,
"Microsoft Visual C++ Debug Library",
MB_TASKMODAL|MB_ICONHAND|MB_ABORTRETRYIGNORE|MB_SETFOREGROUND);
if (gBFApp)
((WinBFApp*) gBFApp)->mInMsgProc = false;
/* Abort: abort the program */
if (IDABORT == nCode)
{
/* note that it is better NOT to call abort() here, because the
* default implementation of abort() will call Watson
*/
/* raise abort signal */
raise(SIGABRT);
/* We usually won't get here, but it's possible that
SIGABRT was ignored. So exit the program anyway. */
_exit(3);
}
/* Retry: return 1 to call the debugger */
if (IDRETRY == nCode)
return 1;
/* Ignore: continue execution */
return 0;
return 1;
}
extern HINSTANCE gDLLInstance;
WinBFApp::WinBFApp()
{
#ifndef BF_MINGW
//_CrtSetReportHook(WinBFReportHook);
#endif
mRunning = false;
mRenderDevice = NULL;
mInstallDir = "Hey";
WCHAR aStr[MAX_PATH];
GetModuleFileNameW(gDLLInstance, aStr, MAX_PATH);
mInstallDir = UTF8Encode(aStr);
int a2DArray[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
int lastSlash = (int) mInstallDir.LastIndexOf(L'\\');
if (lastSlash != -1)
mInstallDir = mInstallDir.Substring(0, lastSlash + 1);
mDataDir = mInstallDir;
mInMsgProc = false;
}
WinBFApp::~WinBFApp()
{
delete mRenderDevice;
}
void WinBFApp::Init()
{
BP_ZONE("WinBFApp::Init");
mRunning = true;
mInMsgProc = false;
mRenderDevice = new DXRenderDevice();
mRenderDevice->Init(this);
}
void WinBFApp::Run()
{
MSG msg;
while (mRunning)
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (mRunning)
Process();
}
}
void WinBFApp::Draw()
{
mRenderDevice->FrameStart();
BFApp::Draw();
mRenderDevice->FrameEnd();
}
void WinBFApp::GetDesktopResolution(int& width, int& height)
{
width = ::GetSystemMetrics(SM_CXSCREEN);
height = ::GetSystemMetrics(SM_CYSCREEN);
}
void WinBFApp::GetWorkspaceRect(int& x, int& y, int& width, int& height)
{
RECT desktopRect;
::SystemParametersInfo(SPI_GETWORKAREA, NULL, &desktopRect, NULL);
x = desktopRect.left;
y = desktopRect.top;
width = desktopRect.right - desktopRect.left;
height = desktopRect.bottom - desktopRect.top;
}
BFWindow* WinBFApp::CreateNewWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags)
{
BFWindow* aWindow = new WinBFWindow(parent, title, x, y, width, height, windowFlags);
mWindowList.push_back(aWindow);
return aWindow;
}
void WinBFApp::RehupMouse()
{
HWND windowAtPoint = ::WindowFromPoint(gLastScreenMouseCoords);
for (auto window : mWindowList)
{
auto winWindow = (WinBFWindow*)window;
winWindow->RehupMouseOver(winWindow->mHWnd == windowAtPoint);
}
}
void WinBFWindow::SetMinimumSize(int minWidth, int minHeight, bool clientSized)
{
if (clientSized)
{
DWORD windowFlags = ::GetWindowLong(mHWnd, GWL_STYLE);
DWORD windowFlagsEx = ::GetWindowLong(mHWnd, GWL_EXSTYLE);
RECT rect = { 0, 0, minWidth, minHeight };
AdjustWindowRectEx(&rect, windowFlags, mMenu != NULL, windowFlagsEx);
minWidth = rect.right - rect.left;
minHeight = rect.bottom - rect.top;
}
mMinWidth = minWidth;
mMinHeight = minHeight;
if (mHWnd != NULL)
{
RECT windowRect;
::GetWindowRect(mHWnd, &windowRect);
bool resized = false;
if (windowRect.right - windowRect.left < minWidth)
{
windowRect.right = windowRect.left + minWidth;
resized = true;
}
if (windowRect.bottom - windowRect.top < minHeight)
{
windowRect.bottom = windowRect.top + minHeight;
resized = true;
}
if (resized)
{
::MoveWindow(mHWnd, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, TRUE);
mRenderWindow->Resized();
if (mMovedFunc != NULL)
mMovedFunc(this);
}
}
}
void WinBFWindow::GetPosition(int* x, int* y, int* width, int* height, int* clientX, int* clientY, int* clientWidth, int* clientHeight)
{
RECT windowRect;
GetWindowRect(mHWnd, &windowRect);
RECT clientRect;
GetClientRect(mHWnd, &clientRect);
if (clientRect.right <= clientRect.left)
return; // TODO: return failure?
*x = windowRect.left;
*y = windowRect.top;
*width = windowRect.right - windowRect.left;
*height = windowRect.bottom - windowRect.top;
*clientWidth = clientRect.right - clientRect.left;
*clientHeight = clientRect.bottom - clientRect.top;
POINT startPt = {0, 0};
::ClientToScreen(mHWnd, &startPt);
*clientX = startPt.x;
*clientY = startPt.y;
}
void WinBFWindow::Resize(int x, int y, int width, int height)
{
::MoveWindow(mHWnd, x, y, width, height, FALSE);
mRenderWindow->Resized();
if (mMovedFunc != NULL)
mMovedFunc(this);
}
void WinBFApp::PhysSetCursor()
{
static HCURSOR cursors [] =
{
::LoadCursor(NULL, IDC_ARROW),
//TODO: mApp->mHandCursor);
::LoadCursor(NULL, IDC_HAND),
//TODO: mApp->mDraggingCursor);
::LoadCursor(NULL, IDC_SIZEALL),
::LoadCursor(NULL, IDC_IBEAM),
::LoadCursor(NULL, IDC_NO),
::LoadCursor(NULL, IDC_SIZEALL),
::LoadCursor(NULL, IDC_SIZENESW),
::LoadCursor(NULL, IDC_SIZENS),
::LoadCursor(NULL, IDC_SIZENWSE),
::LoadCursor(NULL, IDC_SIZEWE),
::LoadCursor(NULL, IDC_WAIT),
NULL
};
::SetCursor(cursors[mCursor]);
}
void WinBFWindow::SetClientPosition(int x, int y)
{
RECT rect;
::GetClientRect(mHWnd, &rect);
::OffsetRect(&rect, x, y);
LONG aStyle = ::GetWindowLong(mHWnd, GWL_STYLE);
LONG exStyle = ::GetWindowLong(mHWnd, GWL_EXSTYLE);
::AdjustWindowRectEx(&rect, aStyle, mMenu != NULL, exStyle);
::MoveWindow(mHWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE);
if (mMovedFunc != NULL)
mMovedFunc(this);
}
void WinBFWindow::SetMouseVisible(bool isMouseVisible)
{
mMouseVisible = isMouseVisible;
LONG aStyle = ::GetWindowLong(mHWnd, GWL_EXSTYLE);
if (!isMouseVisible)
aStyle |= WS_EX_TRANSPARENT;
else
aStyle &= ~WS_EX_TRANSPARENT;
::SetWindowLong(mHWnd, GWL_EXSTYLE, aStyle);
}
void WinBFWindow::SetAlpha(float alpha, uint32 destAlphaSrcMask, bool isMouseVisible)
{
if (destAlphaSrcMask != 0)
{
if (mAlphaMaskBitmap == NULL)
{
RECT clientRect;
GetClientRect(mHWnd, &clientRect);
RECT windowRect;
GetWindowRect(mHWnd, &windowRect);
int aWidth = clientRect.right - clientRect.left;
int aHeight = clientRect.bottom - clientRect.top;
mAlphaMaskWidth = aWidth;
mAlphaMaskHeight = aHeight;
mAlphaMaskDC = CreateCompatibleDC(NULL);
BITMAPINFO bi = {};
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biWidth = aWidth;
bi.bmiHeader.biHeight = -aHeight;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biPlanes = 1;
mAlphaMaskBitmap = CreateDIBSection(mAlphaMaskDC, &bi,
DIB_RGB_COLORS, (void**)&mAlphaMaskPixels, NULL, 0);
GdiFlush();
}
HDC hdc = GetDC(mHWnd);
if (hdc)
{
DXRenderWindow* renderWindow = (DXRenderWindow*) mRenderWindow;
renderWindow->CopyBitsTo(mAlphaMaskPixels, mAlphaMaskWidth, mAlphaMaskHeight);
//for (int i = 0; i < mAlphaMaskWidth*mAlphaMaskHeight/2; i++)
//mAlphaMaskPixels[i] = 0x80FF8000;
HGDIOBJ hPrevObj = 0;
POINT ptDest = {0, 0};
POINT ptSrc = {0, 0};
SIZE client = {mAlphaMaskWidth, mAlphaMaskHeight};
BLENDFUNCTION blendFunc = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
hPrevObj = SelectObject(mAlphaMaskDC, mAlphaMaskBitmap);
ClientToScreen(mHWnd, &ptDest);
BOOL worked = ::UpdateLayeredWindow(mHWnd, hdc, NULL, &client,
mAlphaMaskDC, &ptSrc, 0, &blendFunc, ULW_ALPHA);
DWORD error = GetLastError();
SelectObject(mAlphaMaskDC, hPrevObj);
ReleaseDC(mHWnd, hdc);
}
}
else
{
::SetLayeredWindowAttributes(mHWnd, 0, (int) (alpha * 255), LWA_ALPHA);
}
SetMouseVisible(isMouseVisible);
}
void WinBFWindow::CaptureMouse()
{
//OutputDebugStrF("CaptureMouse() Capture HWnd: %X\n", mHWnd);
::SetCapture(mHWnd);
for (auto window : gBFApp->mWindowList)
{
if (window == this)
continue;
for (int i = 0; i < MOUSEBUTTON_MAX; i++)
{
if (window->mIsMouseDown[i])
{
window->mMouseUpFunc(window, -1, -1, i);
window->mIsMouseDown[i] = false;
}
}
}
}
bool WinBFWindow::IsMouseCaptured()
{
return (mHWnd != NULL) && (GetCapture() == mHWnd);
}
uint32 WinBFApp::GetClipboardFormat(const StringImpl& format)
{
if (format == "text")
return CF_UNICODETEXT;
else if (format == "atext")
return CF_TEXT;
// StringToUIntMap::iterator itr = mClipboardFormatMap.find(format);
// if (itr != mClipboardFormatMap.end())
// return itr->second;
uint32 aFormat;
if (mClipboardFormatMap.TryGetValue(format, &aFormat))
return aFormat;
String sysFormatName = "BF_" + format;
aFormat = ::RegisterClipboardFormatA(sysFormatName.c_str());
mClipboardFormatMap[sysFormatName] = aFormat;
return aFormat;
}
void* WinBFApp::GetClipboardData(const StringImpl& format, int* size)
{
HWND aWindow = NULL;
if (!mWindowList.empty())
aWindow = ((WinBFWindow*) mWindowList.front())->mHWnd;
uint32 aFormat = GetClipboardFormat(format);
if (aFormat != 0)
{
if (OpenClipboard(aWindow))
{
HGLOBAL globalHandle = ::GetClipboardData(aFormat);
if (globalHandle == NULL)
{
if (format == "text")
{
int aSize = 0;
char* charPtr = (char*) GetClipboardData("atext", &aSize);
if (charPtr == NULL)
return NULL;
*size = (int)::GlobalSize(globalHandle);
void* aPtr = ::GlobalLock(globalHandle);
mLockedHGlobalMap[aPtr] = globalHandle;
CloseClipboard();
return aPtr;
}
CloseClipboard();
*size = 0;
return NULL;
}
*size = (int)::GlobalSize(globalHandle);
void* aPtr = ::GlobalLock(globalHandle);
static String utf8String;
utf8String = UTF8Encode((WCHAR*)aPtr);
::GlobalUnlock(globalHandle);
CloseClipboard();
return (void*)utf8String.c_str();
}
}
*size = 0;
return NULL;
}
void WinBFApp::ReleaseClipboardData(void* ptr)
{
HGLOBAL globalHandle;
if (mLockedHGlobalMap.Remove(ptr, &globalHandle))
{
::GlobalUnlock(globalHandle);
}
}
void WinBFApp::SetClipboardData(const StringImpl& format, const void* ptr, int size, bool resetClipboard)
{
BP_ZONE("WinBFApp::SetClipboardData");
HWND aWindow = NULL;
if (!mWindowList.empty())
aWindow = ((WinBFWindow*) mWindowList.front())->mHWnd;
uint32 aFormat = GetClipboardFormat(format);
if (aFormat != 0)
{
if (OpenClipboard(aWindow))
{
if (resetClipboard)
{
BP_ZONE("WinBFApp::SetClipboardData:empty");
EmptyClipboard();
}
if (format == "text")
{
BP_ZONE("WinBFApp::SetClipboardData:text");
HGLOBAL globalHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size * 2);
char* data = (char*)GlobalLock(globalHandle);
UTF16String wString;
//
{
BP_ZONE("WinBFApp::SetClipboardData:utf8decode");
wString = UTF8Decode((char*)ptr);
}
memcpy(data, wString.c_str(), size * 2);
GlobalUnlock(globalHandle);
::SetClipboardData(CF_UNICODETEXT, globalHandle);
}
else if (format == "atext")
{
HGLOBAL globalHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
char* data = (char*)GlobalLock(globalHandle);
memcpy(data, ptr, size);
GlobalUnlock(globalHandle);
::SetClipboardData(CF_TEXT, globalHandle);
}
CloseClipboard();
}
}
/*if (format == "text")
{
//String aString = ToString((const WCHAR*) ptr);
String aString = (const char*)ptr;
SetClipboardData("atext", aString.c_str(), (int)aString.length() + 1, false);
}*/
}
BFMenu* WinBFWindow::AddMenuItem(BFMenu* parent, int insertIdx, const char* text, const char* hotKey, BFSysBitmap* sysBitmap, bool enabled, int checkState, bool radioCheck)
{
UTF16String lText;
if (text != NULL)
lText = UTF8Decode(text);
UTF16String lHotKey;
if (hotKey != NULL)
lHotKey = UTF8Decode(hotKey);
bool wasEmpty = mMenu->mBFMenuList.size() == 0;
if (parent == NULL)
parent = mMenu;
if ((parent->mBFMenuList.size() == 1) && (((WinBFMenu*) parent->mBFMenuList.front())->mIsPlaceholder))
{
// Get rid of placeholder menu item
auto placeholderMenuItem = parent->mBFMenuList.front();
RemoveMenuItem(placeholderMenuItem);
delete placeholderMenuItem;
}
WinBFMenu* winBFMenuParent = (WinBFMenu*) parent;
WinBFMenu* newMenu = new WinBFMenu();
newMenu->mMenuId = ++WinBFMenu::mMenuCount;
newMenu->mParent = parent;
//static int allocIdx = 0;
//allocIdx++;
//OutputDebugStrF("MenuIdx %d %@\n", allocIdx, newMenu);
if ((winBFMenuParent != NULL) && (winBFMenuParent->mMenu == NULL))
{
winBFMenuParent->mMenu = ::CreateMenu();
mHMenuMap[winBFMenuParent->mMenu] = winBFMenuParent;
MENUITEMINFO menuItem;
memset(&menuItem, 0, sizeof(MENUITEMINFO));
menuItem.cbSize = sizeof(MENUITEMINFO);
menuItem.fMask = MIIM_SUBMENU;
menuItem.hSubMenu = winBFMenuParent->mMenu;
::SetMenuItemInfo(((WinBFMenu*) winBFMenuParent->mParent)->mMenu, winBFMenuParent->mMenuId, FALSE, &menuItem);
}
mMenuIDMap[newMenu->mMenuId] = newMenu;
BF_ASSERT(insertIdx <= (int) parent->mBFMenuList.size());
////
UTF16String lCombinedName;
MENUITEMINFOW menuItem;
memset(&menuItem, 0, sizeof(MENUITEMINFO));
menuItem.cbSize = sizeof(MENUITEMINFO);
menuItem.fMask = MIIM_FTYPE | MIIM_ID;
if (text != NULL)
{
menuItem.fMask |= MIIM_STRING;
menuItem.fType = MFT_STRING;
}
else
menuItem.fType = MFT_SEPARATOR;
menuItem.fState = enabled ? MFS_DEFAULT : MFS_GRAYED;
if (checkState == 0)
menuItem.fState |= MFS_UNCHECKED;
if (checkState == 1)
menuItem.fState |= MFS_CHECKED;
if (radioCheck)
menuItem.fType = MFT_RADIOCHECK;
menuItem.wID = newMenu->mMenuId;
if (text != NULL)
{
menuItem.dwTypeData = (WCHAR*)lText.c_str();
}
if (hotKey != NULL)
{
String combinedName = String(text);
combinedName += "\t";
if (hotKey[0] == '#')
{
combinedName += hotKey + 1;
}
else
{
combinedName += hotKey;
newMenu->ParseHotKey(hotKey);
}
lCombinedName = UTF8Decode(combinedName);
menuItem.dwTypeData = (WCHAR*)lCombinedName.c_str();
}
::InsertMenuItemW(winBFMenuParent->mMenu, insertIdx, TRUE, &menuItem);
////////
/*MENUITEMINFO menuItem;
memset(&menuItem, 0, sizeof(MENUITEMINFO));
menuItem.cbSize = sizeof(MENUITEMINFO);
menuItem.fMask = MIIM_ID;
menuItem.wID = newMenu->mMenuId;
::InsertMenuItem(winBFMenuParent->mMenu, insertIdx, TRUE, &menuItem);*/
ModifyMenuItem(newMenu, text, hotKey, sysBitmap, enabled, checkState, radioCheck);
parent->mBFMenuList.push_back(newMenu);
return newMenu;
}
void WinBFWindow::ModifyMenuItem(BFMenu* item, const char* text, const char* hotKey, BFSysBitmap* sysBitmap, bool enabled, int checkState, bool radioCheck)
{
UTF16String lText;
if (text != NULL)
lText = UTF8Decode(text);
UTF16String lHotKey;
if (hotKey != NULL)
lHotKey = UTF8Decode(hotKey);
WinBFMenu* aMenu = (WinBFMenu*)item;
WinBFMenu* parentMenu = (WinBFMenu*) item->mParent;
UTF16String lCombinedName;
MENUITEMINFOW menuItem;
memset(&menuItem, 0, sizeof(MENUITEMINFO));
menuItem.cbSize = sizeof(MENUITEMINFO);
menuItem.fMask = MIIM_FTYPE | MIIM_ID;
::GetMenuItemInfoW(parentMenu->mMenu, aMenu->mMenuId, FALSE, &menuItem);
menuItem.fMask |= MIIM_STATE;
if (text != NULL)
{
menuItem.fMask |= MIIM_STRING;
//menuItem.fType = MFT_STRING;
}
/*else
menuItem.fType = MFT_SEPARATOR;*/
menuItem.fState = enabled ? /*MFS_DEFAULT*/0 : MFS_GRAYED;
if (checkState != -1)
{
menuItem.fMask |= MIIM_CHECKMARKS;
}
if (checkState == 0)
menuItem.fState |= MFS_UNCHECKED;
if (checkState == 1)
menuItem.fState |= MFS_CHECKED;
if (radioCheck)
menuItem.fType = MFT_RADIOCHECK;
menuItem.wID = aMenu->mMenuId;
menuItem.dwTypeData = (WCHAR*)lText.c_str();
if (hotKey != NULL)
{
menuItem.fMask |= MIIM_DATA;
String combinedName = String(text);
combinedName += "\t";
if (hotKey[0] == '#')
{
combinedName += hotKey + 1;
}
else
{
combinedName += hotKey;
aMenu->ParseHotKey(hotKey);
}
lCombinedName = UTF8Decode(combinedName);
menuItem.dwTypeData = (WCHAR*)lCombinedName.c_str();
}
::SetMenuItemInfoW(parentMenu->mMenu, aMenu->mMenuId, FALSE, &menuItem);
}
void WinBFWindow::RemoveMenuItem(BFMenu* item)
{
WinBFMenu* aMenu = (WinBFMenu*) item;
WinBFMenu* parentMenu = (WinBFMenu*) item->mParent;
//auto itr = mMenuIDMap.find(aMenu->mMenuId);
//mMenuIDMap.erase(itr);
mMenuIDMap.Remove(aMenu->mMenuId);
::RemoveMenu(parentMenu->mMenu, aMenu->mMenuId, MF_BYCOMMAND);
}
BFSysBitmap* WinBFApp::LoadSysBitmap(const WCHAR* fileName)
{
return NULL;
}
void WinBFWindow::ModalsRemoved()
{
::EnableWindow(mHWnd, TRUE);
if (mChildren.empty())
::SetFocus(mHWnd);
}
DrawLayer* WinBFApp::CreateDrawLayer(BFWindow* window)
{
DXDrawLayer* drawLayer = new DXDrawLayer();
if (window != NULL)
{
drawLayer->mRenderWindow = window->mRenderWindow;
window->mRenderWindow->mDrawLayerList.push_back(drawLayer);
}
drawLayer->mRenderDevice = mRenderDevice;
return drawLayer;
}