Refactored found skin folder/file data structures

CONFIG and CONFIGMENU have been merged to reduce memory use
This commit is contained in:
Birunthan Mohanathas 2012-06-01 13:05:25 +03:00
parent e3d92d354c
commit 5e4b65ebd2
4 changed files with 335 additions and 258 deletions

View File

@ -457,10 +457,10 @@ void CDialogManage::CTabSkins::Update(CMeterWindow* meterWindow, bool deleted)
TreeView_DeleteAllItems(item); TreeView_DeleteAllItems(item);
TVINSERTSTRUCT tvi = {0}; TVINSERTSTRUCT tvi = {0};
tvi.hInsertAfter = TVI_FIRST; tvi.hInsertAfter = TVI_LAST;
tvi.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE; tvi.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tvi.item.iImage = tvi.item.iSelectedImage = 0; tvi.item.iImage = tvi.item.iSelectedImage = 0;
PopulateTree(item, tvi, Rainmeter->m_ConfigMenu); PopulateTree(item, tvi);
} }
} }
@ -739,26 +739,47 @@ void CDialogManage::CTabSkins::ReadSkin()
** Populates the treeview with folders and skins. ** Populates the treeview with folders and skins.
** **
*/ */
void CDialogManage::CTabSkins::PopulateTree(HWND tree, TVINSERTSTRUCT& tvi, const std::vector<CRainmeter::CONFIGMENU>& configMenuData) int CDialogManage::CTabSkins::PopulateTree(HWND tree, TVINSERTSTRUCT& tvi, int index)
{ {
for (int i = (int)configMenuData.size() - 1; i >= 0; --i) int initialLevel = Rainmeter->m_SkinFolders[index].level;
const size_t max = Rainmeter->m_SkinFolders.size();
while (index < max)
{ {
const CRainmeter::CONFIGMENU& configMenuS = configMenuData[i]; const CRainmeter::SkinFolder& folder = Rainmeter->m_SkinFolders[index];
tvi.item.pszText =(WCHAR*)configMenuS.name.c_str(); if (folder.level != initialLevel)
if (configMenuS.index == -1)
{ {
tvi.item.iImage = tvi.item.iSelectedImage = 0; return index - 1;
HTREEITEM hOldParent = tvi.hParent;
tvi.hParent = (HTREEITEM)TreeView_InsertItem(tree, &tvi);
PopulateTree(tree, tvi, configMenuS.children);
tvi.hParent = hOldParent;
} }
else
HTREEITEM oldParent = tvi.hParent;
// Add folder
tvi.item.iImage = tvi.item.iSelectedImage = 0;
tvi.item.pszText = (WCHAR*)folder.name.c_str();
tvi.hParent = TreeView_InsertItem(tree, &tvi);
// Add subfolders
if ((index + 1) < max &&
Rainmeter->m_SkinFolders[index + 1].level == initialLevel + 1)
{ {
tvi.item.iImage = tvi.item.iSelectedImage = 1; index = PopulateTree(tree, tvi, index + 1);
}
// Add files
tvi.item.iImage = tvi.item.iSelectedImage = 1;
for (int i = 0, isize = (int)folder.files.size(); i < isize; ++i)
{
tvi.item.pszText = (WCHAR*)folder.files[i].c_str();
TreeView_InsertItem(tree, &tvi); TreeView_InsertItem(tree, &tvi);
} }
tvi.hParent = oldParent;
++index;
} }
return index;
} }
/* /*

View File

@ -66,7 +66,7 @@ private:
void DisableControls(bool clear = false); void DisableControls(bool clear = false);
void ReadSkin(); void ReadSkin();
static void PopulateTree(HWND tree, TVINSERTSTRUCT& tvi, const std::vector<CRainmeter::CONFIGMENU>& configMenuData); static int PopulateTree(HWND tree, TVINSERTSTRUCT& tvi, int index = 0);
std::wstring m_FileName; std::wstring m_FileName;
std::wstring m_SkinName; std::wstring m_SkinName;

View File

@ -981,7 +981,7 @@ int CRainmeter::Initialize(LPCWSTR iniPath)
ReloadSettings(); ReloadSettings();
if (m_ConfigStrings.empty()) if (m_SkinFolders.empty())
{ {
std::wstring error = GetFormattedString(ID_STR_NOAVAILABLESKINS, m_SkinPath.c_str()); std::wstring error = GetFormattedString(ID_STR_NOAVAILABLESKINS, m_SkinPath.c_str());
MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONERROR); MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONERROR);
@ -1228,74 +1228,72 @@ void CRainmeter::ActivateActiveConfigs()
std::multimap<int, int>::const_iterator iter = m_ConfigOrders.begin(); std::multimap<int, int>::const_iterator iter = m_ConfigOrders.begin();
for ( ; iter != m_ConfigOrders.end(); ++iter) for ( ; iter != m_ConfigOrders.end(); ++iter)
{ {
const CONFIG& configS = m_ConfigStrings[(*iter).second]; const SkinFolder& folder = m_SkinFolders[(*iter).second];
if (configS.active > 0 && configS.active <= (int)configS.iniFiles.size()) if (folder.active > 0 && folder.active <= (int)folder.files.size())
{ {
ActivateConfig((*iter).second, configS.active - 1); ActivateConfig((*iter).second, folder.active - 1);
} }
} }
} }
void CRainmeter::ActivateConfig(int configIndex, int iniIndex) void CRainmeter::ActivateConfig(int folderIndex, int fileIndex)
{ {
if (configIndex >= 0 && configIndex < (int)m_ConfigStrings.size() && if (folderIndex >= 0 && folderIndex < (int)m_SkinFolders.size() &&
iniIndex >= 0 && iniIndex < (int)m_ConfigStrings[configIndex].iniFiles.size()) fileIndex >= 0 && fileIndex < (int)m_SkinFolders[folderIndex].files.size())
{ {
const std::wstring& skinIniFile = m_ConfigStrings[configIndex].iniFiles[iniIndex]; const SkinFolder& folder = m_SkinFolders[folderIndex];
const std::wstring& skinConfig = m_ConfigStrings[configIndex].config; const std::wstring& skinFile = folder.files[fileIndex];
const WCHAR* file = skinFile.c_str();
std::wstring skinFolder = GetSkinFolderPath(folderIndex);
// Verify that the config is not already active // Verify that the config is not already active
std::map<std::wstring, CMeterWindow*>::const_iterator iter = m_MeterWindows.find(skinConfig); std::map<std::wstring, CMeterWindow*>::const_iterator iter = m_MeterWindows.find(skinFolder);
if (iter != m_MeterWindows.end()) if (iter != m_MeterWindows.end())
{ {
if (((*iter).second)->GetSkinIniFile() == skinIniFile) if (wcscmp(((*iter).second)->GetSkinIniFile().c_str(), file) == 0)
{ {
LogWithArgs(LOG_WARNING, L"!ActivateConfig: \"%s\" already active", skinConfig.c_str()); LogWithArgs(LOG_WARNING, L"!ActivateConfig: \"%s\" already active", skinFolder.c_str());
return; return;
} }
else else
{ {
// Deactivate the existing config // Deactivate the existing config
DeactivateConfig((*iter).second, configIndex); DeactivateConfig((*iter).second, folderIndex);
} }
} }
// Verify whether the ini-file exists // Verify whether the ini-file exists
std::wstring skinIniPath = m_SkinPath + skinConfig; std::wstring skinIniPath = m_SkinPath + skinFolder;
skinIniPath += L'\\'; skinIniPath += L'\\';
skinIniPath += skinIniFile; skinIniPath += skinFile;
if (_waccess(skinIniPath.c_str(), 0) == -1) if (_waccess(skinIniPath.c_str(), 0) == -1)
{ {
std::wstring message = GetFormattedString(ID_STR_UNABLETOACTIVATESKIN, skinConfig.c_str(), skinIniFile.c_str()); std::wstring message = GetFormattedString(ID_STR_UNABLETOACTIVATESKIN, skinFolder.c_str(), file);
MessageBox(NULL, message.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION); MessageBox(NULL, message.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
return; return;
} }
m_ConfigStrings[configIndex].active = iniIndex + 1; m_SkinFolders[folderIndex].active = fileIndex + 1;
WriteActive(skinConfig, iniIndex); WriteActive(skinFolder, fileIndex);
CreateMeterWindow(skinConfig, skinIniFile); CreateMeterWindow(skinFolder, skinFile);
} }
} }
void CRainmeter::DeactivateConfig(CMeterWindow* meterWindow, int configIndex, bool save) void CRainmeter::DeactivateConfig(CMeterWindow* meterWindow, int folderIndex, bool save)
{ {
if (configIndex >= 0 && configIndex < (int)m_ConfigStrings.size()) if (folderIndex >= 0 && folderIndex < (int)m_SkinFolders.size())
{ {
m_ConfigStrings[configIndex].active = 0; // Deactivate the config m_SkinFolders[folderIndex].active = 0; // Deactivate the config
} }
else if (configIndex == -1 && meterWindow) else if (folderIndex == -1 && meterWindow)
{ {
// Deactivate the config by using the meter window's config name folderIndex = FindSkinFolderIndex(meterWindow->GetSkinName());
const WCHAR* skinConfig = meterWindow->GetSkinName().c_str(); if (folderIndex != -1)
for (size_t i = 0, isize = m_ConfigStrings.size(); i < isize; ++i)
{ {
if (_wcsicmp(skinConfig, m_ConfigStrings[i].config.c_str()) == 0) m_SkinFolders[folderIndex].active = 0;
{
m_ConfigStrings[i].active = 0;
break;
}
} }
} }
@ -1311,27 +1309,27 @@ void CRainmeter::DeactivateConfig(CMeterWindow* meterWindow, int configIndex, bo
} }
} }
void CRainmeter::ToggleConfig(int configIndex, int iniIndex) void CRainmeter::ToggleConfig(int folderIndex, int fileIndex)
{ {
if (configIndex >= 0 && configIndex < (int)m_ConfigStrings.size() && if (folderIndex >= 0 && folderIndex < (int)m_SkinFolders.size() &&
iniIndex >= 0 && iniIndex < (int)m_ConfigStrings[configIndex].iniFiles.size()) fileIndex >= 0 && fileIndex < (int)m_SkinFolders[folderIndex].files.size())
{ {
if (m_ConfigStrings[configIndex].active == iniIndex + 1) if (m_SkinFolders[folderIndex].active == fileIndex + 1)
{ {
CMeterWindow* meterWindow = Rainmeter->GetMeterWindow(m_ConfigStrings[configIndex].config); CMeterWindow* meterWindow = Rainmeter->GetMeterWindow(GetSkinFolderPath(folderIndex));
DeactivateConfig(meterWindow, configIndex); DeactivateConfig(meterWindow, folderIndex);
} }
else else
{ {
ActivateConfig(configIndex, iniIndex); ActivateConfig(folderIndex, fileIndex);
} }
} }
} }
void CRainmeter::WriteActive(const std::wstring& config, int iniIndex) void CRainmeter::WriteActive(const std::wstring& config, int fileIndex)
{ {
WCHAR buffer[32]; WCHAR buffer[32];
_itow_s(iniIndex + 1, buffer, 10); _itow_s(fileIndex + 1, buffer, 10);
WritePrivateProfileString(config.c_str(), L"Active", buffer, m_IniFile.c_str()); WritePrivateProfileString(config.c_str(), L"Active", buffer, m_IniFile.c_str());
} }
@ -1429,28 +1427,22 @@ CMeterWindow* CRainmeter::GetMeterWindowByINI(const std::wstring& ini_searching)
std::pair<int, int> CRainmeter::GetMeterWindowIndex(const std::wstring& config, const std::wstring& iniFile) std::pair<int, int> CRainmeter::GetMeterWindowIndex(const std::wstring& config, const std::wstring& iniFile)
{ {
const WCHAR* configName = config.c_str(); int index = FindSkinFolderIndex(config);
std::pair<int, int> indexes; if (index != -1)
for (int i = 0, isize = (int)m_ConfigStrings.size(); i < isize; ++i)
{ {
const CONFIG& configS = m_ConfigStrings[i]; const SkinFolder& folder = m_SkinFolders[index];
if (_wcsicmp(configS.config.c_str(), configName) == 0)
const WCHAR* fileSz = iniFile.c_str();
for (int i = 0, isize = (int)folder.files.size(); i < isize; ++i)
{ {
const WCHAR* iniFileName = iniFile.c_str(); if (_wcsicmp(folder.files[i].c_str(), fileSz) == 0)
for (int j = 0, jsize = (int)configS.iniFiles.size(); j < jsize; ++j)
{ {
if (_wcsicmp(configS.iniFiles[j].c_str(), iniFileName) == 0) return std::make_pair(index, i);
{
indexes = std::make_pair(i, j);
return indexes;
}
} }
} }
} }
indexes = std::make_pair(-1, -1); // error return std::make_pair(-1, -1); // Error
return indexes;
} }
std::pair<int, int> CRainmeter::GetMeterWindowIndex(UINT menuCommand) std::pair<int, int> CRainmeter::GetMeterWindowIndex(UINT menuCommand)
@ -1460,13 +1452,13 @@ std::pair<int, int> CRainmeter::GetMeterWindowIndex(UINT menuCommand)
if (menuCommand >= ID_CONFIG_FIRST && menuCommand <= ID_CONFIG_LAST) if (menuCommand >= ID_CONFIG_FIRST && menuCommand <= ID_CONFIG_LAST)
{ {
// Check which config was selected // Check which config was selected
for (size_t i = 0, isize = m_ConfigStrings.size(); i < isize; ++i) for (size_t i = 0, isize = m_SkinFolders.size(); i < isize; ++i)
{ {
const CONFIG& configS = m_ConfigStrings[i]; const SkinFolder& folder = m_SkinFolders[i];
if (menuCommand >= configS.commandBase && if (menuCommand >= folder.commandBase &&
menuCommand < (configS.commandBase + configS.iniFiles.size())) menuCommand < (folder.commandBase + folder.files.size()))
{ {
indexes = std::make_pair(i, menuCommand - configS.commandBase); indexes = std::make_pair(i, menuCommand - folder.commandBase);
return indexes; return indexes;
} }
} }
@ -1503,12 +1495,75 @@ void CRainmeter::GetMeterWindowsByLoadOrder(std::multimap<int, CMeterWindow*>& w
} }
} }
void CRainmeter::SetLoadOrder(int configIndex, int order) /*
** Returns the skin folder path relative to the skin folder (e.g. illustro\Clock).
**
*/
std::wstring CRainmeter::GetSkinFolderPath(int folderIndex)
{
const SkinFolder& folder = m_SkinFolders[folderIndex];
std::wstring path = folder.name;
for (int i = folder.level - 1, index = folderIndex; i >= 1; --i)
{
while (m_SkinFolders[index].level != i)
{
--index;
}
path.insert(0, L"\\");
path.insert(0, m_SkinFolders[index].name);
}
return path;
}
int CRainmeter::FindSkinFolderIndex(const std::wstring& folderPath)
{
if (!folderPath.empty())
{
const WCHAR* path = folderPath.c_str();
int len = 0;
while (path[len] && path[len] != L'\\') ++len;
int level = 1;
for (int i = 0, isize = (int)m_SkinFolders.size(); i < isize; ++i)
{
const SkinFolder& folder = m_SkinFolders[i];
if (folder.level == level)
{
if (folder.name.length() == len && _wcsnicmp(folder.name.c_str(), path, len) == 0)
{
path += len;
if (*path)
{
++path; // Skip backslash
len = 0;
while (path[len] && path[len] != L'\\') ++len;
}
else
{
// Match found
return i;
}
++level;
}
}
else if (folder.level < level)
{
break;
}
}
}
return -1;
}
void CRainmeter::SetLoadOrder(int folderIndex, int order)
{ {
std::multimap<int, int>::iterator iter = m_ConfigOrders.begin(); std::multimap<int, int>::iterator iter = m_ConfigOrders.begin();
for ( ; iter != m_ConfigOrders.end(); ++iter) for ( ; iter != m_ConfigOrders.end(); ++iter)
{ {
if ((*iter).second == configIndex) // already exists if ((*iter).second == folderIndex) // already exists
{ {
if ((*iter).first != order) if ((*iter).first != order)
{ {
@ -1522,18 +1577,21 @@ void CRainmeter::SetLoadOrder(int configIndex, int order)
} }
} }
m_ConfigOrders.insert(std::pair<int, int>(order, configIndex)); m_ConfigOrders.insert(std::pair<int, int>(order, folderIndex));
} }
int CRainmeter::GetLoadOrder(const std::wstring& config) int CRainmeter::GetLoadOrder(const std::wstring& config)
{ {
const WCHAR* configName = config.c_str(); int index = FindSkinFolderIndex(config);
std::multimap<int, int>::const_iterator iter = m_ConfigOrders.begin(); if (index != -1)
for ( ; iter != m_ConfigOrders.end(); ++iter)
{ {
if (wcscmp(m_ConfigStrings[(*iter).second].config.c_str(), configName) == 0) std::multimap<int, int>::const_iterator iter = m_ConfigOrders.begin();
for ( ; iter != m_ConfigOrders.end(); ++iter)
{ {
return (*iter).first; if ((*iter).second == index)
{
return (*iter).first;
}
} }
} }
@ -1546,21 +1604,19 @@ int CRainmeter::GetLoadOrder(const std::wstring& config)
*/ */
void CRainmeter::ScanForConfigs(const std::wstring& path) void CRainmeter::ScanForConfigs(const std::wstring& path)
{ {
m_ConfigStrings.clear(); m_SkinFolders.clear();
m_ConfigMenu.clear();
m_ConfigOrders.clear(); m_ConfigOrders.clear();
ScanForConfigsRecursive(path, L"", 0, m_ConfigMenu); ScanForConfigsRecursive(path, L"", 0, 0);
} }
int CRainmeter::ScanForConfigsRecursive(const std::wstring& path, std::wstring base, int index, std::vector<CONFIGMENU>& menu, bool rootSkinFolder) int CRainmeter::ScanForConfigsRecursive(const std::wstring& path, std::wstring base, int index, UINT level)
{ {
WIN32_FIND_DATA fileData; // Data structure describes the file found WIN32_FIND_DATA fileData; // Data structure describes the file found
HANDLE hSearch; // Search handle returned by FindFirstFile HANDLE hSearch; // Search handle returned by FindFirstFile
std::list<std::wstring> folders; std::list<std::wstring> subfolders;
const bool first = base.empty();
// Scan all .ini files and folders from the subfolder // Find all .ini files and subfolders
std::wstring filter = path + base; std::wstring filter = path + base;
filter += L"\\*"; filter += L"\\*";
@ -1574,11 +1630,12 @@ int CRainmeter::ScanForConfigsRecursive(const std::wstring& path, std::wstring b
if (hSearch != INVALID_HANDLE_VALUE) if (hSearch != INVALID_HANDLE_VALUE)
{ {
CONFIG config; SkinFolder folder;
config.config = base; folder.commandBase = ID_CONFIG_FIRST + index;
config.commandBase = ID_CONFIG_FIRST + index; folder.active = 0;
config.active = 0; folder.level = level;
bool foundFiles = false;
do do
{ {
const std::wstring filename = fileData.cFileName; const std::wstring filename = fileData.cFileName;
@ -1587,24 +1644,20 @@ int CRainmeter::ScanForConfigsRecursive(const std::wstring& path, std::wstring b
{ {
if (wcscmp(L".", fileData.cFileName) != 0 && if (wcscmp(L".", fileData.cFileName) != 0 &&
wcscmp(L"..", fileData.cFileName) != 0 && wcscmp(L"..", fileData.cFileName) != 0 &&
!(first && wcscmp(L"Backup", fileData.cFileName) == 0) && !(level == 0 && wcscmp(L"Backup", fileData.cFileName) == 0) &&
!(rootSkinFolder && wcscmp(L"@Resources", fileData.cFileName) == 0)) !(level == 1 && wcscmp(L"@Resources", fileData.cFileName) == 0))
{ {
folders.push_back(filename); subfolders.push_back(filename);
} }
} }
else if (!first) else if (level != 0)
{ {
// Check whether the extension is ".ini" // Check whether the extension is ".ini"
size_t filenameLen = filename.size(); size_t filenameLen = filename.size();
if (filenameLen >= 4 && _wcsicmp(fileData.cFileName + (filenameLen - 4), L".ini") == 0) if (filenameLen >= 4 && _wcsicmp(fileData.cFileName + (filenameLen - 4), L".ini") == 0)
{ {
CONFIGMENU menuItem; foundFiles = true;
menuItem.name = filename; folder.files.push_back(filename);
menuItem.index = m_ConfigStrings.size();
menu.push_back(std::move(menuItem));
config.iniFiles.push_back(filename);
++index; ++index;
} }
} }
@ -1613,34 +1666,46 @@ int CRainmeter::ScanForConfigsRecursive(const std::wstring& path, std::wstring b
FindClose(hSearch); FindClose(hSearch);
if (!config.iniFiles.empty()) if (level > 0 && (foundFiles || !subfolders.empty()))
{ {
m_ConfigStrings.push_back(std::move(config)); if (level == 1)
{
folder.name = base;
}
else
{
std::wstring::size_type pos = base.rfind(L'\\') + 1;
folder.name.assign(base, pos, base.length() - pos);
}
m_SkinFolders.push_back(std::move(folder));
} }
} }
if (!first) if (level != 0)
{ {
base += L'\\'; base += L'\\';
} }
menu.reserve(menu.size() + folders.size()); if (!subfolders.empty())
std::list<std::wstring>::const_iterator iter = folders.begin();
for ( ; iter != folders.end(); ++iter)
{ {
CONFIGMENU menuItem; bool emptyFolders = true;
menuItem.name = (*iter);
menuItem.index = -1;
menu.push_back(std::move(menuItem));
std::vector<CONFIGMENU>::iterator iter2 = menu.end() - 1; std::list<std::wstring>::const_iterator iter = subfolders.begin();
index = ScanForConfigsRecursive(path, base + (*iter), index, (*iter2).children, base.empty()); for ( ; iter != subfolders.end(); ++iter)
// Remove menu item if it has no child
if ((*iter2).children.empty())
{ {
menu.erase(iter2); int newIndex = ScanForConfigsRecursive(path, base + (*iter), index, level + 1);
if (newIndex != index)
{
emptyFolders = false;
}
index = newIndex;
}
if (emptyFolders)
{
m_SkinFolders.pop_back();
} }
} }
@ -2236,19 +2301,33 @@ void CRainmeter::ReadGeneralSettings(const std::wstring& iniFile)
m_NormalStayDesktop = 0!=parser.ReadInt(L"Rainmeter", L"NormalStayDesktop", 1); m_NormalStayDesktop = 0!=parser.ReadInt(L"Rainmeter", L"NormalStayDesktop", 1);
for (int i = 0, isize = (int)m_ConfigStrings.size(); i < isize; ++i) for (auto iter = parser.GetSections().cbegin(); iter != parser.GetSections().end(); ++iter)
{ {
CONFIG& configS = m_ConfigStrings[i]; const WCHAR* section = (*iter).c_str();
int active = parser.ReadInt(configS.config.c_str(), L"Active", 0);
// Make sure there is a ini file available if (wcscmp(section, L"Rainmeter") == 0 ||
if (active > 0 && active <= (int)configS.iniFiles.size()) wcscmp(section, L"TrayMeasure") == 0)
{ {
configS.active = active; continue;
} }
int order = parser.ReadInt(configS.config.c_str(), L"LoadOrder", 0); int index = FindSkinFolderIndex(*iter);
SetLoadOrder(i, order); if (index == -1)
{
continue;
}
SkinFolder& folder = m_SkinFolders[index];
// Make sure there is a ini file available
int active = parser.ReadInt(section, L"Active", 0);
if (active > 0 && active <= (int)folder.files.size())
{
folder.active = active;
}
int order = parser.ReadInt(section, L"LoadOrder", 0);
SetLoadOrder(index, order);
} }
} }
@ -2282,52 +2361,46 @@ void CRainmeter::RefreshAll()
CMeterWindow* mw = (*iter).second; CMeterWindow* mw = (*iter).second;
if (mw) if (mw)
{ {
const WCHAR* skinFolder = mw->GetSkinName().c_str();
// Verify whether the cached information is valid // Verify whether the cached information is valid
int found = 0; int index = FindSkinFolderIndex(mw->GetSkinName());
const WCHAR* skinConfig = mw->GetSkinName().c_str(); if (index != -1)
for (int i = 0, isize = (int)m_ConfigStrings.size(); i < isize; ++i)
{ {
CONFIG& configS = m_ConfigStrings[i]; SkinFolder& folder = m_SkinFolders[index];
if (_wcsicmp(skinConfig, configS.config.c_str()) == 0)
const WCHAR* skinIniFile = mw->GetSkinIniFile().c_str();
bool found = false;
for (int i = 0, isize = (int)folder.files.size(); i < isize; ++i)
{ {
found = 1; if (_wcsicmp(skinIniFile, folder.files[i].c_str()) == 0)
const WCHAR* skinIniFile = mw->GetSkinIniFile().c_str();
for (int j = 0, jsize = (int)configS.iniFiles.size(); j < jsize; ++j)
{ {
if (_wcsicmp(skinIniFile, configS.iniFiles[j].c_str()) == 0) found = true;
if (folder.active != i + 1)
{ {
found = 2; // Switch to new ini-file order
if (configS.active != j + 1) folder.active = i + 1;
{ WriteActive(mw->GetSkinName(), i);
// Switch to new ini-file order
configS.active = j + 1;
WriteActive(mw->GetSkinName(), j);
}
break;
} }
break;
} }
if (found == 1) // Not found in ini-files
{
DeactivateConfig(mw, i);
std::wstring error = GetFormattedString(ID_STR_UNABLETOREFRESHSKIN, skinConfig, skinIniFile);
MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
}
break;
} }
}
if (found != 2) if (!found)
{
if (found == 0) // Not found in configs
{ {
DeactivateConfig(mw, -2); // -2 = Deactivate the config forcibly DeactivateConfig(mw, index);
std::wstring error = GetFormattedString(ID_STR_UNABLETOREFRESHSKIN, skinConfig, L""); std::wstring error = GetFormattedString(ID_STR_UNABLETOREFRESHSKIN, skinFolder, skinIniFile);
MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION); MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
} }
continue; }
else
{
DeactivateConfig(mw, -2); // -2 = Deactivate the config forcibly
std::wstring error = GetFormattedString(ID_STR_UNABLETOREFRESHSKIN, skinFolder, L"");
MessageBox(NULL, error.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION);
} }
try try
@ -2631,10 +2704,10 @@ void CRainmeter::ShowContextMenu(POINT pos, CMeterWindow* meterWindow)
HMENU configMenu = GetSubMenu(subMenu, 4); HMENU configMenu = GetSubMenu(subMenu, 4);
if (configMenu) if (configMenu)
{ {
if (!m_ConfigMenu.empty()) if (!m_SkinFolders.empty())
{ {
DeleteMenu(configMenu, 0, MF_BYPOSITION); // "No skins available" menuitem DeleteMenu(configMenu, 0, MF_BYPOSITION); // "No skins available" menuitem
CreateConfigMenu(configMenu, m_ConfigMenu); CreateAllSkinsMenu(configMenu);
} }
if (m_DisableDragging) if (m_DisableDragging)
@ -2734,54 +2807,53 @@ void CRainmeter::ShowContextMenu(POINT pos, CMeterWindow* meterWindow)
} }
} }
HMENU CRainmeter::CreateConfigMenu(HMENU configMenu, const std::vector<CONFIGMENU>& configMenuData) int CRainmeter::CreateAllSkinsMenuRecursive(HMENU skinMenu, int index)
{ {
if (!configMenuData.empty()) int initialLevel = m_SkinFolders[index].level;
int menuIndex = 0;
const size_t max = Rainmeter->m_SkinFolders.size();
while (index < max)
{ {
if (!configMenu) const SkinFolder& folder = Rainmeter->m_SkinFolders[index];
if (folder.level != initialLevel)
{ {
configMenu = CreatePopupMenu(); return index - 1;
} }
bool separator = false; HMENU subMenu = CreatePopupMenu();
for (int i = 0, j = 0, isize = (int)configMenuData.size(); i < isize; ++i)
// Add current folder
InsertMenu(skinMenu, menuIndex, MF_POPUP | MF_BYPOSITION, (UINT_PTR)subMenu, folder.name.c_str());
// Add subfolders
const bool hasSubfolder = (index + 1) < max && m_SkinFolders[index + 1].level == initialLevel + 1;
if (hasSubfolder)
{ {
const CONFIGMENU& configMenuS = configMenuData[i]; index = CreateAllSkinsMenuRecursive(subMenu, index + 1);
if (configMenuS.index == -1) }
// Add files
{
int fileIndex = 0;
int fileCount = (int)folder.files.size();
for ( ; fileIndex < fileCount; ++fileIndex)
{ {
HMENU submenu = CreateConfigMenu(NULL, configMenuS.children); UINT flags = MF_STRING | MF_BYPOSITION | ((folder.active == fileIndex + 1) ? MF_CHECKED : MF_UNCHECKED);
if (submenu) InsertMenu(subMenu, fileIndex, flags, folder.commandBase, folder.files[fileIndex].c_str());
{
if (separator)
{
// Insert a separator
InsertMenu(configMenu, i, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
++j;
separator = false;
}
InsertMenu(configMenu, i + j, MF_BYPOSITION | MF_POPUP, (UINT_PTR)submenu, configMenuS.name.c_str());
}
} }
else
if (hasSubfolder && fileIndex != 0)
{ {
const CONFIG& configS = m_ConfigStrings[configMenuS.index]; InsertMenu(subMenu, fileIndex, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);
InsertMenu(configMenu, i, MF_BYPOSITION | ((configS.active == i + 1) ? MF_CHECKED : MF_UNCHECKED), configS.commandBase + i, configMenuS.name.c_str());
separator = true;
} }
} }
return configMenu; ++menuIndex;
++index;
} }
return NULL; return index;
}
void CRainmeter::CreateThemeMenu(HMENU themeMenu)
{
for (size_t i = 0, isize = m_Themes.size(); i < isize; ++i)
{
InsertMenu(themeMenu, i, MF_BYPOSITION, ID_THEME_FIRST + i, m_Themes[i].c_str());
}
} }
HMENU CRainmeter::CreateSkinMenu(CMeterWindow* meterWindow, int index, HMENU configMenu) HMENU CRainmeter::CreateSkinMenu(CMeterWindow* meterWindow, int index, HMENU configMenu)
@ -2928,18 +3000,10 @@ HMENU CRainmeter::CreateSkinMenu(CMeterWindow* meterWindow, int index, HMENU con
// Add the variants menu // Add the variants menu
if (variantsMenu) if (variantsMenu)
{ {
const WCHAR* skin = skinName.c_str(); const SkinFolder& folder = m_SkinFolders[FindSkinFolderIndex(skinName)];
for (int i = 0, isize = (int)m_ConfigStrings.size(); i < isize; ++i) for (int i = 0, jsize = (int)folder.files.size(); i < jsize; ++i)
{ {
const CONFIG& configS = m_ConfigStrings[i]; InsertMenu(variantsMenu, i, MF_BYPOSITION | ((folder.active == i + 1) ? MF_CHECKED : MF_UNCHECKED), folder.commandBase + i, folder.files[i].c_str());
if (_wcsicmp(configS.config.c_str(), skin) == 0)
{
for (int j = 0, jsize = (int)configS.iniFiles.size(); j < jsize; ++j)
{
InsertMenu(variantsMenu, j, MF_BYPOSITION | ((configS.active == j + 1) ? MF_CHECKED : MF_UNCHECKED), configS.commandBase + j, configS.iniFiles[j].c_str());
}
break;
}
} }
} }
@ -2979,6 +3043,14 @@ HMENU CRainmeter::CreateSkinMenu(CMeterWindow* meterWindow, int index, HMENU con
return skinMenu; return skinMenu;
} }
void CRainmeter::CreateThemeMenu(HMENU themeMenu)
{
for (size_t i = 0, isize = m_Themes.size(); i < isize; ++i)
{
InsertMenu(themeMenu, i, MF_BYPOSITION, ID_THEME_FIRST + i, m_Themes[i].c_str());
}
}
void CRainmeter::CreateMonitorMenu(HMENU monitorMenu, CMeterWindow* meterWindow) void CRainmeter::CreateMonitorMenu(HMENU monitorMenu, CMeterWindow* meterWindow)
{ {
bool screenDefined = meterWindow->GetXScreenDefined(); bool screenDefined = meterWindow->GetXScreenDefined();

View File

@ -58,55 +58,33 @@ class CTrayWindow;
class CRainmeter class CRainmeter
{ {
public: public:
struct CONFIG struct SkinFolder
{
std::wstring config;
std::vector<std::wstring> iniFiles;
UINT commandBase;
int active;
CONFIG() {}
~CONFIG() {}
CONFIG(CONFIG&& r) :
config(std::move(r.config)),
iniFiles(std::move(r.iniFiles)),
commandBase(r.commandBase),
active(r.active)
{
}
CONFIG& operator=(CONFIG&& r)
{
config = std::move(r.config);
iniFiles = std::move(r.iniFiles);
commandBase = r.commandBase;
active = r.active;
return *this;
}
};
struct CONFIGMENU
{ {
std::wstring name; std::wstring name;
size_t index; std::vector<std::wstring> files;
std::vector<CONFIGMENU> children; UINT commandBase;
int16_t active;
int16_t level;
CONFIGMENU() {} SkinFolder() {}
~CONFIGMENU() {} ~SkinFolder() {}
CONFIGMENU(CONFIGMENU&& r) : SkinFolder(SkinFolder&& r) :
name(std::move(r.name)), name(std::move(r.name)),
index(r.index), files(std::move(r.files)),
children(std::move(r.children)) commandBase(r.commandBase),
active(r.active),
level(r.level)
{ {
} }
CONFIGMENU& operator=(CONFIGMENU&& r) SkinFolder& operator=(SkinFolder&& r)
{ {
name = std::move(r.name); name = std::move(r.name);
index = r.index; files = std::move(r.files);
children = std::move(r.children); commandBase = r.commandBase;
active = r.active;
level = r.level;
return *this; return *this;
} }
}; };
@ -141,14 +119,18 @@ public:
CMeterWindow* GetMeterWindow(HWND hwnd); CMeterWindow* GetMeterWindow(HWND hwnd);
void GetMeterWindowsByLoadOrder(std::multimap<int, CMeterWindow*>& windows, const std::wstring& group = std::wstring()); void GetMeterWindowsByLoadOrder(std::multimap<int, CMeterWindow*>& windows, const std::wstring& group = std::wstring());
std::map<std::wstring, CMeterWindow*>& GetAllMeterWindows() { return m_MeterWindows; } std::map<std::wstring, CMeterWindow*>& GetAllMeterWindows() { return m_MeterWindows; }
const std::vector<CONFIG>& GetAllConfigs() { return m_ConfigStrings; }
std::wstring GetSkinFolderPath(int folderIndex);
int FindSkinFolderIndex(const std::wstring& folderPath);
const std::vector<SkinFolder>& GetSkinFolders() { return m_SkinFolders; }
const std::vector<std::wstring>& GetAllThemes() { return m_Themes; } const std::vector<std::wstring>& GetAllThemes() { return m_Themes; }
void DeleteMeterWindow(CMeterWindow* meterWindow, bool force = false); void DeleteMeterWindow(CMeterWindow* meterWindow, bool force = false);
void ActivateConfig(int configIndex, int iniIndex); void ActivateConfig(int folderIndex, int fileIndex);
void DeactivateConfig(CMeterWindow* meterWindow, int configIndex, bool save = true); void DeactivateConfig(CMeterWindow* meterWindow, int folderIndex, bool save = true);
void ToggleConfig(int configIndex, int iniIndex); void ToggleConfig(int folderIndex, int fileIndex);
const std::wstring& GetPath() { return m_Path; } const std::wstring& GetPath() { return m_Path; }
const std::wstring& GetIniFile() { return m_IniFile; } const std::wstring& GetIniFile() { return m_IniFile; }
@ -253,17 +235,20 @@ private:
void ActivateActiveConfigs(); void ActivateActiveConfigs();
void CreateMeterWindow(const std::wstring& config, const std::wstring& iniFile); void CreateMeterWindow(const std::wstring& config, const std::wstring& iniFile);
void WriteActive(const std::wstring& config, int iniIndex); void WriteActive(const std::wstring& config, int fileIndex);
void ScanForConfigs(const std::wstring& path); void ScanForConfigs(const std::wstring& path);
void ScanForThemes(const std::wstring& path); void ScanForThemes(const std::wstring& path);
void ReadGeneralSettings(const std::wstring& iniFile); void ReadGeneralSettings(const std::wstring& iniFile);
void SetLoadOrder(int configIndex, int order); void SetLoadOrder(int folderIndex, int order);
int GetLoadOrder(const std::wstring& config); int GetLoadOrder(const std::wstring& config);
void UpdateDesktopWorkArea(bool reset); void UpdateDesktopWorkArea(bool reset);
HMENU CreateSkinMenu(CMeterWindow* meterWindow, int index, HMENU configMenu); HMENU CreateSkinMenu(CMeterWindow* meterWindow, int index, HMENU configMenu);
void ChangeSkinIndex(HMENU subMenu, int index); void ChangeSkinIndex(HMENU subMenu, int index);
int ScanForConfigsRecursive(const std::wstring& path, std::wstring base, int index, std::vector<CONFIGMENU>& menu, bool rootSkinFolder = false); int ScanForConfigsRecursive(const std::wstring& path, std::wstring base, int index, UINT level);
HMENU CreateConfigMenu(HMENU configMenu, const std::vector<CONFIGMENU>& configMenuData);
void CreateAllSkinsMenu(HMENU skinMenu) { CreateAllSkinsMenuRecursive(skinMenu, 0); }
int CreateAllSkinsMenuRecursive(HMENU skinMenu, int index);
void CreateThemeMenu(HMENU themeMenu); void CreateThemeMenu(HMENU themeMenu);
void CreateMonitorMenu(HMENU monitorMenu, CMeterWindow* meterWindow); void CreateMonitorMenu(HMENU monitorMenu, CMeterWindow* meterWindow);
void CreateDefaultConfigFile(); void CreateDefaultConfigFile();
@ -273,8 +258,7 @@ private:
CTrayWindow* m_TrayWindow; CTrayWindow* m_TrayWindow;
std::vector<CONFIG> m_ConfigStrings; std::vector<SkinFolder> m_SkinFolders;
std::vector<CONFIGMENU> m_ConfigMenu;
std::multimap<int, int> m_ConfigOrders; std::multimap<int, int> m_ConfigOrders;
std::map<std::wstring, CMeterWindow*> m_MeterWindows; std::map<std::wstring, CMeterWindow*> m_MeterWindows;
std::vector<std::wstring> m_Themes; std::vector<std::wstring> m_Themes;