mirror of
https://github.com/Open-Shell/Open-Shell-Menu.git
synced 2026-04-11 17:37:22 +10:00
Debug StartMenuDLL used to not find skins when put to Open-Shell installation folder. Now it will try to look for skins in default location (Skins folder in the same folder as DLL) and use alternative (Skins folder one level up) if not present.
3320 lines
103 KiB
C++
3320 lines
103 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 "SkinManager.h"
|
|
#include "ItemManager.h"
|
|
#include "LogManager.h"
|
|
#include "SettingsParser.h"
|
|
#include "Settings.h"
|
|
#include "SettingsUI.h"
|
|
#include "Translations.h"
|
|
#include "ResourceHelper.h"
|
|
#include "FNVHash.h"
|
|
#include "dllmain.h"
|
|
#include "IatHookHelper.h"
|
|
#include "MenuContainer.h"
|
|
#include "ProgramsTree.h"
|
|
#include <dwmapi.h>
|
|
#include <math.h>
|
|
|
|
//#define SIMULATE_METRO_COLORS "win8_blue"
|
|
|
|
#ifdef BUILD_SETUP
|
|
#undef SIMULATE_METRO_COLORS
|
|
#endif
|
|
|
|
static struct
|
|
{
|
|
const wchar_t *name;
|
|
int code;
|
|
} g_SystemColors[]=
|
|
{
|
|
{L"SystemScrollbar",COLOR_SCROLLBAR},
|
|
{L"SystemBackground",COLOR_BACKGROUND},
|
|
{L"SystemActiveCaption",COLOR_ACTIVECAPTION},
|
|
{L"SystemInactiveCaption",COLOR_INACTIVECAPTION},
|
|
{L"SystemMenu",COLOR_MENU},
|
|
{L"SystemWindow",COLOR_WINDOW},
|
|
{L"SystemWindowFrame",COLOR_WINDOWFRAME},
|
|
{L"SystemMenuText",COLOR_MENUTEXT},
|
|
{L"SystemWindowText",COLOR_WINDOWTEXT},
|
|
{L"SystemCaptionText",COLOR_CAPTIONTEXT},
|
|
{L"SystemActiveBorder",COLOR_ACTIVEBORDER},
|
|
{L"SystemInactiveBorder",COLOR_INACTIVEBORDER},
|
|
{L"SystemAppWorkspace",COLOR_APPWORKSPACE},
|
|
{L"SystemHighlight",COLOR_HIGHLIGHT},
|
|
{L"SystemHighlightText",COLOR_HIGHLIGHTTEXT},
|
|
{L"SystemBtnFace",COLOR_BTNFACE},
|
|
{L"SystemBtnShadow",COLOR_BTNSHADOW},
|
|
{L"SystemGrayText",COLOR_GRAYTEXT},
|
|
{L"SystemBtnText",COLOR_BTNTEXT},
|
|
{L"SystemInactiveCaptionText",COLOR_INACTIVECAPTIONTEXT},
|
|
{L"SystemBtnHighlight",COLOR_BTNHIGHLIGHT},
|
|
{L"System3DDKShadow",COLOR_3DDKSHADOW},
|
|
{L"System3DLight",COLOR_3DLIGHT},
|
|
{L"SystemInfoText",COLOR_INFOTEXT},
|
|
{L"SystemInfoBK",COLOR_INFOBK},
|
|
{L"SystemHotLight",COLOR_HOTLIGHT},
|
|
{L"SystemGradientActiveCaption",COLOR_GRADIENTACTIVECAPTION},
|
|
{L"SystemGradientInactiveCaption",COLOR_GRADIENTINACTIVECAPTION},
|
|
{L"SystemMenuHilight",COLOR_MENUHILIGHT},
|
|
{L"SystemMenuBar",COLOR_MENUBAR},
|
|
};
|
|
|
|
wchar_t MenuSkin::s_SkinError[1024];
|
|
|
|
const RECT DEFAULT_ICON_PADDING={3,3,3,3};
|
|
const RECT DEFAULT_TEXT_PADDING={1,2,8,2};
|
|
const SIZE DEFAULT_ARROW_PADDING={5,7};
|
|
const int DEFAULT_SEPARATOR_WIDTH=4;
|
|
const int DEFAULT_SEPARATOR_HEIGHT=8;
|
|
const POINT DEFAULT_USER_IMAGE_PADDING={-4,8};
|
|
const RECT DEFAULT_SEARCH_PADDING={4,4,4,4};
|
|
|
|
static int g_GlassColorR, g_GlassColorG, g_GlassColorB, g_GlassColorA;
|
|
|
|
#ifdef SIMULATE_METRO_COLORS
|
|
struct SimMetroColor
|
|
{
|
|
unsigned int nameHash;
|
|
COLORREF color;
|
|
};
|
|
static std::vector<SimMetroColor> g_MetroColors;
|
|
|
|
static int GetImmersiveUserColorSetPreference( bool bForceCheckRegistry, bool bSkipCheckOnFail )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static COLORREF GetImmersiveColorFromColorSetEx( UINT dwImmersiveColorSet, UINT dwImmersiveColorType, bool bIgnoreHighContrast, UINT dwHighContrastCacheMode )
|
|
{
|
|
return g_MetroColors[dwImmersiveColorType].color;
|
|
}
|
|
|
|
static int GetImmersiveColorTypeFromName( const wchar_t *name )
|
|
{
|
|
if (wcsncmp(name,L"Immersive",9)==0)
|
|
{
|
|
unsigned int crc=CalcFNVHash(name+9);
|
|
for (int i=0;i<(int)g_MetroColors.size();i++)
|
|
if (g_MetroColors[i].nameHash==crc)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
#else
|
|
typedef int (WINAPI *TGetImmersiveUserColorSetPreference)(bool bForceCheckRegistry, bool bSkipCheckOnFail);
|
|
typedef COLORREF (WINAPI *TGetImmersiveColorFromColorSetEx)(UINT dwImmersiveColorSet, UINT dwImmersiveColorType, bool bIgnoreHighContrast, UINT dwHighContrastCacheMode);
|
|
typedef int (WINAPI *TGetImmersiveColorTypeFromName)(const wchar_t *name);
|
|
|
|
static TGetImmersiveUserColorSetPreference GetImmersiveUserColorSetPreference;
|
|
static TGetImmersiveColorFromColorSetEx GetImmersiveColorFromColorSetEx;
|
|
static TGetImmersiveColorTypeFromName GetImmersiveColorTypeFromName;
|
|
#endif
|
|
static int g_CurrentMetroColorSet;
|
|
|
|
void MenuBitmap::Init( bool bIsColor )
|
|
{
|
|
bIsBitmap=!bIsColor;
|
|
bIsOwned=false;
|
|
bitmap=NULL;
|
|
}
|
|
|
|
void MenuBitmap::Reset( bool bIsColor )
|
|
{
|
|
if (bIsOwned && GetBitmap())
|
|
{
|
|
BOOL res=DeleteObject(bitmap);
|
|
Assert(res);
|
|
}
|
|
Init(bIsColor);
|
|
}
|
|
|
|
MenuSkin::MenuSkin( void )
|
|
{
|
|
Hash=0;
|
|
AboutIcon=NULL;
|
|
BOwnHintFont=false;
|
|
BHasScrollbar=false;
|
|
BHasMetroColors=false;
|
|
Main_bitmap.Init();
|
|
Main_bitmap_search.Init();
|
|
Main_bitmap_jump.Init();
|
|
Caption_font=NULL;
|
|
User_font=NULL;
|
|
Main_separatorV.Init();
|
|
Main_pager.Init();
|
|
Main_pager_arrows.Init();
|
|
User_bitmap.Init();
|
|
User_mask.Init();
|
|
Programs_icon.Init();
|
|
Programs_icon_selected.Init();
|
|
Scrollbar_button.Init();
|
|
Scrollbar_arrows.Init();
|
|
Scrollbar_background.Init();
|
|
Scrollbar_thumb.Init();
|
|
Scrollbar_gripper.Init();
|
|
Submenu_bitmap.Init();
|
|
Submenu_separatorV.Init();
|
|
Submenu_pager.Init();
|
|
Submenu_pager_arrows.Init();
|
|
Pin_bitmap.Init();
|
|
More_bitmap.Init();
|
|
Shutdown_bitmap.Init();
|
|
Search_bitmap.Init();
|
|
Search_arrow.Init();
|
|
Search_background.Init();
|
|
Search_background_search.Init();
|
|
Search_background_jump.Init();
|
|
for (int i=0;i<_countof(Main_emblems);i++)
|
|
Main_emblems[i].Init();
|
|
Main_emblem_mask.Init();
|
|
Main_emblem_search_mask.Init();
|
|
Main_emblem_jump_mask.Init();
|
|
Search_emblem_mask.Init();
|
|
Search_emblem_search_mask.Init();
|
|
Search_emblem_jump_mask.Init();
|
|
for (int i=0;i<_countof(Patterns);i++)
|
|
Patterns[i].Init();
|
|
Main_pattern_mask.Init();
|
|
Main_pattern_search_mask.Init();
|
|
Main_pattern_jump_mask.Init();
|
|
Search_pattern_mask.Init();
|
|
Search_pattern_search_mask.Init();
|
|
Search_pattern_jump_mask.Init();
|
|
Search_hint_font=NULL;
|
|
Search_underline_font=NULL;
|
|
for (int i=0;i<_countof(ItemSettings);i++)
|
|
ItemSettings[i].Init();
|
|
}
|
|
|
|
void MenuSkin::ItemDrawSettings::Init( void )
|
|
{
|
|
font=NULL;
|
|
bOwnFont=true;
|
|
glowSize=0;
|
|
memset(textColors,0,sizeof(textColors));
|
|
memset(textShadowColors,-1,sizeof(textShadowColors));
|
|
memset(&textPadding,0,sizeof(textPadding));
|
|
memset(selSlicesX,0,sizeof(selSlicesX));
|
|
memset(selSlicesY,0,sizeof(selSlicesY));
|
|
arrSize.cx=arrSize.cy=0;
|
|
memset(arrColors,0,sizeof(arrColors));
|
|
arrPadding.cx=arrPadding.cy=0;
|
|
memset(frameSlicesX,0,sizeof(frameSlicesX));
|
|
memset(frameSlicesY,0,sizeof(frameSlicesY));
|
|
iconFrameOffset.x=iconFrameOffset.y=0;
|
|
memset(&iconPadding,0,sizeof(iconPadding));
|
|
memset(sepSlicesX,0,sizeof(sepSlicesX));
|
|
sepHeight=0;
|
|
opacity=MenuSkin::OPACITY_SOLID;
|
|
textTopOffset=iconTopOffset=0;
|
|
|
|
bmpSelection.Init();
|
|
bmpArrow.Init();
|
|
bmpIconFrame.Init();
|
|
bmpSeparator.Init();
|
|
}
|
|
|
|
void MenuSkin::ItemDrawSettings::Reset( void )
|
|
{
|
|
if (font && bOwnFont)
|
|
{
|
|
DeleteObject(font);
|
|
font=NULL;
|
|
bOwnFont=true;
|
|
}
|
|
bmpSelection.Reset();
|
|
bmpArrow.Reset();
|
|
bmpIconFrame.Reset();
|
|
bmpSeparator.Reset();
|
|
}
|
|
|
|
MenuSkin::~MenuSkin( void )
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
void MenuSkin::Reset( void )
|
|
{
|
|
if (AboutIcon) DestroyIcon(AboutIcon);
|
|
AboutIcon=NULL;
|
|
Main_bitmap.Reset();
|
|
Main_bitmap_search.Reset();
|
|
Main_bitmap_jump.Reset();
|
|
if (Caption_font) DeleteObject(Caption_font);
|
|
Caption_font=NULL;
|
|
if (User_font) DeleteObject(User_font);
|
|
User_font=NULL;
|
|
Main_separatorV.Reset();
|
|
User_bitmap.Reset();
|
|
User_mask.Reset();
|
|
Programs_icon.Reset();
|
|
Programs_icon_selected.Reset();
|
|
Scrollbar_button.Reset();
|
|
Scrollbar_arrows.Reset();
|
|
Scrollbar_background.Reset();
|
|
Scrollbar_thumb.Reset();
|
|
Scrollbar_gripper.Reset();
|
|
Submenu_bitmap.Reset();
|
|
Submenu_separatorV.Reset();
|
|
Main_pager.Reset();
|
|
Main_pager_arrows.Reset();
|
|
Submenu_pager.Reset();
|
|
Submenu_pager_arrows.Reset();
|
|
Pin_bitmap.Reset();
|
|
More_bitmap.Reset();
|
|
Shutdown_bitmap.Reset();
|
|
Search_bitmap.Reset();
|
|
Search_arrow.Reset();
|
|
Search_background.Reset();
|
|
Search_background_search.Reset();
|
|
Search_background_jump.Reset();
|
|
for (int i=0;i<_countof(Main_emblems);i++)
|
|
Main_emblems[i].Reset();
|
|
Main_emblem_mask.Reset();
|
|
Main_emblem_search_mask.Reset();
|
|
Main_emblem_jump_mask.Reset();
|
|
Search_emblem_mask.Reset();
|
|
Search_emblem_search_mask.Reset();
|
|
Search_emblem_jump_mask.Reset();
|
|
for (int i=0;i<_countof(Patterns);i++)
|
|
{
|
|
Patterns[i].Reset();
|
|
PatternBits[i].clear();
|
|
}
|
|
Main_pattern_mask.Reset();
|
|
Main_pattern_search_mask.Reset();
|
|
Main_pattern_jump_mask.Reset();
|
|
Search_pattern_mask.Reset();
|
|
Search_pattern_search_mask.Reset();
|
|
Search_pattern_jump_mask.Reset();
|
|
PatternPretileWidth=0;
|
|
if (Search_hint_font && BOwnHintFont) DeleteObject(Search_hint_font);
|
|
BOwnHintFont=false;
|
|
BHasScrollbar=false;
|
|
BHasMetroColors=false;
|
|
Search_hint_font=NULL;
|
|
if (Search_underline_font) DeleteObject(Search_underline_font);
|
|
Search_underline_font=NULL;
|
|
for (int i=0;i<_countof(ItemSettings);i++)
|
|
ItemSettings[i].Reset();
|
|
|
|
for (std::vector<CustomBitmap>::const_iterator it=CustomBitmaps.begin();it!=CustomBitmaps.end();++it)
|
|
DeleteObject(it->bitmap);
|
|
CustomBitmaps.clear();
|
|
|
|
Options.clear();
|
|
Variations.clear();
|
|
Hash=0;
|
|
MetroColorHash=0;
|
|
MetroColors.clear();
|
|
}
|
|
|
|
static void GetErrorMessage( wchar_t *err, int size, DWORD code )
|
|
{
|
|
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,NULL,code,0,err,size,NULL);
|
|
}
|
|
|
|
int MenuSkin::ScaleSkinElement( int num, int scale ) const
|
|
{
|
|
int ddpi=Dpi-96;
|
|
if (ddpi<=0)
|
|
return num;
|
|
if (num<0)
|
|
return (num*(9600+ddpi*scale)-4800)/9600;
|
|
else
|
|
return (num*(9600+ddpi*scale)+4800)/9600;
|
|
}
|
|
|
|
COLORREF MenuSkin::GetMetroColor( const wchar_t *names ) const
|
|
{
|
|
unsigned int crc=CalcFNVHash(names);
|
|
std::map<unsigned int,MetroColor>::const_iterator it=MetroColors.find(crc);
|
|
if (it!=MetroColors.end())
|
|
return it->second.color;
|
|
|
|
MetroColor data={0};
|
|
|
|
wchar_t name[100];
|
|
while (*names)
|
|
{
|
|
if (names[0]=='#')
|
|
{
|
|
wchar_t *end;
|
|
data.color=wcstoul(names+1,&end,16);
|
|
break;
|
|
}
|
|
if (names[0]=='$')
|
|
names++;
|
|
names=GetToken(names,name,_countof(name),L"|");
|
|
|
|
bool bFound=false;
|
|
if (wcsncmp(name,L"System",6)==0)
|
|
{
|
|
for (int i=0;i<_countof(g_SystemColors);i++)
|
|
{
|
|
if (wcscmp(name,g_SystemColors[i].name)==0)
|
|
{
|
|
data.colorType=-2-g_SystemColors[i].code;
|
|
COLORREF color=GetSysColor(g_SystemColors[i].code);
|
|
data.color=((color&0xFF)<<16)|(color&0xFF00)|((color>>16)&0xFF);
|
|
bFound=true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
BHasMetroColors=true;
|
|
if (GetImmersiveUserColorSetPreference!=NULL)
|
|
{
|
|
wchar_t text[256];
|
|
if (wcsncmp(name,L"Immersive",9)==0)
|
|
wcscpy_s(text,name);
|
|
else
|
|
Sprintf(text,_countof(text),L"Immersive%s",name);
|
|
int type=GetImmersiveColorTypeFromName(text);
|
|
data.colorType=type<0?-1:type;
|
|
if (type>=0)
|
|
{
|
|
DWORD color=GetImmersiveColorFromColorSetEx(g_CurrentMetroColorSet,type,true,0);
|
|
data.color=((color&0xFF)<<16)|(color&0xFF00)|((color>>16)&0xFF);
|
|
bFound=true;
|
|
}
|
|
}
|
|
}
|
|
if (bFound)
|
|
break;
|
|
}
|
|
|
|
data.color|=0xFF000000;
|
|
MetroColors[crc]=data;
|
|
return data.color;
|
|
}
|
|
|
|
unsigned int MenuSkin::CalcMetroColorHash( int set ) const
|
|
{
|
|
// if set is -1 returns the currently cached colors
|
|
unsigned int hash=FNV_HASH0;
|
|
for (std::map<unsigned int,MetroColor>::const_iterator it=MetroColors.begin();it!=MetroColors.end();++it)
|
|
{
|
|
COLORREF color=0;
|
|
if (set==-1)
|
|
color=it->second.color;
|
|
else if (it->second.colorType<-1)
|
|
{
|
|
color=GetSysColor(-2-it->second.colorType);
|
|
color=((color&0xFF)<<16)|(color&0xFF00)|((color>>16)&0xFF);
|
|
}
|
|
else if (it->second.colorType>=0)
|
|
{
|
|
color=GetImmersiveColorFromColorSetEx(set,it->second.colorType,true,0);
|
|
color=((color&0xFF)<<16)|(color&0xFF00)|((color>>16)&0xFF);
|
|
}
|
|
color|=0xFF000000;
|
|
hash=CalcFNVHash(&color,sizeof(color),hash);
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
int MenuSkin::LoadSkinNumbers( const wchar_t *str, int *numbers, int count, TSkinNumberType type ) const
|
|
{
|
|
memset(numbers,0,count*4);
|
|
for (int i=0;i<count;i++)
|
|
{
|
|
wchar_t token[256];
|
|
str=GetToken(str,token,_countof(token),L", \t");
|
|
if (!token[0])
|
|
{
|
|
count=i;
|
|
break;
|
|
}
|
|
int num;
|
|
if (token[0]=='#')
|
|
{
|
|
wchar_t *end;
|
|
num=wcstoul(token+1,&end,16);
|
|
}
|
|
else if (token[0]=='$')
|
|
num=GetMetroColor(token+1);
|
|
else
|
|
num=_wtol(token);
|
|
if (type==NUMBERS_COLORS_RGB)
|
|
numbers[i]=num&0xFFFFFF;
|
|
else if (type==NUMBERS_COLORS)
|
|
numbers[i]=((num&0xFF)<<16)|(num&0xFF00)|((num>>16)&0xFF);
|
|
else if (type==NUMBERS_COLORS_ABGR)
|
|
{
|
|
if (Strlen(token+1)==6)
|
|
num|=0xFF000000;
|
|
numbers[i]=((num&0xFF)<<16)|(num&0xFF00FF00)|((num>>16)&0xFF);
|
|
}
|
|
else
|
|
numbers[i]=num;
|
|
}
|
|
|
|
if (type==NUMBERS_PADDING || type==NUMBERS_SIZE)
|
|
{
|
|
int scale=0;
|
|
for (int i=0;i<count;i++)
|
|
{
|
|
wchar_t token[256];
|
|
str=GetToken(str,token,_countof(token),L", \t");
|
|
if (token[0] && token[Strlen(token)-1]=='%')
|
|
{
|
|
scale=_wtol(token);
|
|
if (scale>100) scale=100;
|
|
}
|
|
numbers[i]=ScaleSkinElement(numbers[i],scale);
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
RECT MenuSkin::ScaleSkinElement( const RECT &rect ) const
|
|
{
|
|
RECT res;
|
|
res.left=ScaleSkinElement(rect.left);
|
|
res.right=ScaleSkinElement(rect.right);
|
|
res.top=ScaleSkinElement(rect.top);
|
|
res.bottom=ScaleSkinElement(rect.bottom);
|
|
return res;
|
|
}
|
|
|
|
POINT MenuSkin::ScaleSkinElement( const POINT &point ) const
|
|
{
|
|
POINT res;
|
|
res.x=ScaleSkinElement(point.x);
|
|
res.y=ScaleSkinElement(point.y);
|
|
return res;
|
|
}
|
|
|
|
SIZE MenuSkin::ScaleSkinElement( const SIZE &size ) const
|
|
{
|
|
SIZE res;
|
|
res.cx=ScaleSkinElement(size.cx);
|
|
res.cy=ScaleSkinElement(size.cy);
|
|
return res;
|
|
}
|
|
|
|
HFONT MenuSkin::LoadSkinFont( const wchar_t *str, const wchar_t *name, int weight, float size, bool bScale ) const
|
|
{
|
|
DWORD quality=DEFAULT_QUALITY;
|
|
int smoothing=GetSettingInt(L"FontSmoothing");
|
|
if (smoothing==1)
|
|
quality=NONANTIALIASED_QUALITY;
|
|
else if (smoothing==2)
|
|
quality=ANTIALIASED_QUALITY;
|
|
if (smoothing==3)
|
|
quality=CLEARTYPE_QUALITY;
|
|
wchar_t token[256];
|
|
bool bItalic=false;
|
|
int scale=bScale?100:0;
|
|
if (str)
|
|
{
|
|
if (_wcsicmp(str,L"none")==0)
|
|
return NULL;
|
|
str=GetToken(str,token,_countof(token),L", \t");
|
|
name=token;
|
|
wchar_t token2[256];
|
|
str=GetToken(str,token2,_countof(token2),L", \t");
|
|
weight=FW_NORMAL;
|
|
if (_wcsicmp(token2,L"bold")==0)
|
|
weight=FW_BOLD;
|
|
else if (_wcsicmp(token2,L"italic")==0)
|
|
bItalic=true;
|
|
else if (_wcsicmp(token2,L"bold_italic")==0)
|
|
weight=FW_BOLD, bItalic=true;
|
|
str=GetToken(str,token2,_countof(token2),L", \t");
|
|
size=(float)_wtof(token2);
|
|
str=GetToken(str,token2,_countof(token2),L", \t");
|
|
if (token2[0] && token2[Strlen(token2)-1]=='%')
|
|
{
|
|
scale=_wtol(token2);
|
|
if (scale<0) scale=0;
|
|
if (scale>100) scale=100;
|
|
}
|
|
}
|
|
else if (!name)
|
|
{
|
|
// get the default menu font
|
|
NONCLIENTMETRICS metrics={sizeof(metrics)};
|
|
SystemParametersInfo(SPI_GETNONCLIENTMETRICS,NULL,&metrics,0);
|
|
metrics.lfMenuFont.lfQuality=(BYTE)quality;
|
|
return CreateFontIndirect(&metrics.lfMenuFont);
|
|
}
|
|
size=ScaleSkinElement((int)(size*96),scale)/72.f;
|
|
return CreateFont((int)size,0,0,0,weight,bItalic?1:0,0,0,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,quality,DEFAULT_PITCH,name);
|
|
}
|
|
|
|
static HICON LoadSkinIcon( HMODULE hMod, int index )
|
|
{
|
|
if (hMod)
|
|
{
|
|
return (HICON)LoadImage(hMod,MAKEINTRESOURCE(index),IMAGE_ICON,0,0,LR_DEFAULTSIZE);
|
|
}
|
|
else
|
|
{
|
|
wchar_t path[_MAX_PATH];
|
|
GetSkinsPath(path);
|
|
wchar_t fname[_MAX_PATH];
|
|
Sprintf(fname,_countof(fname),L"%s%d.ico",path,index);
|
|
return (HICON)LoadImage(NULL,fname,IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE);
|
|
}
|
|
}
|
|
|
|
struct DWMCOLORIZATIONPARAMS
|
|
{
|
|
DWORD ColorizationColor;
|
|
DWORD ColorizationAfterglow;
|
|
DWORD ColorizationColorBalance;
|
|
DWORD ColorizationAfterglowBalance;
|
|
DWORD ColorizationBlurBalance;
|
|
DWORD ColorizationGlassReflectionIntensity;
|
|
DWORD ColorizationOpaqueBlend;
|
|
DWORD extra; // Win8 has extra parameter
|
|
};
|
|
|
|
static bool GetSkinColorizationParameters( DWMCOLORIZATIONPARAMS *params )
|
|
{
|
|
typedef HRESULT (WINAPI *tGetColorizationParameters)(DWMCOLORIZATIONPARAMS *params);
|
|
|
|
// HACK: the system function DwmGetColorizationColor is buggy on Win 7. its calculations can overflow and return a totally wrong value
|
|
// (try orange color with full intensity and no transparency - you'll get alpha=0 and green color). so here we use the undocumented
|
|
// function GetColorizationParameters exported by dwmapi.dll, ordinal 127 and then compute the colors manually using integer math
|
|
HMODULE hMod=GetModuleHandle(L"dwmapi.dll");
|
|
if (!hMod) return false;
|
|
tGetColorizationParameters GetColorizationParameters=(tGetColorizationParameters)GetProcAddress(hMod,MAKEINTRESOURCEA(127));
|
|
if (!GetColorizationParameters || FAILED(GetColorizationParameters(params)))
|
|
return false;
|
|
if (GetWinVersion()>=WIN_VER_WIN8)
|
|
params->ColorizationOpaqueBlend=0; // Win8 has no transparency
|
|
return true;
|
|
}
|
|
|
|
COLORREF GetSystemGlassColor8( void )
|
|
{
|
|
COLORREF color=0;
|
|
DWMCOLORIZATIONPARAMS params;
|
|
if (GetSkinColorizationParameters(¶ms))
|
|
{
|
|
int r=(params.ColorizationColor>>16)&255;
|
|
int g=(params.ColorizationColor>>8)&255;
|
|
int b=(params.ColorizationColor)&255;
|
|
int gray=217*(100-params.ColorizationColorBalance)+50;
|
|
r=(r*params.ColorizationColorBalance+gray)/100;
|
|
g=(g*params.ColorizationColorBalance+gray)/100;
|
|
b=(b*params.ColorizationColorBalance+gray)/100;
|
|
r=(r*200+127)/255;
|
|
g=(g*200+127)/255;
|
|
b=(b*200+127)/255;
|
|
color=(r<<16)|(g<<8)|b|(params.ColorizationColor&0xFF000000);
|
|
}
|
|
return color;
|
|
}
|
|
|
|
void GetSystemGlassColor( int &dr, int &dg, int &db, int &da, int &dc )
|
|
{
|
|
dr=dg=db=da=dc=0;
|
|
DWMCOLORIZATIONPARAMS params;
|
|
if (GetSkinColorizationParameters(¶ms))
|
|
{
|
|
// boost the color balance to better match the Windows 7 menu
|
|
params.ColorizationColorBalance=(int)(100.f*powf(params.ColorizationColorBalance/100.f,0.5f));
|
|
int ir=(params.ColorizationColor>>16)&255;
|
|
int ig=(params.ColorizationColor>>8)&255;
|
|
int ib=(params.ColorizationColor)&255;
|
|
|
|
int ir2=(params.ColorizationAfterglow>>16)&255;
|
|
int ig2=(params.ColorizationAfterglow>>8)&255;
|
|
int ib2=(params.ColorizationAfterglow)&255;
|
|
|
|
int brightness=(ir*21+ig*72+ib*7)/255; // [0..100]
|
|
int glowBalance=(brightness*params.ColorizationAfterglowBalance)/100; // [0..100]
|
|
|
|
dr=MulDiv(ir2*glowBalance+ir*100,params.ColorizationColorBalance*255,10000);
|
|
dg=MulDiv(ig2*glowBalance+ig*100,params.ColorizationColorBalance*255,10000);
|
|
db=MulDiv(ib2*glowBalance+ib*100,params.ColorizationColorBalance*255,10000);
|
|
dc=(glowBalance+100)*params.ColorizationColorBalance*255/10000;
|
|
|
|
da=(100-params.ColorizationAfterglowBalance-params.ColorizationBlurBalance)*255/100;
|
|
if (params.ColorizationOpaqueBlend || da>=255)
|
|
da=255;
|
|
else if (da<=0)
|
|
dr=dg=db=da=0;
|
|
}
|
|
}
|
|
|
|
void GetMetroGlassColor( int &dr, int &dg, int &db )
|
|
{
|
|
if (GetImmersiveUserColorSetPreference!=NULL)
|
|
{
|
|
int type=GetImmersiveColorTypeFromName(L"ImmersiveStartBackground");
|
|
if (type>=0)
|
|
{
|
|
int set=GetImmersiveUserColorSetPreference(false,false);
|
|
DWORD color=GetImmersiveColorFromColorSetEx(set,type,true,0);
|
|
db=((color>>16)&255);
|
|
dg=((color>>8)&255);
|
|
dr=((color)&255);
|
|
return;
|
|
}
|
|
}
|
|
dr=dg=db=0;
|
|
}
|
|
|
|
COLORREF GetMetroTaskbarColor( bool &bTransparent )
|
|
{
|
|
bTransparent=true;
|
|
if (GetImmersiveUserColorSetPreference!=NULL)
|
|
{
|
|
CRegKey regTheme;
|
|
if (regTheme.Open(HKEY_CURRENT_USER,L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",KEY_READ)==ERROR_SUCCESS)
|
|
{
|
|
DWORD trans=1;
|
|
bTransparent=regTheme.QueryDWORDValue(L"EnableTransparency",trans)!=ERROR_SUCCESS || trans;
|
|
}
|
|
int type=GetImmersiveColorTypeFromName(bTransparent?L"ImmersiveSystemAccentDark3":L"ImmersiveSystemAccentDark2");
|
|
if (type>=0)
|
|
{
|
|
int set=GetImmersiveUserColorSetPreference(false,false);
|
|
return GetImmersiveColorFromColorSetEx(set,type,true,0);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
COLORREF GetSystemAccentColor( void )
|
|
{
|
|
if (GetImmersiveUserColorSetPreference!=NULL && GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
int type=GetImmersiveColorTypeFromName(L"ImmersiveSystemAccent");
|
|
if (type>=0)
|
|
{
|
|
int set=GetImmersiveUserColorSetPreference(false,false);
|
|
return GetImmersiveColorFromColorSetEx(set,type,true,0);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void GetMenuGlassColor( int &dr, int &dg, int &db, int &da )
|
|
{
|
|
if (GetWinVersion()>=WIN_VER_WIN10)
|
|
{
|
|
bool bDef=true;
|
|
if (GetSettingBool(L"GlassOverride"))
|
|
{
|
|
COLORREF color=GetSettingInt(L"GlassColor",bDef);
|
|
db=((color>>16)&255);
|
|
dg=((color>>8)&255);
|
|
dr=((color)&255);
|
|
}
|
|
if (bDef)
|
|
GetMetroGlassColor(dr,dg,db);
|
|
dr*=255;
|
|
dg*=255;
|
|
db*=255;
|
|
da=255;
|
|
}
|
|
else
|
|
{
|
|
bool bDef=true;
|
|
if (GetSettingBool(L"GlassOverride"))
|
|
{
|
|
bool bDef1, bDef2, bDef3;
|
|
COLORREF color=GetSettingInt(L"GlassColor",bDef1);
|
|
int intensity=GetSettingInt(L"GlassIntensity",bDef2);
|
|
da=GetSettingInt(L"GlassBlending",bDef3);
|
|
bDef=bDef1 && bDef2 && bDef3;
|
|
if (!bDef)
|
|
{
|
|
db=((color>>16)&255);
|
|
dg=((color>>8)&255);
|
|
dr=((color)&255);
|
|
|
|
if (intensity<0) intensity=0;
|
|
if (intensity>100) intensity=100;
|
|
intensity=(intensity*255)/100;
|
|
dr*=intensity;
|
|
dg*=intensity;
|
|
db*=intensity;
|
|
|
|
if (da<0) da=0;
|
|
if (da>100) da=100;
|
|
da=((100-da)*255)/100;
|
|
}
|
|
}
|
|
|
|
if (bDef)
|
|
{
|
|
int dc;
|
|
GetSystemGlassColor(dr,dg,db,da,dc);
|
|
}
|
|
}
|
|
}
|
|
|
|
const COLORREF DEFAULT_GLASS_COLOR=0x00000000;
|
|
const COLORREF DEFAULT_GLASS_CONFLICT=0x00000001;
|
|
|
|
static void BlendColor( int &r, int &g, int &b, int a1, int a2, int a3, COLORREF tintColor1, COLORREF tintColor2, COLORREF tintColor3 )
|
|
{
|
|
int tr1, tg1, tb1;
|
|
int ta2=tintColor2>>24, tr2=(tintColor2)&255, tg2=(tintColor2>>8)&255, tb2=(tintColor2>>16)&255;
|
|
int ta3=tintColor3>>24, tr3=(tintColor3)&255, tg3=(tintColor3>>8)&255, tb3=(tintColor3>>16)&255;
|
|
int a1m=1;
|
|
if (tintColor1==DEFAULT_GLASS_COLOR)
|
|
{
|
|
a1m=g_GlassColorA;
|
|
tr1=g_GlassColorR;
|
|
tg1=g_GlassColorG;
|
|
tb1=g_GlassColorB;
|
|
}
|
|
else
|
|
{
|
|
a1*=tintColor1>>24;
|
|
tr1=(tintColor1)&255;
|
|
tg1=(tintColor1>>8)&255;
|
|
tb1=(tintColor1>>16)&255;
|
|
}
|
|
a2*=ta2;
|
|
a3*=ta3;
|
|
int a4=255*255-a1*a1m-a2-a3; if (a4<0) a4=0;
|
|
r=(tr1*a1+tr2*a2+tr3*a3+r*a4)/(255*255);
|
|
g=(tg1*a1+tg2*a2+tg3*a3+g*a4)/(255*255);
|
|
b=(tb1*a1+tb2*a2+tb3*a3+b*a4)/(255*255);
|
|
if (r>255) r=255;
|
|
if (g>255) g=255;
|
|
if (b>255) b=255;
|
|
}
|
|
|
|
static void BlendColor( COLORREF &color, COLORREF mask, COLORREF tintColor1, COLORREF tintColor2, COLORREF tintColor3 )
|
|
{
|
|
int r=(color)&255, g=(color>>8)&255, b=(color>>16)&255;
|
|
int a1=(mask)&255, a2=(mask>>8)&255, a3=(mask>>16)&255;
|
|
BlendColor(r,g,b,a1,a2,a3,tintColor1,tintColor2,tintColor3);
|
|
color=(b<<16)|(g<<8)|r;
|
|
}
|
|
|
|
static HBITMAP DuplicateBitmap( HBITMAP src )
|
|
{
|
|
BITMAP info;
|
|
GetObject(src,sizeof(info),&info);
|
|
BITMAPINFO bi={0};
|
|
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
|
|
bi.bmiHeader.biWidth=info.bmWidth;
|
|
bi.bmiHeader.biHeight=info.bmHeight;
|
|
bi.bmiHeader.biPlanes=info.bmPlanes;
|
|
bi.bmiHeader.biBitCount=info.bmBitsPixel;
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
void *bits;
|
|
HBITMAP dst=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,&bits,NULL,0);
|
|
DeleteDC(hdc);
|
|
memcpy(bits,info.bmBits,info.bmHeight*info.bmWidthBytes);
|
|
return dst;
|
|
}
|
|
|
|
void MenuSkin::LoadSkinTintColors( CSkinParser &parser, const wchar_t *name, COLORREF &tintColor1, COLORREF &tintColor2, COLORREF &tintColor3, COLORREF backgroundColor ) const
|
|
{
|
|
wchar_t name2[256];
|
|
Sprintf(name2,_countof(name2),L"%s_tint1",name);
|
|
const wchar_t *str=parser.FindSetting(name2);
|
|
if (str && _wcsicmp(str,L"$Default")!=0 && LoadSkinNumbers(str,(int*)&tintColor1,1,NUMBERS_COLORS_ABGR))
|
|
{
|
|
if (tintColor1==DEFAULT_GLASS_COLOR)
|
|
tintColor1=DEFAULT_GLASS_CONFLICT;
|
|
}
|
|
else
|
|
tintColor1=DEFAULT_GLASS_COLOR;
|
|
|
|
Sprintf(name2,_countof(name2),L"%s_tint2",name);
|
|
str=parser.FindSetting(name2);
|
|
if (!str || _wcsicmp(str,L"$Default")==0 || !LoadSkinNumbers(str,(int*)&tintColor2,1,NUMBERS_COLORS_ABGR))
|
|
tintColor2=backgroundColor|0xFF000000;
|
|
|
|
Sprintf(name2,_countof(name2),L"%s_tint3",name);
|
|
str=parser.FindSetting(name2);
|
|
if (!str || _wcsicmp(str,L"$Default")==0 || !LoadSkinNumbers(str,(int*)&tintColor3,1,NUMBERS_COLORS_ABGR))
|
|
tintColor3=0;
|
|
}
|
|
|
|
bool MenuSkin::LoadSkinColors( CSkinParser &parser, const wchar_t *name, COLORREF *colors, int count, COLORREF backgroundColor, TSkinNumberType type ) const
|
|
{
|
|
const wchar_t *str=parser.FindSetting(name);
|
|
if (!str || !LoadSkinNumbers(str,(int*)colors,count,type))
|
|
return false;
|
|
|
|
if (count>10) return false;
|
|
wchar_t name2[256];
|
|
Sprintf(name2,_countof(name2),L"%s_mask",name);
|
|
str=parser.FindSetting(name2);
|
|
if (str)
|
|
{
|
|
COLORREF masks[10], tintColor1, tintColor2, tintColor3;
|
|
if (LoadSkinNumbers(str,(int*)masks,count,NUMBERS_COLORS))
|
|
{
|
|
LoadSkinTintColors(parser,name,tintColor1,tintColor2,tintColor3,backgroundColor);
|
|
for (int i=0;i<count;i++)
|
|
{
|
|
COLORREF a=colors[i]&0xFF000000;
|
|
BlendColor(colors[i],masks[i],tintColor1,tintColor2,tintColor3);
|
|
if (type==NUMBERS_COLORS_ABGR)
|
|
colors[i]|=a;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
MenuBitmap MenuSkin::LoadSkinBitmap( HMODULE hMod, int index, int maskIndex, COLORREF tintColor1, COLORREF tintColor2, COLORREF tintColor3, bool bPremultiply ) const
|
|
{
|
|
// if maskIndex=0, no mask (black mask)
|
|
// if maskIndex>0 - bitmap ID
|
|
// if maskIndex<0 - color RGB
|
|
MenuBitmap res;
|
|
res.Init();
|
|
wchar_t err[1024];
|
|
HBITMAP bmp=NULL;
|
|
if (index>0)
|
|
{
|
|
if ((index&0xFF000000)==0x0F000000)
|
|
{
|
|
bmp=DuplicateBitmap(CustomBitmaps[index&0xFFFFFF].bitmap);
|
|
}
|
|
else if (hMod)
|
|
{
|
|
bmp=(HBITMAP)LoadImage(hMod,MAKEINTRESOURCE(index),IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
|
|
if (!bmp)
|
|
bmp=LoadImageResource(hMod,MAKEINTRESOURCE(index),false,false);
|
|
if (!bmp)
|
|
{
|
|
GetErrorMessage(err,_countof(err),GetLastError());
|
|
Sprintf(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_BMPRES),index,err);
|
|
return res;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wchar_t path[_MAX_PATH];
|
|
GetSkinsPath(path);
|
|
wchar_t fname[_MAX_PATH];
|
|
Sprintf(fname,_countof(fname),L"%s%d.bmp",path,index);
|
|
bmp=(HBITMAP)LoadImage(NULL,fname,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_LOADFROMFILE);
|
|
if (!bmp)
|
|
{
|
|
GetErrorMessage(err,_countof(err),GetLastError());
|
|
Sprintf(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_BMPFILE),fname,err);
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
|
|
HBITMAP bmpMask=NULL;
|
|
BITMAP infoMask={0};
|
|
if (maskIndex>0)
|
|
{
|
|
if ((maskIndex&0xFF000000)==0x0F000000)
|
|
{
|
|
bmpMask=DuplicateBitmap(CustomBitmaps[maskIndex&0xFFFFFF].bitmap);
|
|
}
|
|
else if (hMod)
|
|
{
|
|
bmpMask=(HBITMAP)LoadImage(hMod,MAKEINTRESOURCE(maskIndex),IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
|
|
if (!bmpMask)
|
|
bmpMask=LoadImageResource(hMod,MAKEINTRESOURCE(maskIndex),false,false);
|
|
if (!bmpMask)
|
|
{
|
|
GetErrorMessage(err,_countof(err),GetLastError());
|
|
Sprintf(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_MASKRES),maskIndex,err);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wchar_t path[_MAX_PATH];
|
|
GetSkinsPath(path);
|
|
wchar_t fname[_MAX_PATH];
|
|
Sprintf(fname,_countof(fname),L"%s%d.bmp",path,maskIndex);
|
|
bmpMask=(HBITMAP)LoadImage(NULL,fname,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_LOADFROMFILE);
|
|
if (!bmpMask)
|
|
{
|
|
GetErrorMessage(err,_countof(err),GetLastError());
|
|
Sprintf(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_MASKFILE),fname,err);
|
|
}
|
|
}
|
|
if (!bmpMask)
|
|
{
|
|
res=bmpMask;
|
|
return res;
|
|
}
|
|
GetObject(bmpMask,sizeof(infoMask),&infoMask);
|
|
if (index<0)
|
|
{
|
|
unsigned int colorRGB=index&0xFFFFFF;
|
|
BITMAPINFO bi={0};
|
|
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
|
|
bi.bmiHeader.biWidth=infoMask.bmWidth;
|
|
bi.bmiHeader.biHeight=infoMask.bmHeight;
|
|
bi.bmiHeader.biPlanes=1;
|
|
bi.bmiHeader.biBitCount=32;
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
unsigned int *bits;
|
|
bmp=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,(void**)&bits,NULL,0);
|
|
if (infoMask.bmBitsPixel==32)
|
|
{
|
|
unsigned int *ptrMask=(unsigned int*)infoMask.bmBits;
|
|
for (int i=infoMask.bmWidth*infoMask.bmHeight-1;i>=0;i--)
|
|
bits[i]=colorRGB|(ptrMask[i]&0xFF000000);
|
|
}
|
|
else
|
|
{
|
|
for (int i=infoMask.bmWidth*infoMask.bmHeight-1;i>=0;i--)
|
|
bits[i]=colorRGB|0xFF000000;
|
|
}
|
|
DeleteDC(hdc);
|
|
}
|
|
}
|
|
else if (maskIndex<0)
|
|
{
|
|
infoMask.bmBits=&maskIndex;
|
|
}
|
|
|
|
BITMAP info;
|
|
GetObject(bmp,sizeof(info),&info);
|
|
|
|
if (bmpMask && index>0 && (info.bmWidth!=infoMask.bmWidth || info.bmHeight!=infoMask.bmHeight))
|
|
{
|
|
Sprintf(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_MASKSIZE),index,maskIndex);
|
|
}
|
|
|
|
if (maskIndex<0 || (bmpMask && info.bmWidth==infoMask.bmWidth && info.bmHeight==infoMask.bmHeight))
|
|
{
|
|
// apply color mask
|
|
unsigned char *ptr=(unsigned char*)info.bmBits;
|
|
int stride=info.bmBitsPixel/8;
|
|
int pad=stride*info.bmWidth;
|
|
pad=((pad+3)&~3)-pad;
|
|
unsigned char *ptrMask=(unsigned char*)infoMask.bmBits;
|
|
int strideMask=infoMask.bmBitsPixel/8;
|
|
int padMask=strideMask*info.bmWidth;
|
|
padMask=((padMask+3)&~3)-padMask;
|
|
|
|
for (int y=0;y<info.bmHeight;y++)
|
|
{
|
|
for (int x=0;x<info.bmWidth;x++,ptr+=stride,ptrMask+=strideMask)
|
|
{
|
|
int r=ptr[2];
|
|
int g=ptr[1];
|
|
int b=ptr[0];
|
|
BlendColor(r,g,b,ptrMask[2],ptrMask[1],ptrMask[0],tintColor1,tintColor2,tintColor3);
|
|
ptr[2]=(unsigned char)r;
|
|
ptr[1]=(unsigned char)g;
|
|
ptr[0]=(unsigned char)b;
|
|
}
|
|
ptr+=pad;
|
|
ptrMask+=padMask;
|
|
}
|
|
}
|
|
if (bmpMask) DeleteObject(bmpMask);
|
|
|
|
int n=info.bmWidth*info.bmHeight;
|
|
res.bIs32=false;
|
|
res.bIsOwned=true;
|
|
res=bmp;
|
|
if (info.bmBitsPixel<32)
|
|
return res;
|
|
|
|
// HACK: when LoadImage reads a 24-bit image it creates a 32-bit bitmap with 0 in the alpha channel
|
|
// we use that to detect 24-bit images and don't pre-multiply the alpha
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
unsigned int &pixel=((unsigned int*)info.bmBits)[i];
|
|
if (pixel&0xFF000000)
|
|
{
|
|
res.bIs32=true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (res.bIs32 && bPremultiply)
|
|
{
|
|
// 32-bit bitmap detected. pre-multiply the alpha
|
|
for (int i=0;i<n;i++)
|
|
{
|
|
unsigned int &pixel=((unsigned int*)info.bmBits)[i];
|
|
int a=(pixel>>24);
|
|
int r=(pixel>>16)&255;
|
|
int g=(pixel>>8)&255;
|
|
int b=(pixel)&255;
|
|
r=(r*a)/255;
|
|
g=(g*a)/255;
|
|
b=(b*a)/255;
|
|
pixel=(a<<24)|(r<<16)|(g<<8)|b;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static void MirrorBitmap( HBITMAP bmp )
|
|
{
|
|
BITMAP info;
|
|
GetObject(bmp,sizeof(info),&info);
|
|
|
|
unsigned char *ptr=(unsigned char*)info.bmBits;
|
|
if (!ptr) return;
|
|
int stride=info.bmBitsPixel/8;
|
|
int pitch=(stride*info.bmWidth+3)&~3;
|
|
for (int y=0;y<info.bmHeight;y++,ptr+=pitch)
|
|
{
|
|
unsigned char *start=ptr;
|
|
unsigned char *end=ptr+stride*(info.bmWidth-1);
|
|
for (int x=0;x<info.bmWidth;x+=2,start+=stride,end-=stride)
|
|
{
|
|
char q[4];
|
|
memcpy(q,start,stride);
|
|
memcpy(start,end,stride);
|
|
memcpy(end,q,stride);
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool FindToken( const wchar_t *str, const wchar_t *token )
|
|
{
|
|
wchar_t text[256];
|
|
while (*str)
|
|
{
|
|
str=GetToken(str,text,_countof(text),L" \t,");
|
|
if (_wcsicmp(text,token)==0)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool MenuSkin::LoadSkinBackground( HMODULE hMod, CSkinParser &parser, const wchar_t *name, MenuBitmap &bitmap, COLORREF backgroundColor, int *slicesX, int countX, int *slicesY, int countY, bool bMirror, bool bAllowColor, bool bPremultiply ) const
|
|
{
|
|
if (countX)
|
|
memset(slicesX,0,countX*4);
|
|
else if (slicesX)
|
|
*slicesX=0;
|
|
if (countY)
|
|
memset(slicesY,0,countY*4);
|
|
else if (slicesY)
|
|
*slicesY=0;
|
|
|
|
const wchar_t *str=parser.FindSetting(name);
|
|
if (!str)
|
|
return true;
|
|
|
|
int id;
|
|
if (str[0]=='#' || str[0]=='$')
|
|
{
|
|
LoadSkinNumbers(str,&id,1,NUMBERS_COLORS_RGB);
|
|
id|=0xFF000000;
|
|
}
|
|
else if (str[0]=='@')
|
|
{
|
|
id=_wtol(str+1);
|
|
if (id<0 || id>=(int)CustomBitmaps.size()) return true;
|
|
id|=0x0F000000;
|
|
}
|
|
else
|
|
{
|
|
id=_wtol(str);
|
|
if (id<=0) return true;
|
|
}
|
|
|
|
int id2;
|
|
wchar_t name2[256];
|
|
Sprintf(name2,_countof(name2),L"%s_mask",name);
|
|
str=parser.FindSetting(name2);
|
|
if (!str)
|
|
id2=0;
|
|
else if (str[0]=='#' || str[0]=='$')
|
|
{
|
|
LoadSkinNumbers(str,&id2,1,NUMBERS_COLORS_RGB);
|
|
id2|=0xFF000000;
|
|
}
|
|
else if (str[0]=='@')
|
|
{
|
|
id2=_wtol(str+1);
|
|
if (id2<0 || id2>=(int)CustomBitmaps.size()) return true;
|
|
id2|=0x0F000000;
|
|
}
|
|
else
|
|
{
|
|
id2=_wtol(str);
|
|
if (id2<0) id2=0;
|
|
}
|
|
|
|
if (id2)
|
|
{
|
|
COLORREF tintColor1, tintColor2, tintColor3;
|
|
LoadSkinTintColors(parser,name,tintColor1,tintColor2,tintColor3,backgroundColor);
|
|
if (id>0 || id2>0)
|
|
{
|
|
bitmap=LoadSkinBitmap(hMod,id,id2,tintColor1,tintColor2,tintColor3,bPremultiply);
|
|
}
|
|
else
|
|
{
|
|
COLORREF color=((id>>16)&0xFF)|(id&0xFF00)|((id&0xFF)<<16);
|
|
COLORREF mask=((id2>>16)&0xFF)|(id2&0xFF00)|((id2&0xFF)<<16);
|
|
BlendColor(color,mask,tintColor1,tintColor2,tintColor3);
|
|
bitmap=color;
|
|
}
|
|
}
|
|
else if (id>0)
|
|
{
|
|
bitmap=LoadSkinBitmap(hMod,id,0,0,0,0,bPremultiply);
|
|
}
|
|
else
|
|
{
|
|
COLORREF color=((id>>16)&0xFF)|(id&0xFF00)|((id&0xFF)<<16);
|
|
bitmap=color;
|
|
}
|
|
|
|
if (!bitmap.bIsBitmap)
|
|
{
|
|
if (!bAllowColor)
|
|
Sprintf(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_RECBITMAP),name);
|
|
return bAllowColor;
|
|
}
|
|
|
|
if (!bitmap.GetBitmap())
|
|
return false;
|
|
if (bMirror)
|
|
MirrorBitmap(bitmap.GetBitmap());
|
|
|
|
BITMAP info;
|
|
if ((!countX && slicesX) || (!countY && slicesY))
|
|
GetObject(bitmap.GetBitmap(),sizeof(info),&info);
|
|
if (countX)
|
|
{
|
|
Sprintf(name2,_countof(name2),L"%s_slices_X",name);
|
|
str=parser.FindSetting(name2);
|
|
if (str)
|
|
LoadSkinNumbers(str,slicesX,countX,NUMBERS_SLICES);
|
|
else
|
|
memset(slicesX,0,countX*4);
|
|
}
|
|
else if (slicesX)
|
|
*slicesX=info.bmWidth;
|
|
if (countY)
|
|
{
|
|
Sprintf(name2,_countof(name2),L"%s_slices_Y",name);
|
|
str=parser.FindSetting(name2);
|
|
if (str)
|
|
LoadSkinNumbers(str,slicesY,countY,NUMBERS_SLICES);
|
|
else
|
|
memset(slicesY,0,countY*4);
|
|
}
|
|
else if (slicesY)
|
|
*slicesY=info.bmHeight;
|
|
return true;
|
|
}
|
|
|
|
bool MenuSkin::LoadSkinBitmap( HMODULE hMod, CSkinParser &parser, const wchar_t *name, MenuBitmap &bitmap, SIZE *size, bool bMirror, bool bPremultiply ) const
|
|
{
|
|
int cx, cy;
|
|
if (!LoadSkinBackground(hMod,parser,name,bitmap,0,&cx,0,&cy,0,bMirror,false,bPremultiply))
|
|
return false;
|
|
if (size)
|
|
{
|
|
size->cx=cx;
|
|
size->cy=cy;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
MenuSkin::THAlign MenuSkin::ParseHAlign( const wchar_t *str )
|
|
{
|
|
if (str)
|
|
{
|
|
if (_wcsicmp(str,L"center1")==0)
|
|
return HALIGN_CENTER1;
|
|
else if (_wcsicmp(str,L"center2")==0)
|
|
return HALIGN_CENTER2;
|
|
else if (_wcsicmp(str,L"left")==0)
|
|
return HALIGN_LEFT;
|
|
else if (_wcsicmp(str,L"left1")==0)
|
|
return HALIGN_LEFT1;
|
|
else if (_wcsicmp(str,L"left2")==0)
|
|
return HALIGN_LEFT2;
|
|
else if (_wcsicmp(str,L"right")==0)
|
|
return HALIGN_RIGHT;
|
|
else if (_wcsicmp(str,L"right1")==0)
|
|
return HALIGN_RIGHT1;
|
|
else if (_wcsicmp(str,L"right2")==0)
|
|
return HALIGN_RIGHT2;
|
|
else if (_wcsicmp(str,L"corner")==0)
|
|
return HALIGN_CORNER;
|
|
else if (_wcsicmp(str,L"none")==0)
|
|
return HALIGN_NONE;
|
|
}
|
|
return HALIGN_CENTER;
|
|
}
|
|
|
|
MenuSkin::TIconSize MenuSkin::ParseIconSize( const wchar_t *str )
|
|
{
|
|
if (str)
|
|
{
|
|
if (_wcsicmp(str,L"small")==0)
|
|
return ICON_SIZE_SMALL;
|
|
else if (_wcsicmp(str,L"large")==0)
|
|
return ICON_SIZE_LARGE;
|
|
else if (_wcsicmp(str,L"none")==0)
|
|
return ICON_SIZE_NONE;
|
|
}
|
|
return ICON_SIZE_UNDEFINED;
|
|
}
|
|
|
|
MenuSkin::TVAlign MenuSkin::ParseVAlign( const wchar_t *str )
|
|
{
|
|
if (str)
|
|
{
|
|
if (_wcsicmp(str,L"top")==0)
|
|
return VALIGN_TOP;
|
|
else if (_wcsicmp(str,L"bottom")==0)
|
|
return VALIGN_BOTTOM;
|
|
else if (_wcsicmp(str,L"corner")==0)
|
|
return VALIGN_CORNER;
|
|
else if (_wcsicmp(str,L"none")==0)
|
|
return VALIGN_NONE;
|
|
}
|
|
return VALIGN_CENTER;
|
|
}
|
|
|
|
bool MenuSkin::LoadSkinItem( HMODULE hMod, CSkinParser &parser, const wchar_t *name, MenuSkin::ItemDrawSettings &settings, MenuSkin::ItemDrawSettings *pDefaults, COLORREF backgroundColor, bool bRTL ) const
|
|
{
|
|
wchar_t name2[256];
|
|
const wchar_t *str;
|
|
Sprintf(name2,_countof(name2),L"%s_font",name);
|
|
str=parser.FindSetting(name2);
|
|
if (str)
|
|
{
|
|
settings.font=LoadSkinFont(str,NULL,0,0,true);
|
|
settings.bOwnFont=true;
|
|
}
|
|
else if (pDefaults)
|
|
{
|
|
settings.font=pDefaults->font;
|
|
settings.bOwnFont=false;
|
|
}
|
|
else
|
|
{
|
|
settings.font=LoadSkinFont(NULL,NULL,0,0,true);
|
|
settings.bOwnFont=true;
|
|
}
|
|
|
|
Sprintf(name2,_countof(name2),L"%s_glow_size",name);
|
|
str=parser.FindSetting(name2);
|
|
if (str)
|
|
settings.glowSize=_wtol(str);
|
|
else if (pDefaults)
|
|
settings.glowSize=pDefaults->glowSize;
|
|
else
|
|
settings.glowSize=0;
|
|
|
|
Sprintf(name2,_countof(name2),L"%s_text_color",name);
|
|
if (LoadSkinColors(parser,name2,settings.textColors,_countof(settings.textColors),backgroundColor))
|
|
{}
|
|
else if (pDefaults)
|
|
memcpy(settings.textColors,pDefaults->textColors,sizeof(settings.textColors));
|
|
else
|
|
{
|
|
settings.textColors[0]=GetSysColor(COLOR_MENUTEXT);
|
|
settings.textColors[1]=GetSysColor(COLOR_HIGHLIGHTTEXT);
|
|
settings.textColors[2]=GetSysColor(COLOR_GRAYTEXT);
|
|
settings.textColors[3]=GetSysColor(COLOR_HIGHLIGHTTEXT);
|
|
}
|
|
Sprintf(name2,_countof(name2),L"%s_text_shadow_color",name);
|
|
str=parser.FindSetting(name2);
|
|
if (str && wcscmp(str,L"none")==0)
|
|
memset(settings.textShadowColors,-1,sizeof(settings.textShadowColors));
|
|
else if (LoadSkinColors(parser,name2,settings.textShadowColors,_countof(settings.textShadowColors),backgroundColor))
|
|
{}
|
|
else if (pDefaults)
|
|
memcpy(settings.textShadowColors,pDefaults->textShadowColors,sizeof(settings.textShadowColors));
|
|
else
|
|
memset(settings.textShadowColors,-1,sizeof(settings.textShadowColors));
|
|
|
|
Sprintf(name2,_countof(name2),L"%s_text_padding",name);
|
|
str=parser.FindSetting(name2);
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&settings.textPadding,4,NUMBERS_PADDING);
|
|
else if (pDefaults)
|
|
settings.textPadding=pDefaults->textPadding;
|
|
else
|
|
settings.textPadding=ScaleSkinElement(DEFAULT_TEXT_PADDING);
|
|
|
|
Sprintf(name2,_countof(name2),L"%s_icon_padding",name);
|
|
str=parser.FindSetting(name2);
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&settings.iconPadding,4,NUMBERS_PADDING);
|
|
else if (pDefaults)
|
|
settings.iconPadding=pDefaults->iconPadding;
|
|
else
|
|
settings.iconPadding=ScaleSkinElement(DEFAULT_ICON_PADDING);
|
|
|
|
Sprintf(name2,_countof(name2),L"%s_arrow_color",name);
|
|
if (LoadSkinColors(parser,name2,settings.arrColors,_countof(settings.arrColors),backgroundColor))
|
|
{}
|
|
else if (pDefaults)
|
|
memcpy(settings.arrColors,pDefaults->arrColors,sizeof(settings.arrColors));
|
|
else
|
|
{
|
|
settings.arrColors[0]=settings.textColors[0];
|
|
settings.arrColors[1]=settings.textColors[1];
|
|
}
|
|
|
|
Sprintf(name2,_countof(name2),L"%s_selection",name);
|
|
str=parser.FindSetting(name2);
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,name2,settings.bmpSelection,backgroundColor,settings.selSlicesX,_countof(settings.selSlicesX),settings.selSlicesY,_countof(settings.selSlicesY),bRTL,true))
|
|
return false;
|
|
}
|
|
else if (pDefaults)
|
|
{
|
|
settings.bmpSelection=pDefaults->bmpSelection;
|
|
settings.bmpSelection.bIsOwned=false;
|
|
memcpy(settings.selSlicesX,pDefaults->selSlicesX,sizeof(settings.selSlicesX));
|
|
memcpy(settings.selSlicesY,pDefaults->selSlicesY,sizeof(settings.selSlicesY));
|
|
}
|
|
else
|
|
{
|
|
settings.bmpSelection=GetSysColor(COLOR_HIGHLIGHT);
|
|
}
|
|
|
|
{
|
|
const POINT *sizes=GetArrowsBitmapSizes();
|
|
settings.arrSize.cx=sizes[3].y-sizes[3].x;
|
|
settings.arrSize.cy=sizes[6].y;
|
|
}
|
|
Sprintf(name2,_countof(name2),L"%s_arrow",name);
|
|
str=parser.FindSetting(name2);
|
|
if (str && wcscmp(str,L"0")==0)
|
|
{}
|
|
else if (str)
|
|
{
|
|
if (!LoadSkinBitmap(hMod,parser,name2,settings.bmpArrow,&settings.arrSize,bRTL))
|
|
return false;
|
|
settings.arrSize.cy/=2;
|
|
}
|
|
else if (pDefaults)
|
|
{
|
|
settings.bmpArrow=pDefaults->bmpArrow;
|
|
settings.bmpArrow.bIsOwned=false;
|
|
settings.arrSize=pDefaults->arrSize;
|
|
}
|
|
|
|
Sprintf(name2,_countof(name2),L"%s_arrow_padding",name);
|
|
str=parser.FindSetting(name2);
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&settings.arrPadding,2,NUMBERS_PADDING);
|
|
else if (pDefaults)
|
|
settings.arrPadding=pDefaults->arrPadding;
|
|
else
|
|
settings.arrPadding=ScaleSkinElement(DEFAULT_ARROW_PADDING);
|
|
|
|
Sprintf(name2,_countof(name2),L"%s_icon_frame",name);
|
|
str=parser.FindSetting(name2);
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,name2,settings.bmpIconFrame,backgroundColor,settings.frameSlicesX,_countof(settings.frameSlicesX),settings.frameSlicesY,_countof(settings.frameSlicesY),bRTL))
|
|
return false;
|
|
|
|
if (settings.bmpIconFrame.GetBitmap())
|
|
{
|
|
Sprintf(name2,_countof(name2),L"%s_icon_frame_offset",name);
|
|
str=parser.FindSetting(name2);
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&settings.iconFrameOffset,2,NUMBERS_PADDING);
|
|
else
|
|
memset(&settings.iconFrameOffset,0,sizeof(settings.iconFrameOffset));
|
|
}
|
|
}
|
|
else if (pDefaults)
|
|
{
|
|
settings.bmpIconFrame=pDefaults->bmpIconFrame;
|
|
settings.bmpIconFrame.bIsOwned=false;
|
|
memcpy(settings.frameSlicesX,pDefaults->frameSlicesX,sizeof(settings.frameSlicesX));
|
|
memcpy(settings.frameSlicesY,pDefaults->frameSlicesY,sizeof(settings.frameSlicesY));
|
|
settings.iconFrameOffset=pDefaults->iconFrameOffset;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void MenuSkin::ParseOptionsString( const wchar_t *optionsStr, std::map<CString,CString> &options ) const
|
|
{
|
|
options.clear();
|
|
wchar_t text[1024];
|
|
const wchar_t *str=optionsStr;
|
|
while (*str)
|
|
{
|
|
str=GetToken(str,text,_countof(text),L"\n");
|
|
wchar_t token[256];
|
|
const wchar_t *val=GetToken(text,token,_countof(token),L"=");
|
|
if (*token)
|
|
options[token]=val;
|
|
}
|
|
|
|
if (wcschr(optionsStr,'|'))
|
|
{
|
|
// backwards compatibility for old-style settings
|
|
const wchar_t *end=wcschr(optionsStr,'\n');
|
|
if (end && wcschr(end+1,'\n'))
|
|
return; // multiple lines
|
|
for (std::vector<Option>::const_iterator it=Options.begin();it!=Options.end();++it)
|
|
{
|
|
std::map<CString,CString>::const_iterator find=options.find(it->name);
|
|
if (find==options.end())
|
|
{
|
|
unsigned int hash=CalcFNVHash(it->name)&0xFFFFFFFE;
|
|
wchar_t text[100];
|
|
Sprintf(text,_countof(text),L"%08X|",hash);
|
|
if (wcsstr(optionsStr,text))
|
|
options[it->name]=L"0";
|
|
else
|
|
{
|
|
Sprintf(text,_countof(text),L"%08X|",hash+1);
|
|
if (wcsstr(optionsStr,text))
|
|
options[it->name]=L"1";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool MenuSkin::ComputeOptionStates( const std::map<CString,CString> &options, std::vector<const wchar_t*> &values, bool bTranslateValues ) const
|
|
{
|
|
values.clear();
|
|
if (SkinType==SKIN_TYPE_ALL_PROGRAMS)
|
|
values.push_back(L"ALL_PROGRAMS");
|
|
if (SkinType==SKIN_TYPE_CLASSIC2)
|
|
values.push_back(L"TWO_COLUMNS");
|
|
// for compatibility with existing skins
|
|
if (Dpi>=144)
|
|
values.push_back(L"HIGH_DPI");
|
|
if (Dpi>=240)
|
|
values.push_back(L"240_DPI"); // 250% scaling
|
|
else if (Dpi>=216)
|
|
values.push_back(L"216_DPI"); // 225% scaling
|
|
else if (Dpi>=192)
|
|
values.push_back(L"192_DPI"); // 200% scaling
|
|
else if (Dpi>=168)
|
|
values.push_back(L"168_DPI"); // 175% scaling
|
|
else if (Dpi>=144)
|
|
values.push_back(L"144_DPI"); // 150% scaling
|
|
else if (Dpi>=120)
|
|
values.push_back(L"120_DPI"); // 125% scaling
|
|
if (ForceTouch || (GetWinVersion()>=WIN_VER_WIN8 && GetSettingBool(L"EnableTouch") && (GetSystemMetrics(SM_DIGITIZER)&NID_INTEGRATED_TOUCH)!=0))
|
|
values.push_back(L"TOUCH_ENABLED");
|
|
if (GetSettingInt(L"SearchBox")!=SEARCHBOX_HIDDEN)
|
|
values.push_back(L"SEARCHBOX");
|
|
|
|
// determine bValue for radio buttons (they don't have conditions)
|
|
for (std::vector<Option>::const_iterator it=Options.begin();it!=Options.end();++it)
|
|
{
|
|
const Option &option=*it;
|
|
if (option.type==SKIN_OPTION_GROUP && option.groupId==-1) continue;
|
|
std::map<CString,CString>::const_iterator find=options.find(option.name);
|
|
if (option.type==SKIN_OPTION_BOOL)
|
|
option.bValue=find!=options.end()?find->second==L"1":option.bDefValue;
|
|
else
|
|
option.bValue=find!=options.end() || option.bDefValue;
|
|
}
|
|
|
|
// determine if exactly one option is selected from each group
|
|
for (std::vector<Option>::const_iterator it=Options.begin();it!=Options.end();++it)
|
|
{
|
|
const Option &option=*it;
|
|
if (option.type!=SKIN_OPTION_GROUP) continue;
|
|
int count=0;
|
|
const Option *defOption=NULL;
|
|
for (std::vector<Option>::const_iterator it2=it+1;it2!=Options.end();++it2)
|
|
{
|
|
const Option &option2=*it2;
|
|
if (option2.type!=SKIN_OPTION_GROUP && option2.groupId==option.groupId)
|
|
{
|
|
if (option2.bValue)
|
|
count++;
|
|
if (!defOption && option2.bDefValue)
|
|
defOption=&option2;
|
|
}
|
|
}
|
|
if (count!=1)
|
|
{
|
|
for (std::vector<Option>::const_iterator it2=it+1;it2!=Options.end();++it2)
|
|
{
|
|
const Option &option2=*it2;
|
|
if (option2.type!=SKIN_OPTION_GROUP && option2.groupId==option.groupId)
|
|
{
|
|
if (!defOption) defOption=&option2;
|
|
option2.bValue=defOption==&option2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// calculate values
|
|
for (std::vector<Option>::const_iterator it=Options.begin();it!=Options.end();++it)
|
|
{
|
|
const Option &option=*it;
|
|
if (option.type==SKIN_OPTION_GROUP) continue;
|
|
option.bEnabled=(option.condition.IsEmpty() || EvalCondition(option.condition,values.empty()?NULL:&values[0],(int)values.size()));
|
|
|
|
const CString *optValue=NULL;
|
|
{
|
|
std::map<CString,CString>::const_iterator it=options.find(option.name);
|
|
if (it!=options.end())
|
|
optValue=&it->second;
|
|
}
|
|
if (option.type==SKIN_OPTION_BOOL)
|
|
{
|
|
option.sValue.Empty();
|
|
if (option.groupId==-1)
|
|
{
|
|
if (!option.bEnabled)
|
|
option.bValue=option.disValue==L"1";
|
|
else if (optValue)
|
|
option.bValue=*optValue==L"1";
|
|
else
|
|
option.bValue=option.bDefValue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (option.groupId==-1)
|
|
option.bValue=option.bEnabled && optValue;
|
|
|
|
if (option.bValue && optValue)
|
|
option.sValue=*optValue;
|
|
else
|
|
option.sValue=option.disValue;
|
|
|
|
// translate some value types
|
|
if (bTranslateValues)
|
|
{
|
|
if (option.type==SKIN_OPTION_IMAGE)
|
|
{
|
|
if (option.sValue.IsEmpty())
|
|
option.sValue=L"0";
|
|
else
|
|
{
|
|
wchar_t fname[_MAX_PATH];
|
|
Strcpy(fname,_countof(fname),option.sValue);
|
|
DoEnvironmentSubst(fname,_countof(fname));
|
|
HBITMAP bmp=LoadImageResource(NULL,fname,false,false);
|
|
if (bmp)
|
|
{
|
|
WIN32_FILE_ATTRIBUTE_DATA attributes={0};
|
|
GetFileAttributesEx(fname,GetFileExInfoStandard,&attributes);
|
|
option.sValue.Format(L"@%d",(int)CustomBitmaps.size());
|
|
CustomBitmap custom;
|
|
custom.bitmap=bmp;
|
|
custom.path=fname;
|
|
custom.timestamp=attributes.ftLastWriteTime;
|
|
CustomBitmaps.push_back(custom);
|
|
}
|
|
else
|
|
{
|
|
Sprintf(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_BMPFILE),fname,L"");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else if (option.type==SKIN_OPTION_COLOR)
|
|
{
|
|
wchar_t *end;
|
|
COLORREF color=wcstoul(option.sValue,&end,16);
|
|
color=((color>>16)&0xFF)|(color&0xFF00)|((color&0xFF)<<16);
|
|
option.sValue.Format(L"#%06X",color);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (option.bValue)
|
|
values.push_back(option.name);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void MenuSkin::SerializeOptionStates( std::vector<wchar_t> &buffer ) const
|
|
{
|
|
for (std::vector<Option>::const_iterator it=Options.begin();it!=Options.end();++it)
|
|
{
|
|
if (it->type==SKIN_OPTION_GROUP) continue;
|
|
wchar_t line[1024];
|
|
int len=0;
|
|
if (it->type==SKIN_OPTION_BOOL)
|
|
len=Sprintf(line,_countof(line),L"%s=%d\n",it->name,it->bValue?1:0);
|
|
else if (it->bValue)
|
|
len=Sprintf(line,_countof(line),L"%s=%s\n",it->name,it->sValue);
|
|
|
|
if (len)
|
|
buffer.insert(buffer.end(),line,line+len);
|
|
}
|
|
buffer.push_back(0);
|
|
}
|
|
|
|
// new -> old
|
|
static const wchar_t *g_SkinSettingAliases[]={
|
|
L"Main2_selection", L"Main_selection2",
|
|
L"Main2_selection_mask", L"Main_selection_mask2",
|
|
L"Main2_selection_slices_X", L"Main_selection_slices_X2",
|
|
L"Main2_selection_slices_Y", L"Main_selection_slices_Y2",
|
|
L"Main2_split_selection", L"Main_split_selection2",
|
|
L"Main2_split_selection_mask", L"Main_split_selection_mask2",
|
|
L"Main2_split_selection_slices_X", L"Main_split_selection_slices_X2",
|
|
L"Main2_split_selection_slices_Y", L"Main_split_selection_slices_Y2",
|
|
L"Main2_separator", L"Main_separator2",
|
|
L"Main2_separator_slices_X", L"Main_separator_slices_X2",
|
|
L"Main2_icon_frame", L"Main_icon_frame2",
|
|
L"Main2_icon_frame_slices_X", L"Main_icon_frame_slices_X2",
|
|
L"Main2_icon_frame_slices_Y", L"Main_icon_frame_slices_Y2",
|
|
L"Main2_icon_frame_offset", L"Main_icon_frame_offset2",
|
|
L"Main2_font",L"Main_font2",
|
|
L"Main2_separator_font", L"Main_separator_font2",
|
|
L"Main2_glow_size", L"Main_glow_size2",
|
|
L"Main2_separator_glow_size", L"Main_separator_glow_size2",
|
|
L"Main2_text_color", L"Main_text_color2",
|
|
L"Main2_separator_text_color", L"Main_separator_text_color2",
|
|
L"Main2_arrow", L"Main_arrow2",
|
|
L"Main2_arrow_color", L"Main_arrow_color2",
|
|
L"Main2_arrow_padding", L"Main_arrow_padding2",
|
|
L"Main2_padding", L"Main_padding2",
|
|
L"Main2_icon_padding", L"Main_icon_padding2",
|
|
L"Main2_text_padding", L"Main_text_padding2",
|
|
L"Main2_separator_text_padding", L"Main_separator_text_padding2",
|
|
L"Main2_opacity", L"Main_opacity2",
|
|
L"Main_separatorV_slices_Y", L"Main_separator_slices_Y",
|
|
NULL
|
|
};
|
|
|
|
// Load the skin from the module. If hMod is NULL loads the "custom" skin from 1.txt
|
|
bool MenuSkin::LoadSkin( HMODULE hMod, const wchar_t *variation, const wchar_t *optionsStr, TSkinType skinType, unsigned int flags, int dpi )
|
|
{
|
|
Version=1;
|
|
SkinType=skinType;
|
|
Dpi=dpi;
|
|
CSkinParser parser;
|
|
parser.SetAliases(g_SkinSettingAliases);
|
|
if (hMod)
|
|
{
|
|
HRSRC hResInfo=FindResource(hMod,MAKEINTRESOURCE((hMod==g_Instance && skinType==SKIN_TYPE_WIN7)?2:1),L"SKIN");
|
|
if (!hResInfo)
|
|
{
|
|
Strcpy(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_FIND_RES1));
|
|
return false;
|
|
}
|
|
if (!parser.LoadText(hMod,hResInfo))
|
|
{
|
|
Strcpy(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_LOAD_RES1));
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wchar_t path[_MAX_PATH];
|
|
GetSkinsPath(path);
|
|
Strcat(path,_countof(path),L"1.txt");
|
|
if (!parser.LoadText(path))
|
|
{
|
|
Sprintf(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_LOAD_FILE1),path);
|
|
return false;
|
|
}
|
|
}
|
|
parser.ParseText();
|
|
|
|
const wchar_t *str=NULL;
|
|
|
|
if (skinType==SKIN_TYPE_CLASSIC1)
|
|
str=parser.FindSetting(L"Classic1_options");
|
|
else if (skinType==SKIN_TYPE_CLASSIC2)
|
|
str=parser.FindSetting(L"Classic2_options");
|
|
else if (skinType==SKIN_TYPE_ALL_PROGRAMS)
|
|
str=parser.FindSetting(L"AllPrograms_options");
|
|
CString optionsList;
|
|
if (str)
|
|
optionsList=str;
|
|
if (optionsList.IsEmpty() || FindToken(optionsList,L"variations"))
|
|
{
|
|
for (int i=1;;i++)
|
|
{
|
|
wchar_t name[20];
|
|
Sprintf(name,_countof(name),L"Variation%d",i);
|
|
str=parser.FindSetting(name);
|
|
if (str)
|
|
{
|
|
LOG_MENU(LOG_OPEN,L"Variation setting: '%s'",str);
|
|
wchar_t token[256];
|
|
str=GetToken(str,token,_countof(token),L", \t");
|
|
int res=_wtol(token);
|
|
str=GetToken(str,token,_countof(token),L", \t");
|
|
Variation var;
|
|
if (token[0]=='#')
|
|
{
|
|
int id=_wtol(token+1);
|
|
Strcpy(token,_countof(token),LoadStringEnglish(id));
|
|
wchar_t *find=wcschr(token,'#');
|
|
if (find)
|
|
*find=0;
|
|
var.labelEn=token;
|
|
Strcpy(token,_countof(token),LoadStringEx(id));
|
|
|
|
}
|
|
wchar_t *find=wcschr(token,'#');
|
|
if (find)
|
|
{
|
|
var.tip=find+1;
|
|
*find=0;
|
|
}
|
|
var.label=token;
|
|
if (var.labelEn.IsEmpty())
|
|
var.labelEn=var.label;
|
|
Variations.emplace_back(res,var);
|
|
LOG_MENU(LOG_OPEN,L"Variation found: name=%s, id=%d",token,res);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (variation)
|
|
{
|
|
for (std::vector<std::pair<int,Variation>>::const_iterator it=Variations.begin();it!=Variations.end();++it)
|
|
if (_wcsicmp(variation,it->second.label)==0 || _wcsicmp(variation,it->second.labelEn)==0)
|
|
{
|
|
if (it->first<=1) break;
|
|
LOG_MENU(LOG_OPEN,L"Loading variation: name=%s, id=%d",it->second,it->first);
|
|
if (hMod)
|
|
{
|
|
HRSRC hResInfo=FindResource(hMod,MAKEINTRESOURCE(it->first),L"SKIN");
|
|
if (!hResInfo)
|
|
{
|
|
Sprintf(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_FIND_RES),it->first);
|
|
break;
|
|
}
|
|
if (!parser.LoadVariation(hMod,hResInfo))
|
|
{
|
|
Sprintf(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_LOAD_RES),it->first);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wchar_t path[_MAX_PATH];
|
|
GetSkinsPath(path);
|
|
wchar_t name[20];
|
|
Sprintf(name,_countof(name),L"%d.txt",it->first);
|
|
Strcat(path,_countof(path),name);
|
|
if (!parser.LoadVariation(path))
|
|
{
|
|
Sprintf(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_LOAD_FILE),path);
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// parse options
|
|
std::vector<CString> currentGroup;
|
|
int groupId=-1;
|
|
for (int lineIdx=0;;lineIdx++)
|
|
{
|
|
MenuSkin::Option option;
|
|
CString label;
|
|
if (!parser.ParseOption(option.name,option.type,label,option.bDefValue,option.condition,option.disValue,lineIdx))
|
|
break;
|
|
if (option.name.IsEmpty())
|
|
continue;
|
|
|
|
if (option.type!=SKIN_OPTION_GROUP && !optionsList.IsEmpty() && !FindToken(optionsList,option.name))
|
|
continue;
|
|
int find=label.Find('#');
|
|
if (find>=0)
|
|
{
|
|
option.label=label.Mid(0,find);
|
|
option.tip=label.Mid(find+1);
|
|
}
|
|
else
|
|
option.label=label;
|
|
if (option.type==SKIN_OPTION_GROUP)
|
|
{
|
|
const wchar_t *str=option.condition;
|
|
while (*str)
|
|
{
|
|
wchar_t token[100];
|
|
str=GetToken(str,token,_countof(token),L" \t|");
|
|
CString name=token;
|
|
currentGroup.push_back(name);
|
|
}
|
|
option.condition.Empty();
|
|
option.groupId=++groupId;
|
|
option.bEnabled=true;
|
|
option.bValue=false;
|
|
}
|
|
else
|
|
{
|
|
option.groupId=-1;
|
|
for (std::vector<CString>::const_iterator it=currentGroup.begin();it!=currentGroup.end();++it)
|
|
{
|
|
if (option.name==*it)
|
|
{
|
|
option.groupId=groupId;
|
|
option.condition.Empty(); // radio groups can't be disabled
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (option.name==L"TWO_COLUMNS" && option.type==SKIN_OPTION_BOOL)
|
|
{
|
|
// disable TWO_COLUMNS if it exists
|
|
option.condition=L"FALSE";
|
|
option.bDefValue=(skinType==SKIN_TYPE_CLASSIC2);
|
|
option.disValue.Empty();
|
|
}
|
|
}
|
|
|
|
option.bValue=false;
|
|
Options.push_back(option);
|
|
}
|
|
// remove empty groups
|
|
for (size_t i=0;i<Options.size();)
|
|
{
|
|
if (Options[i].type==SKIN_OPTION_GROUP && (i+1>=Options.size() || Options[i].groupId!=Options[i+1].groupId))
|
|
Options.erase(Options.begin()+i);
|
|
else
|
|
i++;
|
|
}
|
|
|
|
str=parser.FindSetting(L"ForceTouch");
|
|
ForceTouch=(str && _wtol(str)==1); // do before ComputeOptionStates
|
|
|
|
std::map<CString,CString> options;
|
|
ParseOptionsString(optionsStr,options);
|
|
std::vector<const wchar_t*> values; // list of all true values
|
|
if (!ComputeOptionStates(options,values,true))
|
|
return false;
|
|
|
|
if (values.empty())
|
|
parser.FilterConditions(NULL,0);
|
|
else
|
|
parser.FilterConditions(&values[0],(int)values.size());
|
|
|
|
std::vector<std::pair<CString,CString>> macros;
|
|
for (std::vector<Option>::const_iterator it=Options.begin();it!=Options.end();++it)
|
|
{
|
|
if (it->type>SKIN_OPTION_BOOL && it->bValue)
|
|
macros.push_back(std::make_pair(it->name,it->sValue));
|
|
}
|
|
if (!macros.empty())
|
|
parser.ApplyMacros(macros);
|
|
|
|
// parse settings
|
|
str=parser.FindSetting(L"About");
|
|
if (str)
|
|
{
|
|
if (str[0]=='#')
|
|
About=LoadStringEx(_wtol(str+1));
|
|
else
|
|
About=str;
|
|
About.Replace(L"\\n",L"\n");
|
|
}
|
|
else About.Empty();
|
|
|
|
str=parser.FindSetting(L"AboutIcon");
|
|
if (str) AboutIcon=LoadSkinIcon(hMod,_wtol(str));
|
|
|
|
str=parser.FindSetting(L"Version");
|
|
if (str)
|
|
Version=_wtol(str);
|
|
|
|
if (Version>MAX_SKIN_VERSION && (flags&LOADMENU_RESOURCES))
|
|
{
|
|
Strcpy(MenuSkin::s_SkinError,_countof(MenuSkin::s_SkinError),LoadStringEx(IDS_SKIN_ERR_VERSION));
|
|
return false;
|
|
}
|
|
|
|
ForceRTL=false;
|
|
if (!hMod)
|
|
{
|
|
str=parser.FindSetting(L"ForceRTL");
|
|
if (str && _wtol(str))
|
|
ForceRTL=true;
|
|
}
|
|
|
|
bool bRTL=ForceRTL || IsLanguageRTL();
|
|
|
|
g_GlassColorR=g_GlassColorG=g_GlassColorB=g_GlassColorA=0;
|
|
GetMenuGlassColor(g_GlassColorR,g_GlassColorG,g_GlassColorB,g_GlassColorA);
|
|
|
|
if (skinType!=SKIN_TYPE_ALL_PROGRAMS && (flags&LOADMENU_RESOURCES))
|
|
{
|
|
if (!LoadSkinColors(parser,L"Main_background",&Main_background,1,GetSysColor(COLOR_MENU)))
|
|
Main_background=GetSysColor(COLOR_MENU);
|
|
|
|
// CAPTION SECTION - describes the caption portion of the main menu
|
|
str=parser.FindSetting(L"Caption_font");
|
|
Caption_font=LoadSkinFont(str,L"Segoe UI",FW_NORMAL,18,true);
|
|
if (!LoadSkinColors(parser,L"Caption_text_color",&Caption_text_color,1,Main_background))
|
|
Caption_text_color=0xFFFFFF;
|
|
|
|
if (!LoadSkinColors(parser,L"Caption_glow_color",&Caption_glow_color,1,Main_background))
|
|
Caption_glow_color=0xFFFFFF;
|
|
|
|
str=parser.FindSetting(L"Caption_glow_size");
|
|
if (str)
|
|
Caption_glow_size=_wtol(str);
|
|
else
|
|
Caption_glow_size=0;
|
|
|
|
str=parser.FindSetting(L"Caption_padding");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Caption_padding0,4,NUMBERS_PADDING);
|
|
else
|
|
memset(&Caption_padding0,0,sizeof(Caption_padding0));
|
|
|
|
|
|
// MENU SECTION - describes the menu portion of the main menu
|
|
TwoColumns=(skinType==SKIN_TYPE_CLASSIC2 || skinType==SKIN_TYPE_WIN7);
|
|
|
|
memset(Main_bitmap_slices_X,0,sizeof(Main_bitmap_slices_X));
|
|
if (!LoadSkinBackground(hMod,parser,L"Main_bitmap",Main_bitmap,Main_background,Main_bitmap_slices_X+(TwoColumns?3:0),6,Main_bitmap_slices_Y,6,false))
|
|
return false;
|
|
|
|
str=parser.FindSetting(L"Main_opacity");
|
|
Main_opacity=MenuSkin::OPACITY_SOLID;
|
|
if (str && Main_bitmap.GetBitmap())
|
|
{
|
|
if (_wcsicmp(str,L"region")==0) Main_opacity=MenuSkin::OPACITY_REGION;
|
|
if (_wcsicmp(str,L"alpha")==0) Main_opacity=MenuSkin::OPACITY_ALPHA;
|
|
if (_wcsicmp(str,L"glass")==0) Main_opacity=MenuSkin::OPACITY_GLASS;
|
|
if (_wcsicmp(str,L"fullalpha")==0) Main_opacity=MenuSkin::OPACITY_FULLALPHA;
|
|
if (_wcsicmp(str,L"fullglass")==0) Main_opacity=MenuSkin::OPACITY_FULLGLASS;
|
|
}
|
|
Main2_opacity=Main_opacity;
|
|
str=parser.FindSetting(L"Main2_opacity");
|
|
if (str)
|
|
{
|
|
if (Main2_opacity==MenuSkin::OPACITY_ALPHA || Main2_opacity==MenuSkin::OPACITY_FULLALPHA)
|
|
{
|
|
if (_wcsicmp(str,L"alpha")==0) Main2_opacity=MenuSkin::OPACITY_ALPHA;
|
|
if (_wcsicmp(str,L"fullalpha")==0) Main2_opacity=MenuSkin::OPACITY_FULLALPHA;
|
|
}
|
|
if (Main2_opacity==MenuSkin::OPACITY_GLASS || Main2_opacity==MenuSkin::OPACITY_FULLGLASS)
|
|
{
|
|
if (_wcsicmp(str,L"glass")==0) Main2_opacity=MenuSkin::OPACITY_GLASS;
|
|
if (_wcsicmp(str,L"fullglass")==0) Main2_opacity=MenuSkin::OPACITY_FULLGLASS;
|
|
}
|
|
}
|
|
Search_opacity=Main_opacity;
|
|
str=parser.FindSetting(L"Search_opacity");
|
|
if (str)
|
|
{
|
|
if (Search_opacity==MenuSkin::OPACITY_ALPHA || Search_opacity==MenuSkin::OPACITY_FULLALPHA)
|
|
{
|
|
if (_wcsicmp(str,L"alpha")==0) Search_opacity=MenuSkin::OPACITY_ALPHA;
|
|
if (_wcsicmp(str,L"fullalpha")==0) Search_opacity=MenuSkin::OPACITY_FULLALPHA;
|
|
}
|
|
if (Main2_opacity==MenuSkin::OPACITY_GLASS || Main2_opacity==MenuSkin::OPACITY_FULLGLASS)
|
|
{
|
|
if (_wcsicmp(str,L"glass")==0) Search_opacity=MenuSkin::OPACITY_GLASS;
|
|
if (_wcsicmp(str,L"fullglass")==0) Search_opacity=MenuSkin::OPACITY_FULLGLASS;
|
|
}
|
|
}
|
|
Jumplist_opacity=Main_opacity;
|
|
str=parser.FindSetting(L"Jumplist_opacity");
|
|
if (str)
|
|
{
|
|
if (Jumplist_opacity==MenuSkin::OPACITY_ALPHA || Main2_opacity==MenuSkin::OPACITY_FULLALPHA)
|
|
{
|
|
if (_wcsicmp(str,L"alpha")==0) Jumplist_opacity=MenuSkin::OPACITY_ALPHA;
|
|
if (_wcsicmp(str,L"fullalpha")==0) Jumplist_opacity=MenuSkin::OPACITY_FULLALPHA;
|
|
}
|
|
if (Jumplist_opacity==MenuSkin::OPACITY_GLASS || Main2_opacity==MenuSkin::OPACITY_FULLGLASS)
|
|
{
|
|
if (_wcsicmp(str,L"glass")==0) Jumplist_opacity=MenuSkin::OPACITY_GLASS;
|
|
if (_wcsicmp(str,L"fullglass")==0) Jumplist_opacity=MenuSkin::OPACITY_FULLGLASS;
|
|
}
|
|
}
|
|
|
|
Main_shadow=SHADOW_ON;
|
|
str=parser.FindSetting(L"Main_shadow");
|
|
if (str)
|
|
{
|
|
if (_wcsicmp(str,L"1")==0) Main_shadow=MenuSkin::SHADOW_ON;
|
|
if (_wcsicmp(str,L"0")==0) Main_shadow=MenuSkin::SHADOW_OFF;
|
|
if (_wcsicmp(str,L"glass")==0) Main_shadow=MenuSkin::SHADOW_GLASS;
|
|
}
|
|
|
|
str=parser.FindSetting(L"Main_thin_frame");
|
|
Main_thin_frame=(str && _wtol(str));
|
|
|
|
for (int i=0;i<_countof(Main_emblems);i++)
|
|
{
|
|
wchar_t name[100];
|
|
Sprintf(name,_countof(name),L"Main_emblem%d",i+1);
|
|
if (!LoadSkinBitmap(hMod,parser,name,Main_emblems[i],&Main_emblem_sizes[i],bRTL))
|
|
return false;
|
|
Sprintf(name,_countof(name),L"Main_emblem%d_padding",i+1);
|
|
str=parser.FindSetting(name);
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Main_emblem_paddings[i],4,NUMBERS_PADDING);
|
|
else
|
|
memset(&Main_emblem_paddings[i],0,sizeof(Main_emblem_paddings[i]));
|
|
Sprintf(name,_countof(name),L"Main_emblem%d_alignH",i+1);
|
|
str=parser.FindSetting(name);
|
|
if (str)
|
|
{
|
|
wchar_t token[100];
|
|
str=GetToken(str,token,_countof(token),L"|");
|
|
Main_emblem_alignH1[i]=ParseHAlign(token);
|
|
Main_emblem_alignH2[i]=Main_emblem_alignH1[i];
|
|
if (*str)
|
|
{
|
|
str=GetToken(str,token,_countof(token),L"|");
|
|
Main_emblem_alignH2[i]=ParseHAlign(token);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Main_emblem_alignH1[i]=HALIGN_CENTER;
|
|
Main_emblem_alignH2[i]=HALIGN_CENTER;
|
|
}
|
|
Sprintf(name,_countof(name),L"Main_emblem%d_alignV",i+1);
|
|
Main_emblem_alignV[i]=ParseVAlign(parser.FindSetting(name));
|
|
}
|
|
if (!LoadSkinBackground(hMod,parser,L"Main_emblem_mask",Main_emblem_mask,0,NULL,0,NULL,0,false,true,false))
|
|
return false;
|
|
|
|
if (!LoadSkinBitmap(hMod,parser,L"Pattern1",Patterns[0],&Pattern_sizes[0],bRTL))
|
|
return false;
|
|
if (!LoadSkinBitmap(hMod,parser,L"Pattern2",Patterns[1],&Pattern_sizes[1],bRTL))
|
|
return false;
|
|
if (!LoadSkinBitmap(hMod,parser,L"Pattern3",Patterns[2],&Pattern_sizes[2],bRTL))
|
|
return false;
|
|
if (!LoadSkinBitmap(hMod,parser,L"Pattern4",Patterns[3],&Pattern_sizes[3],bRTL))
|
|
return false;
|
|
if (!LoadSkinBackground(hMod,parser,L"Main_pattern_mask",Main_pattern_mask,0,NULL,0,NULL,0,false,true,false))
|
|
return false;
|
|
|
|
Main_icon_size=ParseIconSize(parser.FindSetting(L"Main_icon_size"));
|
|
Main2_icon_size=ParseIconSize(parser.FindSetting(L"Main2_icon_size"));
|
|
|
|
str=parser.FindSetting(L"Main_large_icons");
|
|
bool Main_large_icons2=(str && _wtol(str));
|
|
if (Main_large_icons2)
|
|
Main_icon_size=ICON_SIZE_LARGE;
|
|
|
|
if (skinType==SKIN_TYPE_WIN7)
|
|
Main2_icon_size=ICON_SIZE_NONE;
|
|
else
|
|
{
|
|
str=parser.FindSetting(L"Main_no_icons2");
|
|
if (str && _wtol(str))
|
|
Main2_icon_size=ICON_SIZE_NONE;
|
|
}
|
|
|
|
if (Main_icon_size==ICON_SIZE_UNDEFINED)
|
|
Main_icon_size=ICON_SIZE_SMALL;
|
|
if (Main2_icon_size==ICON_SIZE_UNDEFINED)
|
|
Main2_icon_size=Main_icon_size;
|
|
|
|
str=parser.FindSetting(L"Main_padding");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Main_padding0,4,NUMBERS_PADDING);
|
|
else
|
|
memset(&Main_padding0,0,sizeof(Main_padding0));
|
|
|
|
str=parser.FindSetting(L"Main_search_padding");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Main_search_padding0,4,NUMBERS_PADDING);
|
|
else
|
|
memset(&Main_search_padding0,0,sizeof(Main_search_padding0));
|
|
|
|
str=parser.FindSetting(L"Main_jump_padding");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Main_jump_padding0,4,NUMBERS_PADDING);
|
|
else
|
|
memset(&Main_jump_padding0,0,sizeof(Main_jump_padding0));
|
|
|
|
str=parser.FindSetting(L"Main2_padding");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Main2_padding0,4,NUMBERS_PADDING);
|
|
else
|
|
memset(&Main2_padding0,-1,sizeof(Main2_padding0));
|
|
|
|
str=parser.FindSetting(L"Main_search_indent");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Main_search_indent,1,NUMBERS_SIZE);
|
|
else
|
|
Main_search_indent=0;
|
|
|
|
// first column
|
|
if (!LoadSkinItem(hMod,parser,L"Main",ItemSettings[COLUMN1_ITEM],NULL,Main_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Main_split",ItemSettings[COLUMN1_SPLIT],&ItemSettings[COLUMN1_ITEM],Main_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Main_new",ItemSettings[COLUMN1_NEW],&ItemSettings[COLUMN1_ITEM],Main_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Main_separator",ItemSettings[COLUMN1_SEPARATOR],&ItemSettings[COLUMN1_ITEM],Main_background,bRTL))
|
|
return false;
|
|
ItemSettings[COLUMN1_SEPARATOR].sepHeight=ScaleSkinElement(DEFAULT_SEPARATOR_HEIGHT);
|
|
str=parser.FindSetting(L"Main_separator");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"Main_separator",ItemSettings[COLUMN1_SEPARATOR].bmpSeparator,Main_background,ItemSettings[COLUMN1_SEPARATOR].sepSlicesX,_countof(ItemSettings[COLUMN1_SEPARATOR].sepSlicesX),&ItemSettings[COLUMN1_SEPARATOR].sepHeight,0,bRTL))
|
|
return false;
|
|
}
|
|
|
|
bHasNewItem=parser.FindSetting(L"Main_new_selection")!=NULL;
|
|
|
|
// second column
|
|
if (!LoadSkinItem(hMod,parser,L"Main2",ItemSettings[COLUMN2_ITEM],&ItemSettings[COLUMN1_ITEM],Main_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Main2_split",ItemSettings[COLUMN2_SPLIT],&ItemSettings[COLUMN2_ITEM],Main_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Main2_new",ItemSettings[COLUMN2_NEW],&ItemSettings[COLUMN2_ITEM],Main_background,bRTL))
|
|
return false;
|
|
ItemSettings[COLUMN2_SEPARATOR].sepHeight=ScaleSkinElement(DEFAULT_SEPARATOR_HEIGHT);
|
|
str=parser.FindSetting(L"Main2_separator");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"Main2_separator",ItemSettings[COLUMN2_SEPARATOR].bmpSeparator,Main_background,ItemSettings[COLUMN2_SEPARATOR].sepSlicesX,_countof(ItemSettings[COLUMN2_SEPARATOR].sepSlicesX),&ItemSettings[COLUMN2_SEPARATOR].sepHeight,0,bRTL))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
ItemSettings[COLUMN2_SEPARATOR].bmpSeparator=ItemSettings[COLUMN1_SEPARATOR].bmpSeparator;
|
|
ItemSettings[COLUMN2_SEPARATOR].bmpSeparator.bIsOwned=false;
|
|
ItemSettings[COLUMN2_SEPARATOR].sepHeight=ItemSettings[COLUMN1_SEPARATOR].sepHeight;
|
|
memcpy(ItemSettings[COLUMN2_SEPARATOR].sepSlicesX,ItemSettings[COLUMN1_SEPARATOR].sepSlicesX,sizeof(ItemSettings[COLUMN2_SEPARATOR].sepSlicesX));
|
|
}
|
|
|
|
Main_separatorWidth=ScaleSkinElement(DEFAULT_SEPARATOR_WIDTH);
|
|
str=parser.FindSetting(L"Main_separatorV");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"Main_separatorV",Main_separatorV,Main_background,&Main_separatorWidth,0,Main_separator_slices_Y,_countof(Main_separator_slices_Y),false))
|
|
return false;
|
|
}
|
|
|
|
if (!LoadSkinBackground(hMod,parser,L"Main_pager",Main_pager,Main_background,Main_pager_slices_X,_countof(Main_pager_slices_X),Main_pager_slices_Y,_countof(Main_pager_slices_Y),bRTL))
|
|
return false;
|
|
|
|
if (!LoadSkinBitmap(hMod,parser,L"Main_pager_arrows",Main_pager_arrows,&Main_pager_arrow_Size,bRTL))
|
|
return false;
|
|
Main_pager_arrow_Size.cx/=2;
|
|
Main_pager_arrow_Size.cy/=2;
|
|
|
|
if (!LoadSkinBitmap(hMod,parser,L"User_bitmap",User_bitmap,&User_bitmapSize,bRTL))
|
|
return false;
|
|
if (!LoadSkinBitmap(hMod,parser,L"User_mask",User_mask,&User_maskSize,bRTL))
|
|
return false;
|
|
User_bitmap_outside=false;
|
|
str=parser.FindSetting(L"User_bitmap_outside");
|
|
if (str)
|
|
{
|
|
User_bitmap_outside=_wtol(str)>0;
|
|
}
|
|
|
|
str=parser.FindSetting(L"User_image_size");
|
|
if (str)
|
|
{
|
|
LoadSkinNumbers(str,(int*)&User_image_size,1,(skinType==SKIN_TYPE_WIN7)?NUMBERS_OTHER:NUMBERS_SIZE);
|
|
if (User_image_size<0) User_image_size=0;
|
|
if (User_image_size>128) User_image_size=128;
|
|
}
|
|
else
|
|
User_image_size=(skinType==SKIN_TYPE_WIN7)?48:0;
|
|
|
|
if (User_bitmapSize.cx==0 && User_maskSize.cx>0 && User_image_size>0)
|
|
{
|
|
User_bitmapSize.cx=User_bitmapSize.cy=User_image_size>64?User_image_size:64;
|
|
}
|
|
|
|
memset(&User_frame_position,0,sizeof(User_frame_position));
|
|
str=parser.FindSetting(L"User_frame_position");
|
|
if (str)
|
|
{
|
|
if (skinType!=SKIN_TYPE_WIN7)
|
|
{
|
|
wchar_t token[256];
|
|
const wchar_t *str2=GetToken(str,token,_countof(token),L", \t");
|
|
if (_wcsicmp(token,L"center")==0)
|
|
User_frame_position.x=MenuSkin::USER_CENTER;
|
|
else if (_wcsicmp(token,L"center1")==0)
|
|
User_frame_position.x=MenuSkin::USER_CENTER1;
|
|
else if (_wcsicmp(token,L"center2")==0)
|
|
User_frame_position.x=MenuSkin::USER_CENTER2;
|
|
if (User_frame_position.x==0)
|
|
LoadSkinNumbers(str,(int*)&User_frame_position,2,NUMBERS_PADDING);
|
|
else
|
|
LoadSkinNumbers(str2,(int*)&User_frame_position.y,1,NUMBERS_PADDING);
|
|
}
|
|
else
|
|
{
|
|
LoadSkinNumbers(str,(int*)&User_frame_position,1,NUMBERS_PADDING);
|
|
}
|
|
}
|
|
else if (skinType==SKIN_TYPE_WIN7)
|
|
User_frame_position.x=36;
|
|
|
|
str=parser.FindSetting(L"User_image_offset");
|
|
if (str && User_bitmap.GetBitmap())
|
|
LoadSkinNumbers(str,(int*)&User_image_offset,2,NUMBERS_OTHER);
|
|
else if (skinType==SKIN_TYPE_WIN7)
|
|
{
|
|
User_image_offset.x=(User_bitmapSize.cx-User_image_size)/2;
|
|
User_image_offset.y=(User_bitmapSize.cy-User_image_size)/2;
|
|
}
|
|
else
|
|
User_image_offset.x=User_image_offset.y=2;
|
|
|
|
if (skinType==SKIN_TYPE_WIN7)
|
|
{
|
|
if (User_image_size>User_bitmapSize.cx)
|
|
User_image_size=User_bitmapSize.cx;
|
|
if (User_image_size>User_bitmapSize.cy)
|
|
User_image_size=User_bitmapSize.cy;
|
|
if (User_image_offset.x>User_bitmapSize.cx-User_image_size)
|
|
User_image_offset.x=User_bitmapSize.cx-User_image_size;
|
|
if (User_image_offset.y>User_bitmapSize.cy-User_image_size)
|
|
User_image_offset.y=User_bitmapSize.cy-User_image_size;
|
|
}
|
|
|
|
str=parser.FindSetting(L"User_image_alpha");
|
|
if (str)
|
|
User_image_alpha=_wtol(str)&255;
|
|
else
|
|
User_image_alpha=255;
|
|
|
|
User_image_padding=ScaleSkinElement(DEFAULT_USER_IMAGE_PADDING);
|
|
str=parser.FindSetting(L"User_image_padding");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&User_image_padding,2,NUMBERS_PADDING);
|
|
|
|
str=parser.FindSetting(L"User_name_position");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&User_name_position,4,NUMBERS_SIZE);
|
|
else
|
|
memset(&User_name_position,0,sizeof(User_name_position));
|
|
|
|
User_name_align=ParseHAlign(parser.FindSetting(L"User_name_align"));
|
|
|
|
str=parser.FindSetting(L"User_font");
|
|
User_font=LoadSkinFont(str,L"Segoe UI",FW_NORMAL,18,false);
|
|
if (!LoadSkinColors(parser,L"User_text_color",&User_text_color,1,Main_background))
|
|
User_text_color=GetSysColor(COLOR_MENUTEXT);
|
|
|
|
if (!LoadSkinColors(parser,L"User_glow_color",&User_glow_color,1,Main_background))
|
|
User_glow_color=0xFFFFFF;
|
|
|
|
str=parser.FindSetting(L"User_glow_size");
|
|
if (str)
|
|
User_glow_size=_wtol(str);
|
|
else
|
|
User_glow_size=0;
|
|
|
|
if (Main_bitmap_slices_X[1]==0)
|
|
{
|
|
Main_bitmap_slices_X[0]=Main_bitmap_slices_X[2]=0;
|
|
memset(&Caption_padding0,0,sizeof(Caption_padding0));
|
|
}
|
|
|
|
str=parser.FindSetting(L"Search_hint_font");
|
|
if (str)
|
|
{
|
|
Search_hint_font=LoadSkinFont(str,NULL,0,0,true);
|
|
BOwnHintFont=true;
|
|
}
|
|
else
|
|
{
|
|
Search_hint_font=ItemSettings[COLUMN1_ITEM].font;
|
|
BOwnHintFont=false;
|
|
}
|
|
|
|
if (!LoadSkinColors(parser,L"Search_text_color",Search_text_colors,2,Main_background))
|
|
{
|
|
Search_text_colors[0]=GetSysColor(COLOR_WINDOWTEXT);
|
|
Search_text_colors[1]=GetSysColor(COLOR_GRAYTEXT);
|
|
}
|
|
if (!LoadSkinColors(parser,L"Search_text_background",&Search_text_background,1,Main_background))
|
|
Search_text_background=GetSysColor(COLOR_WINDOW);
|
|
|
|
if (skinType==SKIN_TYPE_WIN7)
|
|
{
|
|
memset(Main_bitmap_search_slices_X,0,sizeof(Main_bitmap_search_slices_X));
|
|
if (!LoadSkinBackground(hMod,parser,L"Main_bitmap_search",Main_bitmap_search,Main_background,Main_bitmap_search_slices_X+3,6,Main_bitmap_search_slices_Y,6,false))
|
|
return false;
|
|
memset(Main_bitmap_jump_slices_X,0,sizeof(Main_bitmap_jump_slices_X));
|
|
if (!LoadSkinBackground(hMod,parser,L"Main_bitmap_jump",Main_bitmap_jump,Main_background,Main_bitmap_jump_slices_X+3,6,Main_bitmap_jump_slices_Y,6,false))
|
|
return false;
|
|
|
|
if (!LoadSkinBackground(hMod,parser,L"Main_emblem_search_mask",Main_emblem_search_mask,0,NULL,0,NULL,0,false,true,false))
|
|
return false;
|
|
if (!LoadSkinBackground(hMod,parser,L"Main_emblem_jump_mask",Main_emblem_jump_mask,0,NULL,0,NULL,0,false,true,false))
|
|
return false;
|
|
if (!LoadSkinBackground(hMod,parser,L"Main_pattern_search_mask",Main_pattern_search_mask,0,NULL,0,NULL,0,false,true,false))
|
|
return false;
|
|
if (!LoadSkinBackground(hMod,parser,L"Main_pattern_jump_mask",Main_pattern_jump_mask,0,NULL,0,NULL,0,false,true,false))
|
|
return false;
|
|
|
|
// Shutdown button
|
|
if (!LoadSkinItem(hMod,parser,L"Shutdown",ItemSettings[SHUTDOWN_BUTTON],&ItemSettings[COLUMN1_ITEM],Main_background,bRTL))
|
|
return false;
|
|
str=parser.FindSetting(L"Shutdown_text_color");
|
|
if (!str)
|
|
ItemSettings[SHUTDOWN_BUTTON].textColors[0]=ItemSettings[SHUTDOWN_BUTTON].textColors[1]=GetSysColor(COLOR_BTNTEXT);
|
|
str=parser.FindSetting(L"Shutdown_arrow_color");
|
|
if (!str)
|
|
ItemSettings[SHUTDOWN_BUTTON].arrColors[0]=ItemSettings[SHUTDOWN_BUTTON].arrColors[1]=GetSysColor(COLOR_BTNTEXT);
|
|
if (!LoadSkinItem(hMod,parser,L"Shutdown_search",ItemSettings[SHUTDOWN_BUTTON_SEARCH],&ItemSettings[SHUTDOWN_BUTTON],Main_background,bRTL))
|
|
return false;
|
|
memcpy(ItemSettings[SHUTDOWN_BUTTON_SEARCH].selSlicesX,ItemSettings[SHUTDOWN_BUTTON].selSlicesX,sizeof(ItemSettings[SHUTDOWN_BUTTON_SEARCH].selSlicesX));
|
|
memcpy(ItemSettings[SHUTDOWN_BUTTON_SEARCH].selSlicesY,ItemSettings[SHUTDOWN_BUTTON].selSlicesY,sizeof(ItemSettings[SHUTDOWN_BUTTON_SEARCH].selSlicesY));
|
|
if (!LoadSkinItem(hMod,parser,L"Shutdown_jump",ItemSettings[SHUTDOWN_BUTTON_JUMP],&ItemSettings[SHUTDOWN_BUTTON],Main_background,bRTL))
|
|
return false;
|
|
memcpy(ItemSettings[SHUTDOWN_BUTTON_JUMP].selSlicesX,ItemSettings[SHUTDOWN_BUTTON].selSlicesX,sizeof(ItemSettings[SHUTDOWN_BUTTON_JUMP].selSlicesX));
|
|
memcpy(ItemSettings[SHUTDOWN_BUTTON_JUMP].selSlicesY,ItemSettings[SHUTDOWN_BUTTON].selSlicesY,sizeof(ItemSettings[SHUTDOWN_BUTTON_JUMP].selSlicesY));
|
|
str=parser.FindSetting(L"Shutdown_padding");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Shutdown_padding,4,NUMBERS_PADDING);
|
|
else
|
|
memset(&Shutdown_padding,0,sizeof(Shutdown_padding));
|
|
|
|
// List items
|
|
if (!LoadSkinItem(hMod,parser,L"List",ItemSettings[LIST_ITEM],&ItemSettings[COLUMN1_ITEM],Main_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"List_split",ItemSettings[LIST_SPLIT],&ItemSettings[LIST_ITEM],Main_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"List_separator",ItemSettings[LIST_SEPARATOR],&ItemSettings[LIST_ITEM],Main_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"List_separator_split",ItemSettings[LIST_SEPARATOR_SPLIT],&ItemSettings[LIST_SPLIT],Main_background,bRTL))
|
|
return false;
|
|
ItemSettings[LIST_SEPARATOR].sepHeight=ScaleSkinElement(DEFAULT_SEPARATOR_HEIGHT);
|
|
str=parser.FindSetting(L"List_separator");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"List_separator",ItemSettings[LIST_SEPARATOR].bmpSeparator,Main_background,ItemSettings[LIST_SEPARATOR].sepSlicesX,_countof(ItemSettings[LIST_SEPARATOR].sepSlicesX),&ItemSettings[LIST_SEPARATOR].sepHeight,0,bRTL))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
ItemSettings[LIST_SEPARATOR].bmpSeparator=ItemSettings[COLUMN1_SEPARATOR].bmpSeparator;
|
|
ItemSettings[LIST_SEPARATOR].bmpSeparator.bIsOwned=false;
|
|
ItemSettings[LIST_SEPARATOR].sepHeight=ItemSettings[COLUMN1_SEPARATOR].sepHeight;
|
|
memcpy(ItemSettings[LIST_SEPARATOR].sepSlicesX,ItemSettings[COLUMN1_SEPARATOR].sepSlicesX,sizeof(ItemSettings[COLUMN1_SEPARATOR].sepSlicesX));
|
|
}
|
|
str=parser.FindSetting(L"List_separator_split");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"List_separator_split",ItemSettings[LIST_SEPARATOR_SPLIT].bmpSeparator,Main_background,ItemSettings[LIST_SEPARATOR_SPLIT].sepSlicesX,_countof(ItemSettings[LIST_SEPARATOR_SPLIT].sepSlicesX),&ItemSettings[LIST_SEPARATOR_SPLIT].sepHeight,0,bRTL))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
ItemSettings[LIST_SEPARATOR_SPLIT].bmpSeparator=ItemSettings[COLUMN1_SEPARATOR].bmpSeparator;
|
|
ItemSettings[LIST_SEPARATOR_SPLIT].bmpSeparator.bIsOwned=false;
|
|
ItemSettings[LIST_SEPARATOR_SPLIT].sepHeight=ItemSettings[COLUMN1_SEPARATOR].sepHeight;
|
|
memcpy(ItemSettings[LIST_SEPARATOR_SPLIT].sepSlicesX,ItemSettings[COLUMN1_SEPARATOR].sepSlicesX,sizeof(ItemSettings[COLUMN1_SEPARATOR].sepSlicesX));
|
|
}
|
|
|
|
// PROGRAMS SECTION
|
|
str=parser.FindSetting(L"Programs_background");
|
|
if (str && _wcsicmp(str,L"transparent")==0)
|
|
Programs_background=0;
|
|
else
|
|
{
|
|
if (!LoadSkinColors(parser,L"Programs_background",&Programs_background,1,Main_background,NUMBERS_COLORS_ABGR))
|
|
Programs_background=GetSysColor(COLOR_WINDOW);
|
|
|
|
// premultiply alpha
|
|
int a=Programs_background>>24;
|
|
if (a==0)
|
|
Programs_background|=0xFF000000;
|
|
else if (a<255)
|
|
{
|
|
int r=(Programs_background&255)*a/255;
|
|
int g=((Programs_background>>8)&255)*a/255;
|
|
int b=((Programs_background>>16)&255)*a/255;
|
|
Programs_background=(a<<24)|(b<<16)|(g<<8)|r;
|
|
}
|
|
}
|
|
|
|
if (!LoadSkinItem(hMod,parser,L"Programs_button",ItemSettings[PROGRAMS_BUTTON],&ItemSettings[COLUMN1_ITEM],Programs_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Programs_button_new",ItemSettings[PROGRAMS_BUTTON_NEW],&ItemSettings[COLUMN1_NEW],Programs_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Programs_cascading",ItemSettings[PROGRAMS_CASCADING],&ItemSettings[PROGRAMS_BUTTON],Programs_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Programs_cascading_new",ItemSettings[PROGRAMS_CASCADING_NEW],&ItemSettings[PROGRAMS_BUTTON_NEW],Programs_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Programs",ItemSettings[PROGRAMS_TREE_ITEM],&ItemSettings[COLUMN1_ITEM],Programs_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Programs_new",ItemSettings[PROGRAMS_TREE_NEW],&ItemSettings[PROGRAMS_TREE_ITEM],Programs_background,bRTL))
|
|
return false;
|
|
str=parser.FindSetting(L"Programs_indent");
|
|
if (str)
|
|
LoadSkinNumbers(str,&Programs_indent,1,NUMBERS_SIZE);
|
|
else
|
|
Programs_indent=0;
|
|
|
|
if (!LoadSkinBitmap(hMod,parser,L"Programs_icon",Programs_icon,&Programs_icon_size,bRTL))
|
|
return false;
|
|
if (Programs_icon.GetBitmap())
|
|
{
|
|
SIZE selSize;
|
|
if (!LoadSkinBitmap(hMod,parser,L"Programs_icon_selected",Programs_icon_selected,&selSize,bRTL))
|
|
return false;
|
|
if (!Programs_icon_selected.GetBitmap() || selSize.cx!=Programs_icon_size.cx || selSize.cy!=Programs_icon_size.cy)
|
|
{
|
|
Programs_icon_selected.Reset();
|
|
Programs_icon_selected=Programs_icon;
|
|
Programs_icon_selected.bIsOwned=false;
|
|
}
|
|
}
|
|
Programs_icon_size.cy/=2;
|
|
|
|
if (parser.FindSetting(L"Scrollbar_button") && parser.FindSetting(L"Scrollbar_thumb") && parser.FindSetting(L"Scrollbar_background") && parser.FindSetting(L"Scrollbar_arrows"))
|
|
{
|
|
BHasScrollbar=true;
|
|
if (!LoadSkinBackground(hMod,parser,L"Scrollbar_button",Scrollbar_button,Programs_background,Scrollbar_button_slices_X,_countof(Scrollbar_button_slices_X),Scrollbar_button_slices_Y,_countof(Scrollbar_button_slices_Y),bRTL,true))
|
|
return false;
|
|
if (!LoadSkinBackground(hMod,parser,L"Scrollbar_thumb",Scrollbar_thumb,Programs_background,Scrollbar_thumb_slices_X,_countof(Scrollbar_thumb_slices_X),Scrollbar_thumb_slices_Y,_countof(Scrollbar_thumb_slices_Y),bRTL,true))
|
|
return false;
|
|
if (!LoadSkinBackground(hMod,parser,L"Scrollbar_background",Scrollbar_background,Programs_background,Scrollbar_background_slices_X,_countof(Scrollbar_background_slices_X),Scrollbar_background_slices_Y,_countof(Scrollbar_background_slices_Y),bRTL,true))
|
|
return false;
|
|
if (!LoadSkinBitmap(hMod,parser,L"Scrollbar_arrows",Scrollbar_arrows,&Scrollbar_arrows_size,bRTL))
|
|
return false;
|
|
Scrollbar_arrows_size.cx/=2;
|
|
Scrollbar_arrows_size.cy/=3;
|
|
|
|
if (parser.FindSetting(L"Scrollbar_gripper"))
|
|
{
|
|
if (!LoadSkinBitmap(hMod,parser,L"Scrollbar_gripper",Scrollbar_gripper,&Scrollbar_gripper_size,bRTL))
|
|
return false;
|
|
Scrollbar_gripper_size.cy/=3;
|
|
}
|
|
else
|
|
Scrollbar_gripper_size.cx=Scrollbar_gripper_size.cy=0;
|
|
}
|
|
}
|
|
|
|
// SEARCH SECTION
|
|
if (!LoadSkinBitmap(hMod,parser,L"Search_bitmap",Search_bitmap,NULL,false))
|
|
return false;
|
|
|
|
if (!LoadSkinBitmap(hMod,parser,L"Search_arrow",Search_arrow,&Search_arrow_size,bRTL))
|
|
return false;
|
|
Search_arrow_size.cy/=2;
|
|
|
|
COLORREF searchColor=GetSysColor(COLOR_WINDOW);
|
|
str=parser.FindSetting(L"Search_padding");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Search_padding,4,NUMBERS_PADDING);
|
|
else
|
|
Search_padding=ScaleSkinElement(DEFAULT_SEARCH_PADDING);
|
|
str=parser.FindSetting(L"Search_frame");
|
|
Search_frame=!str || _wtol(str)!=0;
|
|
str=parser.FindSetting(L"Search_background");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"Search_background",Search_background,searchColor,Search_background_slices_X,_countof(Search_background_slices_X),Search_background_slices_Y,_countof(Search_background_slices_Y),false,true))
|
|
return false;
|
|
}
|
|
str=parser.FindSetting(L"Search_background_padding");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Search_background_padding,4,NUMBERS_PADDING);
|
|
else
|
|
memset(&Search_background_padding,0,sizeof(Search_background_padding));
|
|
|
|
if (!LoadSkinBackground(hMod,parser,L"Search_emblem_mask",Search_emblem_mask,0,NULL,0,NULL,0,false,true,false))
|
|
return false;
|
|
if (!LoadSkinBackground(hMod,parser,L"Search_pattern_mask",Search_pattern_mask,0,NULL,0,NULL,0,false,true,false))
|
|
return false;
|
|
|
|
str=parser.FindSetting(L"Search_background_search");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"Search_background_search",Search_background_search,searchColor,Search_background_search_slices_X,_countof(Search_background_search_slices_X),Search_background_search_slices_Y,_countof(Search_background_search_slices_Y),false,true))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
Search_background_search=Search_background;
|
|
Search_background_search.bIsOwned=false;
|
|
memcpy(Search_background_search_slices_X,Search_background_slices_X,sizeof(Search_background_search_slices_X));
|
|
memcpy(Search_background_search_slices_Y,Search_background_slices_Y,sizeof(Search_background_search_slices_Y));
|
|
}
|
|
str=parser.FindSetting(L"Search_background_search_padding");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Search_background_search_padding,4,NUMBERS_PADDING);
|
|
else
|
|
memcpy(&Search_background_search_padding,&Search_background_padding,sizeof(Search_background_search_padding));
|
|
|
|
str=parser.FindSetting(L"Search_emblem_search_mask");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"Search_emblem_search_mask",Search_emblem_search_mask,0,NULL,0,NULL,0,false,true,false))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
Search_emblem_search_mask=Search_emblem_mask;
|
|
Search_emblem_search_mask.bIsOwned=false;
|
|
}
|
|
|
|
str=parser.FindSetting(L"Search_pattern_search_mask");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"Search_pattern_search_mask",Search_pattern_search_mask,0,NULL,0,NULL,0,false,true,false))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
Search_pattern_search_mask=Search_pattern_mask;
|
|
Search_pattern_search_mask.bIsOwned=false;
|
|
}
|
|
|
|
str=parser.FindSetting(L"Search_background_jump");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"Search_background_jump",Search_background_jump,searchColor,Search_background_jump_slices_X,_countof(Search_background_jump_slices_X),Search_background_jump_slices_Y,_countof(Search_background_jump_slices_Y),false,true))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
Search_background_jump=Search_background;
|
|
Search_background_jump.bIsOwned=false;
|
|
memcpy(Search_background_jump_slices_X,Search_background_slices_X,sizeof(Search_background_jump_slices_X));
|
|
memcpy(Search_background_jump_slices_Y,Search_background_slices_Y,sizeof(Search_background_jump_slices_Y));
|
|
}
|
|
str=parser.FindSetting(L"Search_background_jump_padding");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Search_background_jump_padding,4,NUMBERS_PADDING);
|
|
else
|
|
memcpy(&Search_background_jump_padding,&Search_background_padding,sizeof(Search_background_jump_padding));
|
|
|
|
str=parser.FindSetting(L"Search_emblem_jump_mask");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"Search_emblem_jump_mask",Search_emblem_jump_mask,0,NULL,0,NULL,0,false,true,false))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
Search_emblem_jump_mask=Search_emblem_mask;
|
|
Search_emblem_jump_mask.bIsOwned=false;
|
|
}
|
|
|
|
str=parser.FindSetting(L"Search_pattern_jump_mask");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"Search_pattern_jump_mask",Search_pattern_jump_mask,0,NULL,0,NULL,0,false,true,false))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
Search_pattern_jump_mask=Search_pattern_mask;
|
|
Search_pattern_jump_mask.bIsOwned=false;
|
|
}
|
|
|
|
HMODULE hImageRes=NULL;
|
|
str=parser.FindSetting(L"Pin_bitmap");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBitmap(hMod,parser,L"Pin_bitmap",Pin_bitmap,&Pin_bitmap_Size,bRTL))
|
|
return false;
|
|
Pin_bitmap_Size.cx/=2;
|
|
Pin_bitmap_Size.cy/=2;
|
|
}
|
|
else
|
|
{
|
|
int iconSize=CItemManager::SMALL_ICON_SIZE;
|
|
Pin_bitmap_Size.cx=Pin_bitmap_Size.cy=iconSize;
|
|
BITMAPINFO bi={0};
|
|
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
|
|
bi.bmiHeader.biWidth=bi.bmiHeader.biHeight=iconSize*2;
|
|
bi.bmiHeader.biPlanes=1;
|
|
bi.bmiHeader.biBitCount=32;
|
|
RECT rc={0,0,iconSize*2,iconSize*2};
|
|
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
unsigned int *bits;
|
|
HBITMAP bmp=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,(void**)&bits,NULL,0);
|
|
HGDIOBJ bmp0=SelectObject(hdc,bmp);
|
|
FillRect(hdc,&rc,(HBRUSH)GetStockObject(BLACK_BRUSH));
|
|
|
|
HMODULE hMod=GetModuleHandle(L"imageres.dll");
|
|
if (!hMod)
|
|
{
|
|
hMod=LoadLibraryEx(L"imageres.dll",NULL,LOAD_LIBRARY_AS_DATAFILE|LOAD_LIBRARY_AS_IMAGE_RESOURCE);
|
|
hImageRes=hMod;
|
|
}
|
|
if (hMod)
|
|
{
|
|
HICON hIcon=(HICON)LoadImage(hMod,MAKEINTRESOURCE(5101),IMAGE_ICON,iconSize,iconSize,LR_DEFAULTCOLOR);
|
|
DrawIconEx(hdc,0,0,hIcon,iconSize,iconSize,0,NULL,DI_NORMAL);
|
|
DrawIconEx(hdc,0,iconSize,hIcon,iconSize,iconSize,0,NULL,DI_NORMAL);
|
|
DestroyIcon(hIcon);
|
|
hIcon=(HICON)LoadImage(hMod,MAKEINTRESOURCE(5100),IMAGE_ICON,iconSize,iconSize,LR_DEFAULTCOLOR);
|
|
DrawIconEx(hdc,iconSize,0,hIcon,iconSize,iconSize,0,NULL,DI_NORMAL);
|
|
DrawIconEx(hdc,iconSize,iconSize,hIcon,iconSize,iconSize,0,NULL,DI_NORMAL);
|
|
DestroyIcon(hIcon);
|
|
}
|
|
SelectObject(hdc,bmp0);
|
|
DeleteDC(hdc);
|
|
Pin_bitmap=bmp;
|
|
Pin_bitmap.bIsOwned=true;
|
|
Pin_bitmap.bIs32=true;
|
|
}
|
|
|
|
str=parser.FindSetting(L"More_bitmap");
|
|
if (str)
|
|
{
|
|
if (wcscmp(str,L"none")==0)
|
|
More_bitmap_Size.cx=More_bitmap_Size.cy=0;
|
|
else if (!LoadSkinBitmap(hMod,parser,L"More_bitmap",More_bitmap,&More_bitmap_Size,bRTL))
|
|
return false;
|
|
else
|
|
More_bitmap_Size.cy/=2;
|
|
}
|
|
else
|
|
{
|
|
int iconSize=CItemManager::SMALL_ICON_SIZE;
|
|
More_bitmap_Size.cx=More_bitmap_Size.cy=iconSize;
|
|
BITMAPINFO bi={0};
|
|
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
|
|
bi.bmiHeader.biWidth=iconSize;
|
|
bi.bmiHeader.biHeight=iconSize*2;
|
|
bi.bmiHeader.biPlanes=1;
|
|
bi.bmiHeader.biBitCount=32;
|
|
RECT rc={0,0,iconSize,iconSize*2};
|
|
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
unsigned int *bits;
|
|
HBITMAP bmp=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,(void**)&bits,NULL,0);
|
|
HGDIOBJ bmp0=SelectObject(hdc,bmp);
|
|
FillRect(hdc,&rc,(HBRUSH)GetStockObject(BLACK_BRUSH));
|
|
|
|
HMODULE hMod=GetModuleHandle(L"shell32.dll");
|
|
if (hMod)
|
|
{
|
|
HICON hIcon=(HICON)LoadImage(hMod,MAKEINTRESOURCE(323),IMAGE_ICON,iconSize,iconSize,LR_DEFAULTCOLOR);
|
|
DrawIconEx(hdc,0,0,hIcon,iconSize,iconSize,0,NULL,DI_NORMAL);
|
|
DrawIconEx(hdc,0,iconSize,hIcon,iconSize,iconSize,0,NULL,DI_NORMAL);
|
|
DestroyIcon(hIcon);
|
|
}
|
|
SelectObject(hdc,bmp0);
|
|
DeleteDC(hdc);
|
|
More_bitmap=bmp;
|
|
More_bitmap.bIsOwned=true;
|
|
More_bitmap.bIs32=true;
|
|
}
|
|
|
|
if (skinType==SKIN_TYPE_WIN7)
|
|
{
|
|
str=parser.FindSetting(L"Shutdown_bitmap");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBitmap(hMod,parser,L"Shutdown_bitmap",Shutdown_bitmap,&Shutdown_bitmap_Size,bRTL))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
HMODULE hMod=GetModuleHandle(L"shell32.dll");
|
|
/* if (!hMod)
|
|
{
|
|
if (hImageRes)
|
|
hMod=hImageRes;
|
|
else
|
|
{
|
|
hMod=LoadLibraryEx(L"imageres.dll",NULL,LOAD_LIBRARY_AS_DATAFILE|LOAD_LIBRARY_AS_IMAGE_RESOURCE);
|
|
hImageRes=hMod;
|
|
}
|
|
}*/
|
|
if (hMod)
|
|
{
|
|
int iconSize=Dpi>=144?24:16;
|
|
HICON hIcon=(HICON)LoadImage(hMod,MAKEINTRESOURCE(47),IMAGE_ICON,iconSize,iconSize,LR_DEFAULTCOLOR);
|
|
if (hIcon)
|
|
{
|
|
Shutdown_bitmap=BitmapFromIcon(hIcon,iconSize,NULL,TRUE);
|
|
Shutdown_bitmap.bIsOwned=true;
|
|
Shutdown_bitmap.bIs32=true;
|
|
Shutdown_bitmap_Size.cx=iconSize;
|
|
Shutdown_bitmap_Size.cy=iconSize;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (hImageRes)
|
|
FreeLibrary(hImageRes);
|
|
|
|
}
|
|
|
|
// SUB-MENU SECTION - describes the menu portion of the sub-menu
|
|
if (!LoadSkinColors(parser,L"Submenu_background",&Submenu_background,1,GetSysColor(COLOR_MENU)))
|
|
Submenu_background=GetSysColor(COLOR_MENU);
|
|
|
|
if (flags&LOADMENU_RESOURCES)
|
|
{
|
|
memset(Submenu_bitmap_slices_X,0,sizeof(Submenu_bitmap_slices_X));
|
|
// the submenu bitmap is mirrored here, unlike the main bitmap, which is mirrored in CreateBackground
|
|
if (!LoadSkinBackground(hMod,parser,L"Submenu_bitmap",Submenu_bitmap,Submenu_background,Submenu_bitmap_slices_X+3,6,Submenu_bitmap_slices_Y,_countof(Submenu_bitmap_slices_Y),bRTL))
|
|
return false;
|
|
|
|
str=parser.FindSetting(L"Submenu_opacity");
|
|
Submenu_opacity=MenuSkin::OPACITY_SOLID;
|
|
if (str && Submenu_bitmap.GetBitmap())
|
|
{
|
|
if (_wcsicmp(str,L"region")==0) Submenu_opacity=MenuSkin::OPACITY_REGION;
|
|
if (_wcsicmp(str,L"alpha")==0) Submenu_opacity=MenuSkin::OPACITY_ALPHA;
|
|
if (_wcsicmp(str,L"glass")==0) Submenu_opacity=MenuSkin::OPACITY_GLASS;
|
|
if (_wcsicmp(str,L"fullalpha")==0) Submenu_opacity=MenuSkin::OPACITY_FULLALPHA;
|
|
if (_wcsicmp(str,L"fullglass")==0) Submenu_opacity=MenuSkin::OPACITY_FULLGLASS;
|
|
}
|
|
|
|
Submenu_shadow=SHADOW_ON;
|
|
str=parser.FindSetting(L"Submenu_shadow");
|
|
if (str)
|
|
{
|
|
if (_wcsicmp(str,L"1")==0) Submenu_shadow=MenuSkin::SHADOW_ON;
|
|
if (_wcsicmp(str,L"0")==0) Submenu_shadow=MenuSkin::SHADOW_OFF;
|
|
if (_wcsicmp(str,L"glass")==0) Submenu_shadow=MenuSkin::SHADOW_GLASS;
|
|
}
|
|
|
|
if (!LoadSkinItem(hMod,parser,L"Submenu",ItemSettings[SUBMENU_ITEM],NULL,Submenu_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Submenu_split",ItemSettings[SUBMENU_SPLIT],&ItemSettings[SUBMENU_ITEM],Submenu_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Submenu_new",ItemSettings[SUBMENU_NEW],&ItemSettings[SUBMENU_ITEM],Submenu_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Submenu_separator",ItemSettings[SUBMENU_SEPARATOR],&ItemSettings[SUBMENU_ITEM],Submenu_background,bRTL))
|
|
return false;
|
|
if (!LoadSkinItem(hMod,parser,L"Submenu_separator_split",ItemSettings[SUBMENU_SEPARATOR_SPLIT],&ItemSettings[SUBMENU_SPLIT],Submenu_background,bRTL))
|
|
return false;
|
|
ItemSettings[SUBMENU_SEPARATOR].sepHeight=ScaleSkinElement(DEFAULT_SEPARATOR_HEIGHT);
|
|
str=parser.FindSetting(L"Submenu_separator");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"Submenu_separator",ItemSettings[SUBMENU_SEPARATOR].bmpSeparator,Main_background,ItemSettings[SUBMENU_SEPARATOR].sepSlicesX,_countof(ItemSettings[SUBMENU_SEPARATOR].sepSlicesX),&ItemSettings[SUBMENU_SEPARATOR].sepHeight,0,bRTL))
|
|
return false;
|
|
}
|
|
ItemSettings[SUBMENU_SEPARATOR_SPLIT].sepHeight=ScaleSkinElement(DEFAULT_SEPARATOR_HEIGHT);
|
|
str=parser.FindSetting(L"Submenu_separator_split");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"Submenu_separator_split",ItemSettings[SUBMENU_SEPARATOR_SPLIT].bmpSeparator,Main_background,ItemSettings[SUBMENU_SEPARATOR_SPLIT].sepSlicesX,_countof(ItemSettings[SUBMENU_SEPARATOR_SPLIT].sepSlicesX),&ItemSettings[SUBMENU_SEPARATOR_SPLIT].sepHeight,0,bRTL))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
ItemSettings[SUBMENU_SEPARATOR_SPLIT].bmpSeparator=ItemSettings[SUBMENU_SEPARATOR].bmpSeparator;
|
|
ItemSettings[SUBMENU_SEPARATOR_SPLIT].bmpSeparator.bIsOwned=false;
|
|
ItemSettings[SUBMENU_SEPARATOR_SPLIT].sepHeight=ItemSettings[SUBMENU_SEPARATOR].sepHeight;
|
|
memcpy(ItemSettings[SUBMENU_SEPARATOR_SPLIT].sepSlicesX,ItemSettings[SUBMENU_SEPARATOR].sepSlicesX,sizeof(ItemSettings[SUBMENU_SEPARATOR].sepSlicesX));
|
|
}
|
|
|
|
str=parser.FindSetting(L"Submenu_padding");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Submenu_padding0,4,NUMBERS_PADDING);
|
|
else
|
|
memset(&Submenu_padding0,0,sizeof(Submenu_padding0));
|
|
str=parser.FindSetting(L"Submenu_offset");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&Submenu_offset,1,NUMBERS_SIZE);
|
|
else
|
|
Submenu_offset=0;
|
|
|
|
str=parser.FindSetting(L"AllPrograms_offset");
|
|
if (str)
|
|
LoadSkinNumbers(str,(int*)&AllPrograms_offset,1,NUMBERS_SIZE);
|
|
else
|
|
AllPrograms_offset=0;
|
|
|
|
str=parser.FindSetting(L"Submenu_thin_frame");
|
|
Submenu_thin_frame=(str && _wtol(str));
|
|
|
|
str=parser.FindSetting(L"Submenu_separatorV");
|
|
if (str)
|
|
{
|
|
if (!LoadSkinBackground(hMod,parser,L"Submenu_separatorV",Submenu_separatorV,Submenu_background,&Submenu_separatorWidth,0,Submenu_separator_slices_Y,_countof(Submenu_separator_slices_Y),bRTL))
|
|
return false;
|
|
}
|
|
if (!Submenu_separatorV.GetBitmap())
|
|
Submenu_separatorWidth=ScaleSkinElement(DEFAULT_SEPARATOR_WIDTH);
|
|
if (!LoadSkinBackground(hMod,parser,L"Submenu_pager",Submenu_pager,Submenu_background,Submenu_pager_slices_X,_countof(Submenu_pager_slices_X),Submenu_pager_slices_Y,_countof(Submenu_pager_slices_Y),bRTL))
|
|
return false;
|
|
|
|
if (!LoadSkinBitmap(hMod,parser,L"Submenu_pager_arrows",Submenu_pager_arrows,&Submenu_pager_arrow_Size,bRTL))
|
|
return false;
|
|
Submenu_pager_arrow_Size.cx/=2;
|
|
Submenu_pager_arrow_Size.cy/=2;
|
|
}
|
|
|
|
Main_FakeGlass=false;
|
|
Submenu_FakeGlass=false;
|
|
WORD winVer=GetWinVersion();
|
|
if ((winVer>=WIN_VER_WIN8 && winVer<WIN_VER_WIN10 && !GetSettingBool(L"AeroGlass")) || (winVer>=WIN_VER_WIN10 && !GetSettingBool(L"EnableGlass")))
|
|
{
|
|
// replace GLASS with ALPHA and enable the fake glass (alpha with less opacity)
|
|
if (Main_opacity==OPACITY_GLASS)
|
|
{
|
|
Main_opacity=OPACITY_ALPHA;
|
|
Main_FakeGlass=true;
|
|
}
|
|
if (Main_opacity==OPACITY_FULLGLASS)
|
|
{
|
|
Main_opacity=OPACITY_FULLALPHA;
|
|
Main_FakeGlass=true;
|
|
}
|
|
if (Main2_opacity==OPACITY_GLASS)
|
|
Main2_opacity=OPACITY_ALPHA;
|
|
if (Main2_opacity==OPACITY_FULLGLASS)
|
|
Main2_opacity=OPACITY_FULLALPHA;
|
|
if (Submenu_opacity==OPACITY_GLASS)
|
|
{
|
|
Submenu_opacity=OPACITY_ALPHA;
|
|
Submenu_FakeGlass=true;
|
|
}
|
|
if (Submenu_opacity==OPACITY_FULLGLASS)
|
|
{
|
|
Submenu_opacity=OPACITY_FULLALPHA;
|
|
Submenu_FakeGlass=true;
|
|
}
|
|
}
|
|
|
|
if (Main_shadow==SHADOW_GLASS && Main_opacity!=OPACITY_GLASS && Main_opacity!=OPACITY_FULLGLASS)
|
|
Main_shadow=SHADOW_OFF;
|
|
if (Submenu_shadow==SHADOW_GLASS && Submenu_opacity!=OPACITY_GLASS && Submenu_opacity!=OPACITY_FULLGLASS)
|
|
Submenu_shadow=SHADOW_OFF;
|
|
|
|
ItemSettings[COLUMN2_INLINE]=ItemSettings[COLUMN2_ITEM];
|
|
ItemSettings[COLUMN2_INLINE].bOwnFont=false;
|
|
ItemSettings[COLUMN2_INLINE].bmpSelection.bIsOwned=false;
|
|
ItemSettings[COLUMN2_INLINE].bmpArrow.bIsOwned=false;
|
|
ItemSettings[COLUMN2_INLINE].bmpIconFrame.bIsOwned=false;
|
|
ItemSettings[COLUMN2_INLINE].bmpSeparator.bIsOwned=false;
|
|
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
HGDIOBJ font0=GetCurrentObject(hdc,OBJ_FONT);
|
|
for (int i=0;i<_countof(ItemSettings);i++)
|
|
{
|
|
ItemDrawSettings &settings=ItemSettings[i];
|
|
|
|
switch (i)
|
|
{
|
|
case COLUMN1_ITEM:
|
|
case COLUMN1_SPLIT:
|
|
case COLUMN1_NEW:
|
|
case COLUMN1_SEPARATOR:
|
|
settings.iconSize=Main_icon_size;
|
|
settings.opacity=Main_opacity;
|
|
break;
|
|
case COLUMN2_ITEM:
|
|
case COLUMN2_SPLIT:
|
|
case COLUMN2_NEW:
|
|
case COLUMN2_SEPARATOR:
|
|
settings.iconSize=Main2_icon_size;
|
|
settings.opacity=Main2_opacity;
|
|
break;
|
|
case COLUMN2_INLINE:
|
|
settings.iconSize=Main2_icon_size!=ICON_SIZE_NONE?Main2_icon_size:Main_icon_size;
|
|
settings.opacity=Main2_opacity;
|
|
break;
|
|
case SUBMENU_ITEM:
|
|
case SUBMENU_SPLIT:
|
|
case SUBMENU_NEW:
|
|
case SUBMENU_SEPARATOR:
|
|
case SUBMENU_SEPARATOR_SPLIT:
|
|
settings.iconSize=ICON_SIZE_SMALL;
|
|
settings.opacity=Submenu_opacity;
|
|
break;
|
|
|
|
// special items
|
|
case PROGRAMS_TREE_ITEM:
|
|
case PROGRAMS_TREE_NEW:
|
|
settings.iconSize=ICON_SIZE_SMALL;
|
|
settings.opacity=(((Main_opacity==OPACITY_FULLALPHA || Main_opacity==OPACITY_FULLGLASS) && Programs_background<0xFF000000) || Programs_background==0)?Main_opacity:OPACITY_SOLID;
|
|
break;
|
|
case LIST_ITEM:
|
|
case LIST_SPLIT:
|
|
case LIST_SEPARATOR:
|
|
case LIST_SEPARATOR_SPLIT:
|
|
settings.iconSize=ICON_SIZE_SMALL;
|
|
settings.opacity=(Search_opacity==OPACITY_FULLALPHA || Search_opacity==OPACITY_FULLGLASS)?Search_opacity:OPACITY_SOLID;
|
|
break;
|
|
|
|
case PROGRAMS_BUTTON:
|
|
case PROGRAMS_BUTTON_NEW:
|
|
case PROGRAMS_CASCADING:
|
|
case PROGRAMS_CASCADING_NEW:
|
|
settings.iconSize=ICON_SIZE_PROGRAMS;
|
|
settings.opacity=(Main_opacity==OPACITY_FULLALPHA || Main_opacity==OPACITY_FULLGLASS)?Main_opacity:OPACITY_SOLID;
|
|
if (Programs_icon.GetBitmap())
|
|
{
|
|
int dx=(Main_icon_size==ICON_SIZE_LARGE?g_ItemManager.LARGE_ICON_SIZE:g_ItemManager.SMALL_ICON_SIZE)-Programs_icon_size.cx;
|
|
if (dx>0)
|
|
settings.iconPadding.right+=dx;
|
|
}
|
|
break;
|
|
|
|
case SHUTDOWN_BUTTON:
|
|
settings.iconSize=ICON_SIZE_NONE;
|
|
settings.opacity=Main2_opacity;
|
|
break;
|
|
case SHUTDOWN_BUTTON_SEARCH:
|
|
settings.iconSize=ICON_SIZE_NONE;
|
|
settings.opacity=Search_opacity;
|
|
break;
|
|
case SHUTDOWN_BUTTON_JUMP:
|
|
settings.iconSize=ICON_SIZE_NONE;
|
|
settings.opacity=Jumplist_opacity;
|
|
break;
|
|
}
|
|
|
|
if (settings.font)
|
|
{
|
|
SelectObject(hdc,settings.font);
|
|
GetTextMetrics(hdc,&settings.textMetrics);
|
|
}
|
|
else
|
|
{
|
|
memset(&settings.textMetrics,0,sizeof(settings.textMetrics));
|
|
}
|
|
|
|
int textHeight=settings.font?settings.textMetrics.tmHeight+settings.textPadding.top+settings.textPadding.bottom:0;
|
|
if (i==COLUMN2_INLINE)
|
|
textHeight=0;
|
|
int iconHeight=0;
|
|
if (i==LIST_SEPARATOR_SPLIT || i==SUBMENU_SEPARATOR_SPLIT)
|
|
iconHeight=More_bitmap_Size.cy;
|
|
else if (i==SHUTDOWN_BUTTON || i==SHUTDOWN_BUTTON_SEARCH || i==SHUTDOWN_BUTTON_JUMP)
|
|
iconHeight=Shutdown_bitmap_Size.cy;
|
|
else if (settings.iconSize==ICON_SIZE_SMALL)
|
|
iconHeight=g_ItemManager.SMALL_ICON_SIZE;
|
|
else if (settings.iconSize==ICON_SIZE_LARGE)
|
|
iconHeight=g_ItemManager.LARGE_ICON_SIZE;
|
|
else if (settings.iconSize==ICON_SIZE_PROGRAMS)
|
|
iconHeight=Programs_icon_size.cy?Programs_icon_size.cy:10;
|
|
iconHeight+=settings.iconPadding.top+settings.iconPadding.bottom;
|
|
if (iconHeight<textHeight)
|
|
{
|
|
settings.iconTopOffset=(textHeight-iconHeight)/2;
|
|
settings.textTopOffset=0;
|
|
settings.itemHeight=textHeight;
|
|
}
|
|
else
|
|
{
|
|
settings.iconTopOffset=0;
|
|
settings.textTopOffset=(iconHeight-textHeight)/2;
|
|
settings.itemHeight=iconHeight;
|
|
}
|
|
}
|
|
SelectObject(hdc,font0);
|
|
DeleteDC(hdc);
|
|
|
|
{
|
|
LOGFONT lfont;
|
|
GetObject(ItemSettings[(skinType==SKIN_TYPE_WIN7)?LIST_SEPARATOR:SUBMENU_SEPARATOR].font,sizeof(lfont),&lfont);
|
|
lfont.lfUnderline=TRUE;
|
|
Search_underline_font=CreateFontIndirect(&lfont);
|
|
}
|
|
|
|
#ifndef SIMULATE_METRO_COLORS
|
|
if (!*s_SkinError && BHasMetroColors && GetWinVersion()==WIN_VER_WIN7)
|
|
{
|
|
Strcpy(s_SkinError,_countof(s_SkinError),LoadStringEx(IDS_SKIN_ERR_METRO_COLOR));
|
|
return false;
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
bool MenuSkin::LoadMenuSkin( const wchar_t *fname, const wchar_t *variation, const wchar_t *optionsStr, TSkinType skinType, unsigned int flags, int dpi )
|
|
{
|
|
s_SkinError[0]=0;
|
|
wchar_t path[_MAX_PATH];
|
|
GetSkinsPath(path);
|
|
|
|
if (!*fname || _wcsicmp(fname,LoadStringEx(IDS_DEFAULT_SKIN))==0)
|
|
{
|
|
Reset();
|
|
LoadDefaultMenuSkin(skinType,flags,dpi);
|
|
Hash=0;
|
|
return true;
|
|
}
|
|
|
|
BOOL bTheme=IsAppThemed();
|
|
BOOL bComp;
|
|
if (!bTheme || FAILED(DwmIsCompositionEnabled(&bComp)))
|
|
bComp=FALSE;
|
|
BOOL bEnableTouch=(GetWinVersion()>=WIN_VER_WIN8 && GetSettingBool(L"EnableTouch") && (GetSystemMetrics(SM_DIGITIZER)&NID_INTEGRATED_TOUCH)!=0);
|
|
bool bAeroGlass=GetSettingBool(L"AeroGlass");
|
|
bool bEnableGlass=GetSettingBool(L"EnableGlass");
|
|
bool bSearchBox=GetSettingInt(L"SearchBox")!=SEARCHBOX_HIDDEN;
|
|
int settings[]={
|
|
(bAeroGlass?1:0)|(bEnableGlass?2:0)|(bSearchBox?4:0),
|
|
GetSettingInt(L"FontSmoothing"),
|
|
bTheme,
|
|
bComp,
|
|
bEnableTouch
|
|
};
|
|
|
|
unsigned int skinHash=CalcFNVHash(settings,sizeof(settings));
|
|
if (variation)
|
|
skinHash=CalcFNVHash(variation,skinHash);
|
|
|
|
int colors[4]={0};
|
|
GetMenuGlassColor(colors[0],colors[1],colors[2],colors[3]);
|
|
|
|
skinHash=CalcFNVHash(&colors,sizeof(colors),skinHash);
|
|
skinHash=CalcFNVHash(optionsStr,skinHash);
|
|
|
|
unsigned int metroColorHash;
|
|
if (GetImmersiveUserColorSetPreference!=NULL)
|
|
{
|
|
g_CurrentMetroColorSet=GetImmersiveUserColorSetPreference(false,false);
|
|
metroColorHash=CalcMetroColorHash(g_CurrentMetroColorSet);
|
|
}
|
|
else
|
|
metroColorHash=CalcMetroColorHash(0);
|
|
|
|
if (_wcsicmp(fname,L"Custom")==0)
|
|
{
|
|
Reset();
|
|
if (!LoadSkin(NULL,variation,optionsStr,skinType,flags,dpi))
|
|
{
|
|
Reset();
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Strcat(path,_countof(path),fname);
|
|
Strcat(path,_countof(path),(skinType==SKIN_TYPE_WIN7)?L".skin7":L".skin");
|
|
skinHash=CalcFNVHash(path,skinHash);
|
|
WIN32_FILE_ATTRIBUTE_DATA attributes={0};
|
|
if (GetFileAttributesEx(path,GetFileExInfoStandard,&attributes))
|
|
skinHash=CalcFNVHash(&attributes.ftLastWriteTime,sizeof(FILETIME),skinHash);
|
|
if (Hash==skinHash && MetroColorHash==metroColorHash && dpi==Dpi)
|
|
{
|
|
bool bDifferent=false;
|
|
for (std::vector<CustomBitmap>::const_iterator it=CustomBitmaps.begin();it!=CustomBitmaps.end();++it)
|
|
{
|
|
if (!GetFileAttributesEx(it->path,GetFileExInfoStandard,&attributes) || CompareFileTime(&attributes.ftLastWriteTime,&it->timestamp)!=0)
|
|
{
|
|
bDifferent=true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bDifferent)
|
|
return true;
|
|
}
|
|
Reset();
|
|
HMODULE hMod=LoadLibraryEx(path,NULL,LOAD_LIBRARY_AS_DATAFILE|LOAD_LIBRARY_AS_IMAGE_RESOURCE);
|
|
if (!hMod)
|
|
{
|
|
wchar_t err[1024];
|
|
GetErrorMessage(err,_countof(err),GetLastError());
|
|
Sprintf(s_SkinError,_countof(s_SkinError),LoadStringEx(IDS_SKIN_ERR_LOAD),path,err);
|
|
return false;
|
|
}
|
|
|
|
if (!LoadSkin(hMod,variation,optionsStr,skinType,flags,dpi))
|
|
{
|
|
Reset();
|
|
FreeLibrary(hMod);
|
|
return false;
|
|
}
|
|
|
|
FreeLibrary(hMod);
|
|
}
|
|
Hash=skinHash;
|
|
|
|
MetroColorHash=CalcMetroColorHash();
|
|
|
|
if (!bComp)
|
|
{
|
|
if (Main_opacity!=OPACITY_SOLID)
|
|
Main_opacity=OPACITY_REGION;
|
|
|
|
if (Main2_opacity!=OPACITY_SOLID)
|
|
Main2_opacity=OPACITY_REGION;
|
|
|
|
if (Submenu_opacity!=OPACITY_SOLID)
|
|
Submenu_opacity=OPACITY_REGION;
|
|
|
|
for (int i=0;i<_countof(ItemSettings);i++)
|
|
if (ItemSettings[i].opacity!=OPACITY_SOLID)
|
|
ItemSettings[i].opacity=OPACITY_REGION;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static POINT g_ArrowSizes96[]=
|
|
{
|
|
{0,3}, // insert left
|
|
{3,6}, // middle size
|
|
{6,9}, // insert right
|
|
{10,14}, // right arrow
|
|
{14,18}, // left arrow
|
|
{18,25}, // down arrow
|
|
{25,7}, // total size
|
|
};
|
|
|
|
static POINT g_ArrowSizes144[]=
|
|
{
|
|
{0,4}, // insert left
|
|
{3,8}, // middle size
|
|
{7,11}, // insert right
|
|
{12,18}, // right arrow
|
|
{18,24}, // left arrow
|
|
{24,35}, // down arrow
|
|
{35,11}, // total size
|
|
};
|
|
|
|
const POINT *MenuSkin::GetArrowsBitmapSizes( void ) const
|
|
{
|
|
return Dpi>=144?g_ArrowSizes144:g_ArrowSizes96;
|
|
}
|
|
|
|
void MenuSkin::PretilePatterns( int width )
|
|
{
|
|
if (PatternPretileWidth>=width) return;
|
|
PatternPretileWidth=width;
|
|
for (int i=0;i<4;i++)
|
|
{
|
|
if (Patterns[i].GetBitmap())
|
|
{
|
|
BITMAP info;
|
|
GetObject(Patterns[i].GetBitmap(),sizeof(info),&info);
|
|
const unsigned char *src=(unsigned char*)info.bmBits;
|
|
int width2=((width+info.bmWidth-1)/info.bmWidth)*info.bmWidth;
|
|
|
|
// convert the pattern to 32-bit, pretile horizontally, flip vertically
|
|
PatternBits[i].resize(info.bmHeight*width2);
|
|
unsigned int *dst=&PatternBits[i][(info.bmHeight-1)*width2];
|
|
for (int y=0;y<info.bmHeight;y++,src+=info.bmWidthBytes,dst-=width2)
|
|
{
|
|
if (info.bmBitsPixel==24)
|
|
{
|
|
for (int x=0;x<info.bmWidth;x++)
|
|
{
|
|
const unsigned char *pixel=src+x*3;
|
|
dst[x]=pixel[0]|(pixel[1]<<8)|(pixel[2]<<16)|0xFF000000;
|
|
}
|
|
}
|
|
else if (info.bmBitsPixel==32)
|
|
memcpy(dst,src,info.bmWidth*4);
|
|
for (int x=info.bmWidth;x<width2;x+=info.bmWidth)
|
|
memcpy(dst+x,dst,info.bmWidth*4);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MenuSkin::LoadDefaultMenuSkin( TSkinType skinType, unsigned int flags, int dpi )
|
|
{
|
|
LoadSkin(g_Instance,NULL,L"",skinType,flags,dpi);
|
|
}
|
|
|
|
void GetSkinsPath( wchar_t *path )
|
|
{
|
|
GetModuleFileName(g_Instance,path,_MAX_PATH);
|
|
*PathFindFileName(path)=0;
|
|
Strcat(path,_MAX_PATH,L"Skins\\");
|
|
|
|
#ifndef BUILD_SETUP
|
|
if (!PathIsDirectory(path))
|
|
{
|
|
*PathFindFileName(path) = 0;
|
|
Strcat(path,_MAX_PATH,L"..\\Skins\\");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static IatHookData *g_DrawThemeBackgroundHook;
|
|
|
|
DWORD g_CustomScrollbarThread;
|
|
HTHEME g_CustomScrollbarTheme;
|
|
|
|
static HRESULT STDAPICALLTYPE DrawThemeBackgroundSkin( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCRECT pRect, LPCRECT pClipRect )
|
|
{
|
|
if (g_CustomScrollbarThread && g_CustomScrollbarThread==GetCurrentThreadId() && hTheme==g_CustomScrollbarTheme)
|
|
{
|
|
CProgramsTree::DrawScrollbarBackground(hdc,iPartId,iStateId,pRect);
|
|
return S_OK;
|
|
}
|
|
return DrawThemeBackground(hTheme,hdc,iPartId,iStateId,pRect,pClipRect);
|
|
}
|
|
|
|
void InitializeSkinManager( bool bInitIat )
|
|
{
|
|
if (bInitIat)
|
|
InitializeIatHooks();
|
|
HMODULE hComCtl32=GetModuleHandle(L"comctl32.dll");
|
|
if (hComCtl32)
|
|
g_DrawThemeBackgroundHook=SetIatHook(hComCtl32,"uxtheme.dll","DrawThemeBackground",DrawThemeBackgroundSkin);
|
|
#ifdef SIMULATE_METRO_COLORS
|
|
char path[_MAX_PATH];
|
|
GetModuleFileNameA(g_Instance,path,_countof(path));
|
|
*PathFindFileNameA(path)=0;
|
|
Strcat(path,_countof(path),"..\\MetroColors\\" SIMULATE_METRO_COLORS ".txt");
|
|
FILE *f;
|
|
fopen_s(&f,path,"rt");
|
|
if (f)
|
|
{
|
|
for (int i=0;;i++)
|
|
{
|
|
char buf[200]={0};
|
|
fgets(buf,_countof(buf),f);
|
|
if (Strlen(buf)<10) break;
|
|
char *end;
|
|
CString name(buf+9);
|
|
name.Trim(L"\r\n");
|
|
unsigned int crc=CalcFNVHash(name);
|
|
SimMetroColor color;
|
|
color.nameHash=crc;
|
|
color.color=strtoul(buf,&end,16);
|
|
color.color=((color.color&0xFF)<<16)|(color.color&0xFF00FF00)|((color.color>>16)&0xFF);
|
|
g_MetroColors.push_back(color);
|
|
}
|
|
fclose(f);
|
|
}
|
|
#else
|
|
HMODULE hUxTheme=LoadLibrary(L"uxtheme.dll");
|
|
DWORD ver=GetVersionEx(hUxTheme);
|
|
if (hUxTheme && ver>=0x6020000)
|
|
{
|
|
GetImmersiveUserColorSetPreference=(TGetImmersiveUserColorSetPreference)GetProcAddress(hUxTheme,MAKEINTRESOURCEA(98));
|
|
GetImmersiveColorFromColorSetEx=(TGetImmersiveColorFromColorSetEx)GetProcAddress(hUxTheme,MAKEINTRESOURCEA(95));
|
|
GetImmersiveColorTypeFromName=(TGetImmersiveColorTypeFromName)GetProcAddress(hUxTheme,MAKEINTRESOURCEA(96));
|
|
|
|
if (!GetImmersiveColorFromColorSetEx || !GetImmersiveColorTypeFromName)
|
|
GetImmersiveUserColorSetPreference=NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CloseSkinManager( bool bCloseIat )
|
|
{
|
|
CMenuContainer::s_Skin.Reset();
|
|
ClearIatHook(g_DrawThemeBackgroundHook);
|
|
g_DrawThemeBackgroundHook=NULL;
|
|
if (bCloseIat)
|
|
ClearIatHooks();
|
|
}
|