It's now possible to use the measures as if they were variables (use [MeasureName] instead #VariableName#). Set DynamicVariables=1 for all meters and measures which refer to other measures.

New bang !RainmeterSetVariable can be used to change the value of a variable (DynamicVariables must be 1 in places where the variable is used).
This commit is contained in:
Kimmo Pekkola 2009-08-26 17:37:15 +00:00
parent 7b22d717a3
commit dc3c767efa
10 changed files with 317 additions and 77 deletions

View File

@ -60,6 +60,9 @@ void CConfigParser::Initialize(LPCTSTR filename, CRainmeter* pRainmeter)
m_Filename = filename;
m_Variables.clear();
m_Measures.clear();
ReadIniFile(m_Filename);
// Set the default variables
if (pRainmeter)
@ -99,45 +102,26 @@ void CConfigParser::Initialize(LPCTSTR filename, CRainmeter* pRainmeter)
*/
void CConfigParser::ReadVariables()
{
DWORD size;
TCHAR* buffer;
TCHAR* variable;
int bufferSize = 4096;
bool loop;
std::vector<std::wstring> listVariables = GetKeys(L"Variables");
do
for (size_t i = 0; i < listVariables.size(); i++)
{
loop = false;
buffer = new TCHAR[bufferSize];
size = GetPrivateProfileString(L"Variables", NULL, L"", buffer, bufferSize, m_Filename.c_str());
if (size == bufferSize - 1)
{
// Buffer too small, increase it and retry
delete [] buffer;
bufferSize *= 2;
loop = true;
}
} while(loop);
if (size > 0)
{
// Read all variables
WCHAR* pos = buffer;
while(wcslen(pos) > 0)
{
std::wstring variable = ReadString(L"Variables", pos, L"");
if (!variable.empty())
{
m_Variables[pos] = variable;
}
pos = pos + wcslen(pos) + 1;
}
m_Variables[listVariables[i]] = GetValue(L"Variables", listVariables[i], L"");
}
delete [] buffer;
}
//==============================================================================
/**
** Sets a new value for the variable. The DynamicVariables must be set to 1 in the
** meter/measure for the changes to be applied.
**
** \param strVariable
** \param strValue
** \return void
*/
void CConfigParser::SetVariable(const std::wstring& strVariable, const std::wstring& strValue)
{
m_Variables[strVariable] = strValue;
}
/*
@ -148,32 +132,12 @@ void CConfigParser::ReadVariables()
const std::wstring& CConfigParser::ReadString(LPCTSTR section, LPCTSTR key, LPCTSTR defValue)
{
static std::wstring result;
DWORD size;
TCHAR* buffer;
int bufferSize = 4096;
bool loop;
do
result = GetValue(section, key, defValue);
if (result == defValue)
{
loop = false;
buffer = new TCHAR[bufferSize];
buffer[0] = 0;
size = GetPrivateProfileString(section, key, defValue, buffer, bufferSize, m_Filename.c_str());
if (size == bufferSize - 1)
{
// Buffer too small, increase it and retry
delete [] buffer;
bufferSize *= 2;
loop = true;
}
} while(loop);
result = buffer;
delete [] buffer;
return result;
}
// Check Litestep vars
if (Rainmeter && !Rainmeter->GetDummyLitestep())
@ -188,13 +152,13 @@ const std::wstring& CConfigParser::ReadString(LPCTSTR section, LPCTSTR key, LPCT
}
}
result = CRainmeter::ExpandEnvironmentVariables(result);
CRainmeter::ExpandEnvironmentVariables(result);
// Check for variables (#VAR#)
size_t start = 0;
size_t end = std::wstring::npos;
size_t pos = std::wstring::npos;
loop = true;
bool loop = true;
do
{
@ -229,9 +193,59 @@ const std::wstring& CConfigParser::ReadString(LPCTSTR section, LPCTSTR key, LPCT
}
} while(loop);
// Check for measures ([Measure])
if (!m_Measures.empty())
{
start = 0;
end = std::wstring::npos;
pos = std::wstring::npos;
loop = true;
do
{
pos = result.find(L'[', start);
if (pos != std::wstring::npos)
{
size_t end = result.find(L']', pos + 1);
if (end != std::wstring::npos)
{
std::wstring var(result.begin() + pos + 1, result.begin() + end);
std::map<std::wstring, CMeasure*>::iterator iter = m_Measures.find(var);
if (iter != m_Measures.end())
{
std::wstring value = (*iter).second->GetStringValue(true, 1, 1, false);
// Measure found, replace it with the value
result.replace(result.begin() + pos, result.begin() + end + 1, value);
start = pos + value.length();
}
else
{
start = end;
}
}
else
{
loop = false;
}
}
else
{
loop = false;
}
} while(loop);
}
return result;
}
void CConfigParser::AddMeasure(CMeasure* pMeasure)
{
if (pMeasure)
{
m_Measures[pMeasure->GetName()] = pMeasure;
}
}
double CConfigParser::ReadFloat(LPCTSTR section, LPCTSTR key, double defValue)
{
@ -405,3 +419,159 @@ Color CConfigParser::ParseColor(LPCTSTR string)
return Color(A, R, G, B);
}
//==============================================================================
/**
** Reads the given ini file and fills the m_Values and m_Keys maps.
**
** \param iniFile The ini file to be read.
*/
void CConfigParser::ReadIniFile(const std::wstring& iniFile)
{
m_Keys.clear();
m_Values.clear();
// Get all the sections (i.e. different meters)
WCHAR* items = new WCHAR[MAX_LINE_LENGTH];
int size = MAX_LINE_LENGTH;
// Get all the sections
while(true)
{
items[0] = 0;
int res = GetPrivateProfileString( NULL, NULL, NULL, items, size, iniFile.c_str());
if (res == 0) return; // File not found
if (res != size - 2) break; // Fits in the buffer
delete [] items;
size *= 2;
items = new WCHAR[size];
};
// Read the sections
WCHAR* pos = items;
while(wcslen(pos) > 0)
{
m_Keys[pos] = std::vector<std::wstring>();
pos = pos + wcslen(pos) + 1;
}
// Read the keys and values
int bufferSize = MAX_LINE_LENGTH;
TCHAR* buffer = new TCHAR[bufferSize];
stdext::hash_map<std::wstring, std::vector<std::wstring> >::iterator iter = m_Keys.begin();
for ( ; iter != m_Keys.end(); iter++)
{
while(true)
{
items[0] = 0;
int res = GetPrivateProfileString((*iter).first.c_str(), NULL, NULL, items, size, iniFile.c_str());
if (res != size - 2) break; // Fits in the buffer
delete [] items;
size *= 2;
items = new WCHAR[size];
};
WCHAR* pos = items;
while(wcslen(pos) > 0)
{
std::wstring strKey = pos;
while(true)
{
buffer[0] = 0;
int res = GetPrivateProfileString((*iter).first.c_str(), strKey.c_str(), L"", buffer, bufferSize, iniFile.c_str());
if (res != size - 2) break; // Fits in the buffer
delete [] buffer;
bufferSize *= 2;
buffer = new WCHAR[size];
};
SetValue((*iter).first, strKey, buffer);
pos = pos + wcslen(pos) + 1;
}
}
delete [] buffer;
delete [] items;
}
//==============================================================================
/**
** Sets the value for the key under the given section.
**
** \param strSection The name of the section.
** \param strKey The name of the key.
** \param strValue The value for the key.
*/
void CConfigParser::SetValue(const std::wstring& strSection, const std::wstring& strKey, const std::wstring& strValue)
{
stdext::hash_map<std::wstring, std::vector<std::wstring> >::iterator iter = m_Keys.find(strSection);
if (iter != m_Keys.end())
{
std::vector<std::wstring>& array = (*iter).second;
array.push_back(strKey);
}
m_Values[strSection + L"::" + strKey] = strValue;
}
//==============================================================================
/**
** Returns the value for the key under the given section.
**
** \param strSection The name of the section.
** \param strKey The name of the key.
** \param strDefault The default value for the key.
** \return The value for the key.
*/
const std::wstring& CConfigParser::GetValue(const std::wstring& strSection, const std::wstring& strKey, const std::wstring& strDefault)
{
stdext::hash_map<std::wstring, std::wstring>::iterator iter = m_Values.find(strSection + L"::" + strKey);
if (iter != m_Values.end())
{
return (*iter).second;
}
return strDefault;
}
//==============================================================================
/**
** Returns the list of sections in the ini file.
**
** \return A list of sections in the ini file.
*/
std::vector<std::wstring> CConfigParser::GetSections()
{
std::vector<std::wstring> listSections;
stdext::hash_map<std::wstring, std::vector<std::wstring> >::iterator iter = m_Keys.begin();
for ( ; iter != m_Keys.end(); iter++)
{
listSections.push_back((*iter).first);
}
return listSections;
}
//==============================================================================
/**
** Returns a list of keys under the given section.
**
** \param strSection The name of the section.
** \return A list of keys under the given section.
*/
std::vector<std::wstring> CConfigParser::GetKeys(const std::wstring& strSection)
{
stdext::hash_map<std::wstring, std::vector<std::wstring> >::iterator iter = m_Keys.find(strSection);
if (iter != m_Keys.end())
{
return (*iter).second;
}
return std::vector<std::wstring>();
}

View File

@ -23,10 +23,12 @@
#include <map>
#include <string>
#include <vector>
#include <hash_map>
#include <gdiplus.h>
#include "ccalc-0.5.1/mparser.h"
class CRainmeter;
class CMeasure;
class CConfigParser
{
@ -35,6 +37,8 @@ public:
~CConfigParser();
void Initialize(LPCTSTR filename, CRainmeter* pRainmeter);
void AddMeasure(CMeasure* pMeasure);
void SetVariable(const std::wstring& strVariable, const std::wstring& strValue);
const std::wstring& ReadString(LPCTSTR section, LPCTSTR key, LPCTSTR defValue);
double ReadFloat(LPCTSTR section, LPCTSTR key, double defValue);
@ -50,10 +54,20 @@ private:
Gdiplus::Color ParseColor(LPCTSTR string);
std::vector<std::wstring> Tokenize(const std::wstring& str, const std::wstring delimiters);
void ReadIniFile(const std::wstring& strFileName);
void SetValue(const std::wstring& strSection, const std::wstring& strKey, const std::wstring& strValue);
const std::wstring& GetValue(const std::wstring& strSection, const std::wstring& strKey, const std::wstring& strDefault);
std::vector<std::wstring> GetSections();
std::vector<std::wstring> GetKeys(const std::wstring& strSection);
std::map<std::wstring, std::wstring> m_Variables;
std::wstring m_Filename;
hqMathParser* m_Parser;
std::map<std::wstring, CMeasure*> m_Measures;
stdext::hash_map<std::wstring, std::vector<std::wstring> > m_Keys;
stdext::hash_map<std::wstring, std::wstring> m_Values;
};
#endif

View File

@ -67,6 +67,7 @@ CMeasure::CMeasure(CMeterWindow* meterWindow)
m_AveragePos = 0;
m_AverageSize = 0;
m_MeterWindow = meterWindow;
m_DynamicVariables = false;
}
/*
@ -108,7 +109,9 @@ void CMeasure::ReadConfig(CConfigParser& parser, const WCHAR* section)
m_IfEqualAction = parser.ReadString(section, L"IfEqualAction", L"");
m_AverageSize = parser.ReadInt(section, L"AverageSize", 0);
m_DynamicVariables = 0!=parser.ReadInt(section, L"DynamicVariables", 0);
std::wstring subs;
subs = parser.ReadString(section, L"Substitute", L"");
if (!ParseSubstitute(subs))

View File

@ -43,6 +43,8 @@ public:
void Enable() { m_Disabled = false; };
bool IsDisabled() { return m_Disabled; };
bool HasDynamicVariables() { return m_DynamicVariables; }
virtual void ExecuteBang(const WCHAR* args);
double GetValue();
@ -64,6 +66,7 @@ protected:
std::wstring ExtractWord(std::wstring& buffer);
const WCHAR* CheckSubstitute(const WCHAR* buffer);
bool m_DynamicVariables; // If true, the measure contains dynamic variables
bool m_Invert; // If true, the value should be inverted
bool m_LogMaxValue; // If true, The maximum & minimum values are logged
double m_MinValue; // The minimum value (so far)

View File

@ -62,6 +62,7 @@ CMeter::CMeter(CMeterWindow* meterWindow)
m_SolidAngle = 0.0;
m_MeterWindow = meterWindow;
m_AntiAlias = false;
m_DynamicVariables = false;
}
/*
@ -267,6 +268,7 @@ void CMeter::ReadConfig(const WCHAR* section)
m_UpdateDivider = parser.ReadInt(section, L"UpdateDivider", 1);
m_UpdateCounter = m_UpdateDivider;
m_AntiAlias = 0!=parser.ReadInt(section, L"AntiAlias", 0);
m_DynamicVariables = 0!=parser.ReadInt(section, L"DynamicVariables", 0);
std::vector<Gdiplus::REAL> matrix = parser.ReadFloats(section, L"TransformationMatrix");
if (matrix.size() == 6)

View File

@ -39,6 +39,8 @@ public:
virtual bool Draw(Gdiplus::Graphics& graphics);
virtual void BindMeasure(std::list<CMeasure*>& measures);
virtual bool HasActiveTransition() { return false; }
bool HasDynamicVariables() { return m_DynamicVariables; }
virtual int GetH() { return m_Hidden ? 0 : m_H; };
virtual int GetW() { return m_Hidden ? 0 : m_W; };
@ -100,6 +102,7 @@ protected:
int m_H; // Height of the meter
bool m_Hidden; // Status of the meter
CMeter* m_RelativeMeter;
bool m_DynamicVariables; // If true, the measure contains dynamic variables
static int c_OldX;
static int c_OldY;

View File

@ -247,8 +247,8 @@ int CMeterWindow::Initialize(CRainmeter& Rainmeter)
if (DwmSetWindowAttribute)
{
DwmSetWindowAttribute(m_Window, DWMWA_EXCLUDED_FROM_PEEK, &bValue, sizeof(bValue));
}
FreeLibrary(h);
}
FreeLibrary(h);
}
// Gotta have some kind of buffer during initialization
@ -689,6 +689,20 @@ void CMeterWindow::RunBang(BANGCOMMAND bang, const WCHAR* arg)
// Quit needs to be delayed since it crashes if done during Update()
PostMessage(m_Window, WM_DELAYED_QUIT, (WPARAM)NULL, (LPARAM)NULL);
break;
case BANG_SETVARIABLE:
pos = wcschr(arg, ' ');
if (pos != NULL)
{
std::wstring strVariable(arg, pos - arg);
std::wstring strValue(pos + 1);
m_Parser.SetVariable(strVariable, strValue);
}
else
{
DebugLog(L"Cannot parse parameters for !RainmeterSetVariable");
}
break;
}
}
@ -1338,7 +1352,7 @@ void CMeterWindow::ReadSkin()
}
else
{
wsprintf(buffer, L"%i.%i", appVersion / 1000000, appVersion / 1000);
wsprintf(buffer, L"%i.%i", appVersion / 1000000, (appVersion / 1000) % 1000);
}
text = L"This skin needs Rainmeter version ";
text += buffer;
@ -1428,6 +1442,8 @@ void CMeterWindow::ReadSkin()
measure->SetName(pos);
measure->ReadConfig(m_Parser, pos);
m_Measures.push_back(measure);
m_Parser.AddMeasure(measure);
}
catch (CError& error)
{
@ -1857,6 +1873,10 @@ void CMeterWindow::Update(bool nodraw)
{
try
{
if ((*i)->HasDynamicVariables())
{
(*i)->ReadConfig(m_Parser, (*i)->GetName());
}
(*i)->Update();
}
catch (CError& error)
@ -1871,6 +1891,10 @@ void CMeterWindow::Update(bool nodraw)
{
try
{
if ((*j)->HasDynamicVariables())
{
(*j)->ReadConfig((*j)->GetName());
}
(*j)->Update();
}
catch (CError& error)

View File

@ -99,7 +99,8 @@ enum BANGCOMMAND
BANG_ABOUT,
BANG_MOVEMETER,
BANG_PLUGIN,
BANG_QUIT
BANG_QUIT,
BANG_SETVARIABLE
};
typedef struct

View File

@ -580,6 +580,17 @@ void RainmeterQuit(HWND, const char* arg)
BangWithArgs(BANG_QUIT, ConvertToWide(arg).c_str(), 0);
}
/*
** RainmeterSetVariable
**
** Callback for the !RainmeterSetVariable bang
**
*/
void RainmeterSetVariable(HWND, const char* arg)
{
BangWithArgs(BANG_SETVARIABLE, ConvertToWide(arg).c_str(), 2);
}
// -----------------------------------------------------------------------------------------------
//
// The class starts here
@ -690,7 +701,8 @@ int CRainmeter::Initialize(HWND Parent, HINSTANCE Instance, LPCSTR szPath)
// If the ini file doesn't exist in the program folder store it to the %APPDATA% instead so that things work better in Vista/Win7
if (_waccess(m_IniFile.c_str(), 0) == -1)
{
m_IniFile = ExpandEnvironmentVariables(L"%APPDATA%\\Rainmeter\\Rainmeter.ini");
m_IniFile = L"%APPDATA%\\Rainmeter\\Rainmeter.ini";
ExpandEnvironmentVariables(m_IniFile);
bDefaultIniLocation = true;
// If the ini file doesn't exist in the %APPDATA% either, create a default rainmeter.ini file.
@ -709,7 +721,7 @@ int CRainmeter::Initialize(HWND Parent, HINSTANCE Instance, LPCSTR szPath)
iniFile = iniFile.substr(1, iniFile.length() - 2);
}
iniFile = ExpandEnvironmentVariables(iniFile);
ExpandEnvironmentVariables(iniFile);
if (iniFile[iniFile.length() - 1] == L'\\')
{
@ -738,7 +750,8 @@ int CRainmeter::Initialize(HWND Parent, HINSTANCE Instance, LPCSTR szPath)
WCHAR tmpSz[MAX_LINE_LENGTH];
if (GetPrivateProfileString(L"Rainmeter", L"SkinPath", L"", tmpSz, MAX_LINE_LENGTH, m_IniFile.c_str()) > 0)
{
m_SkinPath = ExpandEnvironmentVariables(tmpSz);
m_SkinPath = tmpSz;
ExpandEnvironmentVariables(m_SkinPath);
}
else if (bDefaultIniLocation)
{
@ -892,6 +905,7 @@ int CRainmeter::Initialize(HWND Parent, HINSTANCE Instance, LPCSTR szPath)
AddBangCommand("!RainmeterMoveMeter", RainmeterMoveMeter);
AddBangCommand("!RainmeterPluginBang", RainmeterPluginBang);
AddBangCommand("!RainmeterQuit", RainmeterQuit);
AddBangCommand("!RainmeterSetVariable", RainmeterSetVariable);
}
// Create meter windows for active configs
@ -1129,6 +1143,7 @@ void CRainmeter::Quit(HINSTANCE dllInst)
RemoveBangCommand("!RainmeterMoveMeter");
RemoveBangCommand("!RainmeterPluginBang");
RemoveBangCommand("!RainmeterQuit");
RemoveBangCommand("!RainmeterSetVariable");
}
}
@ -1337,6 +1352,10 @@ BOOL CRainmeter::ExecuteBang(const std::wstring& bang, const std::wstring& arg,
{
BangWithArgs(BANG_PLUGIN, arg.c_str(), 1);
}
else if (wcsicmp(bang.c_str(), L"!RainmeterSetVariable") == 0)
{
BangWithArgs(BANG_SETVARIABLE, arg.c_str(), 2);
}
else if (wcsicmp(bang.c_str(), L"!RainmeterLsBoxHook") == 0)
{
// Nothing to do here (this works only with Litestep)
@ -2064,7 +2083,8 @@ void CRainmeter::TestSettingsFile(bool bDefaultIniLocation)
if (!bDefaultIniLocation)
{
std::wstring strTarget = ExpandEnvironmentVariables(L"%APPDATA%\\Rainmeter\\");
std::wstring strTarget = L"%APPDATA%\\Rainmeter\\";
ExpandEnvironmentVariables(strTarget);
error += L"You should quit Rainmeter and move the settings file from\n\n";
error += m_IniFile;
@ -2101,7 +2121,7 @@ std::wstring CRainmeter::ExtractPath(const std::wstring& strFilePath)
return L".";
}
std::wstring CRainmeter::ExpandEnvironmentVariables(const std::wstring strPath)
void CRainmeter::ExpandEnvironmentVariables(std::wstring& strPath)
{
if (strPath.find(L'%') != std::wstring::npos)
{
@ -2111,12 +2131,11 @@ std::wstring CRainmeter::ExpandEnvironmentVariables(const std::wstring strPath)
DWORD ret = ExpandEnvironmentStrings(strPath.c_str(), buffer, 4096);
if (ret != 0 && ret < 4096)
{
return buffer;
strPath = buffer;
}
else
{
DebugLog(L"Unable to expand the environment strings for string: %s", strPath.c_str());
}
}
return strPath;
}

View File

@ -32,13 +32,13 @@
#define MAKE_VER(major, minor1, minor2) major * 1000000 + minor1 * 1000 + minor2
#define APPNAME L"Rainmeter"
#define APPVERSION L"1.0"
#define APPVERSION L"1.1"
#ifdef _WIN64
#define APPBITS L"(64-bit)"
#else
#define APPBITS L"(32-bit)"
#endif
#define RAINMETER_VERSION MAKE_VER(1, 0, 0)
#define RAINMETER_VERSION MAKE_VER(1, 1, 0)
enum PLATFORM
{
@ -70,6 +70,7 @@ void RainmeterResetStats(HWND, const char* arg);
void RainmeterMoveMeter(HWND, const char* arg);
void RainmeterPluginBang(HWND, const char* arg);
void RainmeterQuit(HWND, const char* arg);
void RainmeterSetVariable(HWND, const char* arg);
void BangWithArgs(BANGCOMMAND bang, const WCHAR* arg, size_t numOfArgs);
@ -162,7 +163,7 @@ public:
static PLATFORM IsNT();
static std::wstring ExtractPath(const std::wstring& strFilePath);
static std::wstring ExpandEnvironmentVariables(const std::wstring strPath);
static void ExpandEnvironmentVariables(std::wstring& strPath);
private:
void CreateMeterWindow(std::wstring path, std::wstring config, std::wstring iniFile);