📄 skinbase.cpp
字号:
// a bit daggy, but....
int nXPixel = BM.bmWidth;
COLORREF crPixel;
while (nXPixel--)
{
int nYPixel = BM.bmHeight;
while (nYPixel--)
{
crPixel = dcTemp.GetPixel(nXPixel, nYPixel);
// leave the mask color as-is
if (crPixel == crMask)
continue;
const BYTE btRed = GetRValue(crPixel);
const BYTE btGreen = GetGValue(crPixel);
const BYTE btBlue = GetBValue(crPixel);
// if gray already goto next
if (btRed == btGreen && btGreen == btBlue)
continue;
const BYTE btGray = (BYTE)((btRed / 3) + (btGreen / 2) + (btBlue / 4));
// note: SetPixelV() quicker than SetPixel()
dcTemp.SetPixelV(nXPixel, nYPixel, RGB(btGray, btGray, btGray));
}
}
dcTemp.SelectObject(pBMOld);
dcTemp.DeleteDC();
return TRUE;
}
BOOL CSkinBase::DoSysMenu(CWnd* pWnd, CPoint ptCursor, LPRECT prExclude, BOOL bCopy)
{
CMenu* pMenu = pWnd->GetSystemMenu(FALSE);
ASSERT (pMenu);
if (pMenu)
{
TPMPARAMS tpmp;
tpmp.cbSize = sizeof(tpmp);
if (prExclude)
tpmp.rcExclude = *prExclude;
else
SetRectEmpty(&tpmp.rcExclude);
UINT uAlignFlags = TPM_LEFTALIGN | TPM_TOPALIGN | TPM_VERTICAL | TPM_RIGHTBUTTON | TPM_RETURNCMD;
UINT uID = 0;
if (bCopy) // skinning
{
HMENU hSysMenu = CSkinBase::MakeMenuCopy(pMenu);
ASSERT (hSysMenu);
if (hSysMenu)
{
InitSysMenu(CMenu::FromHandle(hSysMenu), pWnd);
uID = ::TrackPopupMenuEx(hSysMenu, uAlignFlags,
ptCursor.x, ptCursor.y, *pWnd, &tpmp);
::DestroyMenu(hSysMenu); // cleanup
}
}
else
{
InitSysMenu(pMenu, pWnd);
uID = ::TrackPopupMenuEx(pMenu->GetSafeHmenu(), uAlignFlags,
ptCursor.x, ptCursor.y, *pWnd, &tpmp);
}
if (uID & 0xf000) // syscommand
{
MSG& curMsg = AfxGetThreadState()->m_lastSentMsg;
pWnd->PostMessage(WM_SYSCOMMAND, (uID & 0xfff0), MAKELPARAM(curMsg.pt.x, curMsg.pt.y));
}
}
return TRUE;
}
void CSkinBase::InitSysMenu(CMenu* pMenu, CWnd* pWnd)
{
// iterate all the menu items looking for something resembling a sys menu item
int nItem = pMenu->GetMenuItemCount();
while (nItem--)
{
UINT uID = pMenu->GetMenuItemID(nItem);
if (uID >= 0xF000)
{
BOOL bEnable = TRUE;
switch (uID & 0xFFF0)
{
case SC_MINIMIZE:
bEnable = (pWnd->GetStyle() & WS_MINIMIZEBOX) && !pWnd->IsIconic();
break;
case SC_MAXIMIZE:
bEnable = (pWnd->GetStyle() & WS_MAXIMIZEBOX) && !pWnd->IsZoomed();
break;
case SC_RESTORE:
bEnable = pWnd->IsIconic() || pWnd->IsZoomed();
break;
case SC_MOVE:
case SC_SIZE:
bEnable = !pWnd->IsIconic() && !pWnd->IsZoomed();
break;
}
pMenu->EnableMenuItem(uID, bEnable ? MF_ENABLED : MF_GRAYED);
}
}
// set close as default item
pMenu->SetDefaultItem(SC_CLOSE);
}
CSize CSkinBase::GetTextExtent(CDC* pDC, LPCTSTR szText)
{
ASSERT (pDC && szText);
if (pDC && szText)
{
CRect rText(0, 0, 0, SHRT_MAX);
pDC->DrawText(szText, rText, DT_SINGLELINE | DT_CALCRECT);
return rText.Size();
}
// else
return 0;
}
const LPCTSTR WORDBREAK = "_-+=,.:;";
const int CHUNK = 32;
int CSkinBase::FormatText(CDC* pDC, CString& sText, CRect& rect, UINT uDTFlags)
{
CString sOrgText(sText);
sText.Empty();
int nPos = 0, nLinePos = 0, nLen = sOrgText.GetLength();
int nLastWhiteSpace = -1;
int nHeight = 0;
const int LINEHEIGHT = pDC->GetTextExtent("W").cy;
int nLongestLine = 0;
// we always allow at least one line of text
BOOL bSingleLine = (uDTFlags & DT_SINGLELINE);
BOOL bCalcRect = (uDTFlags & DT_CALCRECT);
BOOL bEllipsis = (uDTFlags & DT_END_ELLIPSIS);
BOOL bModString = (uDTFlags & DT_MODIFYSTRING);
BOOL bFinished = FALSE;
const int CHUNK = 32;
char* pBuffer = sOrgText.GetBuffer(sOrgText.GetLength() + 1);
while (!bFinished)
{
int nChunk = CHUNK;
BOOL bLonger = TRUE;
int nLinePos = 0;
int nPrevPos = 0;
char* pLine = pBuffer + nPos;
// add chunks till we go over
BOOL bContinue = TRUE;
int nWidth = 0;
while (bContinue)
{
nChunk = min(nChunk, nLen - (nPos + nLinePos));
nLinePos += nChunk;
nWidth = pDC->GetTextExtent(pLine, nLinePos).cx;
bContinue = (nChunk == CHUNK && nWidth < rect.Width());
}
// then iterate back and forth with sub chunks till we are just under
for (int i = 0; i < 5; i++)
{
nChunk /= 2;
if (nWidth == rect.Width())
break;
else if (nWidth > rect.Width())
nLinePos -= nChunk;
else
nLinePos += nChunk;
nWidth = pDC->GetTextExtent(pLine, nLinePos).cx;
}
// one final check to see we haven't ended up over
if (nWidth > rect.Width())
nLinePos--;
// then work back to the previous word break
int nSavePos = nLinePos;
while (nLinePos)
{
// we word break either if the current character is whitespace or
// if the preceding character is a wordbreak character
// or we've reached the end of the string
BOOL bWordBreak = nLinePos == nLen || _istspace(pLine[nLinePos]) ||
(strchr(WORDBREAK, pLine[nLinePos - 1]) != NULL);
if (bWordBreak)
break;
nLinePos--;
}
if (!nLinePos)
nLinePos = nSavePos; // single word spans entire line
nWidth = pDC->GetTextExtent(pLine, nLinePos).cx;
// check for last line and add ellipsis if required
nHeight += LINEHEIGHT;
BOOL bAddEllipsis = FALSE;
if (nHeight + LINEHEIGHT > rect.Height() || bSingleLine)
{
if (bEllipsis && nPos + nLinePos < nLen - 1)
{
const int LEN_ELLIPSIS = pDC->GetTextExtent("...", 3).cx;
// modify the last line to add ellipsis
while (nLinePos)
{
nWidth = pDC->GetTextExtent(pLine, nLinePos).cx + LEN_ELLIPSIS;
if (nWidth > rect.Width())
nLinePos--;
else
break;
}
bAddEllipsis = TRUE;
}
sText += sOrgText.Mid(nPos, nLinePos);
if (bAddEllipsis)
sText += "...";
nLongestLine = max(nLongestLine, nWidth);
break;
}
sText += sOrgText.Mid(nPos, nLinePos);
sText += '\n';
nPos += nLinePos;
bFinished = (nPos >= nLen - 1 || nHeight + LINEHEIGHT > rect.Height());
nLongestLine = max(nLongestLine, nWidth);
// jump white space at the start of the next line
if (!bFinished)
{
while (nPos < nLen - 1)
{
if (!_istspace(pBuffer[nPos]))
break;
// else
nPos++;
}
}
}
sOrgText.ReleaseBuffer();
if (!bModString)
sText = sOrgText;
if (bCalcRect)
{
rect.right = rect.left + nLongestLine;
rect.bottom = rect.top + nHeight;
}
return nHeight;
}
//////////////////////////////
//////////////////////////////
int CALLBACK CheckFontProc(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, DWORD FontType, LPARAM lParam)
{
BOOL* pPresent = (BOOL*)lParam;
ASSERT (pPresent);
if (pPresent && FontType == TRUETYPE_FONTTYPE) // only TT accepted for now
*pPresent = TRUE; // at least one font found to match facename
return 0;
}
BOOL CSkinBase::FontIsPresent(LPCTSTR szFaceName)
{
LOGFONT lf;
HDC hdc = ::GetDC(NULL);
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfPitchAndFamily = 0;
lstrcpy(lf.lfFaceName, szFaceName);
BOOL bPresent = FALSE;
EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC)CheckFontProc, (LPARAM)&bPresent, 0);
::ReleaseDC(NULL, hdc);
return bPresent;
}
//////////////////////////////////
// theming
#ifndef STAP_ALLOW_NONCLIENT
#define STAP_ALLOW_NONCLIENT (1 << 0)
#define STAP_ALLOW_CONTROLS (1 << 1)
#define STAP_ALLOW_WEBCONTENT (1 << 2)
#endif
typedef void (STDAPICALLTYPE* SETTHEMEAPPPROPERTIES)(DWORD);
void CSkinBase::EnableTheming(BOOL bEnable)
{
if (GetOS() < SBOS_XP || bEnable == s_bThemingEnabled)
return;
static HMODULE hUXTheme = ::LoadLibrary("UXTheme.dll");
if (hUXTheme)
{
SETTHEMEAPPPROPERTIES SetThemeAppProperties =
(SETTHEMEAPPPROPERTIES)GetProcAddress(hUXTheme, "SetThemeAppProperties");
if (SetThemeAppProperties)
{
SetThemeAppProperties(bEnable ?
STAP_ALLOW_NONCLIENT | STAP_ALLOW_CONTROLS | STAP_ALLOW_WEBCONTENT :
0);
s_bThemingEnabled = bEnable;
}
}
}
BOOL CSkinBase::CreateThemeManifest(LPCTSTR szName, LPCTSTR szDescription)
{
// if (GetOS() < SBOS_XP)
// return FALSE;
// create the manifest only if one does not exist
CString sFilePath;
::GetModuleFileName(NULL, sFilePath.GetBuffer(MAX_PATH + 1), MAX_PATH);
sFilePath.ReleaseBuffer();
sFilePath += ".Manifest";
CFileStatus fs;
if (CFile::GetStatus(sFilePath, fs))
return TRUE; // already exists
ASSERT (szName && strlen(szName) && szDescription && strlen(szDescription));
if (!(szName && strlen(szName) && szDescription && strlen(szDescription)))
return FALSE;
LPCTSTR szManifestFmt = " \
<?xml version='1.0' encoding='UTF-8' standalone='yes'?> \
<assembly \
xmlns='urn:schemas-microsoft-com:asm.v1' \
manifestVersion='1.0'> \
\
<assemblyIdentity \
version='1.0.0.0' \
processorArchitecture='X86' \
name='%s' \
type='win32' \
/> \
<description>%s</description> \
<dependency> \
<dependentAssembly> \
<assemblyIdentity \
type='win32' \
name='Microsoft.Windows.Common-Controls' \
version='6.0.0.0' \
processorArchitecture='X86' \
publicKeyToken='6595b64144ccf1df' \
language='*' \
/> \
</dependentAssembly> \
</dependency> \
</assembly> ";
CString sManifest;
sManifest.Format(szManifestFmt, szName, szDescription);
CStdioFile file;
if (!file.Open(sFilePath, CFile::modeCreate | CFile::modeWrite | CFile::typeText))
return FALSE;
file.WriteString(sManifest);
file.Close();
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////////////////
HICON CSkinBase::GetWindowIcon(CWnd* pWnd)
{
ASSERT (pWnd);
if (!pWnd)
return NULL;
HICON hIcon = pWnd->GetIcon(FALSE); // small icon
if (!hIcon)
hIcon = pWnd->GetIcon(TRUE); // large icon
if (!hIcon)
{
WNDCLASS wndcls;
CString sClass(CWinClasses::GetClass(*pWnd));
if (GetClassInfo(AfxGetInstanceHandle(), sClass, &wndcls))
hIcon = wndcls.hIcon;
}
return hIcon;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -