Files
Open-Shell-Menu/Src/StartMenu/StartMenuDLL/MenuPaint.cpp
ge0rdi bce9efcc43 Display monochrome icons using color of corresponding text item
Some icons (modern settings, jump-list tasks) are monochrome, basically
they are defined just by alpha channel.
Thus they can be displayed in any color (white is default).

Since these icons are white by default, they look nice on dark
backgrounds. But they are not very visible on light backgrounds.

Thus the idea is to 'colorize' such icon using color of corresponding
text item. That way they will always have proper color.

Fixes #466.
2020-09-26 15:46:19 +02:00

3173 lines
106 KiB
C++

// ## MenuContainer.h
// Classic Shell (c) 2009-2017, Ivo Beltchev
// Open-Shell (c) 2017-2018, The Open-Shell Team
// Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author
// MenuPaint.cpp - handles the painting functionality of CMenuContainer
#include "stdafx.h"
#include "ItemManager.h"
#include "MenuContainer.h"
#include "StartMenuDLL.h"
#include "Settings.h"
#include "Translations.h"
#include "ResourceHelper.h"
#include "LogManager.h"
#include "ProgramsTree.h"
#include "SettingsUI.h"
#include <vsstyle.h>
#include <dwmapi.h>
#include <algorithm>
#include <math.h>
static BLENDFUNCTION g_AlphaFunc={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
MIDL_INTERFACE("4BEDE6E0-A125-46A7-A3BF-4187165E09A5")
IUserTileStore8 : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE SaveUserTileToStream( IStream*, int ) = 0;
virtual HRESULT STDMETHODCALLTYPE SetUserTileFromStream( int, IStream* ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLargePath( const wchar_t *userSid, wchar_t **pPath ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSmallPath( const wchar_t *userSid, wchar_t **pPath ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDynamicPath( const wchar_t *userSid, wchar_t **pPath ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSmallPicture( const wchar_t *userSid, HBITMAP *pBitmap ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLargePicture( const wchar_t *userSid, HBITMAP *pBitmap ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetUserTilePathBySize( const wchar_t *userSid, unsigned int size, wchar_t **pPath ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDynamicPathBySize( const wchar_t *userSid, unsigned int size, wchar_t **pPath ) = 0;
};
MIDL_INTERFACE("A1BA55E7-0F4E-454D-89A4-2376347D504A")
IUserTileStore81 : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE SaveUserTileToStream( IStream*, int ) = 0;
virtual HRESULT STDMETHODCALLTYPE SetUserTileFromStream( int, IStream* ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLargePath( const wchar_t *userSid, wchar_t **pPath ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSmallPath( const wchar_t *userSid, wchar_t **pPath ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDynamicPath( const wchar_t *userSid, wchar_t **pPath ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSmallPicture( const wchar_t *userSid, HBITMAP *pBitmap ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLargePicture( const wchar_t *userSid, HBITMAP *pBitmap ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetUserTilePathBySize( const wchar_t *userSid, unsigned int size, wchar_t **pPath ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDynamicPathBySize( const wchar_t *userSid, unsigned int size, wchar_t **pPath ) = 0;
};
MIDL_INTERFACE("A76E31A3-DED8-4119-ADD8-BF818F05965C")
IUserTileStore10 : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE SaveUserTileToStream( IStream*, int ) = 0;
virtual HRESULT STDMETHODCALLTYPE SetUserTileFromStream( int, IStream* ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLargePath( const wchar_t *userSid, wchar_t **pPath ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSmallPath( const wchar_t *userSid, wchar_t **pPath ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetExtraSmallPath( const wchar_t *userSid, wchar_t **pPath ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDynamicPath( const wchar_t *userSid, wchar_t **pPath ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetSmallPicture( const wchar_t *userSid, HBITMAP *pBitmap ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetLargePicture( const wchar_t *userSid, HBITMAP *pBitmap ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetUserTilePathBySize( const wchar_t *userSid, unsigned int size, wchar_t **pPath ) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDynamicPathBySize( const wchar_t *userSid, unsigned int size, wchar_t **pPath ) = 0;
};
static CLSID CLSID_UserTileStore={0x09c5dd34, 0x009d, 0x40fa, {0xbc, 0xb9, 0x01, 0x65, 0xad, 0x0c, 0x15, 0xd4}};
static void StretchBlt2( HDC hdcDest, int xDest, int yDest, int wDest, int hDest, HDC hdcSrc, int xSrc, int ySrc, int wSrc, int hSrc, bool bAlpha )
{
if (wDest>0 && hDest>0 && wSrc>0 && hSrc>0)
{
if (bAlpha)
AlphaBlend(hdcDest,xDest,yDest,wDest,hDest,hdcSrc,xSrc,ySrc,wSrc,hSrc,g_AlphaFunc);
else if (wDest==wSrc && hDest==hSrc)
{
// HACK: when blitting RTL image with no stretching, StretchBlt adds 1 pixel offset. use BitBlt instead
BitBlt(hdcDest,xDest,yDest,wDest,hDest,hdcSrc,xSrc,ySrc,SRCCOPY);
}
else
StretchBlt(hdcDest,xDest,yDest,wDest,hDest,hdcSrc,xSrc,ySrc,wSrc,hSrc,SRCCOPY);
}
}
HBITMAP CMenuContainer::LoadUserImage( int size, HBITMAP hMask )
{
wchar_t path[_MAX_PATH];
path[0]=0;
CString str=GetSettingString(L"UserPicturePath");
if (str.IsEmpty())
{
if (GetWinVersion()==WIN_VER_WIN8)
{
CComPtr<IUserTileStore8> pStore;
pStore.CoCreateInstance(CLSID_UserTileStore);
if (pStore)
{
CComString pPath;
if (SUCCEEDED(pStore->GetDynamicPathBySize(NULL,size,&pPath)) || SUCCEEDED(pStore->GetUserTilePathBySize(NULL,size,&pPath)))
Strcpy(path,_countof(path),pPath);
}
}
else if (GetWinVersion()==WIN_VER_WIN81)
{
CComPtr<IUserTileStore81> pStore;
pStore.CoCreateInstance(CLSID_UserTileStore);
if (pStore)
{
CComString pPath;
if (SUCCEEDED(pStore->GetDynamicPathBySize(NULL,size,&pPath)) || SUCCEEDED(pStore->GetUserTilePathBySize(NULL,size,&pPath)))
Strcpy(path,_countof(path),pPath);
}
}
else if (GetWinVersion()>=WIN_VER_WIN10)
{
CComPtr<IUserTileStore10> pStore;
pStore.CoCreateInstance(CLSID_UserTileStore);
if (pStore)
{
CComString pPath;
if (SUCCEEDED(pStore->GetDynamicPathBySize(NULL,size,&pPath)) || SUCCEEDED(pStore->GetUserTilePathBySize(NULL,size,&pPath)))
Strcpy(path,_countof(path),pPath);
}
}
if (!path[0])
{
HMODULE hShell32=GetModuleHandle(L"shell32.dll");
typedef HRESULT (__stdcall*tSHGetUserPicturePath)(LPCWSTR, UINT, LPWSTR, ULONG);
tSHGetUserPicturePath SHGetUserPicturePath=(tSHGetUserPicturePath)GetProcAddress(hShell32,MAKEINTRESOURCEA(261));
if (SHGetUserPicturePath)
SHGetUserPicturePath(NULL,0x80000000,path,_countof(path));
}
}
else
{
Strcpy(path,_countof(path),str);
DoEnvironmentSubst(path,_countof(path));
}
HBITMAP hBitmap=NULL;
if (path[0])
{
LOG_MENU(LOG_OPEN,L"Loading user image: '%s'",path);
SIZE s={size,size};
if (str.IsEmpty())
hBitmap=LoadImageFile(path,&s,false,false,NULL);
else
hBitmap=LoadImageFile(path,&s,true,true,NULL);
}
if (hBitmap && hMask)
{
BITMAP info1, info2;
GetObject(hBitmap,sizeof(info1),&info1);
GetObject(hMask,sizeof(info2),&info2);
if (info1.bmBits && info2.bmBits && info1.bmWidth==info2.bmWidth && info1.bmHeight==info2.bmHeight && info1.bmBitsPixel==32 && info2.bmBitsPixel==32)
{
unsigned char *pixels1=(unsigned char*)info1.bmBits;
const unsigned char *pixels2=(const unsigned char*)info2.bmBits;
int n=info1.bmWidth*info1.bmHeight;
bool bHasAlpha=false;
pixels1+=3;
for (int i=0;i<n;i++, pixels1+=4)
if (*pixels1)
{
bHasAlpha=true;
break;
}
pixels1=(unsigned char*)info1.bmBits;
for (int i=0;i<n;i++, pixels1+=4, pixels2+=4)
{
int r=pixels1[0];
int g=pixels1[1];
int b=pixels1[2];
int a=pixels1[3];
int mask=pixels2[3];
pixels1[0]=(unsigned char)(r*mask/255);
pixels1[1]=(unsigned char)(g*mask/255);
pixels1[2]=(unsigned char)(b*mask/255);
pixels1[3]=(unsigned char)(bHasAlpha?(a*mask/255):mask);
}
}
}
return hBitmap;
}
void MarginsBlit( HDC hSrc, HDC hDst, const RECT &rSrc, const RECT &rDst, const RECT &rMargins, bool bAlpha )
{
int x0a=rDst.left;
int x1a=rDst.left+rMargins.left;
if (x1a>rDst.right) x1a=rDst.right;
int x2a=rDst.right-rMargins.right;
if (x2a<rDst.left) x2a=rDst.left;
if (x1a>x2a) x1a=x2a=(x1a+x2a)/2;
int x3a=rDst.right;
int x0b=rSrc.left;
int x1b=rSrc.left+rMargins.left;
int x2b=rSrc.right-rMargins.right;
int x3b=rSrc.right;
int y0a=rDst.top;
int y1a=rDst.top+rMargins.top;
if (y1a>rDst.bottom) y1a=rDst.bottom;
int y2a=rDst.bottom-rMargins.bottom;
if (y2a<rDst.top) y2a=rDst.top;
if (y1a>y2a) y1a=y2a=(y1a+y2a)/2;
int y3a=rDst.bottom;
int y0b=rSrc.top;
int y1b=rSrc.top+rMargins.top;
int y2b=rSrc.bottom-rMargins.bottom;
int y3b=rSrc.bottom;
SetStretchBltMode(hDst,COLORONCOLOR);
StretchBlt2(hDst,x0a,y0a,x1a-x0a,y1a-y0a,hSrc,x0b,y0b,x1b-x0b,y1b-y0b,bAlpha);
StretchBlt2(hDst,x1a,y0a,x2a-x1a,y1a-y0a,hSrc,x1b,y0b,x2b-x1b,y1b-y0b,bAlpha);
StretchBlt2(hDst,x2a,y0a,x3a-x2a,y1a-y0a,hSrc,x2b,y0b,x3b-x2b,y1b-y0b,bAlpha);
StretchBlt2(hDst,x0a,y1a,x1a-x0a,y2a-y1a,hSrc,x0b,y1b,x1b-x0b,y2b-y1b,bAlpha);
StretchBlt2(hDst,x1a,y1a,x2a-x1a,y2a-y1a,hSrc,x1b,y1b,x2b-x1b,y2b-y1b,bAlpha);
StretchBlt2(hDst,x2a,y1a,x3a-x2a,y2a-y1a,hSrc,x2b,y1b,x3b-x2b,y2b-y1b,bAlpha);
StretchBlt2(hDst,x0a,y2a,x1a-x0a,y3a-y2a,hSrc,x0b,y2b,x1b-x0b,y3b-y2b,bAlpha);
StretchBlt2(hDst,x1a,y2a,x2a-x1a,y3a-y2a,hSrc,x1b,y2b,x2b-x1b,y3b-y2b,bAlpha);
StretchBlt2(hDst,x2a,y2a,x3a-x2a,y3a-y2a,hSrc,x2b,y2b,x3b-x2b,y3b-y2b,bAlpha);
}
struct PatternInfo
{
int index;
SIZE size;
int offsetX;
int maskShift;
unsigned int otherMask;
const std::vector<unsigned int> *bits;
const unsigned int *bitsY;
int stride;
};
static HBITMAP CreateMaskedEmblem( HBITMAP bmpEmblem, RECT &rcEmblem, const unsigned int *EMaskBits, int maskWidth, int maskHeight, int channel )
{
if (channel<3) channel=2-channel;
int minx=rcEmblem.left<0?0:rcEmblem.left;
int maxx=rcEmblem.right>maskWidth?maskWidth:rcEmblem.right;
int miny=rcEmblem.top<0?0:rcEmblem.top;
int maxy=rcEmblem.bottom>maskHeight?maskHeight:rcEmblem.bottom;
Assert(minx<maxx && miny<maxy);
BITMAPINFO dib={sizeof(dib)};
dib.bmiHeader.biWidth=maxx-minx;
dib.bmiHeader.biHeight=miny-maxy;
dib.bmiHeader.biPlanes=1;
dib.bmiHeader.biBitCount=32;
dib.bmiHeader.biCompression=BI_RGB;
HDC hdc=CreateCompatibleDC(NULL);
unsigned int *dstBits;
HBITMAP maskedEmblem=CreateDIBSection(hdc,&dib,DIB_RGB_COLORS,(void**)&dstBits,NULL,0);
DeleteDC(hdc);
BITMAP info;
GetObject(bmpEmblem,sizeof(info),&info);
const unsigned char *srcMask=(unsigned char*)(EMaskBits+miny*maskWidth+minx)+channel;
const unsigned char *srcBits=(unsigned char*)info.bmBits+(info.bmHeight-rcEmblem.top+miny-1)*info.bmWidthBytes+(minx-rcEmblem.left)*(info.bmBitsPixel/8);
for (int y=miny;y<maxy;y++, srcMask+=maskWidth*4, srcBits-=info.bmWidthBytes)
{
const unsigned char *srcMask2=srcMask;
const unsigned char *srcBits2=srcBits;
if (info.bmBitsPixel==32)
{
ptrdiff_t start=(char*)srcBits2-(char*)info.bmBits;
Assert(start>=0 && start+(maxx-minx)*4<=info.bmHeight*info.bmWidthBytes);
for (int x=minx;x<maxx;x++,srcMask2+=4,srcBits2+=4,dstBits++)
{
int mask=*srcMask2;
int r=(srcBits2[2]*mask)/255;
int g=(srcBits2[1]*mask)/255;
int b=(srcBits2[0]*mask)/255;
int a=(srcBits2[3]*mask)/255;
*dstBits=(a<<24)|(r<<16)|(g<<8)|b;
}
}
else if (info.bmBitsPixel==24)
{
ptrdiff_t start=(char*)srcBits2-(char*)info.bmBits;
Assert(start>=0 && start+(maxx-minx)*3<=info.bmHeight*info.bmWidthBytes);
for (int x=minx;x<maxx;x++,srcMask2+=4,srcBits2+=3,dstBits++)
{
int mask=*srcMask2;
int r=(srcBits2[2]*mask)/255;
int g=(srcBits2[1]*mask)/255;
int b=(srcBits2[0]*mask)/255;
*dstBits=(mask<<24)|(r<<16)|(g<<8)|b;
}
}
}
rcEmblem.left=minx;
rcEmblem.right=maxx;
rcEmblem.top=miny;
rcEmblem.bottom=maxy;
return maskedEmblem;
}
void CMenuContainer::BlendPatterns( unsigned int *bits, int width, int height )
{
s_Skin.PretilePatterns(width);
LARGE_INTEGER time0;
QueryPerformanceCounter(&time0);
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
PatternInfo patterns[4];
int patCount=0;
unsigned int patMask=0;
const int maskShift[4]={16,8,0,24};
for (int i=0;i<4;i++)
{
if (s_Skin.Patterns[i].GetBitmap())
{
PatternInfo &pattern=patterns[patCount++];
pattern.size=s_Skin.Pattern_sizes[i];
pattern.index=i;
pattern.maskShift=maskShift[i];
pattern.otherMask=~(255<<pattern.maskShift);
patMask|=255<<pattern.maskShift;
pattern.bits=&s_Skin.PatternBits[i];
pattern.stride=(int)pattern.bits->size()/pattern.size.cy;
}
}
for (int y=0;y<height;y++)
{
for (int i=0;i<patCount;i++)
{
PatternInfo &pattern=patterns[i];
pattern.bitsY=&(*pattern.bits)[(y%pattern.size.cy)*pattern.stride];
pattern.offsetX=0;
}
for (int x=0;x<width;x++,bits++)
{
unsigned int &pixel=*bits;
if ((pixel&patMask)==0)
{
pixel=0;
continue;
}
int a=0, r=0, g=0, b=0;
for (int i=0;i<patCount;i++)
{
const PatternInfo &pattern=patterns[i];
int mask=(pixel>>pattern.maskShift)&255;
if (mask==0) continue;
unsigned int pat=pattern.bitsY[x];
if ((pixel&pattern.otherMask)==0)
{
// fast path if only one channel is set
int pa=pat>>24;
if (pa)
{
if (mask==255)
{
// even faster path for straight copy
pixel=pat;
}
else
{
mask++; // a cheat to make the mask from 1 to 256, so we can use >>8 instead of /255
a=(pa*mask)>>8;
if (a==0)
{
pixel=0;
}
else
{
r=(((pat>>16)&255)*mask)>>8;
g=(((pat>>8)&255)*mask)>>8;
b=((pat&255)*mask)>>8;
pixel=(a<<24)|(r<<16)|(g<<8)|b;
}
}
}
else
pixel=0;
goto end;
}
int pa=pat>>24;
if (pa)
{
a+=pa*mask;
r+=((pat>>16)&255)*mask;
g+=((pat>>8)&255)*mask;
b+=(pat&255)*mask;
}
}
a/=255;
if (a==0)
{
pixel=0;
}
else
{
if (a>255) a=255;
r/=255; if (r>255) r=255;
g/=255; if (g>255) g=255;
b/=255; if (b>255) b=255;
pixel=(a<<24)|(r<<16)|(g<<8)|b;
}
end:;
}
}
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
LONGLONG dt=(time.QuadPart-time0.QuadPart)*1000000/freq.QuadPart;
// Trace("BlendPatterns: %.3f ms",(int)dt/1000.f);
}
// Creates the bitmap for the background
void CMenuContainer::CreateBackground( int width1, int width2, int height1, int height2, int &totalWidth, int &totalHeight, bool bCreateRegion )
{
// get the text from the ini file or from the registry
wchar_t caption[256];
Strcpy(caption,_countof(caption),GetSettingString(L"MenuCaption"));
DoEnvironmentSubst(caption,_countof(caption));
MenuBitmap bmpSkin;
MenuBitmap bmpSkinPattern;
MenuBitmap bmpSkinEmblem;
const int *slicesX, *slicesY;
if (s_MenuMode==MODE_SEARCH)
{
bmpSkin=s_Skin.Main_bitmap_search;
slicesX=s_Skin.Main_bitmap_search_slices_X;
slicesY=s_Skin.Main_bitmap_search_slices_Y;
bmpSkinPattern=s_Skin.Main_pattern_search_mask;
bmpSkinEmblem=s_Skin.Main_emblem_search_mask;
}
else if (s_MenuMode==MODE_JUMPLIST)
{
bmpSkin=s_Skin.Main_bitmap_jump;
slicesX=s_Skin.Main_bitmap_jump_slices_X;
slicesY=s_Skin.Main_bitmap_jump_slices_Y;
bmpSkinPattern=s_Skin.Main_pattern_jump_mask;
bmpSkinEmblem=s_Skin.Main_emblem_jump_mask;
}
else
{
bmpSkin=s_Skin.Main_bitmap;
slicesX=s_Skin.Main_bitmap_slices_X;
slicesY=s_Skin.Main_bitmap_slices_Y;
bmpSkinPattern=s_Skin.Main_pattern_mask;
bmpSkinEmblem=s_Skin.Main_emblem_mask;
}
bool bCaption=(slicesX[1]>0);
MenuSkin::TOpacity opacity=s_Skin.Main_opacity;
HDC hdcTemp=CreateCompatibleDC(NULL);
HFONT font0=NULL;
if (bCaption)
font0=(HFONT)SelectObject(hdcTemp,s_Skin.Caption_font);
RECT rc={0,0,0,0};
DTTOPTS opts={sizeof(opts),DTT_COMPOSITED|DTT_CALCRECT};
if (bCaption)
{
if (s_Theme)
DrawThemeTextEx(s_Theme,hdcTemp,0,0,caption,-1,DT_NOPREFIX|DT_SINGLELINE|DT_CALCRECT,&rc,&opts);
else
DrawText(hdcTemp,caption,-1,&rc,DT_NOPREFIX|DT_SINGLELINE|DT_CALCRECT);
}
int textWidth=rc.right+s_Skin.Caption_padding.top+s_Skin.Caption_padding.bottom;
int textHeight=rc.bottom+s_Skin.Caption_padding.left+s_Skin.Caption_padding.right;
int total=slicesX[0]+slicesX[2];
if (textHeight<total) textHeight=total;
RECT menuPadding[2];
if (s_MenuMode==MODE_SEARCH)
{
menuPadding[0]=s_Skin.Main_search_padding;
memset(&menuPadding[1],0,sizeof(menuPadding[1]));
}
else if (s_MenuMode==MODE_JUMPLIST)
{
menuPadding[0]=s_Skin.Main_padding;
menuPadding[1]=s_Skin.Main_jump_padding;
}
else
{
menuPadding[0]=s_Skin.Main_padding;
menuPadding[1]=s_Skin.Main2_padding;
}
int totalWidth1=textHeight+width1;
totalWidth1+=menuPadding[0].left+menuPadding[0].right;
if (totalWidth1<total) totalWidth1=total;
int totalWidth2=0;
if (m_bTwoColumns)
totalWidth2=width2+menuPadding[1].left+menuPadding[1].right;
totalWidth=totalWidth1+totalWidth2;
totalHeight=height1+menuPadding[0].top+menuPadding[0].bottom;
if (m_bTwoColumns)
{
int totalHeight2=height2+menuPadding[1].top+menuPadding[1].bottom;
if (totalHeight<totalHeight2) totalHeight=totalHeight2;
}
total=slicesY[0]+slicesY[2];
if (m_SearchIndex>=0 && s_bWin7Style)
total+=slicesY[3]+slicesY[5];
if (totalHeight<total) totalHeight=total;
if (textWidth>totalHeight) textWidth=totalHeight;
m_rContent.left=menuPadding[0].left+textHeight;
m_rContent.right=totalWidth1-menuPadding[0].right;
m_rContent.top=menuPadding[0].top;
m_rContent.bottom=m_rContent.top+height1;
if (totalWidth2>0)
{
m_rContent2.left=m_rContent.right+menuPadding[0].right+menuPadding[1].left;
m_rContent2.right=totalWidth-menuPadding[1].right;
m_rContent2.top=menuPadding[1].top;
m_rContent2.bottom=m_rContent2.top+height2;
}
MenuBitmap bmpSearch;
MenuBitmap bmpSearchPattern;
MenuBitmap bmpSearchEmblem;
int *searchSlicesX, *searchSlicesY;
RECT searchPadding;
int searchX[4], searchY[4];
if (m_SearchIndex>=0 && s_bWin7Style)
{
if (s_MenuMode==MODE_SEARCH)
{
bmpSearch=s_Skin.Search_background_search;
bmpSearchPattern=s_Skin.Search_pattern_search_mask;
bmpSearchEmblem=s_Skin.Search_emblem_search_mask;
searchSlicesX=s_Skin.Search_background_search_slices_X;
searchSlicesY=s_Skin.Search_background_search_slices_Y;
searchPadding=s_Skin.Search_background_search_padding;
}
else if (s_MenuMode==MODE_JUMPLIST)
{
bmpSearch=s_Skin.Search_background_jump;
bmpSearchPattern=s_Skin.Search_pattern_jump_mask;
bmpSearchEmblem=s_Skin.Search_emblem_jump_mask;
searchSlicesX=s_Skin.Search_background_jump_slices_X;
searchSlicesY=s_Skin.Search_background_jump_slices_Y;
searchPadding=s_Skin.Search_background_jump_padding;
}
else
{
bmpSearch=s_Skin.Search_background;
bmpSearchPattern=s_Skin.Search_pattern_mask;
bmpSearchEmblem=s_Skin.Search_emblem_mask;
searchSlicesX=s_Skin.Search_background_slices_X;
searchSlicesY=s_Skin.Search_background_slices_Y;
searchPadding=s_Skin.Search_background_padding;
}
const MenuSkin::ItemDrawSettings &settings=s_Skin.ItemSettings[MenuSkin::COLUMN1_ITEM];
int searchH=settings.textMetrics.tmHeight*12/8+s_Skin.Search_padding.top+s_Skin.Search_padding.bottom; // 12 DLUs
int searchW=settings.textMetrics.tmAveCharWidth*25;
RECT searchRect;
searchRect.left=m_rContent.left+s_Skin.Search_padding.left;
searchRect.top=m_rContent.bottom-searchH+s_Skin.Search_padding.top;
searchRect.bottom=m_rContent.bottom-s_Skin.Search_padding.bottom;
searchRect.right=m_rContent.right-s_Skin.Search_padding.right;
RECT editRect;
if (m_SearchBox.m_hWnd)
{
m_SearchBox.GetWindowRect(&editRect);
::MapWindowPoints(NULL,m_hWnd,(POINT*)&editRect,2);
OffsetRect(&editRect,-m_BitmapOffset,0);
searchRect.right=editRect.right+(editRect.bottom-editRect.top);
if (!s_Skin.Search_frame)
searchRect.right+=7;
}
else
{
editRect=searchRect;
editRect.right-=(editRect.bottom-editRect.top);
if (!s_Skin.Search_frame)
InflateRect(&editRect,-1,-3);
}
searchX[0]=m_rContent.left-searchPadding.left;
searchX[1]=editRect.left;
searchX[2]=searchRect.right+s_Skin.Search_padding.right;
searchX[3]=((s_MenuMode==MODE_JUMPLIST)?m_rContent2.right:m_rContent.right)+searchPadding.right;
searchY[0]=searchRect.top-s_Skin.Search_padding.top-searchPadding.top;
searchY[1]=editRect.top-2;
searchY[2]=editRect.bottom+2;
searchY[3]=m_rContent.bottom+searchPadding.bottom;
}
BITMAPINFO dib={sizeof(dib)};
dib.bmiHeader.biWidth=totalWidth;
dib.bmiHeader.biHeight=-totalHeight;
dib.bmiHeader.biPlanes=1;
dib.bmiHeader.biBitCount=32;
dib.bmiHeader.biCompression=BI_RGB;
HDC hdc=CreateCompatibleDC(NULL);
unsigned int *bits;
m_Bitmap=CreateDIBSection(hdc,&dib,DIB_RGB_COLORS,(void**)&bits,NULL,0);
HGDIOBJ bmp0=SelectObject(hdc,m_Bitmap);
if (opacity==MenuSkin::OPACITY_SOLID)
{
RECT rc={0,0,totalWidth,totalHeight};
SetDCBrushColor(hdc,s_Skin.Main_background);
FillRect(hdc,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
}
bool bHasPattern=false;
if (s_Skin.Patterns[0].GetBitmap() || s_Skin.Patterns[1].GetBitmap() || s_Skin.Patterns[2].GetBitmap() || s_Skin.Patterns[3].GetBitmap())
{
bHasPattern=(bmpSkinPattern.GetBitmap() || bmpSkinPattern.GetColor() || bmpSearchPattern.GetBitmap() || bmpSearchPattern.GetColor());
}
bool bHasEmblemMask=false;
if (s_Skin.Main_emblems[0].GetBitmap() || s_Skin.Main_emblems[1].GetBitmap() || s_Skin.Main_emblems[2].GetBitmap() || s_Skin.Main_emblems[3].GetBitmap())
{
bHasEmblemMask=(bmpSkinEmblem.GetBitmap() || bmpSkinEmblem.GetColor() || bmpSearchEmblem.GetBitmap() || bmpSearchEmblem.GetColor());
}
HBITMAP PMaskBmp=NULL, EMaskBmp=NULL;
unsigned int *PMaskBits=NULL, *EMaskBits=NULL;
HGDIOBJ bmp02=GetCurrentObject(hdcTemp,OBJ_BITMAP);
HDC hdcPMask=NULL, hdcEMask=NULL;
HDC hdcPMaskTemp=NULL, hdcEMaskTemp=NULL;
HGDIOBJ PMaskBmp0=NULL, PMaskBmp02=NULL, EMaskBmp0=NULL, EMaskBmp02=NULL;
if (bHasPattern)
{
hdcPMask=CreateCompatibleDC(NULL);
PMaskBmp=CreateDIBSection(hdcPMask,&dib,DIB_RGB_COLORS,(void**)&PMaskBits,NULL,0);
PMaskBmp0=SelectObject(hdcPMask,PMaskBmp);
hdcPMaskTemp=CreateCompatibleDC(NULL);
PMaskBmp02=GetCurrentObject(hdcPMaskTemp,OBJ_BITMAP);
}
if (bHasEmblemMask)
{
hdcEMask=CreateCompatibleDC(NULL);
EMaskBmp=CreateDIBSection(hdcEMask,&dib,DIB_RGB_COLORS,(void**)&EMaskBits,NULL,0);
EMaskBmp0=SelectObject(hdcEMask,EMaskBmp);
hdcEMaskTemp=CreateCompatibleDC(NULL);
EMaskBmp02=GetCurrentObject(hdcEMaskTemp,OBJ_BITMAP);
}
if (bmpSkin.GetBitmap())
{
// draw the skinned background
SelectObject(hdcTemp,bmpSkin.GetBitmap());
if (bHasPattern)
{
if (bmpSkinPattern.GetBitmap())
{
SelectObject(hdcPMaskTemp,bmpSkinPattern.GetBitmap());
}
else
{
RECT rc={0,0,totalWidth,totalHeight};
SetDCBrushColor(hdcPMask,bmpSkinPattern.GetColor());
FillRect(hdcPMask,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
}
}
if (bHasEmblemMask)
{
if (bmpSkinEmblem.GetBitmap())
{
SelectObject(hdcEMaskTemp,bmpSkinEmblem.GetBitmap());
}
else
{
RECT rc={0,0,totalWidth,totalHeight};
SetDCBrushColor(hdcEMask,bmpSkinEmblem.GetColor());
FillRect(hdcEMask,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
}
}
int searchHeight=0;
if (m_SearchIndex>=0 && s_bWin7Style && slicesY[3]+slicesY[4]+slicesY[5]>0)
searchHeight=m_Items[m_SearchIndex].itemRect.top-s_Skin.Search_padding.top-searchPadding.top;
RECT rSrc={0,0,slicesX[0]+slicesX[1]+slicesX[2],slicesY[0]+slicesY[1]+slicesY[2]};
RECT rDst={0,0,textHeight,searchHeight?searchHeight:totalHeight};
RECT rMargins={slicesX[0],slicesY[0],slicesX[2],slicesY[2]};
MarginsBlit(hdcTemp,hdc,rSrc,rDst,rMargins,(opacity==MenuSkin::OPACITY_SOLID && bmpSkin.bIs32));
if (bmpSkinPattern.GetBitmap())
MarginsBlit(hdcPMaskTemp,hdcPMask,rSrc,rDst,rMargins,false);
if (bmpSkinEmblem.GetBitmap())
MarginsBlit(hdcEMaskTemp,hdcEMask,rSrc,rDst,rMargins,false);
rSrc.left=rSrc.right;
rSrc.right+=slicesX[3]+slicesX[4]+slicesX[5];
rDst.left=rDst.right;
rDst.right=totalWidth1;
rMargins.left=slicesX[3];
rMargins.right=slicesX[5];
MarginsBlit(hdcTemp,hdc,rSrc,rDst,rMargins,(opacity==MenuSkin::OPACITY_SOLID && bmpSkin.bIs32));
if (bmpSkinPattern.GetBitmap())
MarginsBlit(hdcPMaskTemp,hdcPMask,rSrc,rDst,rMargins,false);
if (bmpSkinEmblem.GetBitmap())
MarginsBlit(hdcEMaskTemp,hdcEMask,rSrc,rDst,rMargins,false);
if (searchHeight>0)
{
RECT rSrc2=rSrc, rDst2=rDst, rMargins2=rMargins;
rSrc2.top=rSrc.bottom;
rSrc2.bottom+=slicesY[3]+slicesY[4]+slicesY[5];
rDst2.top=rDst.bottom;
rDst2.bottom=totalHeight;
rMargins2.top=slicesY[3];
rMargins2.bottom=slicesY[5];
MarginsBlit(hdcTemp,hdc,rSrc2,rDst2,rMargins2,(opacity==MenuSkin::OPACITY_SOLID && bmpSkin.bIs32));
if (bmpSkinPattern.GetBitmap())
MarginsBlit(hdcPMaskTemp,hdcPMask,rSrc2,rDst2,rMargins2,false);
if (bmpSkinEmblem.GetBitmap())
MarginsBlit(hdcEMaskTemp,hdcEMask,rSrc2,rDst2,rMargins2,false);
}
if (totalWidth2>0)
{
rSrc.left=rSrc.right;
rSrc.right+=slicesX[6]+slicesX[7]+slicesX[8];
rDst.left=rDst.right;
rDst.right+=totalWidth2;
rMargins.left=slicesX[6];
rMargins.right=slicesX[8];
MarginsBlit(hdcTemp,hdc,rSrc,rDst,rMargins,(opacity==MenuSkin::OPACITY_SOLID && bmpSkin.bIs32));
if (bmpSkinPattern.GetBitmap())
MarginsBlit(hdcPMaskTemp,hdcPMask,rSrc,rDst,rMargins,false);
if (bmpSkinEmblem.GetBitmap())
MarginsBlit(hdcEMaskTemp,hdcEMask,rSrc,rDst,rMargins,false);
if (searchHeight>0)
{
RECT rSrc2=rSrc, rDst2=rDst, rMargins2=rMargins;
rSrc2.top=rSrc.bottom;
rSrc2.bottom+=slicesY[3]+slicesY[4]+slicesY[5];
rDst2.top=rDst.bottom;
rDst2.bottom=totalHeight;
rMargins2.top=slicesY[3];
rMargins2.bottom=slicesY[5];
MarginsBlit(hdcTemp,hdc,rSrc2,rDst2,rMargins2,(opacity==MenuSkin::OPACITY_SOLID && bmpSkin.bIs32));
if (bmpSkinPattern.GetBitmap())
MarginsBlit(hdcPMaskTemp,hdcPMask,rSrc2,rDst2,rMargins2,false);
if (bmpSkinEmblem.GetBitmap())
MarginsBlit(hdcEMaskTemp,hdcEMask,rSrc2,rDst2,rMargins2,false);
}
}
}
else
{
RECT rc={0,0,totalWidth,totalHeight};
SetDCBrushColor(hdc,s_Skin.Main_background);
FillRect(hdc,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
if (bHasPattern)
{
SetDCBrushColor(hdcPMask,bmpSkinPattern.GetColor());
FillRect(hdcPMask,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
}
if (bHasEmblemMask)
{
SetDCBrushColor(hdcEMask,bmpSkinEmblem.GetColor());
FillRect(hdcEMask,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
}
}
if (m_SearchIndex>=0 && s_bWin7Style)
{
// draw the search background
if (bmpSearch.GetBitmap())
{
if (bHasPattern)
{
if (bmpSearchPattern.GetBitmap())
{
SelectObject(hdcPMaskTemp,bmpSearchPattern.GetBitmap());
}
else if (!bmpSearchPattern.bIsBitmap)
{
RECT rc={searchX[0],searchY[0],searchX[3],searchY[3]};
SetDCBrushColor(hdcPMask,bmpSearchPattern.GetColor());
FillRect(hdcPMask,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
}
}
if (bHasEmblemMask)
{
if (bmpSearchEmblem.GetBitmap())
{
SelectObject(hdcEMaskTemp,bmpSearchEmblem.GetBitmap());
}
else if (!bmpSearchEmblem.bIsBitmap)
{
RECT rc={searchX[0],searchY[0],searchX[3],searchY[3]};
SetDCBrushColor(hdcEMask,bmpSearchEmblem.GetColor());
FillRect(hdcEMask,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
}
}
int u[4], v[4];
u[0]=0;
u[1]=searchSlicesX[0]+searchSlicesX[1]+searchSlicesX[2];
u[2]=u[1]+searchSlicesX[3]+searchSlicesX[4]+searchSlicesX[5];
u[3]=u[2]+searchSlicesX[6]+searchSlicesX[7]+searchSlicesX[8];
v[0]=0;
v[1]=searchSlicesY[0]+searchSlicesY[1]+searchSlicesY[2];
v[2]=v[1]+searchSlicesY[3]+searchSlicesY[4]+searchSlicesY[5];
v[3]=v[2]+searchSlicesY[6]+searchSlicesY[7]+searchSlicesY[8];
SelectObject(hdcTemp,bmpSearch.GetBitmap());
for (int y=0;y<3;y++)
{
for (int x=0;x<3;x++)
{
RECT rDst={searchX[x],searchY[y],searchX[x+1],searchY[y+1]};
RECT rSrc={u[x],v[y],u[x+1],v[y+1]};
RECT rMargins={searchSlicesX[x*3],searchSlicesY[y*3],searchSlicesX[x*3+2],searchSlicesY[y*3+2]};
MarginsBlit(hdcTemp,hdc,rSrc,rDst,rMargins,bmpSearch.bIs32);
if (bmpSearchPattern.GetBitmap())
MarginsBlit(hdcPMaskTemp,hdcPMask,rSrc,rDst,rMargins,bmpSearchPattern.bIs32);
if (bmpSearchEmblem.GetBitmap())
MarginsBlit(hdcEMaskTemp,hdcEMask,rSrc,rDst,rMargins,bmpSearchPattern.bIs32);
}
}
}
else if (!bmpSearch.bIsBitmap)
{
RECT rDst={searchX[0],searchY[0],searchX[3],searchY[3]};
SetDCBrushColor(hdc,bmpSearch.GetColor());
FillRect(hdc,&rDst,(HBRUSH)GetStockObject(DC_BRUSH));
if (bHasPattern && !bmpSearchPattern.bIsBitmap)
{
SetDCBrushColor(hdcPMask,bmpSkinPattern.GetColor());
FillRect(hdcPMask,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
}
if (bHasEmblemMask && !bmpSearchEmblem.bIsBitmap)
{
SetDCBrushColor(hdcEMask,bmpSkinEmblem.GetColor());
FillRect(hdcEMask,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
}
}
}
if (bHasPattern)
{
if (PMaskBmp02)
SelectObject(hdcPMaskTemp,PMaskBmp02);
if (PMaskBmp0)
SelectObject(hdcPMask,PMaskBmp0);
if (hdcPMask)
DeleteDC(hdcPMask);
if (hdcPMaskTemp)
DeleteDC(hdcPMaskTemp);
// apply pattern
BlendPatterns(PMaskBits,totalWidth,totalHeight);
SelectObject(hdcTemp,PMaskBmp);
AlphaBlend(hdc,0,0,totalWidth,totalHeight,hdcTemp,0,0,totalWidth,totalHeight,g_AlphaFunc);
SelectObject(hdcTemp,bmp02);
DeleteObject(PMaskBmp);
}
// draw vertical separator
if (width2)
{
if (s_Skin.Main_separatorV.GetBitmap())
{
SelectObject(hdcTemp,s_Skin.Main_separatorV.GetBitmap());
RECT rSrc2={0,0,s_Skin.Main_separatorWidth,s_Skin.Main_separator_slices_Y[0]+s_Skin.Main_separator_slices_Y[1]+s_Skin.Main_separator_slices_Y[2]};
RECT rDst2={totalWidth1,menuPadding[0].top,totalWidth1+s_Skin.Main_separatorWidth,totalHeight-menuPadding[0].bottom};
if (s_bRTL)
{
rDst2.left=totalWidth-rDst2.right;
rDst2.right=totalWidth-totalWidth1;
}
RECT rMargins2={0,s_Skin.Main_separator_slices_Y[0],0,s_Skin.Main_separator_slices_Y[2]};
MarginsBlit(hdcTemp,hdc,rSrc2,rDst2,rMargins2,s_Skin.Main_separatorV.bIs32);
}
else if (!bmpSkin.GetBitmap()) // only when there is no main bitmap (it may have a built-in separator)
{
rc.left=rc.right=s_bRTL?(totalWidth-totalWidth1-2):totalWidth1;
rc.top=menuPadding[0].top;
rc.bottom=totalHeight-menuPadding[0].bottom;
DrawEdge(hdc,&rc,EDGE_ETCHED,BF_LEFT);
}
}
SelectObject(hdcTemp,bmp02);
for (int i=0;i<_countof(s_Skin.Main_emblems);i++)
{
if (s_Skin.Main_emblems[i].GetBitmap())
{
const SIZE &emblemSize=s_Skin.Main_emblem_sizes[i];
const RECT &emblemPadding=s_Skin.Main_emblem_paddings[i];
MenuSkin::THAlign alignH=s_Skin.Main_emblem_alignH1[i];
if (width2==0 && (alignH==MenuSkin::HALIGN_LEFT2 || alignH==MenuSkin::HALIGN_RIGHT2 || alignH==MenuSkin::HALIGN_CENTER2))
alignH=s_Skin.Main_emblem_alignH2[i];
if (alignH==MenuSkin::HALIGN_CORNER)
alignH=(m_Options&CONTAINER_LEFT)?MenuSkin::HALIGN_LEFT:MenuSkin::HALIGN_RIGHT;
MenuSkin::TVAlign alignV=s_Skin.Main_emblem_alignV[i];
if (alignV==MenuSkin::VALIGN_CORNER)
alignV=(m_Options&CONTAINER_TOP)?MenuSkin::VALIGN_TOP:MenuSkin::VALIGN_BOTTOM;
if (alignH==MenuSkin::HALIGN_NONE || alignV==MenuSkin::VALIGN_NONE)
continue;
int w=emblemSize.cx+emblemPadding.left+emblemPadding.right;
int h=emblemSize.cy+emblemPadding.top+emblemPadding.bottom;
int x0=0, x1=totalWidth;
int y0=0, y1=totalHeight;
if (alignH==MenuSkin::HALIGN_CENTER1 || alignH==MenuSkin::HALIGN_LEFT1 || alignH==MenuSkin::HALIGN_RIGHT1)
x1=totalWidth1;
else if (alignH==MenuSkin::HALIGN_CENTER2 || alignH==MenuSkin::HALIGN_LEFT2 || alignH==MenuSkin::HALIGN_RIGHT2)
x0=totalWidth1;
if (alignH==MenuSkin::HALIGN_LEFT || alignH==MenuSkin::HALIGN_LEFT1 || alignH==MenuSkin::HALIGN_LEFT2)
x1=x0+w;
else if (alignH==MenuSkin::HALIGN_RIGHT || alignH==MenuSkin::HALIGN_RIGHT1 || alignH==MenuSkin::HALIGN_RIGHT2)
x0=x1-w;
else if (alignH==MenuSkin::HALIGN_CENTER || alignH==MenuSkin::HALIGN_CENTER1 || alignH==MenuSkin::HALIGN_CENTER2)
x0=(x0+x1-w)/2, x1=x0+w;
if (alignV==MenuSkin::VALIGN_TOP)
y1=y0+h;
else if (alignV==MenuSkin::VALIGN_BOTTOM)
y0=y1-h;
else if (alignV==MenuSkin::VALIGN_CENTER)
y0=(y0+y1-h)/2, y1=y0+h;
x0+=emblemPadding.left;
y0+=emblemPadding.top;
RECT rcEmblem={x0,y0,x0+emblemSize.cx,y0+emblemSize.cy};
if (rcEmblem.left>=totalWidth || rcEmblem.right<0 || rcEmblem.top>=totalHeight || rcEmblem.bottom<0)
continue;
HBITMAP maskedEmblem=NULL;
if (bHasEmblemMask && i<4)
maskedEmblem=CreateMaskedEmblem(s_Skin.Main_emblems[i].GetBitmap(),rcEmblem,EMaskBits,totalWidth,totalHeight,i);
if (maskedEmblem)
SelectObject(hdcTemp,maskedEmblem);
else
SelectObject(hdcTemp,s_Skin.Main_emblems[i].GetBitmap());
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
w=rcEmblem.right-rcEmblem.left;
h=rcEmblem.bottom-rcEmblem.top;
AlphaBlend(hdc,rcEmblem.left,rcEmblem.top,w,h,hdcTemp,0,0,w,h,func);
SelectObject(hdcTemp,bmp02);
if (maskedEmblem)
DeleteObject(maskedEmblem);
}
}
if (bHasEmblemMask)
{
if (EMaskBmp02)
SelectObject(hdcEMaskTemp,EMaskBmp02);
if (EMaskBmp0)
SelectObject(hdcEMask,EMaskBmp0);
if (hdcEMask)
DeleteDC(hdcEMask);
if (hdcEMaskTemp)
DeleteDC(hdcEMaskTemp);
DeleteObject(EMaskBmp);
}
if (s_bRTL)
{
SelectObject(hdc,bmp0); // deselect m_Bitmap so all the GDI operations get flushed
// mirror the background image for RTL windows
for (int y=0;y<totalHeight;y++)
{
int yw=y*totalWidth;
std::reverse(bits+yw,bits+yw+totalWidth);
}
SelectObject(hdc,m_Bitmap);
}
if (bCaption)
{
// draw the title
BITMAPINFO dib={sizeof(dib)};
dib.bmiHeader.biWidth=textWidth;
dib.bmiHeader.biHeight=-textHeight;
dib.bmiHeader.biPlanes=1;
dib.bmiHeader.biBitCount=32;
dib.bmiHeader.biCompression=BI_RGB;
unsigned int *bits2;
HBITMAP bmpText=CreateDIBSection(hdcTemp,&dib,DIB_RGB_COLORS,(void**)&bits2,NULL,0);
SelectObject(hdcTemp,bmpText);
{
RECT rc={0,0,textWidth,textHeight};
FillRect(hdcTemp,&rc,(HBRUSH)GetStockObject(BLACK_BRUSH));
}
RECT rc={s_Skin.Caption_padding.bottom,s_bRTL?s_Skin.Caption_padding.right:s_Skin.Caption_padding.left,textWidth-s_Skin.Caption_padding.top,textHeight-(s_bRTL?s_Skin.Caption_padding.left:s_Skin.Caption_padding.right)};
if (s_Theme && s_Skin.Caption_glow_size>0)
{
// draw the glow
opts.dwFlags=DTT_COMPOSITED|DTT_TEXTCOLOR|DTT_GLOWSIZE;
opts.crText=0xFFFFFF;
opts.iGlowSize=s_Skin.Caption_glow_size;
DrawThemeTextEx(s_Theme,hdcTemp,0,0,caption,-1,DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE,&rc,&opts);
SelectObject(hdcTemp,bmp02); // deselect bmpText so all the GDI operations get flushed
// change the glow color
int gr=(s_Skin.Caption_glow_color)&255;
int gg=(s_Skin.Caption_glow_color>>8)&255;
int gb=(s_Skin.Caption_glow_color>>16)&255;
for (int y=0;y<textHeight;y++)
for (int x=0;x<textWidth;x++)
{
unsigned int &pixel=bits2[y*textWidth+x];
int a1=(pixel>>24);
int r1=(pixel>>16)&255;
int g1=(pixel>>8)&255;
int b1=(pixel)&255;
r1=(r1*gr)/255;
g1=(g1*gg)/255;
b1=(b1*gb)/255;
pixel=(a1<<24)|(r1<<16)|(g1<<8)|b1;
}
SelectObject(hdcTemp,bmpText);
}
// draw the text
int offset=0;
if (s_bRTL)
offset=totalWidth-textHeight;
if (s_Theme)
{
opts.dwFlags=DTT_COMPOSITED|DTT_TEXTCOLOR;
opts.crText=s_Skin.Caption_text_color;
DrawThemeTextEx(s_Theme,hdcTemp,0,0,caption,-1,DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE,&rc,&opts);
SelectObject(hdcTemp,bmp02);
// rotate and copy the text onto the final bitmap. Combine the alpha channels
for (int y=0;y<textHeight;y++)
for (int x=0;x<textWidth;x++)
{
unsigned int src=bits2[y*textWidth+x];
int a1=(src>>24);
int r1=(src>>16)&255;
int g1=(src>>8)&255;
int b1=(src)&255;
unsigned int &dst=bits[(totalHeight-1-x)*totalWidth+y+offset];
int a2=(dst>>24);
int r2=(dst>>16)&255;
int g2=(dst>>8)&255;
int b2=(dst)&255;
r2=(r2*(255-a1))/255+r1;
g2=(g2*(255-a1))/255+g1;
b2=(b2*(255-a1))/255+b1;
a2=a1+a2-(a1*a2)/255;
dst=(a2<<24)|(r2<<16)|(g2<<8)|b2;
}
}
else
{
// draw white text on black background
SetTextColor(hdcTemp,0xFFFFFF);
SetBkMode(hdcTemp,TRANSPARENT);
DrawText(hdcTemp,caption,-1,&rc,DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE);
SelectObject(hdcTemp,bmp02);
// rotate and copy the text onto the final bitmap
// change the text color
int tr=(s_Skin.Caption_text_color>>16)&255;
int tg=(s_Skin.Caption_text_color>>8)&255;
int tb=(s_Skin.Caption_text_color)&255;
for (int y=0;y<textHeight;y++)
for (int x=0;x<textWidth;x++)
{
unsigned int src=bits2[y*textWidth+x];
int a1=(src)&255;
unsigned int &dst=bits[(totalHeight-1-x)*totalWidth+y+offset];
int a2=(dst>>24);
int r2=(dst>>16)&255;
int g2=(dst>>8)&255;
int b2=(dst)&255;
r2=(r2*(255-a1)+tr*a1)/255;
g2=(g2*(255-a1)+tg*a1)/255;
b2=(b2*(255-a1)+tb*a1)/255;
a2=a1+a2-(a1*a2)/255;
dst=(a2<<24)|(r2<<16)|(g2<<8)|b2;
}
}
DeleteObject(bmpText);
SelectObject(hdcTemp,font0);
}
if (s_Skin.User_image_size && !s_bWin7Style)
{
// draw user image
HBITMAP userPicture;
bool bMask=(s_Skin.User_mask.bIsBitmap && s_Skin.User_mask.bIs32 && s_Skin.User_maskSize.cx==s_Skin.User_image_size && s_Skin.User_maskSize.cy==s_Skin.User_image_size);
if (bMask)
userPicture=LoadUserImage(s_Skin.User_image_size,s_Skin.User_mask.GetBitmap());
else
userPicture=LoadUserImage(s_Skin.User_image_size,NULL);
if (userPicture)
{
// draw user picture
SIZE frameSize;
if (s_Skin.User_bitmap.GetBitmap())
{
BITMAP info;
GetObject(s_Skin.User_bitmap.GetBitmap(),sizeof(info),&info);
frameSize.cx=info.bmWidth;
frameSize.cy=info.bmHeight;
}
else
{
frameSize.cx=s_Skin.User_image_size+s_Skin.User_image_offset.x*2;
frameSize.cy=s_Skin.User_image_size+s_Skin.User_image_offset.y*2;
}
POINT pos=s_Skin.User_frame_position;
if (pos.x==MenuSkin::USER_CENTER)
pos.x=(totalWidth-frameSize.cx)/2;
else if (pos.x==MenuSkin::USER_CENTER1)
pos.x=(totalWidth1+textHeight-frameSize.cx)/2;
else if (pos.x==MenuSkin::USER_CENTER2)
{
if (totalWidth2>0)
pos.x=totalWidth1+(totalWidth2-frameSize.cx)/2;
else
pos.x=(totalWidth-frameSize.cx)/2;
}
if (pos.x<0) pos.x+=totalWidth-frameSize.cx;
if (pos.y<0) pos.y+=totalHeight-frameSize.cy;
if (s_bRTL)
pos.x=totalWidth-frameSize.cx-pos.x;
pos.x+=s_Skin.User_image_offset.x;
pos.y+=s_Skin.User_image_offset.y;
HGDIOBJ bmp02=SelectObject(hdcTemp,userPicture);
unsigned int alpha=s_Skin.User_image_alpha;
if (alpha==255 && !bMask)
{
BitBlt(hdc,pos.x,pos.y,s_Skin.User_image_size,s_Skin.User_image_size,hdcTemp,0,0,SRCCOPY);
}
else
{
BLENDFUNCTION func={AC_SRC_OVER,0U,bMask?255U:(BYTE)alpha,bMask?AC_SRC_ALPHA:0U};
AlphaBlend(hdc,pos.x,pos.y,s_Skin.User_image_size,s_Skin.User_image_size,hdcTemp,0,0,s_Skin.User_image_size,s_Skin.User_image_size,func);
}
if (s_bRTL)
m_rUser1.left=totalWidth-pos.x-s_Skin.User_image_size;
else
m_rUser1.left=pos.x;
m_rUser1.right=m_rUser1.left+s_Skin.User_image_size;
m_rUser1.top=pos.y;
m_rUser1.bottom=pos.y+s_Skin.User_image_size;
if (opacity!=MenuSkin::OPACITY_SOLID && !bMask)
{
// set to opaque
SelectObject(hdc,bmp0); // deselect m_Bitmap so all the GDI operations get flushed
unsigned int *bits2=bits+pos.y*totalWidth+pos.x;
alpha<<=24;
for (int y=0;y<s_Skin.User_image_size;y++,bits2+=totalWidth)
for (int x=0;x<s_Skin.User_image_size;x++)
bits2[x]=alpha|(bits2[x]&0xFFFFFF);
SelectObject(hdc,m_Bitmap);
}
// draw frame
pos.x-=s_Skin.User_image_offset.x;
pos.y-=s_Skin.User_image_offset.y;
if (s_Skin.User_bitmap.GetBitmap())
{
SelectObject(hdcTemp,s_Skin.User_bitmap.GetBitmap());
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
AlphaBlend(hdc,pos.x,pos.y,frameSize.cx,frameSize.cy,hdcTemp,0,0,frameSize.cx,frameSize.cy,func);
}
else if (!s_Skin.User_mask.GetBitmap())
{
RECT rc={pos.x,pos.y,pos.x+frameSize.cx,pos.y+frameSize.cy};
DrawEdge(hdc,&rc,EDGE_BUMP,BF_RECT);
}
SelectObject(hdcTemp,bmp02);
DeleteObject(userPicture);
}
}
if (s_Skin.User_name_position.left!=s_Skin.User_name_position.right)
{
RECT rc0;
int x0=0, x1=totalWidth;
if (s_Skin.User_name_align==MenuSkin::HALIGN_CENTER1 || s_Skin.User_name_align==MenuSkin::HALIGN_LEFT1 || s_Skin.User_name_align==MenuSkin::HALIGN_RIGHT1)
x1=totalWidth1;
else if (s_Skin.User_name_align==MenuSkin::HALIGN_CENTER2 || s_Skin.User_name_align==MenuSkin::HALIGN_LEFT2 || s_Skin.User_name_align==MenuSkin::HALIGN_RIGHT2)
x0=totalWidth1;
if (s_Skin.User_name_position.left<0)
rc0.left=x1+s_Skin.User_name_position.left;
else
rc0.left=x0+s_Skin.User_name_position.left;
if (s_Skin.User_name_position.right<0)
rc0.right=x1+s_Skin.User_name_position.right;
else
rc0.right=x0+s_Skin.User_name_position.right;
rc0.top=s_Skin.User_name_position.top;
if (rc0.top<0) rc0.top+=totalHeight;
rc0.bottom=s_Skin.User_name_position.bottom;
if (rc0.bottom<0) rc0.bottom+=totalHeight;
m_rUser2=rc0;
wchar_t name[256];
Strcpy(name,_countof(name),GetSettingString(L"MenuUsername"));
DoEnvironmentSubst(name,_countof(name));
if (Strlen(name)>0)
{
int nameWidth=rc0.right-rc0.left;
int nameHeight=rc0.bottom-rc0.top;
RECT rc={0,0,nameWidth,nameHeight};
// draw the title
BITMAPINFO dib={sizeof(dib)};
dib.bmiHeader.biWidth=nameWidth;
dib.bmiHeader.biHeight=-nameHeight;
dib.bmiHeader.biPlanes=1;
dib.bmiHeader.biBitCount=32;
dib.bmiHeader.biCompression=BI_RGB;
font0=(HFONT)SelectObject(hdcTemp,s_Skin.User_font);
unsigned int *bits2;
HBITMAP bmpText=CreateDIBSection(hdcTemp,&dib,DIB_RGB_COLORS,(void**)&bits2,NULL,0);
HGDIOBJ bmp02=SelectObject(hdcTemp,bmpText);
FillRect(hdcTemp,&rc,(HBRUSH)GetStockObject(BLACK_BRUSH));
DWORD align=DT_CENTER;
if (s_Skin.User_name_align==MenuSkin::HALIGN_LEFT || s_Skin.User_name_align==MenuSkin::HALIGN_LEFT1 || s_Skin.User_name_align==MenuSkin::HALIGN_LEFT2)
align=s_bRTL?DT_RIGHT:DT_LEFT;
else if (s_Skin.User_name_align==MenuSkin::HALIGN_RIGHT || s_Skin.User_name_align==MenuSkin::HALIGN_RIGHT1 || s_Skin.User_name_align==MenuSkin::HALIGN_RIGHT2)
align=s_bRTL?DT_LEFT:DT_RIGHT;
if (s_Theme && s_Skin.User_glow_size>0)
{
InflateRect(&rc,-s_Skin.User_glow_size,-s_Skin.User_glow_size);
// draw the glow
opts.dwFlags=DTT_COMPOSITED|DTT_TEXTCOLOR|DTT_GLOWSIZE;
opts.crText=0xFFFFFF;
opts.iGlowSize=s_Skin.User_glow_size;
DrawThemeTextEx(s_Theme,hdcTemp,0,0,name,-1,align|DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_NOCLIP,&rc,&opts);
SelectObject(hdcTemp,bmp02); // deselect bmpText so all the GDI operations get flushed
// change the glow color
int gr=(s_Skin.User_glow_color)&255;
int gg=(s_Skin.User_glow_color>>8)&255;
int gb=(s_Skin.User_glow_color>>16)&255;
for (int y=0;y<nameHeight;y++)
for (int x=0;x<nameWidth;x++)
{
unsigned int &pixel=bits2[y*nameWidth+x];
int a1=(pixel>>24);
int r1=(pixel>>16)&255;
int g1=(pixel>>8)&255;
int b1=(pixel)&255;
r1=(r1*gr)/255;
g1=(g1*gg)/255;
b1=(b1*gb)/255;
pixel=(a1<<24)|(r1<<16)|(g1<<8)|b1;
}
SelectObject(hdcTemp,bmpText);
}
// draw the text
int offset=rc0.top*totalWidth+rc0.left;
if (s_bRTL)
offset=rc0.top*totalWidth+totalWidth-rc0.right;
if (s_Theme)
{
opts.dwFlags=DTT_COMPOSITED|DTT_TEXTCOLOR;
opts.crText=s_Skin.User_text_color;
DrawThemeTextEx(s_Theme,hdcTemp,0,0,name,-1,align|DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_NOCLIP,&rc,&opts);
SelectObject(hdcTemp,bmp02);
// copy the text onto the final bitmap. Combine the alpha channels
for (int y=0;y<nameHeight;y++)
for (int x=0;x<nameWidth;x++)
{
unsigned int src=bits2[y*nameWidth+x];
int a1=(src>>24);
int r1=(src>>16)&255;
int g1=(src>>8)&255;
int b1=(src)&255;
unsigned int &dst=bits[y*totalWidth+x+offset];
int a2=(dst>>24);
int r2=(dst>>16)&255;
int g2=(dst>>8)&255;
int b2=(dst)&255;
r2=(r2*(255-a1))/255+r1;
g2=(g2*(255-a1))/255+g1;
b2=(b2*(255-a1))/255+b1;
a2=a1+a2-(a1*a2)/255;
dst=(a2<<24)|(r2<<16)|(g2<<8)|b2;
}
}
else
{
// draw white text on black background
SetTextColor(hdcTemp,0xFFFFFF);
SetBkMode(hdcTemp,TRANSPARENT);
DrawText(hdcTemp,name,-1,&rc,align|DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_NOCLIP);
SelectObject(hdcTemp,bmp02);
// copy the text onto the final bitmap
// change the text color
int tr=(s_Skin.User_text_color>>16)&255;
int tg=(s_Skin.User_text_color>>8)&255;
int tb=(s_Skin.User_text_color)&255;
for (int y=0;y<nameHeight;y++)
for (int x=0;x<nameWidth;x++)
{
unsigned int src=bits2[y*nameWidth+x];
int a1=(src)&255;
unsigned int &dst=bits[y*totalWidth+x+offset];
int a2=(dst>>24);
int r2=(dst>>16)&255;
int g2=(dst>>8)&255;
int b2=(dst)&255;
r2=(r2*(255-a1)+tr*a1)/255;
g2=(g2*(255-a1)+tg*a1)/255;
b2=(b2*(255-a1)+tb*a1)/255;
a2=a1+a2-(a1*a2)/255;
dst=(a2<<24)|(r2<<16)|(g2<<8)|b2;
}
}
DeleteObject(bmpText);
SelectObject(hdcTemp,font0);
}
}
DeleteDC(hdcTemp);
SelectObject(hdc,bmp0);
DeleteDC(hdc);
// calculate the window region
if (bCreateRegion)
{
if (m_Region) DeleteObject(m_Region);
m_Region=NULL;
if (opacity==MenuSkin::OPACITY_REGION || opacity==MenuSkin::OPACITY_GLASS || opacity==MenuSkin::OPACITY_FULLGLASS)
{
for (int y=0;y<totalHeight;y++)
{
int minx=-1, maxx=-1;
int yw=y*totalWidth;
for (int x=0;x<totalWidth;x++)
{
if (bits[yw+x]&0xFF000000)
{
if (minx==-1) minx=x; // first non-transparent pixel
if (maxx<x) maxx=x; // last non-transparent pixel
}
}
if (minx>=0)
{
maxx++;
HRGN r=CreateRectRgn(minx,y,maxx,y+1);
AddTrackedObject(r);
if (!m_Region)
m_Region=r;
else
{
CombineRgn(m_Region,m_Region,r,RGN_OR);
DeleteObject(r);
}
}
}
}
else if (opacity==MenuSkin::OPACITY_ALPHA || opacity==MenuSkin::OPACITY_FULLALPHA)
m_Region=CreateRectRgn(0,0,totalWidth,totalHeight);
}
}
void CMenuContainer::CreateContentRects( int width1, int width2, int height1, int height2, int &totalWidth, int &totalHeight )
{
const int *slicesY;
RECT menuPadding[2];
if (s_MenuMode==MODE_SEARCH)
{
slicesY=s_Skin.Main_bitmap_search_slices_Y;
menuPadding[0]=s_Skin.Main_search_padding;
memset(&menuPadding[1],0,sizeof(menuPadding[1]));
}
else if (s_MenuMode==MODE_JUMPLIST)
{
slicesY=s_Skin.Main_bitmap_jump_slices_Y;
menuPadding[0]=s_Skin.Main_padding;
menuPadding[1]=s_Skin.Main_jump_padding;
}
else
{
slicesY=s_Skin.Main_bitmap_slices_Y;
menuPadding[0]=s_Skin.Main_padding;
menuPadding[1]=s_Skin.Main2_padding;
}
int totalWidth1=width1+menuPadding[0].left+menuPadding[0].right;
int totalWidth2=width2+menuPadding[1].left+menuPadding[1].right;
totalWidth=totalWidth1+totalWidth2;
totalHeight=height1+menuPadding[0].top+menuPadding[0].bottom;
int totalHeight2=height2+menuPadding[1].top+menuPadding[1].bottom;
if (totalHeight<totalHeight2) totalHeight=totalHeight2;
if (totalHeight<slicesY[0]+slicesY[2]) totalHeight=slicesY[0]+slicesY[2];
m_rContent.left=menuPadding[0].left;
m_rContent.right=totalWidth1-menuPadding[0].right;
m_rContent.top=menuPadding[0].top;
m_rContent.bottom=m_rContent.top+height1;
if (totalWidth2>0)
{
m_rContent2.left=m_rContent.right+menuPadding[0].right+menuPadding[1].left;
m_rContent2.right=totalWidth-menuPadding[1].right;
m_rContent2.top=menuPadding[1].top;
m_rContent2.bottom=m_rContent2.top+height2;
}
}
void CMenuContainer::CreateSubmenuRegion( int width, int height )
{
int totalWidth=s_Skin.Submenu_padding.left+s_Skin.Submenu_padding.right+width;
int totalHeight=s_Skin.Submenu_padding.top+s_Skin.Submenu_padding.bottom+height;
if (m_Region) DeleteObject(m_Region);
m_Region=NULL;
if (s_Skin.Submenu_opacity==MenuSkin::OPACITY_SOLID)
return;
if (!s_Skin.Submenu_bitmap.GetBitmap() || !s_Skin.Submenu_bitmap.bIs32)
return;
if (s_Skin.Submenu_opacity==MenuSkin::OPACITY_ALPHA || s_Skin.Submenu_opacity==MenuSkin::OPACITY_FULLALPHA)
{
m_Region=CreateRectRgn(0,0,totalWidth,totalHeight-m_ExtraTop-m_ExtraBottom);
return;
}
BITMAP info;
GetObject(s_Skin.Submenu_bitmap.GetBitmap(),sizeof(info),&info);
const int *slicesX=s_Skin.Submenu_bitmap_slices_X+3;
const int *slicesY=s_Skin.Submenu_bitmap_slices_Y;
int slicesX0=slicesX[s_bRTL?2:0];
int slicesX2=slicesX[s_bRTL?0:2];
int bmpWidth=slicesX0+slicesX[1]+slicesX2;
int bmpHeight=slicesY[0]+slicesY[1]+slicesY[2];
unsigned int *bits=(unsigned int*)info.bmBits;
{
for (int y=m_ExtraTop;y<totalHeight-m_ExtraBottom;y++)
{
int yy;
if (y<=slicesY[0])
yy=y;
else if (y>=totalHeight-slicesY[2])
yy=bmpHeight-totalHeight+y;
else
yy=slicesY[0]+((y-slicesY[0])*slicesY[1])/(totalHeight-slicesY[0]-slicesY[2]);
if (info.bmHeight>0)
yy=info.bmHeight-yy-1;
int yw=yy*info.bmWidth;
int minx=-1, maxx=-1;
for (int x=0;x<bmpWidth;x++)
{
if (bits[yw+x]&0xFF000000)
{
if (minx==-1) minx=x; // first non-transparent pixel
if (maxx<x) maxx=x; // last non-transparent pixel
}
}
if (minx>=0)
{
if (minx>=bmpWidth-slicesX2)
minx+=totalWidth-bmpWidth;
else if (minx>slicesX0)
minx=slicesX0+((minx-slicesX0)*(totalWidth-slicesX0-slicesX2))/slicesX[1];
if (maxx>=bmpWidth-slicesX2)
maxx+=totalWidth-bmpWidth;
else if (minx>slicesX0)
maxx=slicesX0+((maxx-slicesX0)*(totalWidth-slicesX0-slicesX2))/slicesX[1];
maxx++;
HRGN r=CreateRectRgn(minx,y-m_ExtraTop,maxx,y-m_ExtraTop+1);
AddTrackedObject(r);
if (!m_Region)
m_Region=r;
else
{
CombineRgn(m_Region,m_Region,r,RGN_OR);
DeleteObject(r);
}
}
}
}
}
void CMenuContainer::DrawBackground( HDC hdc, const RECT &drawRect )
{
HDC hdc2=CreateCompatibleDC(hdc);
// draw the background (bitmap or solid color)
HBITMAP bmpMain=NULL;
RECT rMarginsMain, rSrcMain;
bool bAlphaMain;
if (m_Bitmap)
{
HGDIOBJ bmp0=SelectObject(hdc2,m_Bitmap);
BitBlt(hdc,m_BitmapOffset,0,m_rMenu.right,m_rMenu.bottom,hdc2,0,0,SRCCOPY);
SelectObject(hdc2,bmp0);
bmpMain=m_Bitmap;
{ RECT rc={m_rMenu.right-m_rMenu.left,m_rMenu.bottom,0,0}; rMarginsMain=rc; }
{ RECT rc={0,0,m_rMenu.right-m_rMenu.left,m_rMenu.bottom}; rSrcMain=rc; }
bAlphaMain=false;
}
else if (m_bSubMenu && s_Skin.Submenu_bitmap.GetBitmap())
{
bAlphaMain=(s_Skin.Submenu_opacity==MenuSkin::OPACITY_SOLID && s_Skin.Submenu_bitmap.bIs32);
if (bAlphaMain)
{
SetDCBrushColor(hdc,s_Skin.Submenu_background);
FillRect(hdc,&drawRect,(HBRUSH)GetStockObject(DC_BRUSH));
}
HGDIOBJ bmp0=SelectObject(hdc2,s_Skin.Submenu_bitmap.GetBitmap());
const int *slicesX=s_Skin.Submenu_bitmap_slices_X;
const int *slicesY=s_Skin.Submenu_bitmap_slices_Y;
RECT rSrc={0,0,slicesX[3]+slicesX[4]+slicesX[5],slicesY[0]+slicesY[1]+slicesY[2]};
RECT rMargins={slicesX[3],slicesY[0],slicesX[5],slicesY[2]};
RECT rDst=m_rMenu;
rDst.top-=m_ExtraTop;
rDst.bottom+=m_ExtraBottom;
MarginsBlit(hdc2,hdc,rSrc,rDst,rMargins,bAlphaMain);
SelectObject(hdc2,bmp0);
bmpMain=s_Skin.Submenu_bitmap.GetBitmap();
rMarginsMain=rMargins;
rSrcMain=rSrc;
}
else
{
SetDCBrushColor(hdc,m_bSubMenu?s_Skin.Submenu_background:s_Skin.Main_background);
FillRect(hdc,&m_rMenu,(HBRUSH)GetStockObject(DC_BRUSH));
}
MenuBitmap bmpSeparatorV;
int sepWidth=0;
const int *sepSlicesY=NULL;
MenuBitmap bmpPager;
const int *pagSlicesX=NULL;
const int *pagSlicesY=NULL;
MenuBitmap bmpPagerArrows;
SIZE pagArrowSize;
MenuSkin::TOpacity opacity=m_bSubMenu?s_Skin.Submenu_opacity:s_Skin.Main_opacity;
int glow=s_Skin.ItemSettings[m_bSubMenu?MenuSkin::SUBMENU_ITEM:MenuSkin::COLUMN1_ITEM].glowSize;
if (!s_Theme) glow=0;
TRecentKeys recentType=(TRecentKeys)GetSettingInt(L"RecentProgKeys");
if (m_bSubMenu)
{
bmpSeparatorV=s_Skin.Submenu_separatorV;
sepWidth=s_Skin.Submenu_separatorWidth;
sepSlicesY=s_Skin.Submenu_separator_slices_Y;
bmpPager=s_Skin.Submenu_pager;
pagSlicesX=s_Skin.Submenu_pager_slices_X;
pagSlicesY=s_Skin.Submenu_pager_slices_Y;
bmpPagerArrows=s_Skin.Submenu_pager_arrows;
pagArrowSize=s_Skin.Submenu_pager_arrow_Size;
}
else
{
bmpSeparatorV=s_Skin.Main_separatorV;
sepWidth=s_Skin.Main_separatorWidth;
sepSlicesY=s_Skin.Main_separator_slices_Y;
bmpPager=s_Skin.Main_pager;
pagSlicesX=s_Skin.Main_pager_slices_X;
pagSlicesY=s_Skin.Main_pager_slices_Y;
bmpPagerArrows=s_Skin.Main_pager_arrows;
pagArrowSize=s_Skin.Main_pager_arrow_Size;
}
HGDIOBJ font0=GetCurrentObject(hdc,OBJ_FONT);
SetBkMode(hdc,TRANSPARENT);
// set clip rectangle for the scrollable items
int clipTop=m_rContent.top;
int clipBottom=m_rContent.bottom;
if (m_bScrollUp)
clipTop=m_rContent.top+m_ScrollButtonSize;
if (m_bScrollDown)
clipBottom=m_rContent.top+m_ScrollHeight-m_ScrollButtonSize;
if (m_ScrollHeight>0)
IntersectClipRect(hdc,0,clipTop,m_rMenu.right,clipBottom);
// draw items
for (int index=0;;index++)
{
if (!m_bSubMenu)
{
if (index==m_ProgramTreeIndex) continue;
if (s_MenuMode==MODE_PROGRAMS)
{
if (index<m_ScrollCount) continue;
}
}
if (m_ScrollHeight>0 && index==m_ScrollCount)
{
// clean up after the scrollable items
SelectClipRgn(hdc,NULL);
if (m_bScrollUp)
{
if (glow || opacity==MenuSkin::OPACITY_FULLALPHA || opacity==MenuSkin::OPACITY_FULLGLASS)
{
// fix background behind the up button (DrawThemeTextEx may spill onto the tablecloth)
RECT rc={m_rContent.left,0,m_rContent.right,clipTop};
if (bAlphaMain || !bmpMain)
{
SetDCBrushColor(hdc,m_bSubMenu?s_Skin.Submenu_background:s_Skin.Main_background);
FillRect(hdc,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
}
if (bmpMain)
{
HGDIOBJ bmp0=SelectObject(hdc2,bmpMain);
IntersectClipRect(hdc,m_rContent.left,0,m_rContent.right,clipTop);
MarginsBlit(hdc2,hdc,rSrcMain,m_rMenu,rMarginsMain,bAlphaMain);
SelectObject(hdc2,bmp0);
SelectClipRgn(hdc,NULL);
}
}
// draw up button
RECT rc=m_rContent;
rc.bottom=clipTop;
if (bmpPager.GetBitmap() && bmpPagerArrows.GetBitmap())
{
// background
HGDIOBJ bmp0=SelectObject(hdc2,bmpPager.GetBitmap());
RECT rSrc={0,0,pagSlicesX[0]+pagSlicesX[1]+pagSlicesX[2],pagSlicesY[0]+pagSlicesY[1]+pagSlicesY[2]};
if (m_bScrollUpHot)
OffsetRect(&rSrc,0,rSrc.bottom);
RECT rMargins={pagSlicesX[0],pagSlicesY[0],pagSlicesX[2],pagSlicesY[2]};
MarginsBlit(hdc2,hdc,rSrc,rc,rMargins,bmpPager.bIs32);
// arrow
SelectObject(hdc2,bmpPagerArrows.GetBitmap());
int x=(rc.left+rc.right-pagArrowSize.cx)/2;
int y=(rc.top+rc.bottom-pagArrowSize.cy)/2;
if (bmpPagerArrows.bIs32)
{
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
AlphaBlend(hdc,x,y,pagArrowSize.cx,pagArrowSize.cy,hdc2,m_bScrollUpHot?pagArrowSize.cx:0,0,pagArrowSize.cx,pagArrowSize.cy,func);
}
else
BitBlt(hdc,x,y,pagArrowSize.cx,pagArrowSize.cy,hdc2,m_bScrollUpHot?pagArrowSize.cx:0,0,SRCCOPY);
SelectObject(hdc2,bmp0);
}
else
{
if (s_PagerTheme)
DrawThemeBackground(s_PagerTheme,hdc,SBP_ARROWBTN,(m_bScrollUpHot?ABS_UPHOT:ABS_UPHOVER),&rc,NULL);
else
DrawFrameControl(hdc,&rc,DFC_SCROLL,DFCS_SCROLLUP|DFCS_FLAT|(m_bScrollUpHot?DFCS_PUSHED:0));
}
}
if (m_bScrollDown)
{
int bottom=clipBottom+s_Skin.ItemSettings[m_bSubMenu?MenuSkin::SUBMENU_ITEM:MenuSkin::COLUMN1_ITEM].itemHeight;
if (bottom>=m_rMenu.bottom) bottom=m_rMenu.bottom;
if (bottom>clipBottom && (glow || opacity==MenuSkin::OPACITY_FULLALPHA || opacity==MenuSkin::OPACITY_FULLGLASS))
{
// fix background behind the up button (DrawThemeTextEx may spill onto the tablecloth)
RECT rc={m_rContent.left,clipBottom,m_rContent.right,bottom};
if (bAlphaMain || !bmpMain)
{
SetDCBrushColor(hdc,m_bSubMenu?s_Skin.Submenu_background:s_Skin.Main_background);
FillRect(hdc,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
}
if (bmpMain)
{
HGDIOBJ bmp0=SelectObject(hdc2,bmpMain);
IntersectClipRect(hdc,m_rContent.left,clipBottom,m_rContent.right,bottom);
MarginsBlit(hdc2,hdc,rSrcMain,m_rMenu,rMarginsMain,bAlphaMain);
SelectObject(hdc2,bmp0);
SelectClipRgn(hdc,NULL);
}
}
// draw down button
RECT rc=m_rContent;
rc.bottom=m_rContent.top+m_ScrollHeight;
rc.top=clipBottom;
if (bmpPager.GetBitmap() && bmpPagerArrows.GetBitmap())
{
// background
HGDIOBJ bmp0=SelectObject(hdc2,bmpPager.GetBitmap());
RECT rSrc={0,0,pagSlicesX[0]+pagSlicesX[1]+pagSlicesX[2],pagSlicesY[0]+pagSlicesY[1]+pagSlicesY[2]};
if (m_bScrollDownHot)
OffsetRect(&rSrc,0,rSrc.bottom);
RECT rMargins={pagSlicesX[0],pagSlicesY[0],pagSlicesX[2],pagSlicesY[2]};
MarginsBlit(hdc2,hdc,rSrc,rc,rMargins,bmpPager.bIs32);
// arrow
SelectObject(hdc2,bmpPagerArrows.GetBitmap());
int x=(rc.left+rc.right-pagArrowSize.cx)/2;
int y=(rc.top+rc.bottom-pagArrowSize.cy)/2;
if (bmpPagerArrows.bIs32)
{
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
AlphaBlend(hdc,x,y,pagArrowSize.cx,pagArrowSize.cy,hdc2,m_bScrollDownHot?pagArrowSize.cx:0,pagArrowSize.cy,pagArrowSize.cx,pagArrowSize.cy,func);
}
else
BitBlt(hdc,x,y,pagArrowSize.cx,pagArrowSize.cy,hdc2,m_bScrollDownHot?pagArrowSize.cx:0,pagArrowSize.cy,SRCCOPY);
SelectObject(hdc2,bmp0);
}
else
{
if (s_PagerTheme)
DrawThemeBackground(s_PagerTheme,hdc,SBP_ARROWBTN,(m_bScrollDownHot?ABS_DOWNHOT:ABS_DOWNHOVER),&rc,NULL);
else
DrawFrameControl(hdc,&rc,DFC_SCROLL,DFCS_SCROLLDOWN|DFCS_FLAT|(m_bScrollDownHot?DFCS_PUSHED:0));
}
}
}
if (index>=(int)m_Items.size()) break;
const MenuItem &item=m_Items[index];
RECT itemRect=item.itemRect;
// ignore offscreen items
if (m_ScrollHeight>0 && index<m_ScrollCount)
{
OffsetRect(&itemRect,0,-m_ScrollOffset);
if (itemRect.bottom<=clipTop) continue;
if (itemRect.top>=clipBottom) continue;
}
else if (m_SearchScrollCount>m_SearchScrollHeight && index>=m_OriginalCount)
{
if (index-m_OriginalCount<m_SearchScrollPos || index-m_OriginalCount>=m_SearchScrollPos+m_SearchScrollHeight)
continue;
OffsetRect(&itemRect,0,-m_SearchScrollPos*(itemRect.bottom-itemRect.top));
}
{
RECT q;
if (!IntersectRect(&q,&drawRect,&itemRect))
continue;
}
bool bHot=(index==m_HotItem || index==m_SubJumpItem || (m_HotItem==-1 && (index==m_Submenu || index==m_ContextItem)));
bool bSplit=false;
int stateLeft=0, stateRight=0;
bool bNew=!bHot && item.bNew && !(s_bWin7Style && item.id==MENU_PROGRAMS && s_MenuMode==MODE_PROGRAMS);
MenuSkin::TItemDrawType drawType=item.drawType;
if (!bNew)
{
if (drawType==MenuSkin::COLUMN1_NEW)
drawType=MenuSkin::COLUMN1_ITEM;
else if (drawType==MenuSkin::COLUMN2_NEW)
drawType=MenuSkin::COLUMN2_ITEM;
else if (drawType==MenuSkin::PROGRAMS_BUTTON_NEW)
drawType=MenuSkin::PROGRAMS_BUTTON;
else if (drawType==MenuSkin::PROGRAMS_CASCADING_NEW)
drawType=MenuSkin::PROGRAMS_CASCADING;
else if (drawType==MenuSkin::SUBMENU_NEW)
drawType=MenuSkin::SUBMENU_ITEM;
if (!bHot && index==m_DropTargetIndex)
{
if (drawType==MenuSkin::COLUMN1_SPLIT)
drawType=MenuSkin::COLUMN1_ITEM;
if (drawType==MenuSkin::COLUMN2_SPLIT)
drawType=MenuSkin::COLUMN2_ITEM;
}
}
if (item.id==MENU_SEARCH_BOX)
{
itemRect.left=itemRect.right-(itemRect.bottom-itemRect.top);
bHot=(index==m_HotItem && m_SearchState>=SEARCH_TEXT);
}
if (item.id==MENU_PROGRAMS_TREE)
bHot=false;
int splitX=itemRect.right;
const MenuSkin::ItemDrawSettings &settings=s_Skin.ItemSettings[drawType];
int glowSize=s_Theme?settings.glowSize:0;
if (bHot || bNew || item.id==MENU_SHUTDOWN_BUTTON || index==m_DropTargetIndex)
{
if (bHot || item.id==MENU_SHUTDOWN_BUTTON)
{
bSplit=(item.bSplit && (item.bFolder || item.jumpIndex>=0 || item.id==MENU_SEARCH_CATEGORY || item.id==MENU_SHUTDOWN_BUTTON));
if (item.id==MENU_SHUTDOWN_BUTTON)
{
if (GetCapture()==m_hWnd)
{
if (index==m_ClickIndex && !m_bClickArrow && index==m_HotItem && !m_bHotArrow)
stateLeft=2;
else if (index==m_ClickIndex || index==m_Submenu || index==m_SubJumpItem)
stateLeft=1;
}
else if (index==m_HotItem || index==m_Submenu || index==m_SubJumpItem)
stateLeft=1;
if (index==m_Submenu || index==m_SubJumpItem)
stateRight=2;
else if (GetCapture()==m_hWnd)
{
if (index==m_ClickIndex && m_bClickArrow && index==m_HotItem && m_bHotArrow)
stateRight=2;
}
else if (index==m_HotItem)
stateRight=1;
}
else
{
if ((index==m_HotItem && !m_bHotArrow) || index==m_ContextItem)
stateLeft=1;
if ((index==m_HotItem && m_bHotArrow) || index==m_Submenu || index==m_SubJumpItem || index==m_ContextItem)
stateRight=1;
}
splitX=itemRect.right-settings.arrPadding.cx-settings.arrPadding.cy-1;
if (item.jumpIndex>=0)
splitX-=s_Skin.Pin_bitmap_Size.cx;
else if (item.id==MENU_SEARCH_CATEGORY)
splitX-=s_Skin.More_bitmap_Size.cx;
else
splitX-=settings.arrSize.cx;
}
// draw selection background
if (bSplit && settings.bmpSelection.GetBitmap())
{
int srcHeight=settings.selSlicesY[0]+settings.selSlicesY[1]+settings.selSlicesY[2];
HGDIOBJ bmp0=SelectObject(hdc2,settings.bmpSelection.GetBitmap());
{
// draw left half
RECT rSrc={0,0,settings.selSlicesX[0]+settings.selSlicesX[1]+settings.selSlicesX[2],srcHeight};
OffsetRect(&rSrc,0,srcHeight*stateLeft);
RECT rMargins={settings.selSlicesX[0],settings.selSlicesY[0],settings.selSlicesX[2],settings.selSlicesY[2]};
RECT itemRect2=itemRect;
itemRect2.right=splitX;
int w=itemRect2.right-itemRect2.left;
int h=itemRect2.bottom-itemRect2.top;
if (rMargins.left>w) rMargins.left=w;
if (rMargins.right>w) rMargins.right=w;
if (rMargins.top>h) rMargins.top=h;
if (rMargins.bottom>h) rMargins.bottom=h;
MarginsBlit(hdc2,hdc,rSrc,itemRect2,rMargins,settings.bmpSelection.bIs32);
}
{
// draw right half
RECT rSrc={settings.selSlicesX[0]+settings.selSlicesX[1]+settings.selSlicesX[2],0,0,srcHeight};
OffsetRect(&rSrc,0,srcHeight*stateRight);
rSrc.right=rSrc.left+settings.selSlicesX[3]+settings.selSlicesX[4]+settings.selSlicesX[5];
RECT rMargins={settings.selSlicesX[3],settings.selSlicesY[0],settings.selSlicesX[5],settings.selSlicesY[2]};
RECT itemRect2=itemRect;
itemRect2.left=splitX;
int w=itemRect2.right-itemRect2.left;
int h=itemRect2.bottom-itemRect2.top;
if (rMargins.left>w) rMargins.left=w;
if (rMargins.right>w) rMargins.right=w;
if (rMargins.top>h) rMargins.top=h;
if (rMargins.bottom>h) rMargins.bottom=h;
MarginsBlit(hdc2,hdc,rSrc,itemRect2,rMargins,settings.bmpSelection.bIs32);
}
SelectObject(hdc2,bmp0);
}
else if (settings.bmpSelection.GetBitmap())
{
HGDIOBJ bmp0=SelectObject(hdc2,settings.bmpSelection.GetBitmap());
RECT rSrc={0,0,settings.selSlicesX[0]+settings.selSlicesX[1]+settings.selSlicesX[2],settings.selSlicesY[0]+settings.selSlicesY[1]+settings.selSlicesY[2]};
{
RECT rMargins={settings.selSlicesX[0],settings.selSlicesY[0],settings.selSlicesX[2],settings.selSlicesY[2]};
RECT itemRect2=itemRect;
if (bSplit) itemRect2.right=splitX;
int w=itemRect2.right-itemRect2.left;
int h=itemRect2.bottom-itemRect2.top;
if (rMargins.left>w) rMargins.left=w;
if (rMargins.right>w) rMargins.right=w;
if (rMargins.top>h) rMargins.top=h;
if (rMargins.bottom>h) rMargins.bottom=h;
MarginsBlit(hdc2,hdc,rSrc,itemRect2,rMargins,settings.bmpSelection.bIs32);
}
if (bSplit)
{
RECT rMargins={settings.selSlicesX[0],settings.selSlicesY[0],settings.selSlicesX[2],settings.selSlicesY[2]};
RECT itemRect2=itemRect;
itemRect2.left=splitX;
int w=itemRect2.right-itemRect2.left;
int h=itemRect2.bottom-itemRect2.top;
if (rMargins.left>w) rMargins.left=w;
if (rMargins.right>w) rMargins.right=w;
if (rMargins.top>h) rMargins.top=h;
if (rMargins.bottom>h) rMargins.bottom=h;
MarginsBlit(hdc2,hdc,rSrc,itemRect2,rMargins,settings.bmpSelection.bIs32);
}
SelectObject(hdc2,bmp0);
}
else if (item.id==MENU_SHUTDOWN_BUTTON)
{
RECT itemRect2=itemRect;
itemRect2.right=splitX;
DrawEdge(hdc,&itemRect2,stateLeft==2?BDR_SUNKENOUTER:BDR_RAISEDINNER,BF_RECT|BF_MIDDLE);
if (bHot && m_Submenu==-1 && s_bKeyboardCues)
{
RECT focus=itemRect2;
if (s_Skin.Dpi>=144)
InflateRect(&focus,-3,-3);
else
InflateRect(&focus,-2,-2);
SetBkColor(hdc,0);
SetTextColor(hdc,0xFFFFFF);
DrawFocusRect(hdc,&focus);
}
itemRect2.left=itemRect2.right;
itemRect2.right=itemRect.right;
DrawEdge(hdc,&itemRect2,stateRight==2?BDR_SUNKENOUTER:BDR_RAISEDINNER,BF_RECT|BF_MIDDLE);
}
else
{
SetDCBrushColor(hdc,settings.bmpSelection.GetColor());
SetDCPenColor(hdc,settings.bmpSelection.GetColor());
if (bSplit)
{
if (stateLeft>0)
{
RECT itemRect2=itemRect;
itemRect2.right=splitX;
FillRect(hdc,&itemRect2,(HBRUSH)GetStockObject(DC_BRUSH));
}
else
{
SelectObject(hdc,GetStockObject(DC_PEN));
SelectObject(hdc,GetStockObject(NULL_BRUSH));
Rectangle(hdc,itemRect.left,itemRect.top,splitX+1,itemRect.bottom);
}
if (stateRight>0)
{
RECT itemRect2=itemRect;
itemRect2.left=splitX+1;
FillRect(hdc,&itemRect2,(HBRUSH)GetStockObject(DC_BRUSH));
}
else
{
SelectObject(hdc,GetStockObject(DC_PEN));
SelectObject(hdc,GetStockObject(NULL_BRUSH));
Rectangle(hdc,splitX-1,itemRect.top,itemRect.right,itemRect.bottom);
}
}
else
{
FillRect(hdc,&itemRect,(HBRUSH)GetStockObject(DC_BRUSH));
}
}
}
if (item.id==MENU_SEPARATOR || item.id==MENU_SEARCH_CATEGORY)
{
// draw separator
if (!item.bBlankSeparator && itemRect.bottom>itemRect.top)
{
RECT itemRect2=itemRect;
if (item.id==MENU_SEARCH_CATEGORY)
{
itemRect2.left+=settings.iconPadding.left;
if (item.bSplit)
itemRect2.right=splitX;
if (s_Skin.Search_arrow.GetBitmap())
{
int x=itemRect2.left;
int y=(itemRect2.top+itemRect2.bottom-s_Skin.Search_arrow_size.cy)/2;
int v=(m_SearchCategoryHash==item.categoryHash?s_Skin.Search_arrow_size.cy:0);
HGDIOBJ bmp0=SelectObject(hdc2,s_Skin.Search_arrow.GetBitmap());
if (s_Skin.Search_arrow.bIs32)
{
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
AlphaBlend(hdc,x,y,s_Skin.Search_arrow_size.cx,s_Skin.Search_arrow_size.cy,hdc2,0,v,s_Skin.Search_arrow_size.cx,s_Skin.Search_arrow_size.cy,func);
}
else
BitBlt(hdc,x,y,s_Skin.Search_arrow_size.cx,s_Skin.Search_arrow_size.cy,hdc2,0,v,SRCCOPY);
SelectObject(hdc2,bmp0);
itemRect2.left+=settings.iconPadding.right+s_Skin.Search_arrow_size.cx;
}
else
{
const POINT *sizes=s_Skin.GetArrowsBitmapSizes();
int x=itemRect2.left;
int y=(itemRect2.top+itemRect2.bottom-sizes[6].y)/2;
HGDIOBJ bmp0=SelectObject(hdc2,GetArrowsBitmap(settings.arrColors[((bHot && (!bSplit || stateLeft>0))?1:0)]));
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
if (m_SearchCategoryHash==item.categoryHash)
{
SIZE s={sizes[5].y-sizes[5].x,sizes[6].y};
AlphaBlend(hdc,x,y,s.cx,s.cy,hdc2,s_bRTL?sizes[6].x-sizes[5].y:sizes[5].x,0,s.cx,s.cy,func);
}
else
{
SIZE s={sizes[3].y-sizes[3].x,sizes[6].y};
int dx=(sizes[5].y-sizes[5].x-s.cx+1)/2;
AlphaBlend(hdc,x+dx,y,s.cx,s.cy,hdc2,s_bRTL?sizes[6].x-sizes[4].y:sizes[3].x,0,s.cx,s.cy,func);
}
SelectObject(hdc2,bmp0);
itemRect2.left+=settings.iconPadding.right+sizes[5].y-sizes[5].x+1;
}
}
if (!item.name.IsEmpty())
{
if (item.id==MENU_SEARCH_CATEGORY && !item.bSplit && item.categoryHash>=CSearchManager::CATEGORY_FILE && index==m_HotItem && m_bHotArrow)
SelectObject(hdc,s_Skin.Search_underline_font);
else
SelectObject(hdc,settings.font);
COLORREF color=settings.textColors[(bHot && (!bSplit || stateLeft>0))?1:0];
COLORREF shadowColor=settings.textShadowColors[(bHot && (!bSplit || stateLeft>0))?1:0];
RECT rc={itemRect2.left+settings.textPadding.left,itemRect2.top+settings.textTopOffset+settings.textPadding.top-settings.textPadding.bottom,
itemRect2.right-settings.arrSize.cx-settings.arrPadding.cx-settings.arrPadding.cy-settings.textPadding.right,itemRect2.bottom-settings.textTopOffset};
DWORD flags=DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS|DT_NOPREFIX;
if (s_Theme)
{
DTTOPTS opts={sizeof(opts),DTT_TEXTCOLOR};
if (glowSize || settings.opacity==MenuSkin::OPACITY_FULLALPHA || settings.opacity==MenuSkin::OPACITY_FULLGLASS)
opts.dwFlags|=DTT_COMPOSITED;
if (glowSize)
{
opts.dwFlags|=DTT_GLOWSIZE;
opts.iGlowSize=glowSize;
}
if (shadowColor!=0xFFFFFFFF)
{
opts.crText=shadowColor;
RECT rc2=rc;
OffsetRect(&rc2,1,1);
DrawThemeTextEx(s_Theme,hdc,0,0,item.name,item.name.GetLength(),flags,&rc2,&opts);
}
opts.crText=color;
DrawThemeTextEx(s_Theme,hdc,0,0,item.name,item.name.GetLength(),flags,&rc,&opts);
}
else
{
if (shadowColor!=0xFFFFFFFF)
{
RECT rc2=rc;
OffsetRect(&rc2,1,1);
SetTextColor(hdc,shadowColor);
DrawText(hdc,item.name,item.name.GetLength(),&rc,flags);
}
SetTextColor(hdc,color);
DrawText(hdc,item.name,item.name.GetLength(),&rc,flags);
}
SIZE size;
GetTextExtentPoint32(hdc,item.name,item.name.GetLength(),&size);
itemRect2.left=rc.left+size.cx+settings.textPadding.right;
}
if (itemRect2.left<itemRect2.right)
{
if (settings.bmpSeparator.GetBitmap())
{
itemRect2.top=(itemRect2.top+itemRect2.bottom-settings.sepHeight)/2;
itemRect2.bottom=itemRect2.top+settings.sepHeight;
HGDIOBJ bmp0=SelectObject(hdc2,settings.bmpSeparator.GetBitmap());
RECT rSrc={0,0,settings.sepSlicesX[0]+settings.sepSlicesX[1]+settings.sepSlicesX[2],settings.sepHeight};
RECT rMargins={settings.sepSlicesX[0],settings.sepHeight,settings.sepSlicesX[2],0};
MarginsBlit(hdc2,hdc,rSrc,itemRect2,rMargins,settings.bmpSeparator.bIs32);
SelectObject(hdc2,bmp0);
}
else
{
if (s_Theme)
{
SIZE size;
if (SUCCEEDED(GetThemePartSize(s_Theme,hdc,TP_SEPARATORVERT,TS_NORMAL,NULL,TS_MIN,&size)))
OffsetRect(&itemRect2,0,(itemRect2.bottom-itemRect2.top-size.cy)/2);
DrawThemeBackground(s_Theme,hdc,TP_SEPARATORVERT,TS_NORMAL,&itemRect2,NULL);
}
else
{
itemRect2.top=itemRect2.bottom=(itemRect2.top+itemRect2.bottom)/2-1;
DrawEdge(hdc,&itemRect2,EDGE_ETCHED,BF_TOP);
}
}
}
}
if (bHot && item.bSplit && item.id==MENU_SEARCH_CATEGORY)
{
int x=itemRect.right-settings.arrPadding.cy-s_Skin.More_bitmap_Size.cx;
int y=(itemRect.top+itemRect.bottom-s_Skin.More_bitmap_Size.cy)/2;
HGDIOBJ bmp0=SelectObject(hdc2,s_Skin.More_bitmap.GetBitmap());
if (s_Skin.More_bitmap.bIs32)
{
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
AlphaBlend(hdc,x,y,s_Skin.More_bitmap_Size.cx,s_Skin.More_bitmap_Size.cy,hdc2,0,stateRight==0?s_Skin.More_bitmap_Size.cy:0,s_Skin.More_bitmap_Size.cx,s_Skin.More_bitmap_Size.cy,func);
}
else
{
BitBlt(hdc,x,y,s_Skin.More_bitmap_Size.cx,s_Skin.More_bitmap_Size.cy,hdc2,0,stateRight==0?s_Skin.More_bitmap_Size.cy:0,SRCCOPY);
}
SelectObject(hdc2,bmp0);
}
continue;
}
if (item.id==MENU_SEARCH_BOX)
{
MenuBitmap searchIcons;
if (s_Skin.Search_bitmap.GetBitmap())
searchIcons=s_Skin.Search_bitmap;
else
{
searchIcons.Init();
searchIcons=m_SearchIcons;
searchIcons.bIs32=true;
}
RECT rc;
m_SearchBox.GetWindowRect(&rc);
int iconSize=16, iconY=0;
int icon;
if (m_SearchState<SEARCH_TEXT)
icon=s_bRTL?4:0;
else
icon=s_bRTL?3:1;
if (rc.bottom-rc.top>=30)
{
iconSize=20;
iconY=16;
if (s_bRTL)
icon--;
}
HGDIOBJ bmp0=SelectObject(hdc2,searchIcons.GetBitmap());
RECT rSrc={0,0,iconSize,iconSize};
RECT rDst=rSrc;
OffsetRect(&rSrc,iconSize*icon,iconY);
OffsetRect(&rDst,(itemRect.right+itemRect.left-iconSize)/2,(itemRect.bottom+itemRect.top-iconSize)/2);
RECT rMargins={0,0,0,0};
MarginsBlit(hdc2,hdc,rSrc,rDst,rMargins,searchIcons.bIs32);
SelectObject(hdc2,bmp0);
continue;
}
bool bNoIcon=!item.bInline && settings.iconSize==MenuSkin::ICON_SIZE_NONE;
SIZE iconSize;
if (settings.iconSize==MenuSkin::ICON_SIZE_SMALL)
iconSize.cx=iconSize.cy=g_ItemManager.SMALL_ICON_SIZE;
else if (settings.iconSize==MenuSkin::ICON_SIZE_LARGE)
iconSize.cx=iconSize.cy=g_ItemManager.LARGE_ICON_SIZE;
else if (settings.iconSize==MenuSkin::ICON_SIZE_PROGRAMS)
{
if (s_Skin.Programs_icon.GetBitmap())
iconSize=s_Skin.Programs_icon_size;
else
{
iconSize.cx=s_Skin.ItemSettings[MenuSkin::COLUMN1_ITEM].iconSize==MenuSkin::ICON_SIZE_SMALL?g_ItemManager.SMALL_ICON_SIZE:g_ItemManager.LARGE_ICON_SIZE;
iconSize.cy=7;
}
}
else
iconSize.cx=iconSize.cy=0;
COLORREF color, shadowColor;
{
bool bHotColor = (bHot && !bSplit) || stateLeft > 0;
if (item.id == MENU_EMPTY || item.id == MENU_EMPTY_TOP)
{
color = settings.textColors[bHotColor ? 3 : 2];
shadowColor = settings.textShadowColors[bHotColor ? 3 : 2];
}
else
{
color = settings.textColors[bHotColor ? 1 : 0];
shadowColor = settings.textShadowColors[bHotColor ? 1 : 0];
}
}
// draw icon
if (drawType==MenuSkin::PROGRAMS_BUTTON || drawType==MenuSkin::PROGRAMS_BUTTON_NEW)
{
if (s_Skin.Programs_icon.GetBitmap())
{
int iconX=itemRect.left+settings.iconPadding.left;
int iconY=itemRect.top+settings.iconPadding.top+settings.iconTopOffset;
const MenuBitmap &icon=bHot?s_Skin.Programs_icon_selected:s_Skin.Programs_icon;
HGDIOBJ bmp0=SelectObject(hdc2,icon.GetBitmap());
if (icon.bIs32)
{
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
AlphaBlend(hdc,iconX,iconY,s_Skin.Programs_icon_size.cx,s_Skin.Programs_icon_size.cy,hdc2,0,s_MenuMode==MODE_PROGRAMS?s_Skin.Programs_icon_size.cy:0,s_Skin.Programs_icon_size.cx,s_Skin.Programs_icon_size.cy,func);
}
else
BitBlt(hdc,iconX,iconY,s_Skin.Programs_icon_size.cx,s_Skin.Programs_icon_size.cy,hdc2,0,s_MenuMode==MODE_PROGRAMS?s_Skin.Programs_icon_size.cy:0,SRCCOPY);
SelectObject(hdc2,bmp0);
}
else
{
const POINT *sizes=s_Skin.GetArrowsBitmapSizes();
SIZE s={sizes[4].y-sizes[4].x,sizes[6].y};
int x=itemRect.left+settings.arrPadding.cx;
int y=(itemRect.top+itemRect.bottom-s.cy)/2;
HGDIOBJ bmp0=SelectObject(hdc2,GetArrowsBitmap(settings.arrColors[bHot?1:0]));
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
if (s_MenuMode==MODE_PROGRAMS)
{
AlphaBlend(hdc,x,y,s.cx,s.cy,hdc2,s_bRTL?sizes[6].x-sizes[3].y:sizes[4].x,0,s.cx,s.cy,func);
}
else
{
AlphaBlend(hdc,x,y,s.cx,s.cy,hdc2,s_bRTL?sizes[6].x-sizes[4].y:sizes[3].x,0,s.cx,s.cy,func);
}
SelectObject(hdc2,bmp0);
}
}
else if (item.pItemInfo && !bNoIcon)
{
int iconX=itemRect.left+settings.iconPadding.left;
int iconY=itemRect.top+settings.iconPadding.top+settings.iconTopOffset;
if (settings.bmpIconFrame.GetBitmap())
{
HGDIOBJ bmp0=SelectObject(hdc2,settings.bmpIconFrame.GetBitmap());
RECT rSrc={0,0,settings.frameSlicesX[0]+settings.frameSlicesX[1]+settings.frameSlicesX[2],settings.frameSlicesY[0]+settings.frameSlicesY[1]+settings.frameSlicesY[2]};
if (bHot)
OffsetRect(&rSrc,rSrc.right,0);
RECT rDst={iconX,iconY,iconX+iconSize.cx,iconY+iconSize.cy};
InflateRect(&rDst,settings.iconFrameOffset.x,settings.iconFrameOffset.y);
RECT rMargins={settings.frameSlicesX[0],settings.frameSlicesY[0],settings.frameSlicesX[2],settings.frameSlicesY[2]};
MarginsBlit(hdc2,hdc,rSrc,rDst,rMargins,settings.bmpIconFrame.bIs32);
SelectObject(hdc2,bmp0);
}
const CItemManager::IconInfo *pIcon=(settings.iconSize==MenuSkin::ICON_SIZE_LARGE)?item.pItemInfo->largeIcon:item.pItemInfo->smallIcon;
if (pIcon && pIcon->bitmap)
{
HBITMAP temp = ColorizeMonochromeImage(pIcon->bitmap, color);
HBITMAP bitmap = temp ? temp : pIcon->bitmap;
BITMAP info;
GetObject(bitmap,sizeof(info),&info);
HGDIOBJ bmp0=SelectObject(hdc2,bitmap);
if (bmp0)
{
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
AlphaBlend(hdc,iconX,iconY,iconSize.cx,iconSize.cy,hdc2,0,0,info.bmWidth,info.bmHeight,func);
SelectObject(hdc2,bmp0);
}
if (temp)
DeleteObject(temp);
}
}
else if (item.id==MENU_SHUTDOWN_BUTTON && s_bHasUpdates && s_Skin.Shutdown_bitmap.GetBitmap())
{
int iconX=itemRect.left+settings.iconPadding.left;
int iconY=itemRect.top+settings.iconPadding.top+settings.iconTopOffset;
if (stateLeft==2 && !settings.bmpSelection.GetBitmap())
iconX++, iconY++;
HGDIOBJ bmp0=SelectObject(hdc2,s_Skin.Shutdown_bitmap.GetBitmap());
if (s_Skin.Shutdown_bitmap.bIs32)
{
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
AlphaBlend(hdc,iconX,iconY,s_Skin.Shutdown_bitmap_Size.cx,s_Skin.Shutdown_bitmap_Size.cy,hdc2,0,0,s_Skin.Shutdown_bitmap_Size.cx,s_Skin.Shutdown_bitmap_Size.cy,func);
}
else
BitBlt(hdc,iconX,iconY,s_Skin.Shutdown_bitmap_Size.cx,s_Skin.Shutdown_bitmap_Size.cy,hdc2,0,0,SRCCOPY);
SelectObject(hdc2,bmp0);
}
// draw text
SelectObject(hdc,settings.font);
RECT rc={itemRect.left+settings.iconPadding.left+settings.iconPadding.right+settings.textPadding.left,itemRect.top+settings.textPadding.top,
itemRect.right-settings.arrPadding.cx-settings.arrPadding.cy-settings.textPadding.right,itemRect.bottom-settings.textPadding.bottom};
if (item.id==MENU_SHUTDOWN_BUTTON)
{
if (s_bHasUpdates && s_Skin.Shutdown_bitmap.GetBitmap())
rc.left+=s_Skin.Shutdown_bitmap_Size.cx-settings.iconPadding.left-settings.iconPadding.right;
if (stateLeft==2 && !settings.bmpSelection.GetBitmap())
OffsetRect(&rc,1,1);
}
if (s_MenuMode==MODE_SEARCH && !m_bSubMenu && item.id==MENU_NO && index>=m_OriginalCount)
rc.right+=settings.arrPadding.cx+settings.arrPadding.cy;
else
rc.right-=(item.jumpIndex>=0)?s_Skin.Pin_bitmap_Size.cx:settings.arrSize.cx;
if (!bNoIcon)
rc.left+=iconSize.cx;
DWORD flags=DT_END_ELLIPSIS;
if (item.id==MENU_NO || (item.id==MENU_RECENT && recentType!=RECENT_KEYS_DIGITS))
flags|=DT_NOPREFIX;
else if (!s_bKeyboardCues)
flags|=DT_HIDEPREFIX;
CString name;
if (drawType==MenuSkin::PROGRAMS_BUTTON || drawType==MenuSkin::PROGRAMS_BUTTON_NEW || drawType==MenuSkin::PROGRAMS_CASCADING || drawType==MenuSkin::PROGRAMS_CASCADING_NEW)
name=s_MenuMode==MODE_PROGRAMS?FindTranslation(L"Menu.Back",L"Back"):FindTranslation(L"Menu.AllPrograms",L"All Programs");
else
name=item.name;
if (settings.textMetrics.tmHeight*2<=rc.bottom-rc.top)
{
// if the height can fit two lines, see if we can make use of them
RECT rc2={0,0,rc.right-rc.left,0};
DrawText(hdc,name,name.GetLength(),&rc2,flags|DT_WORDBREAK|DT_CALCRECT);
if (2*rc2.bottom>settings.textMetrics.tmHeight*3)
{
flags|=DT_EDITCONTROL|DT_WORDBREAK;
int d=rc.bottom-rc.top-settings.textMetrics.tmHeight*2;
rc.top+=d/2;
}
}
if (!(flags&DT_WORDBREAK))
flags|=DT_VCENTER|DT_SINGLELINE;
if (s_Theme)
{
DTTOPTS opts={sizeof(opts),DTT_TEXTCOLOR};
if (glowSize || settings.opacity==MenuSkin::OPACITY_FULLALPHA || settings.opacity==MenuSkin::OPACITY_FULLGLASS)
opts.dwFlags|=DTT_COMPOSITED;
if (glowSize)
{
opts.dwFlags|=DTT_GLOWSIZE;
opts.iGlowSize=glowSize;
}
if (shadowColor!=0xFFFFFFFF)
{
opts.crText=shadowColor;
RECT rc2=rc;
OffsetRect(&rc2,1,1);
DrawThemeTextEx(s_Theme,hdc,0,0,name,name.GetLength(),flags,&rc2,&opts);
}
opts.crText=color;
DrawThemeTextEx(s_Theme,hdc,0,0,name,name.GetLength(),flags,&rc,&opts);
}
else
{
if (shadowColor!=0xFFFFFFFF)
{
RECT rc2=rc;
OffsetRect(&rc2,1,1);
SetTextColor(hdc,shadowColor);
DrawText(hdc,item.name,item.name.GetLength(),&rc,flags);
}
SetTextColor(hdc,color);
DrawText(hdc,name,name.GetLength(),&rc,flags);
}
if (item.bFolder && drawType!=MenuSkin::PROGRAMS_BUTTON && drawType!=MenuSkin::PROGRAMS_BUTTON_NEW)
{
// draw the sub-menu arrows
bool bHotArrow=(bHot && !bSplit) || stateRight>0;
if (settings.bmpArrow.GetBitmap())
{
int x=itemRect.right-settings.arrPadding.cy-settings.arrSize.cx;
int y=(itemRect.top+itemRect.bottom-settings.arrSize.cy)/2;
if (stateRight==2 && !settings.bmpSelection.GetBitmap())
x++, y++;
HGDIOBJ bmp0=SelectObject(hdc2,settings.bmpArrow.GetBitmap());
if (settings.bmpArrow.bIs32)
{
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
AlphaBlend(hdc,x,y,settings.arrSize.cx,settings.arrSize.cy,hdc2,0,bHotArrow?settings.arrSize.cy:0,settings.arrSize.cx,settings.arrSize.cy,func);
}
else
{
BitBlt(hdc,x,y,settings.arrSize.cx,settings.arrSize.cy,hdc2,0,bHotArrow?settings.arrSize.cy:0,SRCCOPY);
}
SelectObject(hdc2,bmp0);
}
else
{
const POINT *sizes=s_Skin.GetArrowsBitmapSizes();
SIZE s={sizes[3].y-sizes[3].x,sizes[6].y};
int x=itemRect.right-settings.arrPadding.cy-s.cx;
int y=(itemRect.top+itemRect.bottom-s.cy)/2;
if (stateRight==2 && !settings.bmpSelection.GetBitmap())
x++, y++;
HGDIOBJ bmp0=SelectObject(hdc2,GetArrowsBitmap(settings.arrColors[bHotArrow?1:0]));
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
AlphaBlend(hdc,x,y,s.cx,s.cy,hdc2,s_bRTL?sizes[6].x-sizes[4].y:sizes[3].x,0,s.cx,s.cy,func);
SelectObject(hdc2,bmp0);
}
}
else if (bHot && item.bSplit && item.jumpIndex>=0)
{
int x=itemRect.right-settings.arrPadding.cy-s_Skin.Pin_bitmap_Size.cx;
int y=(itemRect.top+itemRect.bottom-s_Skin.Pin_bitmap_Size.cy)/2;
HGDIOBJ bmp0=SelectObject(hdc2,s_Skin.Pin_bitmap.GetBitmap());
bool bPinned=s_JumpList.groups[LOWORD(item.jumpIndex)].type==CJumpGroup::TYPE_PINNED;
if (s_Skin.Pin_bitmap.bIs32)
{
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
AlphaBlend(hdc,x,y,s_Skin.Pin_bitmap_Size.cx,s_Skin.Pin_bitmap_Size.cy,hdc2,bPinned?s_Skin.Pin_bitmap_Size.cx:0,stateRight==0?s_Skin.Pin_bitmap_Size.cy:0,s_Skin.Pin_bitmap_Size.cx,s_Skin.Pin_bitmap_Size.cy,func);
}
else
{
BitBlt(hdc,x,y,s_Skin.Pin_bitmap_Size.cx,s_Skin.Pin_bitmap_Size.cy,hdc2,bPinned?s_Skin.Pin_bitmap_Size.cx:0,stateRight==0?s_Skin.Pin_bitmap_Size.cy:0,SRCCOPY);
}
SelectObject(hdc2,bmp0);
}
}
// draw vertical separators
if (m_bSubMenu && m_ColumnOffsets.size()>1)
{
if (bmpSeparatorV.GetBitmap())
{
HGDIOBJ bmp0=SelectObject(hdc2,bmpSeparatorV.GetBitmap());
RECT rSrc={0,0,sepWidth,sepSlicesY[0]+sepSlicesY[1]+sepSlicesY[2]};
RECT rMargins={0,sepSlicesY[0],0,sepSlicesY[2]};
for (size_t i=1;i<m_ColumnOffsets.size();i++)
{
int x=m_rContent.left+m_ColumnOffsets[i];
RECT rc={x-sepWidth,m_rContent.top,x,m_rContent.bottom};
MarginsBlit(hdc2,hdc,rSrc,rc,rMargins,bmpSeparatorV.bIs32);
}
SelectObject(hdc2,bmp0);
}
else
{
int offset=0;
if (s_Theme)
{
SIZE size;
if (SUCCEEDED(GetThemePartSize(s_Theme,hdc,TP_SEPARATOR,TS_NORMAL,NULL,TS_MIN,&size)))
offset=(sepWidth-size.cx)/2;
}
else
{
offset=(sepWidth-2)/2;
}
for (size_t i=1;i<m_ColumnOffsets.size();i++)
{
int x=m_rContent.left+m_ColumnOffsets[i]+offset;
RECT rc={x-sepWidth,m_rContent.top,x,m_rContent.bottom};
if (s_Theme)
DrawThemeBackground(s_Theme,hdc,TP_SEPARATOR,TS_NORMAL,&rc,NULL);
else
DrawEdge(hdc,&rc,EDGE_ETCHED,BF_LEFT);
}
}
}
// draw insert mark
{
RECT rc;
if (GetInsertRect(rc))
{
HGDIOBJ bmp0=SelectObject(hdc2,GetArrowsBitmap(s_Skin.ItemSettings[m_bSubMenu?MenuSkin::SUBMENU_ITEM:MenuSkin::COLUMN1_ITEM].arrColors[0])); // the insert mask can't be in the second column of the main menu
const POINT *sizes=s_Skin.GetArrowsBitmapSizes();
RECT rSrc={s_bRTL?sizes[6].x-sizes[2].y:sizes[0].x,0,s_bRTL?sizes[6].x-sizes[0].x:sizes[2].y,sizes[1].y};
RECT rMargins={sizes[0].y-sizes[0].x,0,sizes[2].y-sizes[2].x,0};
MarginsBlit(hdc2,hdc,rSrc,rc,rMargins,true);
SelectObject(hdc2,bmp0);
}
}
SelectObject(hdc,font0);
DeleteDC(hdc2);
}
LRESULT CMenuContainer::OnPaint( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
// handles both WM_PAINT and WM_PRINTCLIENT
MenuSkin::TOpacity opacity=(m_bSubMenu?s_Skin.Submenu_opacity:s_Skin.Main_opacity);
MenuSkin::TOpacity opacity2=s_MenuMode==MODE_JUMPLIST?s_Skin.Jumplist_opacity:s_Skin.Main2_opacity;
if ((!m_bSubMenu && m_Bitmap) || (m_bSubMenu && s_Skin.Submenu_bitmap.GetBitmap()))
{
if (opacity==MenuSkin::OPACITY_GLASS || opacity==MenuSkin::OPACITY_FULLGLASS)
{
DWM_BLURBEHIND blur={DWM_BB_ENABLE|DWM_BB_BLURREGION,TRUE,m_Region,FALSE};
DwmEnableBlurBehindWindow(m_hWnd,&blur);
}
else if (opacity==MenuSkin::OPACITY_REGION)
{
DWM_BLURBEHIND blur={DWM_BB_ENABLE|((uMsg==WM_PRINTCLIENT)?DWM_BB_BLURREGION:0U),(uMsg==WM_PRINTCLIENT),m_Region,FALSE};
DwmEnableBlurBehindWindow(m_hWnd,&blur);
}
}
PAINTSTRUCT ps;
HDC hdc;
if (uMsg==WM_PRINTCLIENT)
{
hdc=(HDC)wParam;
GetClientRect(&ps.rcPaint);
}
else
{
hdc=BeginPaint(&ps);
OffsetViewportOrgEx(hdc,m_PaintOffset.x,m_PaintOffset.y,NULL);
OffsetRect(&ps.rcPaint,-m_PaintOffset.x,-m_PaintOffset.y);
}
BP_PAINTPARAMS paintParams={sizeof(paintParams)};
paintParams.dwFlags=BPPF_ERASE;
HDC hdcPaint=NULL;
HPAINTBUFFER hBufferedPaint=BeginBufferedPaint(hdc,&ps.rcPaint,BPBF_TOPDOWNDIB,&paintParams,&hdcPaint);
if (hdcPaint)
{
if (s_OldMenuState.mode!=MODE_UNKNOWN)
{
HDC hSrc=CreateCompatibleDC(hdcPaint);
HGDIOBJ bmp0=SelectObject(hSrc,m_Bitmap);
BITMAP info;
GetObject(m_Bitmap,sizeof(info),&info);
RECT rc1={m_BitmapOffset,0,info.bmWidth+m_BitmapOffset,info.bmHeight};
RECT rc2;
IntersectRect(&rc2,&rc1,&ps.rcPaint);
BitBlt(hdcPaint,rc2.left,rc2.top,rc2.right-rc2.left,rc2.bottom-rc2.top,hSrc,rc2.left-m_BitmapOffset,rc2.top,SRCCOPY);
SelectObject(hSrc,bmp0);
DeleteDC(hSrc);
}
else
{
DrawBackground(hdcPaint,ps.rcPaint);
}
if (m_bSubMenu?s_Skin.Submenu_FakeGlass:s_Skin.Main_FakeGlass)
{
static unsigned char remapAlpha[256];
if (!remapAlpha[255])
{
for (int i=0;i<256;i++)
remapAlpha[i]=(unsigned char)(255*pow(i/255.f,0.2f));
}
HBITMAP bmp0=CreateCompatibleBitmap(hdcPaint,1,1);
HGDIOBJ bmp=SelectObject(hdcPaint,bmp0);
BITMAP info;
GetObject(bmp,sizeof(info),&info);
if (info.bmBitsPixel==32)
{
int n=info.bmWidth*info.bmHeight;
for (int i=0;i<n;i++)
{
unsigned int &pixel=((unsigned int*)info.bmBits)[i];
int a=pixel>>24;
a=remapAlpha[a];
pixel=(a<<24)|(pixel&0xFFFFFF);
}
}
SelectObject(hdcPaint,bmp);
DeleteObject(bmp0);
}
if (m_SearchBox.m_hWnd && ((uMsg==WM_PRINTCLIENT && (lParam&PRF_CHILDREN)) || (uMsg==WM_PAINT && !m_bSearchDrawn)))
{
RECT rc;
GetWindowRect(&rc);
m_SearchBox.GetWindowRect(&rc);
::MapWindowPoints(NULL,m_hWnd,(POINT*)&rc,2);
// print the editbox to a new bitmap, and then blit to hdcPaint. printing directly into hdcPaint doesn't quite work with RTL
HDC hdcSearch=CreateCompatibleDC(hdcPaint);
HBITMAP bmpSearch=CreateCompatibleBitmap(hdcPaint,rc.right-rc.left,rc.bottom-rc.top);
HGDIOBJ bmp0=SelectObject(hdcSearch,bmpSearch);
if (s_bRTL) SetLayout(hdcSearch,0);
m_SearchBox.SendMessage(WM_PRINTCLIENT,(WPARAM)hdcSearch,PRF_CLIENT);
if (s_bRTL) SetLayout(hdcSearch,LAYOUT_RTL);
BitBlt(hdcPaint,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,hdcSearch,0,0,SRCCOPY);
BufferedPaintSetAlpha(hBufferedPaint,&rc,255);
SelectObject(hdcSearch,bmp0);
DeleteDC(hdcSearch);
DeleteObject(bmpSearch);
}
if (m_pProgramsTree && s_MenuMode==MODE_PROGRAMS)
{
bool bDrawTree=(uMsg==WM_PAINT && (m_PaintOffset.x!=0 || m_PaintOffset.y!=0)) || (uMsg==WM_PRINTCLIENT && (lParam&PRF_CHILDREN));
if (bDrawTree)
{
RECT rc;
m_pProgramsTree->GetWindowRect(&rc);
::MapWindowPoints(NULL,m_hWnd,(POINT*)&rc,2);
SetViewportOrgEx(hdcPaint,rc.left,rc.top,NULL);
m_pProgramsTree->GetClientRect(&rc);
m_pProgramsTree->DrawTree(hdcPaint,rc);
m_pProgramsTree->Print(hdcPaint,PRF_NONCLIENT);
SetViewportOrgEx(hdcPaint,0,0,NULL);
}
}
if (opacity==MenuSkin::OPACITY_REGION && uMsg==WM_PRINTCLIENT && m_bSubMenu && s_Skin.Submenu_bitmap.bIsBitmap && !s_Skin.Submenu_bitmap.bIs32)
{
// if the bitmap is 24-bit, the alpha channel may be undefined
BufferedPaintSetAlpha(hBufferedPaint,&ps.rcPaint,255);
}
else
{
if (s_OldMenuState.mode==MODE_UNKNOWN)
{
if (opacity==MenuSkin::OPACITY_GLASS || opacity==MenuSkin::OPACITY_ALPHA || (opacity==MenuSkin::OPACITY_REGION && uMsg==WM_PRINTCLIENT))
{
RECT rc;
IntersectRect(&rc,&ps.rcPaint,&m_rContent);
BufferedPaintSetAlpha(hBufferedPaint,&rc,255);
}
if (m_bTwoColumns && (opacity2==MenuSkin::OPACITY_GLASS || opacity2==MenuSkin::OPACITY_ALPHA || (opacity2==MenuSkin::OPACITY_REGION && uMsg==WM_PRINTCLIENT)))
{
RECT rc;
IntersectRect(&rc,&ps.rcPaint,&m_rContent2);
BufferedPaintSetAlpha(hBufferedPaint,&rc,255);
}
}
if (m_SearchIndex>=0 && s_bWin7Style && ((s_Skin.Search_background_jump.GetBitmap() && !s_Skin.Search_background_jump.bIs32) || !s_Skin.Search_background_jump.bIsBitmap))
{
RECT padding;
if (s_MenuMode==MODE_SEARCH)
padding=s_Skin.Search_background_search_padding;
else if (s_MenuMode==MODE_JUMPLIST)
padding=s_Skin.Search_background_jump_padding;
else
padding=s_Skin.Search_background_padding;
RECT rcSearch;
rcSearch.left=m_rContent.right-padding.left;
rcSearch.right=m_rContent2.left+padding.right;
rcSearch.top=m_Items[m_SearchIndex].itemRect.top-s_Skin.Search_padding.top-padding.top;
rcSearch.bottom=m_rContent.bottom+padding.bottom;
RECT rc;
IntersectRect(&rc,&ps.rcPaint,&rcSearch);
BufferedPaintSetAlpha(hBufferedPaint,&rc,255);
}
}
EndBufferedPaint(hBufferedPaint,TRUE);
}
if (uMsg!=WM_PRINTCLIENT)
EndPaint(&ps);
return 0;
}
static void FillSolidGlassRect( HDC hdc, LPCRECT pRect, COLORREF color )
{
BP_PAINTPARAMS paintParams={sizeof(paintParams)};
paintParams.dwFlags=0;
HDC hdcPaint=NULL;
HPAINTBUFFER hBufferedPaint=BeginBufferedPaint(hdc,pRect,BPBF_TOPDOWNDIB,&paintParams,&hdcPaint);
if (hdcPaint)
{
SetDCBrushColor(hdcPaint,color);
FillRect(hdcPaint,pRect,(HBRUSH)GetStockObject(DC_BRUSH));
BufferedPaintSetAlpha(hBufferedPaint,pRect,255);
EndBufferedPaint(hBufferedPaint,TRUE);
}
}
void CProgramsTree::DrawTree( HDC hdc, const RECT &drawRect )
{
RECT rcClient;
GetClientRect(&rcClient);
{
RECT rc;
TreeView_GetItemRect(m_hWnd,TreeView_GetRoot(m_hWnd),&rc,TRUE);
m_MinX=rc.left-m_RootX; // detect when the tree auto-scrolls
// find the widest of the visible elements
m_MaxX=rcClient.right;
int maxy=rcClient.bottom;
for (HTREEITEM hItem=TreeView_GetFirstVisible(m_hWnd);hItem;hItem=TreeView_GetNextVisible(m_hWnd,hItem))
{
TreeView_GetItemRect(m_hWnd,hItem,&rc,TRUE);
if (m_MaxX<rc.right) m_MaxX=rc.right;
if (rc.bottom>=maxy)
break;
}
}
BP_PAINTPARAMS paintParams={sizeof(paintParams)};
HDC hdcPaint=NULL;
HPAINTBUFFER hBufferedPaint=BeginBufferedPaint(hdc,&drawRect,BPBF_TOPDOWNDIB,&paintParams,&hdcPaint);
if (hdcPaint)
{
HDC hsrc=CreateCompatibleDC(hdcPaint);
const MenuSkin &skin=CMenuContainer::s_Skin;
int alpha;
if (skin.Programs_background==0)
{
RECT bmpRect=drawRect;
::MapWindowPoints(m_hWnd,m_pOwner->m_hWnd,(POINT*)&bmpRect,2);
HGDIOBJ bmp0=SelectObject(hsrc,m_pOwner->m_Bitmap);
BitBlt(hdcPaint,drawRect.left,drawRect.top,drawRect.right-drawRect.left,drawRect.bottom-drawRect.top,hsrc,bmpRect.left,bmpRect.top,SRCCOPY);
SelectObject(hsrc,bmp0);
alpha=(skin.Main_opacity==MenuSkin::OPACITY_ALPHA || skin.Main_opacity==MenuSkin::OPACITY_GLASS)?255:0;
}
else
{
SetDCBrushColor(hdcPaint,skin.Programs_background&0xFFFFFF);
FillRect(hdcPaint,&drawRect,(HBRUSH)GetStockObject(DC_BRUSH));
alpha=skin.Programs_background>>24;
if (alpha<255)
{
if (skin.Main_FakeGlass)
alpha=(unsigned char)(255*pow(alpha/255.f,0.2f));
BufferedPaintSetAlpha(hBufferedPaint,&drawRect,alpha);
}
}
SelectObject(hdcPaint,GetFont());
HTREEITEM hSelection=TreeView_GetSelection(m_hWnd);
HTREEITEM hHilight=TreeView_GetDropHilight(m_hWnd);
HWND focus=GetFocus();
for (HTREEITEM hItem=TreeView_GetFirstVisible(m_hWnd);hItem;hItem=TreeView_GetNextVisible(m_hWnd,hItem))
{
RECT itemRect;
TreeView_GetItemRect(m_hWnd,hItem,&itemRect,TRUE);
if (itemRect.top>=drawRect.bottom)
break;
bool bHot=((hItem==hSelection && m_DropLocation==DROP_NOWHERE) || hItem==hHilight) && (m_pOwner->m_HotItem==m_pOwner->m_ProgramTreeIndex || focus==m_hWnd);
if (itemRect.bottom>drawRect.top)
DrawTreeItem(hdcPaint,hsrc,hItem,itemRect,bHot);
}
RECT rc;
if (GetInsertRect(rc))
{
const POINT *sizes=skin.GetArrowsBitmapSizes();
HGDIOBJ bmp0=SelectObject(hsrc,CMenuContainer::GetArrowsBitmap(CMenuContainer::s_Skin.ItemSettings[MenuSkin::PROGRAMS_TREE_ITEM].textColors[0]));
RECT rSrc={CMenuContainer::s_bRTL?sizes[6].x-sizes[2].y:sizes[0].x,0,CMenuContainer::s_bRTL?sizes[6].x-sizes[0].x:sizes[2].y,sizes[1].y};
RECT rMargins={sizes[0].y-sizes[0].x,0,sizes[2].y-sizes[2].x,0};
MarginsBlit(hsrc,hdcPaint,rSrc,rc,rMargins,true);
SelectObject(hsrc,bmp0);
}
DeleteDC(hsrc);
if (alpha==255)
BufferedPaintSetAlpha(hBufferedPaint,&drawRect,alpha);
EndBufferedPaint(hBufferedPaint,TRUE);
}
}
void CProgramsTree::DrawTreeItem( HDC hdc, HDC hsrc, HTREEITEM hItem, const RECT &itemRect, bool bHot ) const
{
TVITEM item={TVIF_PARAM|TVIF_STATE,hItem,0,TVIS_SELECTED};
TreeView_GetItem(m_hWnd,&item);
const MenuSkin &skin=CMenuContainer::s_Skin;
const CTreeItem *pItem=(CTreeItem*)item.lParam;
COLORREF textColor;
COLORREF shadowColor;
MenuBitmap bmp;
const int *slicesX, *slicesY;
RECT iconPadding;
int iconTopOffset, textTopOffset;
int glowSize;
if (bHot)
{
// selected
const MenuSkin::ItemDrawSettings &settings=skin.ItemSettings[MenuSkin::PROGRAMS_TREE_ITEM];
bmp=settings.bmpSelection;
slicesX=settings.selSlicesX;
slicesY=settings.selSlicesY;
iconPadding=settings.iconPadding;
iconTopOffset=settings.iconTopOffset+settings.iconPadding.top;
textTopOffset=settings.textTopOffset+settings.textPadding.top;
textColor=settings.textColors[pItem->bEmpty?3:1];
shadowColor=settings.textShadowColors[bHot?1:0];
glowSize=settings.glowSize;
}
else if (pItem->bNew)
{
// highlighted
const MenuSkin::ItemDrawSettings &settings=skin.ItemSettings[MenuSkin::PROGRAMS_TREE_NEW];
bmp=settings.bmpSelection;
slicesX=settings.selSlicesX;
slicesY=settings.selSlicesY;
iconPadding=settings.iconPadding;
iconTopOffset=settings.iconTopOffset+settings.iconPadding.top;
textTopOffset=settings.textTopOffset+settings.textPadding.top;
textColor=settings.textColors[pItem->bEmpty?2:0];
shadowColor=settings.textShadowColors[bHot?1:0];
glowSize=settings.glowSize;
}
else
{
// not selected
bmp=skin.Programs_background;
const MenuSkin::ItemDrawSettings &settings=skin.ItemSettings[MenuSkin::PROGRAMS_TREE_ITEM];
iconPadding=settings.iconPadding;
iconTopOffset=settings.iconTopOffset+settings.iconPadding.top;
textTopOffset=settings.textTopOffset+settings.textPadding.top;
textColor=settings.textColors[pItem->bEmpty?2:0];
shadowColor=settings.textShadowColors[bHot?1:0];
glowSize=settings.glowSize;
}
RECT rc=itemRect;
int left=rc.left;
rc.left=m_MinX;
rc.right=m_MaxX;
if (bHot || pItem->bNew)
{
// draw background
if (bmp.bIsBitmap)
{
HGDIOBJ bmp0=SelectObject(hsrc,bmp.GetBitmap());
RECT rSrc={0,0,slicesX[0]+slicesX[1]+slicesX[2],slicesY[0]+slicesY[1]+slicesY[2]};
RECT rMargins={slicesX[0],slicesY[0],slicesX[2],slicesY[2]};
MarginsBlit(hsrc,hdc,rSrc,rc,rMargins,bmp.bIs32);
SelectObject(hsrc,bmp0);
}
else
{
SetDCBrushColor(hdc,bmp.GetColor());
FillRect(hdc,&rc,(HBRUSH)GetStockObject(DC_BRUSH));
}
}
// draw icon
rc.left=left;
int iconSize=CItemManager::SMALL_ICON_SIZE;
int x=rc.left-iconSize-3-iconPadding.right;
int y=rc.top+iconTopOffset;
if (pItem->pItemInfo1 && pItem->pItemInfo1->smallIcon)
{
HGDIOBJ bmp0=SelectObject(hsrc,pItem->pItemInfo1->smallIcon->bitmap);
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
AlphaBlend(hdc,x,y,iconSize,iconSize,hsrc,0,0,iconSize,iconSize,func);
SelectObject(hsrc,bmp0);
}
// draw text
rc.top+=textTopOffset;
if (m_TreeTheme)
{
DTTOPTS opts={sizeof(opts),DTT_TEXTCOLOR};
if (glowSize || skin.ItemSettings[MenuSkin::PROGRAMS_TREE_ITEM].opacity==MenuSkin::OPACITY_FULLALPHA || skin.ItemSettings[MenuSkin::PROGRAMS_TREE_ITEM].opacity==MenuSkin::OPACITY_FULLGLASS)
opts.dwFlags|=DTT_COMPOSITED;
if (glowSize)
{
opts.dwFlags|=DTT_GLOWSIZE;
opts.iGlowSize=glowSize;
}
if (shadowColor!=0xFFFFFFFF)
{
opts.crText=shadowColor;
RECT rc2=rc;
OffsetRect(&rc2,1,1);
DrawThemeTextEx(m_TreeTheme,hdc,0,0,pItem->name,pItem->name.GetLength(),DT_SINGLELINE|DT_NOPREFIX,&rc2,&opts);
}
opts.crText=textColor;
DrawThemeTextEx(m_TreeTheme,hdc,0,0,pItem->name,pItem->name.GetLength(),DT_SINGLELINE|DT_NOPREFIX,&rc,&opts);
}
else
{
SetBkMode(hdc,TRANSPARENT);
if (shadowColor!=0xFFFFFFFF)
{
RECT rc2=rc;
OffsetRect(&rc2,1,1);
SetTextColor(hdc,shadowColor);
DrawText(hdc,pItem->name,pItem->name.GetLength(),&rc,DT_SINGLELINE|DT_NOPREFIX);
}
SetTextColor(hdc,textColor);
DrawText(hdc,pItem->name,pItem->name.GetLength(),&rc,DT_SINGLELINE|DT_NOPREFIX);
}
}
void CProgramsTree::DrawScrollbarBackground( HDC hdc, int iPartId, int iStateId, LPCRECT pRect )
{
const MenuSkin &skin=CMenuContainer::s_Skin;
HDC hSrc=CreateCompatibleDC(hdc);
if (iPartId==SBP_ARROWBTN)
{
// draw arrows
int state=0;
if (iStateId==ABS_UPHOT || iStateId==ABS_DOWNHOT)
state=1;
else if (iStateId==ABS_UPPRESSED || iStateId==ABS_DOWNPRESSED)
state=2;
HGDIOBJ bmp0=GetCurrentObject(hSrc,OBJ_BITMAP);
if (skin.Scrollbar_button.bIsBitmap)
{
SelectObject(hSrc,skin.Scrollbar_button.GetBitmap());
int w=skin.Scrollbar_button_slices_X[0]+skin.Scrollbar_button_slices_X[1]+skin.Scrollbar_button_slices_X[2];
int h=skin.Scrollbar_button_slices_Y[0]+skin.Scrollbar_button_slices_Y[1]+skin.Scrollbar_button_slices_Y[2];
RECT rSrc={0,h*state,w,h*(state+1)};
RECT rMargins={skin.Scrollbar_button_slices_X[0],skin.Scrollbar_button_slices_Y[0],skin.Scrollbar_button_slices_X[2],skin.Scrollbar_button_slices_Y[2]};
MarginsBlit(hSrc,hdc,rSrc,*pRect,rMargins,false);
}
else
{
FillSolidGlassRect(hdc,pRect,skin.Scrollbar_button.GetColor());
}
int arrowOffset=0;
if ((iStateId>=ABS_DOWNNORMAL && iStateId<=ABS_DOWNDISABLED) || iStateId==ABS_DOWNHOVER)
arrowOffset=skin.Scrollbar_arrows_size.cx;
SelectObject(hSrc,skin.Scrollbar_arrows.GetBitmap());
int x=(pRect->right+pRect->left-skin.Scrollbar_arrows_size.cx)/2;
int y=(pRect->bottom+pRect->top-skin.Scrollbar_arrows_size.cy)/2;
StretchBlt2(hdc,x,y,skin.Scrollbar_arrows_size.cx,skin.Scrollbar_arrows_size.cy,hSrc,arrowOffset,skin.Scrollbar_arrows_size.cy*state,skin.Scrollbar_arrows_size.cx,skin.Scrollbar_arrows_size.cy,true);
SelectObject(hSrc,bmp0);
}
else if (iPartId==SBP_LOWERTRACKVERT || iPartId==SBP_UPPERTRACKVERT)
{
// draw background
if (skin.Scrollbar_background.bIsBitmap)
{
int state=0;
if (iStateId==SCRBS_HOT)
state=1;
else if (iStateId==SCRBS_PRESSED)
state=2;
HGDIOBJ bmp0=SelectObject(hSrc,skin.Scrollbar_background.GetBitmap());
int w=skin.Scrollbar_background_slices_X[0]+skin.Scrollbar_background_slices_X[1]+skin.Scrollbar_background_slices_X[2];
int h=skin.Scrollbar_background_slices_Y[0]+skin.Scrollbar_background_slices_Y[1]+skin.Scrollbar_background_slices_Y[2];
RECT rSrc={0,h*state,w,h*(state+1)};
RECT rMargins={skin.Scrollbar_background_slices_X[0],skin.Scrollbar_background_slices_Y[0],skin.Scrollbar_background_slices_X[2],skin.Scrollbar_background_slices_Y[2]};
MarginsBlit(hSrc,hdc,rSrc,*pRect,rMargins,false);
SelectObject(hSrc,bmp0);
}
else
{
FillSolidGlassRect(hdc,pRect,skin.Scrollbar_background.GetColor());
}
}
else if (iPartId==SBP_THUMBBTNVERT)
{
// draw thumb
if (skin.Scrollbar_thumb.bIsBitmap)
{
int state=0;
if (iStateId==SCRBS_HOT)
state=1;
else if (iStateId==SCRBS_PRESSED)
state=2;
HGDIOBJ bmp0=SelectObject(hSrc,skin.Scrollbar_thumb.GetBitmap());
int w=skin.Scrollbar_thumb_slices_X[0]+skin.Scrollbar_thumb_slices_X[1]+skin.Scrollbar_thumb_slices_X[2];
int h=skin.Scrollbar_thumb_slices_Y[0]+skin.Scrollbar_thumb_slices_Y[1]+skin.Scrollbar_thumb_slices_Y[2];
RECT rSrc={0,h*state,w,h*(state+1)};
RECT rMargins={skin.Scrollbar_thumb_slices_X[0],skin.Scrollbar_thumb_slices_Y[0],skin.Scrollbar_thumb_slices_X[2],skin.Scrollbar_thumb_slices_Y[2]};
MarginsBlit(hSrc,hdc,rSrc,*pRect,rMargins,false);
}
else
{
FillSolidGlassRect(hdc,pRect,skin.Scrollbar_thumb.GetColor());
}
}
else if (iPartId==SBP_GRIPPERVERT)
{
// draw gripper
if (skin.Scrollbar_gripper.GetBitmap())
{
int state=0;
if (iStateId==SCRBS_HOT)
state=1;
else if (iStateId==SCRBS_PRESSED)
state=2;
HGDIOBJ bmp0=SelectObject(hSrc,skin.Scrollbar_gripper.GetBitmap());
int x=(pRect->right+pRect->left-skin.Scrollbar_gripper_size.cx)/2;
int y=(pRect->bottom+pRect->top-skin.Scrollbar_gripper_size.cy)/2;
StretchBlt2(hdc,x,y,skin.Scrollbar_gripper_size.cx,skin.Scrollbar_gripper_size.cy,hSrc,0,skin.Scrollbar_gripper_size.cy*state,skin.Scrollbar_gripper_size.cx,skin.Scrollbar_gripper_size.cy,true);
SelectObject(hSrc,bmp0);
}
}
DeleteDC(hSrc);
}
void CMenuContainer::AnimateMenu( int flags, int speed, const RECT &rect )
{
RECT clipRect=m_bSubMenu?s_MenuLimits:s_MainMenuLimits;
bool bUserPic=(!m_bSubMenu && s_bWin7Style && s_UserPicture.m_hWnd && s_UserPictureRect.top<s_UserPictureRect.bottom);
if ((flags&AW_BLEND) && speed>0)
{
// fade in
SetWindowLong(GWL_EXSTYLE,GetWindowLong(GWL_EXSTYLE)|WS_EX_LAYERED);
SetWindowPos((flags&AW_TOPMOST)?HWND_TOPMOST:HWND_TOP,&rect,SWP_SHOWWINDOW|((flags&AW_ACTIVATE)?0:SWP_NOACTIVATE));
if (!m_bSubMenu && s_TaskBar && s_bBehindTaskbar)
{
// position the start button on top
if (s_StartButton)
::SetWindowPos(s_StartButton,(flags&AW_TOPMOST)?HWND_TOPMOST:HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
// position the start menu behind the taskbar
SetWindowPos(s_TaskBar,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
}
if (bUserPic)
{
s_UserPicture.Update(0);
s_UserPicture.SetWindowPos(NULL,&s_UserPictureRect,SWP_NOZORDER|SWP_NOACTIVATE|SWP_SHOWWINDOW);
}
// animate
int time0=GetTickCount();
while (true)
{
int dt=GetTickCount()-time0;
if (dt>speed) break;
float f=dt/(float)speed;
int alpha=(int)(f*255);
SetLayeredWindowAttributes(m_hWnd,0,(BYTE)alpha,LWA_ALPHA);
RedrawWindow();
if (bUserPic)
s_UserPicture.Update(alpha);
}
SetWindowLong(GWL_EXSTYLE,GetWindowLong(GWL_EXSTYLE)&~WS_EX_LAYERED);
RedrawWindow();
}
else if ((flags&AW_SLIDE) && speed>0)
{
// slide in
HRGN rgn=CreateRectRgn(0,0,0,0);
if (!SetWindowRgn(rgn,FALSE)) // set empty region
DeleteObject(rgn);
SetWindowPos((flags&AW_TOPMOST)?HWND_TOPMOST:HWND_TOP,&rect,SWP_SHOWWINDOW|((flags&AW_ACTIVATE)?0:SWP_NOACTIVATE));
if (!m_bSubMenu && s_TaskBar && s_bBehindTaskbar)
{
// position the start button on top
if (s_StartButton)
::SetWindowPos(s_StartButton,(flags&AW_TOPMOST)?HWND_TOPMOST:HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
// position the start menu behind the taskbar
SetWindowPos(s_TaskBar,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
}
if (bUserPic)
{
s_UserPicture.Update(0);
s_UserPicture.SetWindowPos(NULL,&s_UserPictureRect,SWP_NOZORDER|SWP_NOACTIVATE|SWP_SHOWWINDOW);
}
if (m_pProgramsTree && s_MenuMode==MODE_PROGRAMS)
m_pProgramsTree->ShowWindow(SW_HIDE);
HRGN rgn0=NULL;
if (m_Region)
{
int rgnSize=GetRegionData(m_Region,0,NULL);
std::vector<char> buf(rgnSize);
GetRegionData(m_Region,rgnSize,(RGNDATA*)&buf[0]);
XFORM xform={1,0,0,1};
if (s_bRTL)
{
// mirror the region (again)
xform.eM11=-1;
xform.eDx=(float)(m_rMenu.right+m_rMenu.left-m_BitmapOffset);
}
rgn0=ExtCreateRegion(&xform,rgnSize,(RGNDATA*)&buf[0]);
}
// animate
int time0=GetTickCount();
int movex=0, movey=0;
if (flags&AW_HOR_POSITIVE)
{
movex=rect.right-rect.left;
clipRect.left=rect.left;
}
else if (flags&AW_HOR_NEGATIVE)
{
movex=rect.left-rect.right;
clipRect.right=rect.right;
}
else if (flags&AW_VER_POSITIVE)
{
movey=rect.bottom-rect.top;
clipRect.top=rect.top;
}
else
{
movey=rect.top-rect.bottom;
clipRect.bottom=rect.bottom;
}
HRGN clipRgn=CreateRectRgn(clipRect.left-rect.left,clipRect.top-rect.top,clipRect.right-rect.left,clipRect.bottom-rect.top); // clip region in window space
while (true)
{
int dt=GetTickCount()-time0;
if (dt>speed) break;
float f=1-dt/(float)speed;
f=powf(f,5);
int dx=(int)(movex*f);
int dy=(int)(movey*f);
if (dx==0 && dy==0) break;
m_PaintOffset.x=-dx;
m_PaintOffset.y=-dy;
// calculate region
HRGN wndRgn=CreateRectRgn(0,0,rect.right-rect.left,rect.bottom-rect.top); // window region
if (rgn0)
CombineRgn(wndRgn,rgn0,NULL,RGN_COPY);
OffsetRgn(wndRgn,-dx,-dy);
HRGN rgn=CreateRectRgn(0,0,0,0);
CombineRgn(rgn,clipRgn,wndRgn,RGN_AND); // clipped window region
if (!SetWindowRgn(rgn,FALSE))
DeleteObject(rgn);
DeleteObject(wndRgn);
RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
// move user pic
if (bUserPic)
{
POINT pos={s_UserPictureRect.left-dx,s_UserPictureRect.top-dy};
s_UserPicture.UpdatePartial(pos,&clipRect);
}
}
DeleteObject(clipRgn);
m_PaintOffset.x=m_PaintOffset.y=0;
if (!SetWindowRgn(rgn0,FALSE) && rgn0)
DeleteObject(rgn0);
if (m_pProgramsTree && s_MenuMode==MODE_PROGRAMS)
m_pProgramsTree->ShowWindow(SW_SHOW);
RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
}
else
{
// no animation
SetWindowPos((flags&AW_TOPMOST)?HWND_TOPMOST:HWND_TOP,&rect,SWP_SHOWWINDOW|((flags&AW_ACTIVATE)?0:SWP_NOACTIVATE));
RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
if (bUserPic)
{
s_UserPicture.Update(255);
s_UserPicture.SetWindowPos(NULL,&s_UserPictureRect,SWP_NOZORDER|SWP_NOACTIVATE|SWP_SHOWWINDOW);
}
}
if (m_SearchBox.m_hWnd)
m_SearchBox.ShowWindow(SW_SHOW);
if (bUserPic)
{
POINT pos={s_UserPictureRect.left,s_UserPictureRect.top};
s_UserPicture.UpdatePartial(pos,NULL);
}
}