mirror of
https://github.com/Open-Shell/Open-Shell-Menu.git
synced 2026-04-12 01:47:24 +10:00
674 lines
19 KiB
C++
674 lines
19 KiB
C++
// 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
|
|
|
|
#include "stdafx.h"
|
|
#include "resource.h"
|
|
#include "Translations.h"
|
|
#include "Settings.h"
|
|
#include "SettingsUI.h"
|
|
#include "ResourceHelper.h"
|
|
#include "ItemManager.h"
|
|
#include "StartMenuDLL.h"
|
|
#include "StartButton.h"
|
|
#include "MenuContainer.h"
|
|
#include "TouchHelper.h"
|
|
#include "dllmain.h"
|
|
#include <uxtheme.h>
|
|
#include <vsstyle.h>
|
|
#include <vssym32.h>
|
|
#include <dwmapi.h>
|
|
|
|
static int START_ICON_SIZE=0;
|
|
const int START_BUTTON_PADDING=3;
|
|
const int START_BUTTON_OFFSET=2;
|
|
const int START_TEXT_PADDING=2;
|
|
const int BLEND_PRECISION=1000;
|
|
|
|
bool g_bAllowMoveButton;
|
|
|
|
// CStartButton - implementation of a start button (for Windows 8)
|
|
class CStartButton: public CWindowImpl<CStartButton>
|
|
{
|
|
public:
|
|
DECLARE_WND_CLASS_EX(L"OpenShell.CStartButton",CS_DBLCLKS,COLOR_MENU)
|
|
CStartButton( void );
|
|
|
|
// message handlers
|
|
BEGIN_MSG_MAP( CStartButton )
|
|
MESSAGE_HANDLER( WM_CREATE, OnCreate )
|
|
MESSAGE_HANDLER( WM_DESTROY, OnDestroy )
|
|
MESSAGE_HANDLER( WM_CLOSE, OnClose )
|
|
MESSAGE_HANDLER( WM_MOUSEACTIVATE, OnMouseActivate )
|
|
MESSAGE_HANDLER( WM_MOUSEMOVE, OnMouseMove )
|
|
MESSAGE_HANDLER( WM_ERASEBKGND, OnEraseBkgnd )
|
|
MESSAGE_HANDLER( WM_TIMER, OnTimer )
|
|
MESSAGE_HANDLER( WM_SETTINGCHANGE, OnSettingChange )
|
|
MESSAGE_HANDLER( WM_THEMECHANGED, OnThemeChanged )
|
|
MESSAGE_HANDLER( WM_POINTERDOWN, OnPointer )
|
|
MESSAGE_HANDLER( WM_POINTERUPDATE, OnPointer )
|
|
MESSAGE_HANDLER( WM_POINTERUP, OnPointer )
|
|
END_MSG_MAP()
|
|
|
|
void SetPressed( bool bPressed );
|
|
void UpdateButton( void );
|
|
void TaskBarMouseMove( void );
|
|
|
|
SIZE GetSize( void ) const { return m_Size; }
|
|
bool GetSmallIcons( void ) const { return m_bSmallIcons; }
|
|
|
|
protected:
|
|
LRESULT OnCreate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnClose( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { return 0; }
|
|
LRESULT OnEraseBkgnd( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { return 1; }
|
|
LRESULT OnMouseActivate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { return MA_NOACTIVATE; }
|
|
LRESULT OnMouseMove( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnSettingChange( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnThemeChanged( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnPointer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
|
|
private:
|
|
enum { TIMER_BLEND=1, TIMER_LEAVE=2 };
|
|
|
|
size_t m_TaskbarId;
|
|
SIZE m_Size;
|
|
HBITMAP m_Bitmap, m_Blendmap;
|
|
unsigned int *m_Bits, *m_BlendBits;
|
|
HICON m_Icon;
|
|
HFONT m_Font;
|
|
bool m_bHot, m_bPressed;
|
|
bool m_bTrackMouse;
|
|
bool m_bClassic;
|
|
bool m_bRTL;
|
|
bool m_bSmallIcons;
|
|
int m_HotBlend; // 0..BLEND_PRECISION
|
|
CWindow m_Tooltip;
|
|
HTHEME m_Theme;
|
|
|
|
// animations
|
|
int m_YOffset;
|
|
int m_Frames[3];
|
|
|
|
struct Animation
|
|
{
|
|
std::vector<int> frames;
|
|
int duration; // in ms
|
|
bool bBlend;
|
|
};
|
|
Animation m_Animations[2];
|
|
|
|
void ParseAnimation( Animation &animation, const std::vector<unsigned int> &pixels, int &index, int totalFrames );
|
|
void LoadBitmap( void );
|
|
void SetHot( bool bHot );
|
|
};
|
|
|
|
CStartButton::CStartButton( void )
|
|
{
|
|
m_Size.cx=m_Size.cy=0;
|
|
m_TaskbarId=-1;
|
|
m_Bitmap=m_Blendmap=NULL;
|
|
m_Bits=m_BlendBits=NULL;
|
|
m_Icon=NULL;
|
|
m_Font=NULL;
|
|
m_bHot=m_bPressed=false;
|
|
m_bTrackMouse=false;
|
|
m_bClassic=m_bSmallIcons=false;
|
|
m_bRTL=false;
|
|
m_HotBlend=0;
|
|
m_Theme=NULL;
|
|
}
|
|
|
|
LRESULT CStartButton::OnCreate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
size_t params=(intptr_t)(((CREATESTRUCT*)lParam)->lpCreateParams);
|
|
m_bRTL=(params&1)!=0;
|
|
m_TaskbarId=params>>1;
|
|
m_bSmallIcons=IsTaskbarSmallIcons();
|
|
std::vector<HMODULE> modules;
|
|
m_Icon=NULL;
|
|
START_ICON_SIZE=0;
|
|
CString iconPath=GetSettingString(L"StartButtonIcon");
|
|
if (_wcsicmp(iconPath,L"none")!=0)
|
|
{
|
|
START_ICON_SIZE=GetSettingInt(L"StartButtonIconSize");
|
|
if (START_ICON_SIZE==0)
|
|
START_ICON_SIZE=GetSystemMetrics(m_bSmallIcons?SM_CXSMICON:SM_CXICON);
|
|
if (START_ICON_SIZE<8) START_ICON_SIZE=8;
|
|
if (START_ICON_SIZE>64) START_ICON_SIZE=64;
|
|
m_Icon=LoadIcon(START_ICON_SIZE,iconPath,modules);
|
|
for (std::vector<HMODULE>::const_iterator it=modules.begin();it!=modules.end();++it)
|
|
FreeLibrary(*it);
|
|
if (!m_Icon)
|
|
m_Icon=(HICON)LoadImage(g_Instance,MAKEINTRESOURCE(IDI_APPICON),IMAGE_ICON,START_ICON_SIZE,START_ICON_SIZE,LR_DEFAULTCOLOR);
|
|
}
|
|
int dpi=CItemManager::GetDPI(false);
|
|
m_Font=CreateFont(MulDiv(10,dpi,72),0,0,0,FW_BOLD,0,0,0,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,L"Tahoma");
|
|
int val=1;
|
|
DwmSetWindowAttribute(m_hWnd,DWMWA_EXCLUDED_FROM_PEEK,&val,sizeof(val));
|
|
val=DWMFLIP3D_EXCLUDEABOVE;
|
|
DwmSetWindowAttribute(m_hWnd,DWMWA_FLIP3D_POLICY,&val,sizeof(val));
|
|
LoadBitmap();
|
|
m_Tooltip=CreateWindowEx(WS_EX_TOPMOST|WS_EX_TOOLWINDOW|WS_EX_TRANSPARENT|(m_bRTL?WS_EX_LAYOUTRTL:0),TOOLTIPS_CLASS,NULL,WS_POPUP|TTS_NOPREFIX|TTS_ALWAYSTIP,0,0,0,0,NULL,NULL,g_Instance,NULL);
|
|
OnThemeChanged(WM_THEMECHANGED,0,0,bHandled);
|
|
m_bPressed=true;
|
|
SetPressed(false);
|
|
ResizeClient(m_Size.cx,m_Size.cy);
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CStartButton::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_Bitmap) DeleteObject(m_Bitmap);
|
|
if (m_Blendmap) DeleteObject(m_Blendmap);
|
|
if (m_Icon) DestroyIcon(m_Icon);
|
|
if (m_Font) DeleteObject(m_Font);
|
|
if (m_Theme) CloseThemeData(m_Theme);
|
|
m_Tooltip.DestroyWindow();
|
|
KillTimer(TIMER_BLEND);
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
void CStartButton::UpdateButton( void )
|
|
{
|
|
BLENDFUNCTION func={AC_SRC_OVER,0,255,AC_SRC_ALPHA};
|
|
|
|
HDC hSrc=CreateCompatibleDC(NULL);
|
|
RECT rc;
|
|
GetWindowRect(&rc);
|
|
SIZE size={rc.right-rc.left,rc.bottom-rc.top};
|
|
if (m_bClassic)
|
|
{
|
|
if (m_bRTL)
|
|
SetLayout(hSrc,LAYOUT_RTL);
|
|
HGDIOBJ bmp0=SelectObject(hSrc,m_Blendmap);
|
|
RECT rc={0,0,m_Size.cx,m_Size.cy};
|
|
FillRect(hSrc,&rc,(HBRUSH)GetStockObject(BLACK_BRUSH));
|
|
InflateRect(&rc,-START_BUTTON_OFFSET,-START_BUTTON_OFFSET);
|
|
int offset=0;
|
|
if (m_Theme)
|
|
{
|
|
int state=m_bPressed?PBS_PRESSED:(m_bHot?PBS_HOT:PBS_NORMAL);
|
|
DrawThemeBackground(m_Theme,hSrc,BP_PUSHBUTTON,state,&rc,NULL);
|
|
}
|
|
else
|
|
{
|
|
DrawFrameControl(hSrc,&rc,DFC_BUTTON,DFCS_BUTTONPUSH|(m_bPressed?DFCS_PUSHED:0));
|
|
offset=m_bPressed?1:0;
|
|
}
|
|
if (m_Icon)
|
|
DrawIconEx(hSrc,START_BUTTON_PADDING+START_BUTTON_OFFSET+offset,(m_Size.cy-START_ICON_SIZE)/2+offset,m_Icon,0,0,0,NULL,DI_NORMAL|DI_NOMIRROR);
|
|
rc.left+=START_BUTTON_PADDING+START_ICON_SIZE+START_TEXT_PADDING+offset;
|
|
rc.top+=START_BUTTON_PADDING+offset;
|
|
rc.right-=START_BUTTON_PADDING+START_TEXT_PADDING-offset;
|
|
rc.bottom-=START_BUTTON_PADDING-offset;
|
|
HFONT font0=(HFONT)SelectObject(hSrc,m_Font);
|
|
COLORREF color=GetSysColor(COLOR_BTNTEXT);
|
|
if (m_Theme)
|
|
{
|
|
int state=m_bPressed?PBS_PRESSED:(m_bHot?PBS_HOT:PBS_NORMAL);
|
|
if (FAILED(GetThemeColor(m_Theme,BP_PUSHBUTTON,state,TMT_TEXTCOLOR,&color)))
|
|
color=GetSysColor(COLOR_BTNTEXT);
|
|
}
|
|
SetTextColor(hSrc,color);
|
|
SetBkMode(hSrc,TRANSPARENT);
|
|
CString startStr=GetSettingString(L"StartButtonText");
|
|
const wchar_t *startText=startStr;
|
|
if (startText[0]=='$')
|
|
startText=FindTranslation(startText+1,L"Start");
|
|
DrawText(hSrc,startText,-1,&rc,DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER);
|
|
SelectObject(hSrc,bmp0);
|
|
// mark the button pixels as opaque
|
|
for (int y=START_BUTTON_OFFSET;y<m_Size.cy-START_BUTTON_OFFSET;y++)
|
|
for (int x=START_BUTTON_OFFSET;x<m_Size.cx-START_BUTTON_OFFSET;x++)
|
|
m_BlendBits[y*m_Size.cx+x]|=0xFF000000;
|
|
SelectObject(hSrc,m_Blendmap);
|
|
|
|
POINT pos={0,0};
|
|
UpdateLayeredWindow(m_hWnd,NULL,NULL,&size,hSrc,&pos,0,&func,ULW_ALPHA);
|
|
SelectObject(hSrc,font0);
|
|
SelectObject(hSrc,bmp0);
|
|
}
|
|
else
|
|
{
|
|
int image=-1;
|
|
int frame1, frame2, blend;
|
|
if (m_bPressed) image=m_Frames[2];
|
|
else if (m_HotBlend==0) image=m_Frames[0];
|
|
else if (m_HotBlend==BLEND_PRECISION) image=m_Frames[1];
|
|
else
|
|
{
|
|
const Animation &animation=m_Animations[m_bHot?0:1];
|
|
int count=(int)animation.frames.size()-1;
|
|
blend=m_bHot?m_HotBlend:(BLEND_PRECISION-m_HotBlend);
|
|
if (count<1 || animation.duration==0)
|
|
{
|
|
image=m_Frames[m_bHot?1:0];
|
|
}
|
|
else if (!animation.bBlend)
|
|
{
|
|
int index=(blend*count+50)/BLEND_PRECISION; // [0..count]
|
|
image=animation.frames[index];
|
|
}
|
|
else
|
|
{
|
|
int index=(blend*count)/BLEND_PRECISION; // [0..count-1]
|
|
blend=(blend*count)%BLEND_PRECISION;
|
|
|
|
frame1=animation.frames[index];
|
|
frame2=animation.frames[index+1];
|
|
}
|
|
}
|
|
|
|
if (image!=-1)
|
|
{
|
|
HGDIOBJ bmp0=SelectObject(hSrc,m_Bitmap);
|
|
POINT pos={0,image*m_Size.cy+m_YOffset};
|
|
UpdateLayeredWindow(m_hWnd,NULL,NULL,&size,hSrc,&pos,0,&func,ULW_ALPHA);
|
|
SelectObject(hSrc,bmp0);
|
|
}
|
|
else if (m_Bits)
|
|
{
|
|
// blend the two images
|
|
int n=m_Size.cx*m_Size.cy;
|
|
int n1=frame1*n;
|
|
int n2=frame2*n;
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
unsigned int pixel1=m_Bits[i+n1];
|
|
unsigned int pixel2=m_Bits[i+n2];
|
|
int a1=(pixel1>>24);
|
|
int r1=(pixel1>>16)&255;
|
|
int g1=(pixel1>>8)&255;
|
|
int b1=(pixel1)&255;
|
|
int a2=(pixel2>>24);
|
|
int r2=(pixel2>>16)&255;
|
|
int g2=(pixel2>>8)&255;
|
|
int b2=(pixel2)&255;
|
|
int a=a1+(a2-a1)*blend/BLEND_PRECISION;
|
|
int r=r1+(r2-r1)*blend/BLEND_PRECISION;
|
|
int g=g1+(g2-g1)*blend/BLEND_PRECISION;
|
|
int b=b1+(b2-b1)*blend/BLEND_PRECISION;
|
|
m_BlendBits[i]=(a<<24)|(r<<16)|(g<<8)|b;
|
|
}
|
|
HGDIOBJ bmp0=SelectObject(hSrc,m_Blendmap);
|
|
POINT pos={0,0};
|
|
UpdateLayeredWindow(m_hWnd,NULL,NULL,&size,hSrc,&pos,0,&func,ULW_ALPHA);
|
|
SelectObject(hSrc,bmp0);
|
|
}
|
|
}
|
|
DeleteDC(hSrc);
|
|
}
|
|
|
|
void CStartButton::SetHot( bool bHot )
|
|
{
|
|
if (m_bHot!=bHot)
|
|
{
|
|
m_bHot=bHot;
|
|
if (!m_bPressed)
|
|
{
|
|
if (bHot)
|
|
CMenuContainer::PlayMenuSound(SOUND_BUTTON_HOVER);
|
|
SetTimer(TIMER_BLEND,30);
|
|
}
|
|
}
|
|
}
|
|
|
|
LRESULT CStartButton::OnMouseMove( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
SetTimer(TIMER_LEAVE,30);
|
|
SetHot(true);
|
|
return 0;
|
|
}
|
|
|
|
void CStartButton::TaskBarMouseMove( void )
|
|
{
|
|
SetHot(true);
|
|
SetTimer(CStartButton::TIMER_LEAVE,30);
|
|
}
|
|
|
|
LRESULT CStartButton::OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (wParam==TIMER_BLEND)
|
|
{
|
|
int duration=m_Animations[m_bHot?0:1].duration;
|
|
int blend;
|
|
if (duration>0)
|
|
{
|
|
int dp=(30*BLEND_PRECISION)/duration;
|
|
blend=m_HotBlend+(m_bHot?dp:-dp);
|
|
if (blend<0) blend=0;
|
|
if (blend>BLEND_PRECISION) blend=BLEND_PRECISION;
|
|
}
|
|
else
|
|
{
|
|
blend=m_bHot?BLEND_PRECISION:0;
|
|
}
|
|
if (blend!=m_HotBlend)
|
|
{
|
|
m_HotBlend=blend;
|
|
UpdateButton();
|
|
}
|
|
else
|
|
KillTimer(TIMER_BLEND);
|
|
}
|
|
else if (wParam==TIMER_LEAVE)
|
|
{
|
|
CPoint pt(GetMessagePos());
|
|
if (WindowFromPoint(pt)!=m_hWnd && !PointAroundStartButton(m_TaskbarId))
|
|
{
|
|
KillTimer(TIMER_LEAVE);
|
|
SetHot(false);
|
|
}
|
|
}
|
|
else
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CStartButton::OnSettingChange( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
UpdateButton();
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CStartButton::OnThemeChanged( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_Theme) CloseThemeData(m_Theme);
|
|
m_Theme=NULL;
|
|
HIGHCONTRAST contrast={sizeof(contrast)};
|
|
if (GetWinVersion()>=WIN_VER_WIN8 && SystemParametersInfo(SPI_GETHIGHCONTRAST,sizeof(contrast),&contrast,0) && (contrast.dwFlags&HCF_HIGHCONTRASTON))
|
|
{
|
|
// only use themes on Win8 with high contrast
|
|
m_Theme=OpenThemeData(m_hWnd,L"button");
|
|
UpdateButton();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CStartButton::OnPointer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
POINTER_INPUT_TYPE type;
|
|
GetPointerType2(GET_POINTERID_WPARAM(wParam),&type);
|
|
if (type==PT_TOUCH)
|
|
return GetParent().SendMessage(uMsg,wParam,lParam);
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
void CStartButton::SetPressed( bool bPressed )
|
|
{
|
|
if (m_bPressed!=bPressed)
|
|
{
|
|
m_bPressed=bPressed;
|
|
m_HotBlend=m_bHot?BLEND_PRECISION:0;
|
|
KillTimer(TIMER_BLEND);
|
|
TOOLINFO tool={sizeof(tool),TTF_CENTERTIP|TTF_SUBCLASS|TTF_IDISHWND|TTF_TRANSPARENT|(m_bRTL?TTF_RTLREADING:0U),m_hWnd};
|
|
tool.uId=(UINT_PTR)m_hWnd;
|
|
CString startStr=GetSettingString(L"StartButtonTip");
|
|
const wchar_t *startText=startStr;
|
|
if (startText[0]=='$')
|
|
startText=FindTranslation(startText+1,L"Start");
|
|
wchar_t buf[256];
|
|
Strcpy(buf,_countof(buf),startText);
|
|
DoEnvironmentSubst(buf,_countof(buf));
|
|
tool.lpszText=buf;
|
|
m_Tooltip.SendMessage(bPressed?TTM_DELTOOL:TTM_ADDTOOL,0,(LPARAM)&tool);
|
|
UpdateButton();
|
|
}
|
|
}
|
|
|
|
TStartButtonType GetStartButtonType( void )
|
|
{
|
|
bool bDef;
|
|
TStartButtonType buttonType=(TStartButtonType)GetSettingInt(L"StartButtonType",bDef);
|
|
if (bDef)
|
|
{
|
|
bool bClassic;
|
|
if (GetWinVersion()<WIN_VER_WIN8)
|
|
bClassic=!IsAppThemed();
|
|
else
|
|
{
|
|
HIGHCONTRAST contrast={sizeof(contrast)};
|
|
bClassic=(SystemParametersInfo(SPI_GETHIGHCONTRAST,sizeof(contrast),&contrast,0) && (contrast.dwFlags&HCF_HIGHCONTRASTON));
|
|
}
|
|
buttonType=bClassic?START_BUTTON_CLASSIC:START_BUTTON_AERO;
|
|
}
|
|
return buttonType;
|
|
}
|
|
|
|
void CStartButton::ParseAnimation( Animation &animation, const std::vector<unsigned int> &pixels, int &index, int totalFrames )
|
|
{
|
|
animation.duration=0;
|
|
animation.bBlend=true;
|
|
if (index>=(int)pixels.size())
|
|
{
|
|
animation.frames.clear();
|
|
return;
|
|
}
|
|
|
|
animation.duration=((pixels[index]&255)*1000)/60;
|
|
animation.bBlend=((pixels[index]>>16)&255)==1;
|
|
int ranges=(pixels[index]>>8)&255;
|
|
if (ranges>0 && index+ranges<(int)pixels.size())
|
|
{
|
|
animation.frames.clear();
|
|
for (int r=1;r<=ranges;r++)
|
|
{
|
|
int from=pixels[index+r]&255;
|
|
if (from>totalFrames-1) from=totalFrames-1;
|
|
int to=(pixels[index+r]>>16)&255;
|
|
if (to>totalFrames-1) to=totalFrames-1;
|
|
if (from<to)
|
|
{
|
|
for (int i=from;i<=to;i++)
|
|
animation.frames.push_back(i);
|
|
}
|
|
else if (from>to)
|
|
{
|
|
for (int i=from;i>=to;i--)
|
|
animation.frames.push_back(i);
|
|
}
|
|
else
|
|
{
|
|
animation.frames.push_back(from);
|
|
}
|
|
}
|
|
}
|
|
index+=ranges+1;
|
|
}
|
|
|
|
void CStartButton::LoadBitmap( void )
|
|
{
|
|
m_Size.cx=m_Size.cy=0;
|
|
if (m_Bitmap) DeleteObject(m_Bitmap);
|
|
if (m_Blendmap) DeleteObject(m_Blendmap);
|
|
m_Bitmap=m_Blendmap=NULL;
|
|
m_Bits=m_BlendBits=NULL;
|
|
TStartButtonType buttonType=GetStartButtonType();
|
|
m_bClassic=(buttonType==START_BUTTON_CLASSIC);
|
|
wchar_t path[_MAX_PATH];
|
|
SIZE size={0,0};
|
|
if (buttonType==START_BUTTON_CUSTOM)
|
|
{
|
|
Strcpy(path,_countof(path),GetSettingString(L"StartButtonPath"));
|
|
DoEnvironmentSubst(path,_countof(path));
|
|
size.cx=GetSettingInt(L"StartButtonSize");
|
|
}
|
|
|
|
m_YOffset=0;
|
|
m_Frames[0]=0; // Normal
|
|
m_Frames[1]=1; // Hot
|
|
m_Frames[2]=2; // Pressed
|
|
m_Animations[0].frames.resize(2); m_Animations[0].frames[0]=0; m_Animations[0].frames[1]=1; m_Animations[0].duration=300; m_Animations[0].bBlend=true; // NH
|
|
m_Animations[1].frames.resize(2); m_Animations[1].frames[0]=1; m_Animations[1].frames[1]=0; m_Animations[1].duration=300; m_Animations[1].bBlend=true; // HN
|
|
|
|
if (m_bClassic)
|
|
{
|
|
// classic theme
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
HFONT font0=(HFONT)SelectObject(hdc,m_Font);
|
|
RECT rc={0,0,0,0};
|
|
CString startStr=GetSettingString(L"StartButtonText");
|
|
const wchar_t *startText=startStr;
|
|
if (startText[0]=='$')
|
|
startText=FindTranslation(startText+1,L"Start");
|
|
DrawText(hdc,startText,-1,&rc,DT_NOPREFIX|DT_SINGLELINE|DT_CALCRECT);
|
|
m_Size.cx=rc.right+START_ICON_SIZE+2*START_TEXT_PADDING+2*START_BUTTON_PADDING+2*START_BUTTON_OFFSET;
|
|
m_Size.cy=rc.bottom;
|
|
if (m_Size.cy<START_ICON_SIZE) m_Size.cy=START_ICON_SIZE;
|
|
m_Size.cy+=2*START_BUTTON_PADDING+2*START_BUTTON_OFFSET;
|
|
DeleteDC(hdc);
|
|
}
|
|
else
|
|
{
|
|
int dpi=GetDpi(GetParent());
|
|
bool bResource=false;
|
|
std::vector<unsigned int> buttonAnim;
|
|
if (*path)
|
|
{
|
|
m_Bitmap=LoadImageFile(path,&size,true,true,&buttonAnim,dpi);
|
|
}
|
|
if (!m_Bitmap)
|
|
{
|
|
int id;
|
|
if (dpi<120)
|
|
id=IDB_BUTTON96;
|
|
else if (dpi<144)
|
|
id=IDB_BUTTON120;
|
|
else if (dpi<168)
|
|
id=IDB_BUTTON144;
|
|
else
|
|
id=IDB_BUTTON180;
|
|
m_Bitmap=LoadImageResource(g_Instance,MAKEINTRESOURCE(id),true,true);
|
|
bResource=true;
|
|
}
|
|
BITMAP info;
|
|
GetObject(m_Bitmap,sizeof(info),&info);
|
|
m_Size.cx=info.bmWidth;
|
|
m_Size.cy=info.bmHeight;
|
|
m_Bits=(unsigned int*)info.bmBits;
|
|
if (buttonAnim.empty() && info.bmWidth>=10 && (m_Bits[0]&0xFFFFFF)==ANIM_BUTTON_TAG1 && (m_Bits[1]&0xFFFFFF)==ANIM_BUTTON_TAG2)
|
|
{
|
|
m_YOffset=(m_Bits[2]>>16)&255;
|
|
if (m_YOffset>info.bmHeight) m_YOffset=info.bmHeight;
|
|
if (m_YOffset>0)
|
|
{
|
|
int size=info.bmWidth*m_YOffset;
|
|
buttonAnim.resize(size);
|
|
memcpy(&buttonAnim[0],m_Bits,size*4);
|
|
m_Bits+=size;
|
|
m_Size.cy=info.bmHeight-m_YOffset;
|
|
}
|
|
}
|
|
if (!buttonAnim.empty())
|
|
{
|
|
int total=buttonAnim[2]&255;
|
|
if (total<1) total=1;
|
|
if (total>info.bmHeight-1) total=info.bmHeight-1;
|
|
m_Size.cy/=total;
|
|
m_Frames[0]=buttonAnim[3]&255; // Normal
|
|
if (m_Frames[0]>total-1) m_Frames[0]=total-1;
|
|
m_Frames[1]=buttonAnim[4]&255; // Hot
|
|
if (m_Frames[1]>total-1) m_Frames[1]=total-1;
|
|
m_Frames[2]=buttonAnim[5]&255; // Pressed
|
|
if (m_Frames[2]>total-1) m_Frames[2]=total-1;
|
|
|
|
m_Animations[0].frames[0]=m_Animations[1].frames[1]=m_Frames[0];
|
|
m_Animations[0].frames[1]=m_Animations[1].frames[0]=m_Frames[1];
|
|
int index=6;
|
|
ParseAnimation(m_Animations[0],buttonAnim,index,total);
|
|
ParseAnimation(m_Animations[1],buttonAnim,index,total);
|
|
}
|
|
else
|
|
{
|
|
m_Size.cy/=3;
|
|
}
|
|
}
|
|
if (m_Size.cx>0)
|
|
{
|
|
BITMAPINFO bi={0};
|
|
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
|
|
bi.bmiHeader.biWidth=m_Size.cx;
|
|
bi.bmiHeader.biHeight=-m_Size.cy;
|
|
bi.bmiHeader.biPlanes=1;
|
|
bi.bmiHeader.biBitCount=32;
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
m_Blendmap=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,(void**)&m_BlendBits,NULL,0);
|
|
DeleteDC(hdc);
|
|
}
|
|
}
|
|
|
|
static std::map<int,CStartButton> g_StartButtons;
|
|
|
|
HWND CreateStartButton( int taskbarId, HWND taskBar, HWND rebar )
|
|
{
|
|
bool bRTL=(GetWindowLongPtr(rebar,GWL_EXSTYLE)&WS_EX_LAYOUTRTL)!=0;
|
|
DWORD styleTopmost=GetWindowLongPtr(taskBar,GWL_EXSTYLE)&WS_EX_TOPMOST;
|
|
CStartButton &button=g_StartButtons[taskbarId];
|
|
button.Create(taskBar,NULL,NULL,WS_POPUP,styleTopmost|WS_EX_TOOLWINDOW|WS_EX_LAYERED,0U,(void*)(intptr_t)(taskbarId*2+(bRTL?1:0)));
|
|
return button.m_hWnd;
|
|
}
|
|
|
|
void DestroyStartButton( int taskbarId )
|
|
{
|
|
std::map<int,CStartButton>::iterator it=g_StartButtons.find(taskbarId);
|
|
if (it!=g_StartButtons.end())
|
|
{
|
|
if (it->second.m_hWnd)
|
|
it->second.DestroyWindow();
|
|
g_StartButtons.erase(it);
|
|
}
|
|
}
|
|
|
|
void UpdateStartButton( int taskbarId )
|
|
{
|
|
std::map<int,CStartButton>::iterator it=g_StartButtons.find(taskbarId);
|
|
if (it!=g_StartButtons.end())
|
|
it->second.UpdateButton();
|
|
}
|
|
|
|
void PressStartButton( int taskbarId, bool bPressed )
|
|
{
|
|
std::map<int,CStartButton>::iterator it=g_StartButtons.find(taskbarId);
|
|
if (it!=g_StartButtons.end())
|
|
it->second.SetPressed(bPressed);
|
|
}
|
|
|
|
SIZE GetStartButtonSize( int taskbarId )
|
|
{
|
|
std::map<int,CStartButton>::iterator it=g_StartButtons.find(taskbarId);
|
|
if (it!=g_StartButtons.end())
|
|
return it->second.GetSize();
|
|
SIZE size={0,0};
|
|
return size;
|
|
}
|
|
|
|
bool IsStartButtonSmallIcons( int taskbarId )
|
|
{
|
|
std::map<int,CStartButton>::iterator it=g_StartButtons.find(taskbarId);
|
|
if (it!=g_StartButtons.end())
|
|
return it->second.GetSmallIcons();
|
|
return false;
|
|
}
|
|
|
|
bool IsTaskbarSmallIcons( void )
|
|
{
|
|
CRegKey regKey;
|
|
if (regKey.Open(HKEY_CURRENT_USER,L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced")!=ERROR_SUCCESS)
|
|
return true;
|
|
DWORD val;
|
|
return regKey.QueryDWORDValue(L"TaskbarSmallIcons",val)!=ERROR_SUCCESS || val;
|
|
}
|
|
|
|
void TaskBarMouseMove( int taskbarId )
|
|
{
|
|
std::map<int,CStartButton>::iterator it=g_StartButtons.find(taskbarId);
|
|
if (it!=g_StartButtons.end())
|
|
it->second.TaskBarMouseMove();
|
|
}
|