/* 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 . * */ #include "common/system.h" #include "common/config-manager.h" #include "common/events.h" #include "common/textconsole.h" #include "graphics/paletteman.h" #include "bagel/mfc/global_functions.h" #include "bagel/mfc/afxwin.h" #include "bagel/mfc/win_hand.h" #include "bagel/mfc/gfx/cursor.h" #include "bagel/mfc/libs/events.h" #include "engines/engine.h" namespace Bagel { namespace MFC { /** * Used for temporary handle wrapper objects */ class CTempGdiObject : public CGdiObject { DECLARE_DYNCREATE(CTempGdiObject) }; IMPLEMENT_DYNCREATE(CTempGdiObject, CGdiObject) IMPLEMENT_DYNAMIC(CWinApp, CWinThread) CWinApp *CWinApp::_activeApp = nullptr; CWinApp::CWinApp(const char *appName) : CWinThread(), EventLoop(), _cursors(_resources), _fonts(_resources) { _priorWinApp = _activeApp; _activeApp = this; Libs::Event::init(); } CWinApp::~CWinApp() { // Free the defaults _defaultFont.DeleteObject(); _defaultPen.DeleteObject(); _defaultBrush.DeleteObject(); _currentPalette.DeleteObject(); _systemPalette.DeleteObject(); // Release the handle maps delete m_pmapHDC; delete m_pmapHGDIOBJ; m_pmapHDC = nullptr; m_pmapHGDIOBJ = nullptr; _activeApp = _priorWinApp; } bool CWinApp::InitApplication() { _settings.load(); _defaultFont.CreateFont(8, 0, 0, 0, FW_NORMAL, 0, 0, 0, 0, OUT_RASTER_PRECIS, 0, PROOF_QUALITY, FF_ROMAN, "MS Sans Serif"); _defaultPen.CreatePen(PS_SOLID, 1, 0); _defaultBrush.CreateSolidBrush(RGB(255, 255, 255)); // Set up current palette. It's empty by default, but // we need to at least get it registered. // Then it will be filled out via setPalette later LOGPALETTE lp; lp.palVersion = 0x300; lp.palNumEntries = 0; _currentPalette.CreatePalette(&lp); // Set up system palette LOGPALETTE *lps = (LOGPALETTE *)malloc(sizeof(LOGPALETTE) + 255 * sizeof(PALETTEENTRY)); lps->palVersion = 0x300; lps->palNumEntries = 256; Common::fill((byte *)&lps->palPalEntry[0], (byte *)&lps->palPalEntry[Graphics::PALETTE_COUNT], 0); // Set first 10 system palette colors PALETTEENTRY sysColorsStart[10] = { { 0x00, 0x00, 0x00, 0 }, // 0: Black { 0x80, 0x00, 0x00, 0 }, // 1: Dark Red { 0x00, 0x80, 0x00, 0 }, // 2: Dark Green { 0x80, 0x80, 0x00, 0 }, // 3: Olive { 0x00, 0x00, 0x80, 0 }, // 4: Dark Blue { 0x80, 0x00, 0x80, 0 }, // 5: Purple { 0x00, 0x80, 0x80, 0 }, // 6: Teal { 0xC0, 0xC0, 0xC0, 0 }, // 7: Gray { 0xC0, 0xDC, 0xC0, 0 }, // 8: Silver (Windows UI color) { 0xA6, 0xCA, 0xF0, 0 } // 9: Light Gray (Windows UI color) }; for (int i = 0; i < 10; ++i) { lps->palPalEntry[i] = sysColorsStart[i]; } // Set last 10 system palette colors PALETTEENTRY sysColorsEnd[10] = { { 0xFF, 0xFF, 0xFF, 0 }, // 246: White { 0xFF, 0x00, 0x00, 0 }, // 247: Red { 0x00, 0xFF, 0x00, 0 }, // 248: Green { 0xFF, 0xFF, 0x00, 0 }, // 249: Yellow { 0x00, 0x00, 0xFF, 0 }, // 250: Blue { 0xFF, 0x00, 0xFF, 0 }, // 251: Magenta { 0x00, 0xFF, 0xFF, 0 }, // 252: Cyan { 0xFF, 0xFF, 0xFF, 0 }, // 253: White again (duplicate of 246) { 0xFF, 0xFB, 0xF0, 0 }, // 254: Light Gray (UI highlight) { 0xA0, 0xA0, 0xA4, 0 } // 255: "Button face" gray }; for (int i = 0; i < 10; ++i) { lps->palPalEntry[246 + i] = sysColorsEnd[i]; } // Set up the system palette with the palette data _systemPalette.CreatePalette(lps); free(lps); return true; } bool CWinApp::InitInstance() { return true; } int CWinApp::ExitInstance() { return 0; } bool CWinApp::SaveAllModified() { _settings.save(); return true; } int CWinApp::Run() { if (shouldQuit()) return 0; // Ensure app has been initialized assert(_defaultFont.font()); SetCursor(LoadCursor(IDC_ARROW)); if (!m_pMainWnd) { m_pMainWnd = GetActiveWindow(); assert(m_pMainWnd); } else { assert(m_pMainWnd); SetActiveWindow(m_pMainWnd); } runEventLoop(false); SaveAllModified(); ExitInstance(); return 0; } void CWinApp::SetDialogBkColor() { } HCURSOR CWinApp::LoadStandardCursor(const char *lpszCursorName) { return _cursors.loadCursor((intptr)lpszCursorName); } HCURSOR CWinApp::LoadCursor(const char *lpszResourceName) { return _cursors.loadCursor((intptr)lpszResourceName); } HCURSOR CWinApp::LoadCursor(unsigned int nIDResource) { return _cursors.loadCursor(nIDResource); } HCURSOR CWinApp::SetCursor(HCURSOR hCursor) { if (hCursor == _currentCursor) return hCursor; HCURSOR oldCursor = _currentCursor; _currentCursor = hCursor; Gfx::Cursor *c = (Gfx::Cursor *)hCursor; if (c) { c->showCursor(); } else { Gfx::Cursor::hide(); } return oldCursor; } void CWinApp::BeginWaitCursor() { DoWaitCursor(1); } void CWinApp::EndWaitCursor() { DoWaitCursor(-1); } void CWinApp::DoWaitCursor(int nCode) { assert(nCode == 0 || nCode == 1 || nCode == -1); m_nWaitCursorCount += nCode; if (m_nWaitCursorCount > 0) { // Set wait cursor HCURSOR hcurPrev = MFC::SetCursor(_cursors._waitCursor); if (nCode > 0 && m_nWaitCursorCount == 1) m_hcurWaitCursorRestore = hcurPrev; } else { // Turn off wait cursor m_nWaitCursorCount = 0; MFC::SetCursor(m_hcurWaitCursorRestore); } } HFONT CWinApp::getFont(const char *lpszFacename, int nHeight) { if ((!lpszFacename || !*lpszFacename) || !nHeight) // Use default font return _fonts.getFont("MS Sans Serif", 8); else return _fonts.getFont(lpszFacename, nHeight); } void CWinApp::AddDocTemplate(CDocTemplate *pTemplate) { if (m_pDocManager == NULL) m_pDocManager = new CDocManager(); m_pDocManager->AddDocTemplate(pTemplate); } void CWinApp::OnFileNew() { if (m_pDocManager != nullptr) m_pDocManager->OnFileNew(); } void CWinApp::OnFileOpen() { assert(m_pDocManager != nullptr); m_pDocManager->OnFileOpen(); } void CWinApp::CloseAllDocuments(bool bEndSession) { if (m_pDocManager != nullptr) m_pDocManager->CloseAllDocuments(bEndSession); } unsigned int CWinApp::GetProfileInt(const char *lpszSection, const char *lpszEntry, int nDefault) { return _settings[lpszSection].getInt(lpszEntry, nDefault); } void CWinApp::WriteProfileInt(const char *lpszSection, const char *lpszEntry, int nValue) { _settings[lpszSection].setInt(lpszEntry, nValue); } CString CWinApp::GetProfileString(const char *lpszSection, const char *lpszEntry, const char *lpszDefault) { Common::String str = _settings[lpszSection].getString(lpszEntry, lpszDefault); return CString(str.c_str()); } bool CWinApp::WriteProfileString(const char *lpszSection, const char *lpszEntry, const char *lpszValue) { _settings[lpszSection].setString(lpszEntry, lpszValue); return true; } void CWinApp::setDirectory(const char *folder) { const Common::FSNode gameDataDir(ConfMan.getPath("path")); SearchMan.remove("CurrentDir"); _currentDirectory = gameDataDir; if (folder && *folder) { _currentDirectory = gameDataDir.getChild(folder); SearchMan.addDirectory("CurrentDir", _currentDirectory, 10, 2); } } void CWinApp::setPalette(const Graphics::Palette &pal) { _currentPalette.SetPaletteEntries(pal); g_system->getPaletteManager()->setPalette(pal); } byte CWinApp::getColor(COLORREF color) const { if (_currentPalette.isEmpty()) return 0; if (color <= 0xff || (color >> 24) == 1) return (byte)(color & 0xff); return _currentPalette.palette()->findBestColor( GetRValue(color), GetGValue(color), GetBValue(color) ); } HRSRC CWinApp::findResource(const char *lpName, const char *lpType) { return _resources.findResource(lpName, lpType); } size_t CWinApp::sizeofResource(HRSRC hResInfo) { return _resources.resourceSize(hResInfo); } HGLOBAL CWinApp::loadResource(HRSRC hResInfo) { return _resources.loadResource(hResInfo); } void *CWinApp::lockResource(HGLOBAL hResData) { return GlobalLock(hResData); } void CWinApp::unlockResource(HGLOBAL hResData) { GlobalUnlock(hResData); } bool CWinApp::freeResource(HGLOBAL hResData) { GlobalFree(hResData); return true; } CHandleMap *CWinApp::afxMapHGDIOBJ(bool bCreate) { if (m_pmapHGDIOBJ == nullptr && bCreate) m_pmapHGDIOBJ = new CHandleMap(); return m_pmapHGDIOBJ; } CHandleMap *CWinApp::afxMapHDC(bool bCreate) { if (m_pmapHDC == nullptr && bCreate) m_pmapHDC = new CHandleMap(); return m_pmapHDC; } CHandleMap *CWinApp::afxMapWnd(bool bCreate) { if (m_pmapWnd == nullptr && bCreate) m_pmapWnd = new CHandleMap(); return m_pmapWnd; } void CWinApp::AfxUnlockTempMaps() { if (m_pmapHDC) m_pmapHDC->DeleteTemp(); if (m_pmapHGDIOBJ) m_pmapHGDIOBJ->DeleteTemp(); } const char *CWinApp::AfxRegisterWndClass(unsigned int nClassStyle, HCURSOR hCursor, HBRUSH hbrBackground, HICON hIcon) { return "ScummVMWindow"; } bool CWinApp::GetClassInfo(HINSTANCE hInstance, const char *lpClassName, LPWNDCLASS lpWndClass) { assert(lpWndClass); WNDCLASS &wc = *lpWndClass; memset(lpWndClass, 0, sizeof(WNDCLASS)); wc.style = CS_DBLCLKS | CS_BYTEALIGNWINDOW | CS_OWNDC; return true; } /*--------------------------------------------*/ CWinApp *AfxGetApp() { return CWinApp::_activeApp; } CWnd *AfxGetMainWnd() { assert(CWinApp::_activeApp); return CWinApp::_activeApp->m_pMainWnd; } HINSTANCE AfxGetInstanceHandle() { // Unused in ScummVM return 0; } int LoadString(HINSTANCE hInstance, unsigned int uID, char *lpBuffer, int cchBufferMax) { if (lpBuffer == nullptr || cchBufferMax <= 0) return 0; // Calculate which string block (resource ID) contains this string unsigned int blockID = (uID / 16) + 1; unsigned int indexInBlock = uID % 16; // Find the RT_STRING resource with that block ID HRSRC hRes = FindResource(hInstance, MAKEINTRESOURCE(blockID), RT_STRING); if (!hRes) return 0; HGLOBAL hResData = LoadResource(hInstance, hRes); if (!hResData) return 0; const byte *pData = (const byte *)LockResource(hResData); assert(pData); // Walk through up to 16 strings in the block for (uint i = 0; i < 16; ++i) { uint length = *pData++; if (i == indexInBlock) { // Found the desired string int copyLen = MIN((int)length, cchBufferMax - 1); memcpy(lpBuffer, (const char *)pData, copyLen); lpBuffer[copyLen] = '\0'; UnlockResource(hResData); FreeResource(hResData); return copyLen; } // Skip this string pData += length; } // String ID not found (shouldn't happen if resource is valid) UnlockResource(hResData); FreeResource(hResData); return 0; } HMODULE LoadLibrary(const char *lpLibFileName) { error("LoadLibrary is unsupported"); } void FreeLibrary(HMODULE hModule) { error("FreeLibrary is unsupported"); } FARPROC GetProcAddress(HMODULE hModule, const char *lpProcName) { error("TODO: GetProcAddress"); } HMODULE GetModuleHandle(const char *lpModuleName) { error("TODO: GetModuleHandle"); } const char *AfxRegisterWndClass(unsigned int nClassStyle, HCURSOR hCursor, HBRUSH hbrBackground, HICON hIcon) { return AfxGetApp()->AfxRegisterWndClass(nClassStyle, hCursor, hbrBackground, hIcon); } bool GetClassInfo(HINSTANCE hInstance, const char *lpClassName, LPWNDCLASS lpWndClass) { return AfxGetApp()->GetClassInfo(hInstance, lpClassName, lpWndClass); } int GetSystemMetrics(int nIndex) { switch (nIndex) { case SM_CXCURSOR: return Gfx::CURSOR_W; case SM_CYCURSOR: return Gfx::CURSOR_H; case SM_CXSCREEN: return g_system->getWidth(); case SM_CYSCREEN: return g_system->getHeight(); default: error("TODO: GetSystemMetrics"); break; } } } // namespace MFC } // namespace Bagel