#include "StdAfx.h" #include #include #include "Utils/UnZip.h" namespace ui { std::wstring GlobalManager::m_pStrResourcePath; std::vector GlobalManager::m_aPreMessages; std::map> GlobalManager::m_builderMap; CreateControlCallback GlobalManager::m_createControlCallback; GlobalManager::MapStringToImagePtr GlobalManager::m_mImageHash; std::map GlobalManager::m_mapTextColor; std::map GlobalManager::m_mGlobalClass; std::map GlobalManager::m_mCustomFonts; std::wstring GlobalManager::m_sDefaultFontId; short GlobalManager::m_H = 180; short GlobalManager::m_S = 100; short GlobalManager::m_L = 100; std::wstring GlobalManager::m_strDefaultFontName; std::wstring GlobalManager::m_strDefaultDisabledColor = L"textdefaultdisablecolor"; std::wstring GlobalManager::m_strDefaultFontColor = L"textdefaultcolor"; DWORD GlobalManager::m_dwDefaultLinkFontColor = 0xFF0000FF; DWORD GlobalManager::m_dwDefaultLinkHoverFontColor = 0xFFD3215F; DWORD GlobalManager::m_dwDefaultSelectedBkColor = 0xFFBAE4FF; std::unique_ptr GlobalManager::m_renderFactory; static ULONG_PTR g_gdiplusToken; static Gdiplus::GdiplusStartupInput g_gdiplusStartupInput; static HZIP g_hzip = NULL; void GlobalManager::Startup(const std::wstring& strResourcePath, const CreateControlCallback& callback, bool bAdaptDpi, const std::wstring& theme, const std::wstring& language) { m_renderFactory = std::make_unique(); GlobalManager::SetResourcePath(strResourcePath + theme); m_createControlCallback = callback; // 适配DPI if (bAdaptDpi) { DpiManager::GetInstance()->SetAdaptDPI(); DpiManager::GetInstance()->SetScale(DpiManager::GetMainMonitorDPI()); } // 解析全局资源信息 LoadGlobalResource(); // 加载多语言文件,如果使用了资源压缩包则从内存中加载语言文件 if (g_hzip) { HGLOBAL hGlobal = GetData(m_pStrResourcePath + language + L"\\gdstrings.ini"); if (hGlobal) { ui::MutiLanSupport::GetInstance()->LoadStringTable(hGlobal); GlobalFree(hGlobal); } } else { MutiLanSupport::GetInstance()->LoadStringTable(strResourcePath + language + L"\\gdstrings.ini"); } GdiplusStartup(&g_gdiplusToken, &g_gdiplusStartupInput, NULL); // Boot Windows Common Controls (for the ToolTip control) ::InitCommonControls(); } void GlobalManager::Shutdown() { if (g_hzip) { CloseZip(g_hzip); g_hzip = NULL; } m_renderFactory.reset(); RemoveAllFonts(); Gdiplus::GdiplusShutdown(g_gdiplusToken); } std::wstring GlobalManager::GetCurrentPath() { TCHAR tszModule[MAX_PATH + 1] = { 0 }; ::GetCurrentDirectory(MAX_PATH, tszModule); return tszModule; } std::wstring GlobalManager::GetResourcePath() { return m_pStrResourcePath; } void GlobalManager::SetCurrentPath(const std::wstring& strPath) { ::SetCurrentDirectory(strPath.c_str()); } void GlobalManager::SetResourcePath(const std::wstring& strPath) { m_pStrResourcePath = strPath; if( m_pStrResourcePath.empty() ) return; TCHAR cEnd = m_pStrResourcePath.at(m_pStrResourcePath.length() - 1); if( cEnd != _T('\\') && cEnd != _T('/') ) m_pStrResourcePath += _T('\\'); } void GlobalManager::LoadGlobalResource() { ui::WindowBuilder dialog_builder; ui::Window paint_manager; dialog_builder.Create(L"global.xml", CreateControlCallback(), &paint_manager); } void GlobalManager::ReloadSkin(const std::wstring& resourcePath) { RemoveAllFonts(); RemoveAllTextColors(); RemoveAllClasss(); RemoveAllImages(); SetResourcePath(resourcePath); LoadGlobalResource(); for (auto it = m_aPreMessages.begin(); it != m_aPreMessages.end(); it++) { (*it)->GetRoot()->Invalidate(); } } ui::IRenderFactory* GlobalManager::GetRenderFactory() { return m_renderFactory.get(); } std::unique_ptr GlobalManager::CreateRenderContext() { std::unique_ptr p; p.reset(m_renderFactory->CreateRenderContext()); return p; } std::unique_ptr GlobalManager::CreatePen(DWORD color, int width /*= 1*/) { std::unique_ptr p; p.reset(m_renderFactory->CreatePen(color, width)); return p; } std::unique_ptr GlobalManager::CreateBrush(DWORD color) { std::unique_ptr p; p.reset(m_renderFactory->CreateBrush(color)); return p; } std::unique_ptr GlobalManager::CreateMatrix() { std::unique_ptr p; p.reset(m_renderFactory->CreateMatrix()); return p; } std::unique_ptr GlobalManager::CreatePath() { std::unique_ptr p; p.reset(m_renderFactory->CreatePath()); return p; } void GlobalManager::MessageLoop() { MSG msg = { 0 }; while( ::GetMessage(&msg, NULL, 0, 0) ) { if( !GlobalManager::TranslateMessage(&msg) ) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } } } bool GlobalManager::TranslateMessage(const LPMSG pMsg) { // Pretranslate Message takes care of system-wide messages, such as // tabbing and shortcut key-combos. We'll look for all messages for // each window and any child control attached. UINT uStyle = GetWindowStyle(pMsg->hwnd); UINT uChildRes = uStyle & WS_CHILD; LRESULT lRes = 0; if (uChildRes != 0) { HWND hWndParent = ::GetParent(pMsg->hwnd); for( auto it = m_aPreMessages.begin(); it != m_aPreMessages.end(); it++ ) { auto pT = *it; HWND hTempParent = hWndParent; while(hTempParent) { if(pMsg->hwnd == pT->GetHWND() || hTempParent == pT->GetHWND()) { if (pT->TranslateAccelerator(pMsg)) return true; if( pT->PreMessageHandler(pMsg->message, pMsg->wParam, pMsg->lParam, lRes) ) return true; return false; } hTempParent = GetParent(hTempParent); } } } else { for( auto it = m_aPreMessages.begin(); it != m_aPreMessages.end(); it++ ) { auto pT = *it; if(pMsg->hwnd == pT->GetHWND()) { if (pT->TranslateAccelerator(pMsg)) return true; if( pT->PreMessageHandler(pMsg->message, pMsg->wParam, pMsg->lParam, lRes) ) return true; return false; } } } return false; } void GlobalManager::AddPreMessage(Window* pWindow) { m_aPreMessages.push_back(pWindow); } void GlobalManager::RemovePreMessage(Window* pWindow) { auto it = std::find(m_aPreMessages.begin(), m_aPreMessages.end(), pWindow); if (it != m_aPreMessages.end()) { m_aPreMessages.erase(it); } } void GlobalManager::AddClass(const std::wstring& strClassName, const std::wstring& strControlAttrList) { ASSERT(!strClassName.empty()); ASSERT(!strControlAttrList.empty()); m_mGlobalClass[strClassName] = strControlAttrList; } std::wstring GlobalManager::GetClassAttributes(const std::wstring& strClassName) { auto it = m_mGlobalClass.find(strClassName); if (it != m_mGlobalClass.end()) { return it->second; } return L""; } void GlobalManager::RemoveAllClasss() { m_mGlobalClass.clear(); } void GlobalManager::AddTextColor(const std::wstring& strName, const std::wstring& strValue) { std::wstring strColor = strValue.substr(1); LPTSTR pstr = NULL; DWORD dwBackColor = _tcstoul(strColor.c_str(), &pstr, 16); m_mapTextColor[strName] = dwBackColor; } DWORD GlobalManager::GetTextColor(const std::wstring& strName) { // 必须在global.xml中提前定义到颜色值 ASSERT(m_mapTextColor[strName] != 0); return m_mapTextColor[strName]; } void GlobalManager::RemoveAllTextColors() { m_mapTextColor.clear(); } std::shared_ptr GlobalManager::IsImageCached(const std::wstring& strImagePath) { std::wstring imageFullPath = StringHelper::ReparsePath(strImagePath); std::shared_ptr sharedImage; auto it = m_mImageHash.find(imageFullPath); if (it != m_mImageHash.end()) { sharedImage = it->second.lock(); } return sharedImage; } std::shared_ptr GlobalManager::AddImageCached(const std::shared_ptr& sharedImage) { ASSERT(m_mImageHash[sharedImage->sImageFullPath].expired() == true); m_mImageHash[sharedImage->sImageFullPath] = sharedImage; sharedImage->SetCached(true); return sharedImage; } void GlobalManager::RemoveFromImageCache(const std::wstring& imageFullPath) { auto it = m_mImageHash.find(imageFullPath); if (it != m_mImageHash.end()) { m_mImageHash.erase(it); } else { ASSERT(FALSE); } } void GlobalManager::OnImageInfoDestroy(ImageInfo* pImageInfo) { ASSERT(pImageInfo); if (pImageInfo && pImageInfo->IsCached()) { if (!pImageInfo->sImageFullPath.empty()) { GlobalManager::RemoveFromImageCache(pImageInfo->sImageFullPath); } } delete pImageInfo; } std::shared_ptr GlobalManager::GetImage(const std::wstring& bitmap) { std::wstring imageFullPath = StringHelper::ReparsePath(bitmap); if (IsUseZip()) { imageFullPath = GetZipFilePath(imageFullPath); } std::shared_ptr sharedImage; auto it = m_mImageHash.find(imageFullPath); if (it == m_mImageHash.end()) { std::unique_ptr data; if (IsUseZip()) { data = ImageInfo::LoadImage(GetData(imageFullPath), imageFullPath); } if (!data) { data = ImageInfo::LoadImage(imageFullPath); } if (!data) return sharedImage; sharedImage.reset(data.release(), &OnImageInfoDestroy); m_mImageHash[imageFullPath] = sharedImage; sharedImage->SetCached(true); } else { sharedImage = it->second.lock(); } return sharedImage; } std::wstring GlobalManager::GetDefaultFontName() { return m_strDefaultFontName; } void GlobalManager::RemoveAllImages() { for (auto it = m_aPreMessages.begin(); it != m_aPreMessages.end(); it++) { (*it)->GetRoot()->ClearImageCache(); } m_mImageHash.clear(); } HFONT GlobalManager::AddFont(const std::wstring& strFontId, const std::wstring& strFontName, int nSize, bool bBold, bool bUnderline, bool bItalic, bool bDefault) { std::wstring strNewFontId = strFontId; if (strNewFontId.empty()) { strNewFontId = std::to_wstring(m_mCustomFonts.size()); } auto iter = m_mCustomFonts.find(strNewFontId); ASSERT(iter == m_mCustomFonts.end()); static bool bOsOverXp = IsWindowsVistaOrGreater(); std::wstring fontName = strFontName; if ( fontName == L"system" ) { fontName = bOsOverXp ? L"微软雅黑" : L"新宋体"; } LOGFONT lf = { 0 }; ::GetObject(::GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &lf); _tcscpy(lf.lfFaceName, fontName.c_str()); lf.lfCharSet = DEFAULT_CHARSET; lf.lfHeight = -DpiManager::GetInstance()->ScaleInt(nSize); if( bBold ) lf.lfWeight += FW_BOLD; if( bUnderline ) lf.lfUnderline = TRUE; if( bItalic ) lf.lfItalic = TRUE; HFONT hFont = ::CreateFontIndirect(&lf); if( hFont == NULL ) return NULL; TFontInfo* pFontInfo = new TFontInfo; if( !pFontInfo ) return false; pFontInfo->hFont = hFont; pFontInfo->sFontName = fontName; pFontInfo->iSize = nSize; pFontInfo->bBold = bBold; pFontInfo->bUnderline = bUnderline; pFontInfo->bItalic = bItalic; ::ZeroMemory(&pFontInfo->tm, sizeof(pFontInfo->tm)); m_mCustomFonts.insert(std::make_pair(strNewFontId, pFontInfo)); if (bDefault) m_sDefaultFontId = strNewFontId; return hFont; } TFontInfo* GlobalManager::GetTFontInfo(const std::wstring& strFontId) { std::wstring strFindId = strFontId; if (strFindId.empty()) { ASSERT(!m_sDefaultFontId.empty()); strFindId = m_sDefaultFontId; } auto iter = m_mCustomFonts.find(strFindId); ASSERT(iter != m_mCustomFonts.end()); TFontInfo* pFontInfo = static_cast(iter->second); return pFontInfo; } HFONT GlobalManager::GetFont(const std::wstring& strFontId) { TFontInfo* pFontInfo = GetTFontInfo(strFontId); if (pFontInfo) return pFontInfo->hFont; return nullptr; } HFONT GlobalManager::GetFont(const std::wstring& strFontName, int nSize, bool bBold, bool bUnderline, bool bItalic) { for (auto it = m_mCustomFonts.begin(); it != m_mCustomFonts.end(); it++) { auto pFontInfo = it->second; if( pFontInfo->sFontName == strFontName && pFontInfo->iSize == nSize && pFontInfo->bBold == bBold && pFontInfo->bUnderline == bUnderline && pFontInfo->bItalic == bItalic) return pFontInfo->hFont; } return NULL; } TFontInfo* GlobalManager::GetFontInfo(const std::wstring& strFontId, HDC hDcPaint) { TFontInfo* pFontInfo = GetTFontInfo(strFontId); if( pFontInfo->tm.tmHeight == 0 ) { HFONT hOldFont = (HFONT) ::SelectObject(hDcPaint, pFontInfo->hFont); ::GetTextMetrics(hDcPaint, &pFontInfo->tm); ::SelectObject(hDcPaint, hOldFont); } return pFontInfo; } TFontInfo* GlobalManager::GetFontInfo(HFONT hFont, HDC hDcPaint) { for( auto it = m_mCustomFonts.begin(); it != m_mCustomFonts.end(); it++ ) { auto pFontInfo = it->second; if( pFontInfo->hFont == hFont ) { if( pFontInfo->tm.tmHeight == 0 ) { HFONT hOldFont = (HFONT) ::SelectObject(hDcPaint, pFontInfo->hFont); ::GetTextMetrics(hDcPaint, &pFontInfo->tm); ::SelectObject(hDcPaint, hOldFont); } return pFontInfo; } } ASSERT(FALSE); return NULL; } bool GlobalManager::FindFont(HFONT hFont) { for( auto it = m_mCustomFonts.begin(); it != m_mCustomFonts.end(); it++ ) { auto pFontInfo = it->second; if( pFontInfo->hFont == hFont ) return true; } return false; } bool GlobalManager::FindFont(const std::wstring& strFontName, int nSize, bool bBold, bool bUnderline, bool bItalic) { for (auto it = m_mCustomFonts.begin(); it != m_mCustomFonts.end(); it++) { auto pFontInfo = it->second; if( pFontInfo->sFontName == strFontName && pFontInfo->iSize == nSize && pFontInfo->bBold == bBold && pFontInfo->bUnderline == bUnderline && pFontInfo->bItalic == bItalic) return true; } return false; } bool GlobalManager::RemoveFontAt(const std::wstring& strFontId) { auto iter = m_mCustomFonts.find(strFontId); if (iter == m_mCustomFonts.end()) return false; TFontInfo* pFontInfo = static_cast(iter->second); ::DeleteObject(pFontInfo->hFont); delete pFontInfo; m_mCustomFonts.erase(iter); return true; } void GlobalManager::RemoveAllFonts() { for (auto it = m_mCustomFonts.begin(); it != m_mCustomFonts.end(); it++) { auto pFontInfo = it->second; ::DeleteObject(pFontInfo->hFont); delete pFontInfo; } m_mCustomFonts.clear(); } std::wstring GlobalManager::GetDefaultDisabledTextColor() { return m_strDefaultDisabledColor; } void GlobalManager::SetDefaultDisabledTextColor(const std::wstring& strColor) { m_strDefaultDisabledColor = strColor; } std::wstring GlobalManager::GetDefaultTextColor() { return m_strDefaultFontColor; } void GlobalManager::SetDefaultTextColor(const std::wstring& strColor) { m_strDefaultFontColor = strColor; } DWORD GlobalManager::GetDefaultLinkFontColor() { return m_dwDefaultLinkFontColor; } void GlobalManager::SetDefaultLinkFontColor(DWORD strColor) { m_dwDefaultLinkFontColor = strColor; } DWORD GlobalManager::GetDefaultLinkHoverFontColor() { return m_dwDefaultLinkHoverFontColor; } void GlobalManager::SetDefaultLinkHoverFontColor(DWORD dwColor) { m_dwDefaultLinkHoverFontColor = dwColor; } DWORD GlobalManager::GetDefaultSelectedBkColor() { return m_dwDefaultSelectedBkColor; } void GlobalManager::SetDefaultSelectedBkColor(DWORD dwColor) { m_dwDefaultSelectedBkColor = dwColor; } Box* GlobalManager::CreateBox(const std::wstring& strXmlPath, CreateControlCallback callback) { WindowBuilder builder; Box* box = builder.Create(strXmlPath.c_str(), callback); ASSERT(box); return box; } Box* GlobalManager::CreateBoxWithCache(const std::wstring& strXmlPath, CreateControlCallback callback) { Box* box = nullptr; auto it = m_builderMap.find(strXmlPath); if (it == m_builderMap.end()) { WindowBuilder* builder = new WindowBuilder(); box = builder->Create(strXmlPath.c_str(), callback); if (box) { m_builderMap[strXmlPath].reset(builder); } else { ASSERT(FALSE); } } else { box = it->second->Create(callback); } return box; } void GlobalManager::FillBox(Box* pUserDefinedBox, const std::wstring& strXmlPath, CreateControlCallback callback) { WindowBuilder winBuilder; Box* box = winBuilder.Create(strXmlPath.c_str(), callback, pUserDefinedBox->GetWindow(), nullptr, pUserDefinedBox); ASSERT(box); return; } void GlobalManager::FillBoxWithCache(Box* pUserDefinedBox, const std::wstring& strXmlPath, CreateControlCallback callback) { Box* box = nullptr; auto it = m_builderMap.find(strXmlPath); if (it == m_builderMap.end()) { WindowBuilder* winBuilder = new WindowBuilder(); box = winBuilder->Create(strXmlPath.c_str(), callback, pUserDefinedBox->GetWindow(), nullptr, pUserDefinedBox); if (box) { m_builderMap[strXmlPath].reset(winBuilder); } else { ASSERT(FALSE); } } else { box = it->second->Create(callback, pUserDefinedBox->GetWindow(), nullptr, pUserDefinedBox); } return; } Control* GlobalManager::CreateControl(const std::wstring& strControlName) { if (m_createControlCallback) { return m_createControlCallback(strControlName); } return nullptr; } bool GlobalManager::IsUseZip() { return g_hzip != NULL; } bool GlobalManager::OpenResZip(LPCTSTR resource_name, LPCTSTR resource_type, const std::string& password) { HRSRC rsc = FindResource(NULL, resource_name, resource_type); HGLOBAL resource = LoadResource(NULL, rsc); DWORD size = SizeofResource(NULL, rsc); if (resource && size > 0) { } if (g_hzip) { CloseZip(g_hzip); g_hzip = NULL; } g_hzip = OpenZip(resource, size, password.c_str()); return g_hzip != NULL; } bool GlobalManager::OpenResZip(const std::wstring& path, const std::string& password) { if (g_hzip) { CloseZip(g_hzip); g_hzip = NULL; } g_hzip = OpenZip(path.c_str(), password.c_str()); return g_hzip != NULL; } HGLOBAL GlobalManager::GetData(const std::wstring& path) { HGLOBAL hGlobal = NULL; std::wstring file_path = GetZipFilePath(path); if (g_hzip && !file_path.empty()) { ZIPENTRY ze; int i = 0; if (FindZipItem(g_hzip, file_path.c_str(), true, &i, &ze) == ZR_OK) { if (ze.index >= 0) { hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, ze.unc_size); if (hGlobal) { TCHAR *pData = (TCHAR*)GlobalLock(hGlobal); if (pData) { ZRESULT res = UnzipItem(g_hzip, ze.index, pData, ze.unc_size); GlobalUnlock(hGlobal); if (res != ZR_OK) { GlobalFree(hGlobal); hGlobal = NULL; } } else { GlobalFree(hGlobal); hGlobal = NULL; } } } } } return hGlobal; } std::wstring GlobalManager::GetZipFilePath(const std::wstring& path) { std::wstring file_path = path; StringHelper::ReplaceAll(L"\\", L"/", file_path); StringHelper::ReplaceAll(L"//", L"/", file_path); for (unsigned int i = 0; i < file_path.size();) { bool start_node = false; if (i == 0 || file_path.at(i - 1) == L'/') { start_node = true; } WCHAR wch = file_path.at(i); if (start_node && wch == L'/')//"//" { file_path.erase(i, 1); continue; } if (start_node && wch == L'.') { if (i + 1 < file_path.size() && file_path.at(i + 1) == L'/')// "./" { file_path.erase(i, 2); continue; } else if (i + 2 < file_path.size() && file_path.at(i + 1) == L'.' && file_path.at(i + 2) == L'/')// "../" { file_path.erase(i, 2); int i_erase = i - 2; if (i_erase < 0) { ASSERT(0); } while (i_erase > 0 && file_path.at(i_erase) != L'/') i_erase--; file_path.erase(i_erase, i - i_erase); i = i_erase; continue; } } i++; } return file_path; } bool GlobalManager::ImageCacheKeyCompare::operator()(const std::wstring& key1, const std::wstring& key2) const { int nLen1 = (int)key1.length(); int nLen2 = (int)key2.length(); if (nLen1 != nLen2) return nLen1 < nLen2; LPCWSTR pStr1Begin = key1.c_str(); LPCWSTR pStr2Begin = key2.c_str(); LPCWSTR pStr1End = pStr1Begin + nLen1; LPCWSTR pStr2End = pStr2Begin + nLen2; // 逆向比较 while (--pStr1End >= pStr1Begin && --pStr2End >= pStr2Begin && *pStr1End == *pStr2End); // 两个串都已经比光了,那么肯定相等,返回false if (pStr1End < pStr1Begin) { return false; } return *pStr1End < *pStr2End; } } // namespace ui