mirror of
https://github.com/chibicitiberiu/rainmeter-studio.git
synced 2024-02-24 04:33:31 +00:00
Refactor skin scanning and skin folder indexing into SkinRegistry.cpp
This also adds tests.
This commit is contained in:
parent
6332702f75
commit
5c91ab365d
@ -577,26 +577,11 @@ void CommandHandler::DoActivateSkinBang(std::vector<std::wstring>& args, MeterWi
|
|||||||
{
|
{
|
||||||
if (args.size() == 1)
|
if (args.size() == 1)
|
||||||
{
|
{
|
||||||
int index = GetRainmeter().FindSkinFolderIndex(args[0]);
|
if (GetRainmeter().ActivateSkin(args[0])) return;
|
||||||
if (index != -1)
|
|
||||||
{
|
|
||||||
const Rainmeter::SkinFolder& skinFolder = GetRainmeter().m_SkinFolders[index];
|
|
||||||
if (!(skinFolder.active == 1 && skinFolder.files.size() == 1))
|
|
||||||
{
|
|
||||||
// Activate the next index.
|
|
||||||
GetRainmeter().ActivateSkin(index, (skinFolder.active < skinFolder.files.size()) ? skinFolder.active : 0);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (args.size() > 1)
|
else if (args.size() > 1)
|
||||||
{
|
{
|
||||||
std::pair<int, int> indexes = GetRainmeter().GetMeterWindowIndex(args[0], args[1]);
|
if (GetRainmeter().ActivateSkin(args[0], args[1])) return;
|
||||||
if (indexes.first != -1 && indexes.second != -1)
|
|
||||||
{
|
|
||||||
GetRainmeter().ActivateSkin(indexes.first, indexes.second);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LogError(L"!ActivateConfig: Invalid parameters");
|
LogError(L"!ActivateConfig: Invalid parameters");
|
||||||
|
@ -570,7 +570,7 @@ void DialogManage::TabSkins::Update(MeterWindow* meterWindow, bool deleted)
|
|||||||
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;
|
||||||
|
|
||||||
if (!GetRainmeter().m_SkinFolders.empty())
|
if (!GetRainmeter().m_SkinRegistry.IsEmpty())
|
||||||
{
|
{
|
||||||
PopulateTree(item, tvi);
|
PopulateTree(item, tvi);
|
||||||
}
|
}
|
||||||
@ -881,12 +881,12 @@ std::wstring DialogManage::TabSkins::GetTreeSelectionPath(HWND tree)
|
|||||||
*/
|
*/
|
||||||
int DialogManage::TabSkins::PopulateTree(HWND tree, TVINSERTSTRUCT& tvi, int index)
|
int DialogManage::TabSkins::PopulateTree(HWND tree, TVINSERTSTRUCT& tvi, int index)
|
||||||
{
|
{
|
||||||
int initialLevel = GetRainmeter().m_SkinFolders[index].level;
|
int initialLevel = GetRainmeter().m_SkinRegistry.GetFolder(index).level;
|
||||||
|
|
||||||
const size_t max = GetRainmeter().m_SkinFolders.size();
|
const size_t max = GetRainmeter().m_SkinRegistry.GetFolderCount();
|
||||||
while (index < max)
|
while (index < max)
|
||||||
{
|
{
|
||||||
const Rainmeter::SkinFolder& skinFolder = GetRainmeter().m_SkinFolders[index];
|
const auto& skinFolder = GetRainmeter().m_SkinRegistry.GetFolder(index);
|
||||||
if (skinFolder.level != initialLevel)
|
if (skinFolder.level != initialLevel)
|
||||||
{
|
{
|
||||||
return index - 1;
|
return index - 1;
|
||||||
@ -901,7 +901,7 @@ int DialogManage::TabSkins::PopulateTree(HWND tree, TVINSERTSTRUCT& tvi, int ind
|
|||||||
|
|
||||||
// Add subfolders
|
// Add subfolders
|
||||||
if ((index + 1) < max &&
|
if ((index + 1) < max &&
|
||||||
GetRainmeter().m_SkinFolders[index + 1].level == initialLevel + 1)
|
GetRainmeter().m_SkinRegistry.GetFolder(index + 1).level == initialLevel + 1)
|
||||||
{
|
{
|
||||||
index = PopulateTree(tree, tvi, index + 1);
|
index = PopulateTree(tree, tvi, index + 1);
|
||||||
}
|
}
|
||||||
@ -1048,11 +1048,12 @@ INT_PTR DialogManage::TabSkins::OnCommand(WPARAM wParam, LPARAM lParam)
|
|||||||
if (!m_SkinWindow)
|
if (!m_SkinWindow)
|
||||||
{
|
{
|
||||||
// Skin not active, load
|
// Skin not active, load
|
||||||
std::pair<int, int> indexes = GetRainmeter().GetMeterWindowIndex(m_SkinFolderPath, m_SkinFileName);
|
const SkinRegistry::Indexes indexes =
|
||||||
if (indexes.first != -1 && indexes.second != -1)
|
GetRainmeter().m_SkinRegistry.FindIndexes(m_SkinFolderPath, m_SkinFileName);
|
||||||
|
if (indexes.IsValid())
|
||||||
{
|
{
|
||||||
m_HandleCommands = false;
|
m_HandleCommands = false;
|
||||||
GetRainmeter().ActivateSkin(indexes.first, indexes.second);
|
GetRainmeter().ActivateSkin(indexes.folder, indexes.file);
|
||||||
m_HandleCommands = true;
|
m_HandleCommands = true;
|
||||||
|
|
||||||
// Fake selection change to update controls
|
// Fake selection change to update controls
|
||||||
@ -1147,10 +1148,11 @@ INT_PTR DialogManage::TabSkins::OnCommand(WPARAM wParam, LPARAM lParam)
|
|||||||
Edit_SetSel((HWND)lParam, LOWORD(sel), HIWORD(sel));
|
Edit_SetSel((HWND)lParam, LOWORD(sel), HIWORD(sel));
|
||||||
|
|
||||||
WritePrivateProfileString(m_SkinFolderPath.c_str(), L"LoadOrder", buffer, GetRainmeter().GetIniFile().c_str());
|
WritePrivateProfileString(m_SkinFolderPath.c_str(), L"LoadOrder", buffer, GetRainmeter().GetIniFile().c_str());
|
||||||
std::pair<int, int> indexes = GetRainmeter().GetMeterWindowIndex(m_SkinWindow);
|
const SkinRegistry::Indexes indexes = GetRainmeter().m_SkinRegistry.FindIndexes(
|
||||||
if (indexes.first != -1)
|
m_SkinWindow->GetFolderPath(), m_SkinWindow->GetFileName());
|
||||||
|
if (indexes.IsValid())
|
||||||
{
|
{
|
||||||
GetRainmeter().SetLoadOrder(indexes.first, value);
|
GetRainmeter().SetLoadOrder(indexes.folder, value);
|
||||||
|
|
||||||
std::multimap<int, MeterWindow*> windows;
|
std::multimap<int, MeterWindow*> windows;
|
||||||
GetRainmeter().GetMeterWindowsByLoadOrder(windows);
|
GetRainmeter().GetMeterWindowsByLoadOrder(windows);
|
||||||
|
@ -218,6 +218,12 @@
|
|||||||
<ClCompile Include="Section.cpp">
|
<ClCompile Include="Section.cpp">
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="SkinRegistry.cpp">
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="SkinRegistry_Test.cpp">
|
||||||
|
<ExcludedFromBuild>$(ExcludeTests)</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="StdAfx.cpp">
|
<ClCompile Include="StdAfx.cpp">
|
||||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -352,6 +358,7 @@
|
|||||||
<ClInclude Include="RainmeterQuery.h" />
|
<ClInclude Include="RainmeterQuery.h" />
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
<ClInclude Include="Section.h" />
|
<ClInclude Include="Section.h" />
|
||||||
|
<ClInclude Include="SkinRegistry.h" />
|
||||||
<ClInclude Include="StdAfx.h" />
|
<ClInclude Include="StdAfx.h" />
|
||||||
<ClInclude Include="System.h" />
|
<ClInclude Include="System.h" />
|
||||||
<ClInclude Include="TintedImage.h" />
|
<ClInclude Include="TintedImage.h" />
|
||||||
|
@ -381,6 +381,12 @@
|
|||||||
<ClCompile Include="CommandHandler.cpp">
|
<ClCompile Include="CommandHandler.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="SkinRegistry.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="SkinRegistry_Test.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="ConfigParser.h">
|
<ClInclude Include="ConfigParser.h">
|
||||||
@ -653,6 +659,9 @@
|
|||||||
<ClInclude Include="CommandHandler.h">
|
<ClInclude Include="CommandHandler.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="SkinRegistry.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="Library.rc">
|
<ResourceCompile Include="Library.rc">
|
||||||
|
@ -375,7 +375,7 @@ int Rainmeter::Initialize(LPCWSTR iniPath, LPCWSTR layout)
|
|||||||
|
|
||||||
ReloadSettings();
|
ReloadSettings();
|
||||||
|
|
||||||
if (m_SkinFolders.empty())
|
if (m_SkinRegistry.IsEmpty())
|
||||||
{
|
{
|
||||||
std::wstring error = GetFormattedString(ID_STR_NOAVAILABLESKINS, m_SkinPath.c_str());
|
std::wstring error = GetFormattedString(ID_STR_NOAVAILABLESKINS, m_SkinPath.c_str());
|
||||||
ShowMessage(nullptr, error.c_str(), MB_OK | MB_ICONERROR);
|
ShowMessage(nullptr, error.c_str(), MB_OK | MB_ICONERROR);
|
||||||
@ -794,24 +794,63 @@ void Rainmeter::ActivateActiveSkins()
|
|||||||
std::multimap<int, int>::const_iterator iter = m_SkinOrders.begin();
|
std::multimap<int, int>::const_iterator iter = m_SkinOrders.begin();
|
||||||
for ( ; iter != m_SkinOrders.end(); ++iter)
|
for ( ; iter != m_SkinOrders.end(); ++iter)
|
||||||
{
|
{
|
||||||
const SkinFolder& skinFolder = m_SkinFolders[(*iter).second];
|
const SkinRegistry::Folder& skinFolder = m_SkinRegistry.GetFolder((*iter).second);
|
||||||
if (skinFolder.active > 0 && skinFolder.active <= (int)skinFolder.files.size())
|
if (skinFolder.active > 0 && skinFolder.active <= (uint16_t)skinFolder.files.size())
|
||||||
{
|
{
|
||||||
ActivateSkin((*iter).second, skinFolder.active - 1);
|
ActivateSkin((*iter).second, skinFolder.active - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Activates the skin, or, if it is already active, the next variant of the skin. Returns true
|
||||||
|
** if the skin was activated (or was already active).
|
||||||
|
*/
|
||||||
|
bool Rainmeter::ActivateSkin(const std::wstring& folderPath)
|
||||||
|
{
|
||||||
|
const int index = m_SkinRegistry.FindFolderIndex(folderPath);
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
const SkinRegistry::Folder& skinFolder = m_SkinRegistry.GetFolder(index);
|
||||||
|
if (!(skinFolder.active == 1 && skinFolder.files.size() == 1))
|
||||||
|
{
|
||||||
|
// Activate the next index.
|
||||||
|
ActivateSkin(
|
||||||
|
index, (skinFolder.active < skinFolder.files.size()) ? skinFolder.active : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Activates the skin, or, if it is already active, the next variant of the skin. Returns true
|
||||||
|
** if the skin was activated (or was already active).
|
||||||
|
*/
|
||||||
|
bool Rainmeter::ActivateSkin(const std::wstring& folderPath, const std::wstring& file)
|
||||||
|
{
|
||||||
|
const SkinRegistry::Indexes indexes = m_SkinRegistry.FindIndexes(folderPath, file);
|
||||||
|
if (indexes.IsValid())
|
||||||
|
{
|
||||||
|
ActivateSkin(indexes.folder, indexes.file);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Rainmeter::ActivateSkin(int folderIndex, int fileIndex)
|
void Rainmeter::ActivateSkin(int folderIndex, int fileIndex)
|
||||||
{
|
{
|
||||||
if (folderIndex >= 0 && folderIndex < (int)m_SkinFolders.size() &&
|
if (folderIndex >= 0 && folderIndex < m_SkinRegistry.GetFolderCount() &&
|
||||||
fileIndex >= 0 && fileIndex < (int)m_SkinFolders[folderIndex].files.size())
|
fileIndex >= 0 && fileIndex < m_SkinRegistry.GetFolder(folderIndex).files.size())
|
||||||
{
|
{
|
||||||
SkinFolder& skinFolder = m_SkinFolders[folderIndex];
|
auto& skinFolder = m_SkinRegistry.GetFolder(folderIndex);
|
||||||
const std::wstring& file = skinFolder.files[fileIndex];
|
const std::wstring& file = skinFolder.files[fileIndex];
|
||||||
const WCHAR* fileSz = file.c_str();
|
const WCHAR* fileSz = file.c_str();
|
||||||
|
|
||||||
std::wstring folderPath = GetFolderPath(folderIndex);
|
std::wstring folderPath = m_SkinRegistry.GetFolderPath(folderIndex);
|
||||||
|
|
||||||
// Verify that the skin is not already active
|
// Verify that the skin is not already active
|
||||||
std::map<std::wstring, MeterWindow*>::const_iterator iter = m_MeterWindows.find(folderPath);
|
std::map<std::wstring, MeterWindow*>::const_iterator iter = m_MeterWindows.find(folderPath);
|
||||||
@ -854,16 +893,16 @@ void Rainmeter::ActivateSkin(int folderIndex, int fileIndex)
|
|||||||
|
|
||||||
void Rainmeter::DeactivateSkin(MeterWindow* meterWindow, int folderIndex, bool save)
|
void Rainmeter::DeactivateSkin(MeterWindow* meterWindow, int folderIndex, bool save)
|
||||||
{
|
{
|
||||||
if (folderIndex >= 0 && folderIndex < (int)m_SkinFolders.size())
|
if (folderIndex >= 0 && folderIndex < m_SkinRegistry.GetFolderCount())
|
||||||
{
|
{
|
||||||
m_SkinFolders[folderIndex].active = 0; // Deactivate the skin
|
m_SkinRegistry.GetFolder(folderIndex).active = 0; // Deactivate the skin
|
||||||
}
|
}
|
||||||
else if (folderIndex == -1 && meterWindow)
|
else if (folderIndex == -1 && meterWindow)
|
||||||
{
|
{
|
||||||
folderIndex = FindSkinFolderIndex(meterWindow->GetFolderPath());
|
SkinRegistry::Folder* folder = m_SkinRegistry.FindFolder(meterWindow->GetFolderPath());
|
||||||
if (folderIndex != -1)
|
if (folder)
|
||||||
{
|
{
|
||||||
m_SkinFolders[folderIndex].active = 0;
|
folder->active = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,12 +920,12 @@ void Rainmeter::DeactivateSkin(MeterWindow* meterWindow, int folderIndex, bool s
|
|||||||
|
|
||||||
void Rainmeter::ToggleSkin(int folderIndex, int fileIndex)
|
void Rainmeter::ToggleSkin(int folderIndex, int fileIndex)
|
||||||
{
|
{
|
||||||
if (folderIndex >= 0 && folderIndex < (int)m_SkinFolders.size() &&
|
if (folderIndex >= 0 && folderIndex < m_SkinRegistry.GetFolderCount() &&
|
||||||
fileIndex >= 0 && fileIndex < (int)m_SkinFolders[folderIndex].files.size())
|
fileIndex >= 0 && fileIndex < m_SkinRegistry.GetFolder(folderIndex).files.size())
|
||||||
{
|
{
|
||||||
if (m_SkinFolders[folderIndex].active == fileIndex + 1)
|
if (m_SkinRegistry.GetFolder(folderIndex).active == fileIndex + 1)
|
||||||
{
|
{
|
||||||
MeterWindow* meterWindow = GetRainmeter().GetMeterWindow(GetFolderPath(folderIndex));
|
MeterWindow* meterWindow = GetMeterWindow(m_SkinRegistry.GetFolderPath(folderIndex));
|
||||||
DeactivateSkin(meterWindow, folderIndex);
|
DeactivateSkin(meterWindow, folderIndex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -896,6 +935,15 @@ void Rainmeter::ToggleSkin(int folderIndex, int fileIndex)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Rainmeter::ToggleSkinWithID(UINT id)
|
||||||
|
{
|
||||||
|
const SkinRegistry::Indexes indexes = m_SkinRegistry.FindIndexesForID(id);
|
||||||
|
if (indexes.IsValid())
|
||||||
|
{
|
||||||
|
ToggleSkin(indexes.folder, indexes.file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Rainmeter::SetSkinPath(const std::wstring& skinPath)
|
void Rainmeter::SetSkinPath(const std::wstring& skinPath)
|
||||||
{
|
{
|
||||||
WritePrivateProfileString(L"Rainmeter", L"SkinPath", skinPath.c_str(), m_IniFile.c_str());
|
WritePrivateProfileString(L"Rainmeter", L"SkinPath", skinPath.c_str(), m_IniFile.c_str());
|
||||||
@ -1053,45 +1101,6 @@ MeterWindow* Rainmeter::GetMeterWindowByINI(const std::wstring& ini_searching)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<int, int> Rainmeter::GetMeterWindowIndex(const std::wstring& folderPath, const std::wstring& file)
|
|
||||||
{
|
|
||||||
int index = FindSkinFolderIndex(folderPath);
|
|
||||||
if (index != -1)
|
|
||||||
{
|
|
||||||
const SkinFolder& skinFolder = m_SkinFolders[index];
|
|
||||||
|
|
||||||
const WCHAR* fileSz = file.c_str();
|
|
||||||
for (size_t i = 0, isize = skinFolder.files.size(); i < isize; ++i)
|
|
||||||
{
|
|
||||||
if (_wcsicmp(skinFolder.files[i].c_str(), fileSz) == 0)
|
|
||||||
{
|
|
||||||
return std::make_pair(index, (int)i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair(-1, -1); // Error
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<int, int> Rainmeter::GetMeterWindowIndex(UINT menuCommand)
|
|
||||||
{
|
|
||||||
if (menuCommand >= ID_CONFIG_FIRST && menuCommand <= ID_CONFIG_LAST)
|
|
||||||
{
|
|
||||||
// Check which skin was selected
|
|
||||||
for (size_t i = 0, isize = m_SkinFolders.size(); i < isize; ++i)
|
|
||||||
{
|
|
||||||
const SkinFolder& skinFolder = m_SkinFolders[i];
|
|
||||||
if (menuCommand >= skinFolder.commandBase &&
|
|
||||||
menuCommand < (skinFolder.commandBase + skinFolder.files.size()))
|
|
||||||
{
|
|
||||||
return std::make_pair((int)i, (int)(menuCommand - skinFolder.commandBase));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair(-1, -1); // error;
|
|
||||||
}
|
|
||||||
|
|
||||||
MeterWindow* Rainmeter::GetMeterWindow(HWND hwnd)
|
MeterWindow* Rainmeter::GetMeterWindow(HWND hwnd)
|
||||||
{
|
{
|
||||||
std::map<std::wstring, MeterWindow*>::const_iterator iter = m_MeterWindows.begin();
|
std::map<std::wstring, MeterWindow*>::const_iterator iter = m_MeterWindows.begin();
|
||||||
@ -1119,69 +1128,6 @@ void Rainmeter::GetMeterWindowsByLoadOrder(std::multimap<int, MeterWindow*>& win
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** Returns the skin folder path relative to the skin folder (e.g. illustro\Clock).
|
|
||||||
**
|
|
||||||
*/
|
|
||||||
std::wstring Rainmeter::GetFolderPath(int folderIndex)
|
|
||||||
{
|
|
||||||
const SkinFolder& skinFolder = m_SkinFolders[folderIndex];
|
|
||||||
std::wstring path = skinFolder.name;
|
|
||||||
for (int i = skinFolder.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 Rainmeter::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& skinFolder = m_SkinFolders[i];
|
|
||||||
if (skinFolder.level == level)
|
|
||||||
{
|
|
||||||
if (skinFolder.name.length() == len && _wcsnicmp(skinFolder.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 (skinFolder.level < level)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Rainmeter::SetLoadOrder(int folderIndex, int order)
|
void Rainmeter::SetLoadOrder(int folderIndex, int order)
|
||||||
{
|
{
|
||||||
std::multimap<int, int>::iterator iter = m_SkinOrders.begin();
|
std::multimap<int, int>::iterator iter = m_SkinOrders.begin();
|
||||||
@ -1206,7 +1152,7 @@ void Rainmeter::SetLoadOrder(int folderIndex, int order)
|
|||||||
|
|
||||||
int Rainmeter::GetLoadOrder(const std::wstring& folderPath)
|
int Rainmeter::GetLoadOrder(const std::wstring& folderPath)
|
||||||
{
|
{
|
||||||
int index = FindSkinFolderIndex(folderPath);
|
const int index = m_SkinRegistry.FindFolderIndex(folderPath);
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
{
|
{
|
||||||
std::multimap<int, int>::const_iterator iter = m_SkinOrders.begin();
|
std::multimap<int, int>::const_iterator iter = m_SkinOrders.begin();
|
||||||
@ -1228,112 +1174,8 @@ int Rainmeter::GetLoadOrder(const std::wstring& folderPath)
|
|||||||
*/
|
*/
|
||||||
void Rainmeter::ScanForSkins()
|
void Rainmeter::ScanForSkins()
|
||||||
{
|
{
|
||||||
m_SkinFolders.clear();
|
m_SkinRegistry.Populate(m_SkinPath);
|
||||||
m_SkinOrders.clear();
|
m_SkinOrders.clear();
|
||||||
|
|
||||||
ScanForSkinsRecursive(m_SkinPath, L"", 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Rainmeter::ScanForSkinsRecursive(const std::wstring& path, std::wstring base, int index, UINT level)
|
|
||||||
{
|
|
||||||
WIN32_FIND_DATA fileData; // Data structure describes the file found
|
|
||||||
HANDLE hSearch; // Search handle returned by FindFirstFile
|
|
||||||
std::list<std::wstring> subfolders;
|
|
||||||
|
|
||||||
// Find all .ini files and subfolders
|
|
||||||
std::wstring filter = path + base;
|
|
||||||
filter += L"\\*";
|
|
||||||
|
|
||||||
hSearch = FindFirstFileEx(
|
|
||||||
filter.c_str(),
|
|
||||||
(Platform::IsAtLeastWin7()) ? FindExInfoBasic : FindExInfoStandard,
|
|
||||||
&fileData,
|
|
||||||
FindExSearchNameMatch,
|
|
||||||
nullptr,
|
|
||||||
0);
|
|
||||||
|
|
||||||
bool foundFiles = false;
|
|
||||||
if (hSearch != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
SkinFolder skinFolder;
|
|
||||||
skinFolder.commandBase = ID_CONFIG_FIRST + index;
|
|
||||||
skinFolder.active = 0;
|
|
||||||
skinFolder.level = level;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
const std::wstring filename = fileData.cFileName;
|
|
||||||
|
|
||||||
if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
||||||
{
|
|
||||||
if (!PathUtil::IsDotOrDotDot(fileData.cFileName) &&
|
|
||||||
!(level == 0 && wcscmp(L"@Backup", fileData.cFileName) == 0) &&
|
|
||||||
!(level == 0 && wcscmp(L"Backup", fileData.cFileName) == 0) &&
|
|
||||||
!(level == 1 && wcscmp(L"@Resources", fileData.cFileName) == 0))
|
|
||||||
{
|
|
||||||
subfolders.push_back(filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (level != 0)
|
|
||||||
{
|
|
||||||
// Check whether the extension is ".ini"
|
|
||||||
size_t filenameLen = filename.size();
|
|
||||||
if (filenameLen >= 4 && _wcsicmp(fileData.cFileName + (filenameLen - 4), L".ini") == 0)
|
|
||||||
{
|
|
||||||
foundFiles = true;
|
|
||||||
skinFolder.files.push_back(filename);
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (FindNextFile(hSearch, &fileData));
|
|
||||||
|
|
||||||
FindClose(hSearch);
|
|
||||||
|
|
||||||
if (level > 0 && (foundFiles || !subfolders.empty()))
|
|
||||||
{
|
|
||||||
if (level == 1)
|
|
||||||
{
|
|
||||||
skinFolder.name = base;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::wstring::size_type pos = base.rfind(L'\\') + 1;
|
|
||||||
skinFolder.name.assign(base, pos, base.length() - pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_SkinFolders.push_back(std::move(skinFolder));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (level != 0)
|
|
||||||
{
|
|
||||||
base += L'\\';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!subfolders.empty())
|
|
||||||
{
|
|
||||||
bool popFolder = !foundFiles;
|
|
||||||
|
|
||||||
std::list<std::wstring>::const_iterator iter = subfolders.begin();
|
|
||||||
for ( ; iter != subfolders.end(); ++iter)
|
|
||||||
{
|
|
||||||
int newIndex = ScanForSkinsRecursive(path, base + (*iter), index, level + 1);
|
|
||||||
if (newIndex != index)
|
|
||||||
{
|
|
||||||
popFolder = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
index = newIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (popFolder)
|
|
||||||
{
|
|
||||||
m_SkinFolders.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1489,13 +1331,13 @@ void Rainmeter::ReadGeneralSettings(const std::wstring& iniFile)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = FindSkinFolderIndex(*iter);
|
const int index = m_SkinRegistry.FindFolderIndex(*iter);
|
||||||
if (index == -1)
|
if (index == -1)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkinFolder& skinFolder = m_SkinFolders[index];
|
SkinRegistry::Folder& skinFolder = m_SkinRegistry.GetFolder(index);
|
||||||
|
|
||||||
// Make sure there is a ini file available
|
// Make sure there is a ini file available
|
||||||
int active = parser.ReadInt(section, L"Active", 0);
|
int active = parser.ReadInt(section, L"Active", 0);
|
||||||
@ -1540,11 +1382,10 @@ void Rainmeter::RefreshAll()
|
|||||||
if (mw)
|
if (mw)
|
||||||
{
|
{
|
||||||
// Verify whether the cached information is valid
|
// Verify whether the cached information is valid
|
||||||
int index = FindSkinFolderIndex(mw->GetFolderPath());
|
const int index = m_SkinRegistry.FindFolderIndex(mw->GetFolderPath());
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
{
|
{
|
||||||
SkinFolder& skinFolder = m_SkinFolders[index];
|
SkinRegistry::Folder& skinFolder = m_SkinRegistry.GetFolder(index);
|
||||||
|
|
||||||
const WCHAR* skinIniFile = mw->GetFileName().c_str();
|
const WCHAR* skinIniFile = mw->GetFileName().c_str();
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
@ -1934,7 +1775,7 @@ void Rainmeter::ShowContextMenu(POINT pos, MeterWindow* meterWindow)
|
|||||||
HMENU allSkinsMenu = GetSubMenu(menu, 4);
|
HMENU allSkinsMenu = GetSubMenu(menu, 4);
|
||||||
if (allSkinsMenu)
|
if (allSkinsMenu)
|
||||||
{
|
{
|
||||||
if (!m_SkinFolders.empty())
|
if (!m_SkinRegistry.IsEmpty())
|
||||||
{
|
{
|
||||||
DeleteMenu(allSkinsMenu, 0, MF_BYPOSITION); // "No skins available" menuitem
|
DeleteMenu(allSkinsMenu, 0, MF_BYPOSITION); // "No skins available" menuitem
|
||||||
CreateAllSkinsMenu(allSkinsMenu);
|
CreateAllSkinsMenu(allSkinsMenu);
|
||||||
@ -2035,13 +1876,13 @@ void Rainmeter::ShowContextMenu(POINT pos, MeterWindow* meterWindow)
|
|||||||
|
|
||||||
int Rainmeter::CreateAllSkinsMenuRecursive(HMENU skinMenu, int index)
|
int Rainmeter::CreateAllSkinsMenuRecursive(HMENU skinMenu, int index)
|
||||||
{
|
{
|
||||||
int initialLevel = m_SkinFolders[index].level;
|
const int initialLevel = m_SkinRegistry.GetFolder(index).level;
|
||||||
int menuIndex = 0;
|
int menuIndex = 0;
|
||||||
|
|
||||||
const size_t max = GetRainmeter().m_SkinFolders.size();
|
const size_t max = m_SkinRegistry.GetFolderCount();
|
||||||
while (index < max)
|
while (index < max)
|
||||||
{
|
{
|
||||||
const SkinFolder& skinFolder = GetRainmeter().m_SkinFolders[index];
|
const SkinRegistry::Folder& skinFolder = m_SkinRegistry.GetFolder(index);
|
||||||
if (skinFolder.level != initialLevel)
|
if (skinFolder.level != initialLevel)
|
||||||
{
|
{
|
||||||
return index - 1;
|
return index - 1;
|
||||||
@ -2053,7 +1894,7 @@ int Rainmeter::CreateAllSkinsMenuRecursive(HMENU skinMenu, int index)
|
|||||||
InsertMenu(skinMenu, menuIndex, MF_POPUP | MF_BYPOSITION, (UINT_PTR)subMenu, skinFolder.name.c_str());
|
InsertMenu(skinMenu, menuIndex, MF_POPUP | MF_BYPOSITION, (UINT_PTR)subMenu, skinFolder.name.c_str());
|
||||||
|
|
||||||
// Add subfolders
|
// Add subfolders
|
||||||
const bool hasSubfolder = (index + 1) < max && m_SkinFolders[index + 1].level == initialLevel + 1;
|
const bool hasSubfolder = (index + 1) < max && m_SkinRegistry.GetFolder(index + 1).level == initialLevel + 1;
|
||||||
if (hasSubfolder)
|
if (hasSubfolder)
|
||||||
{
|
{
|
||||||
index = CreateAllSkinsMenuRecursive(subMenu, index + 1);
|
index = CreateAllSkinsMenuRecursive(subMenu, index + 1);
|
||||||
@ -2065,7 +1906,7 @@ int Rainmeter::CreateAllSkinsMenuRecursive(HMENU skinMenu, int index)
|
|||||||
int fileCount = (int)skinFolder.files.size();
|
int fileCount = (int)skinFolder.files.size();
|
||||||
for ( ; fileIndex < fileCount; ++fileIndex)
|
for ( ; fileIndex < fileCount; ++fileIndex)
|
||||||
{
|
{
|
||||||
InsertMenu(subMenu, fileIndex, MF_STRING | MF_BYPOSITION, skinFolder.commandBase + fileIndex, skinFolder.files[fileIndex].c_str());
|
InsertMenu(subMenu, fileIndex, MF_STRING | MF_BYPOSITION, skinFolder.baseID + fileIndex, skinFolder.files[fileIndex].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skinFolder.active)
|
if (skinFolder.active)
|
||||||
@ -2258,10 +2099,10 @@ HMENU Rainmeter::CreateSkinMenu(MeterWindow* meterWindow, int index, HMENU menu)
|
|||||||
// Add the variants menu
|
// Add the variants menu
|
||||||
if (variantsMenu)
|
if (variantsMenu)
|
||||||
{
|
{
|
||||||
const SkinFolder& skinFolder = m_SkinFolders[FindSkinFolderIndex(skinName)];
|
const SkinRegistry::Folder& skinFolder = *m_SkinRegistry.FindFolder(skinName);
|
||||||
for (int i = 0, isize = (int)skinFolder.files.size(); i < isize; ++i)
|
for (int i = 0, isize = (int)skinFolder.files.size(); i < isize; ++i)
|
||||||
{
|
{
|
||||||
InsertMenu(variantsMenu, i, MF_BYPOSITION, skinFolder.commandBase + i, skinFolder.files[i].c_str());
|
InsertMenu(variantsMenu, i, MF_BYPOSITION, skinFolder.baseID + i, skinFolder.files[i].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skinFolder.active)
|
if (skinFolder.active)
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "CommandHandler.h"
|
#include "CommandHandler.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "MeterWindow.h"
|
#include "MeterWindow.h"
|
||||||
|
#include "SkinRegistry.h"
|
||||||
|
|
||||||
#define MAX_LINE_LENGTH 4096
|
#define MAX_LINE_LENGTH 4096
|
||||||
|
|
||||||
@ -59,37 +60,6 @@ class TrayWindow;
|
|||||||
class Rainmeter
|
class Rainmeter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct SkinFolder
|
|
||||||
{
|
|
||||||
std::wstring name;
|
|
||||||
std::vector<std::wstring> files;
|
|
||||||
UINT commandBase;
|
|
||||||
int16_t active;
|
|
||||||
int16_t level;
|
|
||||||
|
|
||||||
SkinFolder() {}
|
|
||||||
~SkinFolder() {}
|
|
||||||
|
|
||||||
SkinFolder(SkinFolder&& r) :
|
|
||||||
name(std::move(r.name)),
|
|
||||||
files(std::move(r.files)),
|
|
||||||
commandBase(r.commandBase),
|
|
||||||
active(r.active),
|
|
||||||
level(r.level)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SkinFolder& operator=(SkinFolder&& r)
|
|
||||||
{
|
|
||||||
name = std::move(r.name);
|
|
||||||
files = std::move(r.files);
|
|
||||||
commandBase = r.commandBase;
|
|
||||||
active = r.active;
|
|
||||||
level = r.level;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static Rainmeter& GetInstance();
|
static Rainmeter& GetInstance();
|
||||||
|
|
||||||
int Initialize(LPCWSTR iniPath, LPCWSTR layout);
|
int Initialize(LPCWSTR iniPath, LPCWSTR layout);
|
||||||
@ -109,27 +79,23 @@ public:
|
|||||||
|
|
||||||
MeterWindow* GetMeterWindow(const std::wstring& folderPath);
|
MeterWindow* GetMeterWindow(const std::wstring& folderPath);
|
||||||
MeterWindow* GetMeterWindowByINI(const std::wstring& ini_searching);
|
MeterWindow* GetMeterWindowByINI(const std::wstring& ini_searching);
|
||||||
std::pair<int, int> GetMeterWindowIndex(const std::wstring& folderPath, const std::wstring& file);
|
|
||||||
std::pair<int, int> GetMeterWindowIndex(MeterWindow* meterWindow) { return GetMeterWindowIndex(meterWindow->GetFolderPath(), meterWindow->GetFileName()); }
|
|
||||||
std::pair<int, int> GetMeterWindowIndex(UINT menuCommand);
|
|
||||||
|
|
||||||
MeterWindow* GetMeterWindow(HWND hwnd);
|
MeterWindow* GetMeterWindow(HWND hwnd);
|
||||||
void GetMeterWindowsByLoadOrder(std::multimap<int, MeterWindow*>& windows, const std::wstring& group = std::wstring());
|
void GetMeterWindowsByLoadOrder(std::multimap<int, MeterWindow*>& windows, const std::wstring& group = std::wstring());
|
||||||
std::map<std::wstring, MeterWindow*>& GetAllMeterWindows() { return m_MeterWindows; }
|
std::map<std::wstring, MeterWindow*>& GetAllMeterWindows() { return m_MeterWindows; }
|
||||||
|
|
||||||
std::wstring GetFolderPath(int folderIndex);
|
|
||||||
int FindSkinFolderIndex(const std::wstring& folderPath);
|
|
||||||
|
|
||||||
const std::vector<SkinFolder>& GetFolders() { return m_SkinFolders; }
|
|
||||||
const std::vector<std::wstring>& GetAllLayouts() { return m_Layouts; }
|
const std::vector<std::wstring>& GetAllLayouts() { return m_Layouts; }
|
||||||
|
|
||||||
void RemoveMeterWindow(MeterWindow* meterWindow);
|
void RemoveMeterWindow(MeterWindow* meterWindow);
|
||||||
void AddUnmanagedMeterWindow(MeterWindow* meterWindow);
|
void AddUnmanagedMeterWindow(MeterWindow* meterWindow);
|
||||||
void RemoveUnmanagedMeterWindow(MeterWindow* meterWindow);
|
void RemoveUnmanagedMeterWindow(MeterWindow* meterWindow);
|
||||||
|
|
||||||
|
bool ActivateSkin(const std::wstring& folderPath);
|
||||||
|
bool ActivateSkin(const std::wstring& folderPath, const std::wstring& file);
|
||||||
void ActivateSkin(int folderIndex, int fileIndex);
|
void ActivateSkin(int folderIndex, int fileIndex);
|
||||||
void DeactivateSkin(MeterWindow* meterWindow, int folderIndex, bool save = true);
|
void DeactivateSkin(MeterWindow* meterWindow, int folderIndex, bool save = true);
|
||||||
void ToggleSkin(int folderIndex, int fileIndex);
|
void ToggleSkin(int folderIndex, int fileIndex);
|
||||||
|
void ToggleSkinWithID(UINT id);
|
||||||
|
|
||||||
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; }
|
||||||
@ -235,7 +201,6 @@ private:
|
|||||||
void UpdateDesktopWorkArea(bool reset);
|
void UpdateDesktopWorkArea(bool reset);
|
||||||
HMENU CreateSkinMenu(MeterWindow* meterWindow, int index, HMENU menu);
|
HMENU CreateSkinMenu(MeterWindow* meterWindow, int index, HMENU menu);
|
||||||
void ChangeSkinIndex(HMENU subMenu, int index);
|
void ChangeSkinIndex(HMENU subMenu, int index);
|
||||||
int ScanForSkinsRecursive(const std::wstring& path, std::wstring base, int index, UINT level);
|
|
||||||
|
|
||||||
void CreateAllSkinsMenu(HMENU skinMenu) { CreateAllSkinsMenuRecursive(skinMenu, 0); }
|
void CreateAllSkinsMenu(HMENU skinMenu) { CreateAllSkinsMenuRecursive(skinMenu, 0); }
|
||||||
int CreateAllSkinsMenuRecursive(HMENU skinMenu, int index);
|
int CreateAllSkinsMenuRecursive(HMENU skinMenu, int index);
|
||||||
@ -249,7 +214,6 @@ private:
|
|||||||
|
|
||||||
TrayWindow* m_TrayWindow;
|
TrayWindow* m_TrayWindow;
|
||||||
|
|
||||||
std::vector<SkinFolder> m_SkinFolders;
|
|
||||||
std::multimap<int, int> m_SkinOrders;
|
std::multimap<int, int> m_SkinOrders;
|
||||||
std::map<std::wstring, MeterWindow*> m_MeterWindows;
|
std::map<std::wstring, MeterWindow*> m_MeterWindows;
|
||||||
std::list<MeterWindow*> m_UnmanagedMeterWindows;
|
std::list<MeterWindow*> m_UnmanagedMeterWindows;
|
||||||
@ -295,6 +259,8 @@ private:
|
|||||||
|
|
||||||
CommandHandler m_CommandHandler;
|
CommandHandler m_CommandHandler;
|
||||||
|
|
||||||
|
SkinRegistry m_SkinRegistry;
|
||||||
|
|
||||||
ConfigParser* m_CurrentParser;
|
ConfigParser* m_CurrentParser;
|
||||||
|
|
||||||
HWND m_Window;
|
HWND m_Window;
|
||||||
|
243
Library/SkinRegistry.cpp
Normal file
243
Library/SkinRegistry.cpp
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2013 Rainmeter Team
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#include "../Common/PathUtil.h"
|
||||||
|
#include "../Common/Platform.h"
|
||||||
|
#include "SkinRegistry.h"
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Returns the skin folder path relative to the skin folder (e.g. illustro\Clock).
|
||||||
|
*/
|
||||||
|
std::wstring SkinRegistry::GetFolderPath(int folderIndex) const
|
||||||
|
{
|
||||||
|
// Traverse |m_Folders| backwards until level 1 is reached.
|
||||||
|
const auto& skinFolder = m_Folders[folderIndex];
|
||||||
|
std::wstring path = skinFolder.name;
|
||||||
|
for (int i = skinFolder.level - 1, index = folderIndex; i >= 1; --i)
|
||||||
|
{
|
||||||
|
while (m_Folders[index].level != i)
|
||||||
|
{
|
||||||
|
--index;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.insert(0, L"\\");
|
||||||
|
path.insert(0, m_Folders[index].name);
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Finds the skin index for the specified skin folder path.
|
||||||
|
*/
|
||||||
|
int SkinRegistry::FindFolderIndex(const std::wstring& folderPath) const
|
||||||
|
{
|
||||||
|
if (folderPath.empty()) return -1;
|
||||||
|
|
||||||
|
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_Folders.size(); i < isize; ++i)
|
||||||
|
{
|
||||||
|
const auto& skinFolder = m_Folders[i];
|
||||||
|
if (skinFolder.level == level)
|
||||||
|
{
|
||||||
|
if (skinFolder.name.length() == len && _wcsnicmp(skinFolder.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 (skinFolder.level < level)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkinRegistry::Folder* SkinRegistry::FindFolder(const std::wstring& folderPath)
|
||||||
|
{
|
||||||
|
const int folderIndex = FindFolderIndex(folderPath);
|
||||||
|
return (folderIndex != -1) ? &m_Folders[folderIndex] : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkinRegistry::Indexes SkinRegistry::FindIndexes(const std::wstring& folderPath, const std::wstring& file)
|
||||||
|
{
|
||||||
|
const int folderIndex = FindFolderIndex(folderPath);
|
||||||
|
if (folderIndex != -1)
|
||||||
|
{
|
||||||
|
const Folder& skinFolder = m_Folders[folderIndex];
|
||||||
|
const WCHAR* fileSz = file.c_str();
|
||||||
|
for (size_t i = 0, isize = skinFolder.files.size(); i < isize; ++i)
|
||||||
|
{
|
||||||
|
if (_wcsicmp(skinFolder.files[i].c_str(), fileSz) == 0)
|
||||||
|
{
|
||||||
|
return Indexes(folderIndex, (int)i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Indexes::Invalid(); // Not found.
|
||||||
|
}
|
||||||
|
|
||||||
|
SkinRegistry::Indexes SkinRegistry::FindIndexesForID(UINT id)
|
||||||
|
{
|
||||||
|
if (id >= ID_CONFIG_FIRST && id <= ID_CONFIG_LAST)
|
||||||
|
{
|
||||||
|
// Check which skin was selected
|
||||||
|
for (size_t i = 0, isize = m_Folders.size(); i < isize; ++i)
|
||||||
|
{
|
||||||
|
const Folder& skinFolder = m_Folders[i];
|
||||||
|
if (id >= skinFolder.baseID &&
|
||||||
|
id < (skinFolder.baseID + skinFolder.files.size()))
|
||||||
|
{
|
||||||
|
return Indexes((int)i, (int)(id - skinFolder.baseID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Indexes::Invalid(); // Not found.
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Re-scans all the subfolders of |path| for .ini files and populates |m_Folders|.
|
||||||
|
*/
|
||||||
|
void SkinRegistry::Populate(const std::wstring& path)
|
||||||
|
{
|
||||||
|
m_Folders.clear();
|
||||||
|
PopulateRecursive(path, L"", 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SkinRegistry::PopulateRecursive(const std::wstring& path, std::wstring base, int index, UINT level)
|
||||||
|
{
|
||||||
|
WIN32_FIND_DATA fileData; // Data structure describes the file found
|
||||||
|
HANDLE hSearch; // Search handle returned by FindFirstFile
|
||||||
|
std::list<std::wstring> subfolders;
|
||||||
|
|
||||||
|
// Find all .ini files and subfolders
|
||||||
|
std::wstring filter = path + base;
|
||||||
|
filter += L"\\*";
|
||||||
|
|
||||||
|
hSearch = FindFirstFileEx(
|
||||||
|
filter.c_str(),
|
||||||
|
(Platform::IsAtLeastWin7()) ? FindExInfoBasic : FindExInfoStandard,
|
||||||
|
&fileData,
|
||||||
|
FindExSearchNameMatch,
|
||||||
|
nullptr,
|
||||||
|
0);
|
||||||
|
|
||||||
|
bool foundFiles = false;
|
||||||
|
if (hSearch != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
Folder folder;
|
||||||
|
folder.baseID = ID_CONFIG_FIRST + index;
|
||||||
|
folder.active = 0;
|
||||||
|
folder.level = level;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const std::wstring filename = fileData.cFileName;
|
||||||
|
|
||||||
|
if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
|
{
|
||||||
|
if (!PathUtil::IsDotOrDotDot(fileData.cFileName) &&
|
||||||
|
!(level == 0 && wcscmp(L"@Backup", fileData.cFileName) == 0) &&
|
||||||
|
!(level == 0 && wcscmp(L"Backup", fileData.cFileName) == 0) &&
|
||||||
|
!(level == 1 && wcscmp(L"@Resources", fileData.cFileName) == 0))
|
||||||
|
{
|
||||||
|
subfolders.push_back(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (level != 0)
|
||||||
|
{
|
||||||
|
// Check whether the extension is ".ini"
|
||||||
|
size_t filenameLen = filename.size();
|
||||||
|
if (filenameLen >= 4 && _wcsicmp(fileData.cFileName + (filenameLen - 4), L".ini") == 0)
|
||||||
|
{
|
||||||
|
foundFiles = true;
|
||||||
|
folder.files.push_back(filename);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (FindNextFile(hSearch, &fileData));
|
||||||
|
|
||||||
|
FindClose(hSearch);
|
||||||
|
|
||||||
|
if (level > 0 && (foundFiles || !subfolders.empty()))
|
||||||
|
{
|
||||||
|
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_Folders.push_back(std::move(folder));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level != 0)
|
||||||
|
{
|
||||||
|
base += L'\\';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!subfolders.empty())
|
||||||
|
{
|
||||||
|
bool popFolder = !foundFiles;
|
||||||
|
|
||||||
|
std::list<std::wstring>::const_iterator iter = subfolders.begin();
|
||||||
|
for ( ; iter != subfolders.end(); ++iter)
|
||||||
|
{
|
||||||
|
int newIndex = PopulateRecursive(path, base + (*iter), index, level + 1);
|
||||||
|
if (newIndex != index)
|
||||||
|
{
|
||||||
|
popFolder = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = newIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (popFolder)
|
||||||
|
{
|
||||||
|
m_Folders.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
101
Library/SkinRegistry.h
Normal file
101
Library/SkinRegistry.h
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2013 Rainmeter Team
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RM_LIBRARY_SKINDIRECTORY_H_
|
||||||
|
#define RM_LIBRARY_SKINDIRECTORY_H_
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// Reprsents a hierarchy of skin folders (reprsented by the Folder struct) and the names of their
|
||||||
|
// respective files.
|
||||||
|
class SkinRegistry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Folder
|
||||||
|
{
|
||||||
|
std::wstring name;
|
||||||
|
std::vector<std::wstring> files;
|
||||||
|
UINT baseID;
|
||||||
|
|
||||||
|
int16_t active;
|
||||||
|
int16_t level;
|
||||||
|
|
||||||
|
Folder() {}
|
||||||
|
~Folder() {}
|
||||||
|
|
||||||
|
Folder(Folder&& r) :
|
||||||
|
name(std::move(r.name)),
|
||||||
|
files(std::move(r.files)),
|
||||||
|
baseID(r.baseID),
|
||||||
|
active(r.active),
|
||||||
|
level(r.level)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Folder& operator=(Folder&& r)
|
||||||
|
{
|
||||||
|
name = std::move(r.name);
|
||||||
|
files = std::move(r.files);
|
||||||
|
baseID = r.baseID;
|
||||||
|
active = r.active;
|
||||||
|
level = r.level;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Indexes
|
||||||
|
{
|
||||||
|
int folder;
|
||||||
|
int file;
|
||||||
|
|
||||||
|
Indexes(int folderIndex = 0, int fileIndex = 0) : folder(folderIndex), file(fileIndex) {}
|
||||||
|
|
||||||
|
bool IsValid() const { return folder != -1; }
|
||||||
|
|
||||||
|
static Indexes Invalid() { return Indexes(-1, 0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
int FindFolderIndex(const std::wstring& folderPath) const;
|
||||||
|
Folder* FindFolder(const std::wstring& folderPath);
|
||||||
|
|
||||||
|
Indexes FindIndexes(const std::wstring& folderPath, const std::wstring& file);
|
||||||
|
Indexes FindIndexesForID(UINT id);
|
||||||
|
|
||||||
|
std::wstring GetFolderPath(int folderIndex) const;
|
||||||
|
|
||||||
|
Folder& GetFolder(int index) { return m_Folders[index]; }
|
||||||
|
int GetFolderCount() const { return (int)m_Folders.size(); }
|
||||||
|
bool IsEmpty() const { return m_Folders.empty(); }
|
||||||
|
|
||||||
|
void Populate(const std::wstring& path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int PopulateRecursive(const std::wstring& path, std::wstring base, int index, UINT level);
|
||||||
|
|
||||||
|
// Contains a sequential list of Folders. The folders are arranged as follows:
|
||||||
|
// A (index: 0, level: 1)
|
||||||
|
// B (index: 1, level: 2)
|
||||||
|
// C (index: 2, level: 3)
|
||||||
|
// D (index: 3, level: 2)
|
||||||
|
std::vector<Folder> m_Folders;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
105
Library/SkinRegistry_Test.cpp
Normal file
105
Library/SkinRegistry_Test.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2013 Rainmeter Team
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SkinRegistry.h"
|
||||||
|
#include <CppUnitTest.h>
|
||||||
|
|
||||||
|
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||||
|
|
||||||
|
TEST_CLASS(Library_SkinRegistry_Test)
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Library_SkinRegistry_Test()
|
||||||
|
{
|
||||||
|
m_SkinRegistry.Populate(L"..\\..\\..\\Library\\Test\\SkinRegistry\\");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(TestContents)
|
||||||
|
{
|
||||||
|
std::vector<std::wstring> files1;
|
||||||
|
files1.push_back(L"1.ini");
|
||||||
|
|
||||||
|
std::vector<std::wstring> files3;
|
||||||
|
files3.push_back(L"1.ini");
|
||||||
|
files3.push_back(L"2.ini");
|
||||||
|
files3.push_back(L"3.ini");
|
||||||
|
|
||||||
|
Assert::AreEqual(5, m_SkinRegistry.GetFolderCount());
|
||||||
|
|
||||||
|
const auto& folderA1 = m_SkinRegistry.GetFolder(0);
|
||||||
|
Assert::AreEqual(L"A1", folderA1.name.c_str());
|
||||||
|
Assert::AreEqual((int16_t)1, folderA1.level);
|
||||||
|
Assert::IsTrue(folderA1.files.empty());
|
||||||
|
|
||||||
|
const auto& folderA1_B1 = m_SkinRegistry.GetFolder(1);
|
||||||
|
Assert::AreEqual(L"B1", folderA1_B1.name.c_str());
|
||||||
|
Assert::AreEqual((int16_t)2, folderA1_B1.level);
|
||||||
|
Assert::IsTrue(files1 == folderA1_B1.files);
|
||||||
|
|
||||||
|
const auto& folderA1_B2 = m_SkinRegistry.GetFolder(2);
|
||||||
|
Assert::AreEqual(L"B2", folderA1_B2.name.c_str());
|
||||||
|
Assert::AreEqual((int16_t)2, folderA1_B2.level);
|
||||||
|
Assert::IsTrue(files1 == folderA1_B2.files);
|
||||||
|
|
||||||
|
const auto& folderA1_B2_C1 = m_SkinRegistry.GetFolder(3);
|
||||||
|
Assert::AreEqual(L"C1", folderA1_B2_C1.name.c_str());
|
||||||
|
Assert::AreEqual((int16_t)3, folderA1_B2_C1.level);
|
||||||
|
Assert::IsTrue(files1 == folderA1_B2_C1.files);
|
||||||
|
|
||||||
|
const auto& folderA2 = m_SkinRegistry.GetFolder(4);
|
||||||
|
Assert::AreEqual(L"A2", folderA2.name.c_str());
|
||||||
|
Assert::AreEqual((int16_t)1, folderA2.level);
|
||||||
|
Assert::IsTrue(files3 == folderA2.files);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(TestFindFolderIndex)
|
||||||
|
{
|
||||||
|
Assert::AreEqual(3, m_SkinRegistry.FindFolderIndex(L"A1\\B2\\C1"));
|
||||||
|
Assert::AreEqual(-1, m_SkinRegistry.FindFolderIndex(L"A1\\B5\\C1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(TestFindIndexes)
|
||||||
|
{
|
||||||
|
const auto indexes1 = m_SkinRegistry.FindIndexes(L"A1\\B2", L"1.ini");
|
||||||
|
Assert::IsTrue(indexes1.folder == 2 && indexes1.file == 0);
|
||||||
|
|
||||||
|
const auto indexes2 = m_SkinRegistry.FindIndexes(L"A2", L"2.ini");
|
||||||
|
Assert::IsTrue(indexes2.folder == 4 && indexes2.file == 1);
|
||||||
|
|
||||||
|
const auto indexes3 = m_SkinRegistry.FindIndexes(L"A3", L"1.ini");
|
||||||
|
Assert::IsFalse(indexes3.IsValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(TestFindIndexesForID)
|
||||||
|
{
|
||||||
|
const auto indexes1 = m_SkinRegistry.FindIndexesForID(30002);
|
||||||
|
Assert::IsTrue(indexes1.folder == 2 && indexes1.file == 0);
|
||||||
|
|
||||||
|
const auto indexes2 = m_SkinRegistry.FindIndexesForID(30005);
|
||||||
|
Assert::IsTrue(indexes2.folder == 4 && indexes2.file == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(TestGetFolderPath)
|
||||||
|
{
|
||||||
|
Assert::AreEqual(L"A1\\B2\\C1", m_SkinRegistry.GetFolderPath(3).c_str());
|
||||||
|
Assert::AreEqual(L"A2", m_SkinRegistry.GetFolderPath(4).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SkinRegistry m_SkinRegistry;
|
||||||
|
};
|
0
Library/Test/SkinRegistry/@Backup/1.ini
Normal file
0
Library/Test/SkinRegistry/@Backup/1.ini
Normal file
0
Library/Test/SkinRegistry/A1/B1/1.ini
Normal file
0
Library/Test/SkinRegistry/A1/B1/1.ini
Normal file
0
Library/Test/SkinRegistry/A1/B2/1.ini
Normal file
0
Library/Test/SkinRegistry/A1/B2/1.ini
Normal file
0
Library/Test/SkinRegistry/A1/B2/C1/1.ini
Normal file
0
Library/Test/SkinRegistry/A1/B2/C1/1.ini
Normal file
0
Library/Test/SkinRegistry/A1/B3/.gitkeep
Normal file
0
Library/Test/SkinRegistry/A1/B3/.gitkeep
Normal file
0
Library/Test/SkinRegistry/A2/1.ini
Normal file
0
Library/Test/SkinRegistry/A2/1.ini
Normal file
0
Library/Test/SkinRegistry/A2/2.ini
Normal file
0
Library/Test/SkinRegistry/A2/2.ini
Normal file
0
Library/Test/SkinRegistry/A2/3.ini
Normal file
0
Library/Test/SkinRegistry/A2/3.ini
Normal file
0
Library/Test/SkinRegistry/A2/@Resources/1.ini
Normal file
0
Library/Test/SkinRegistry/A2/@Resources/1.ini
Normal file
0
Library/Test/SkinRegistry/A2/B1/.gitkeep
Normal file
0
Library/Test/SkinRegistry/A2/B1/.gitkeep
Normal file
@ -536,11 +536,7 @@ LRESULT CALLBACK TrayWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
|
|||||||
}
|
}
|
||||||
else if (mID >= ID_CONFIG_FIRST && mID <= ID_CONFIG_LAST)
|
else if (mID >= ID_CONFIG_FIRST && mID <= ID_CONFIG_LAST)
|
||||||
{
|
{
|
||||||
std::pair<int, int> indexes = GetRainmeter().GetMeterWindowIndex(mID);
|
GetRainmeter().ToggleSkinWithID(mID);
|
||||||
if (indexes.first != -1 && indexes.second != -1)
|
|
||||||
{
|
|
||||||
GetRainmeter().ToggleSkin(indexes.first, indexes.second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user