diff --git a/Library/ConfigParser.cpp b/Library/ConfigParser.cpp index a9dbdb14..bb988e71 100644 --- a/Library/ConfigParser.cpp +++ b/Library/ConfigParser.cpp @@ -950,45 +950,41 @@ Color CConfigParser::ParseColor(LPCTSTR string) } /* -** Parse4 +** ParseInt4 ** ** This is a helper template that parses four comma separated values from the given string. ** */ template -bool Parse4(LPCTSTR string, T& v1, T& v2, T& v3, T& v4) +void ParseInt4(LPCTSTR string, T& v1, T& v2, T& v3, T& v4) { - if (wcschr(string, L',') != NULL) + if (wcschr(string, L',')) { WCHAR* parseSz = _wcsdup(string); WCHAR* token; token = wcstok(parseSz, L","); - if (token != NULL) + if (token) { v1 = _wtoi(token); } - token = wcstok( NULL, L","); - if (token != NULL) + token = wcstok(NULL, L","); + if (token) { v2 = _wtoi(token); } - token = wcstok( NULL, L","); - if (token != NULL) + token = wcstok(NULL, L","); + if (token) { v3 = _wtoi(token); } - token = wcstok( NULL, L","); - if (token != NULL) + token = wcstok(NULL, L","); + if (token) { v4 = _wtoi(token); } free(parseSz); - - return true; } - - return false; } /* @@ -1001,7 +997,7 @@ bool Parse4(LPCTSTR string, T& v1, T& v2, T& v3, T& v4) Rect CConfigParser::ParseRect(LPCTSTR string) { Rect r; - Parse4(string, r.X, r.Y, r.Width, r.Height); + ParseInt4(string, r.X, r.Y, r.Width, r.Height); return r; } @@ -1015,7 +1011,7 @@ Rect CConfigParser::ParseRect(LPCTSTR string) RECT CConfigParser::ParseRECT(LPCTSTR string) { RECT r = {0}; - Parse4(string, r.left, r.top, r.right, r.bottom); + ParseInt4(string, r.left, r.top, r.right, r.bottom); return r; } diff --git a/Library/Meter.cpp b/Library/Meter.cpp index 1fff5132..52ba3677 100644 --- a/Library/Meter.cpp +++ b/Library/Meter.cpp @@ -557,7 +557,7 @@ void CMeter::SetAllMeasures(CMeasure* measure) /* ** SetAllMeasures ** -** Creates a vector containing all the defined measures (for Line/String) +** Creates a vector containing all the defined measures (for Image/Line/String) */ void CMeter::SetAllMeasures(const std::vector& measures) { @@ -571,13 +571,42 @@ void CMeter::SetAllMeasures(const std::vector& measures) } } +/* +** ReadMeasureNames +** +** Reads measure names (MeasureName2 - MeasureName[N]) +*/ +void CMeter::ReadMeasureNames(CConfigParser& parser, const WCHAR* section, std::vector& measureNames) +{ + WCHAR tmpName[64]; + + int i = 2; + bool loop = true; + do + { + swprintf(tmpName, L"MeasureName%i", i); + std::wstring measure = parser.ReadString(section, tmpName, L""); + if (!measure.empty()) + { + measureNames.push_back(measure); + } + else + { + loop = false; + } + ++i; + } while(loop); +} + /* ** ReplaceMeasures ** ** Replaces %1, %2 etc with the corresponding measure value */ -void CMeter::ReplaceMeasures(const std::vector& stringValues, std::wstring& str) +bool CMeter::ReplaceMeasures(const std::vector& stringValues, std::wstring& str) { + bool replaced = false; + if (str.find(L'%') != std::wstring::npos) { WCHAR buffer[64]; @@ -597,10 +626,13 @@ void CMeter::ReplaceMeasures(const std::vector& stringValues, std: { str.replace(str.begin() + pos, str.begin() + pos + wcslen(buffer), stringValues[i - 1]); start = pos + stringValues[i - 1].length(); + replaced = true; } } while(pos != std::wstring::npos); } } + + return replaced; } /* diff --git a/Library/Meter.h b/Library/Meter.h index 2b59027c..bd5c9a9f 100644 --- a/Library/Meter.h +++ b/Library/Meter.h @@ -116,7 +116,8 @@ protected: void SetAllMeasures(const std::vector& measures); void ReplaceToolTipMeasures(std::wstring& str); - static void ReplaceMeasures(const std::vector& stringValues, std::wstring& str); + static void ReadMeasureNames(CConfigParser& parser, const WCHAR* section, std::vector& measureNames); + static bool ReplaceMeasures(const std::vector& stringValues, std::wstring& str); Gdiplus::Matrix m_Transformation; // The transformation matrix std::wstring m_Name; // Name of the meter @@ -171,7 +172,7 @@ protected: Gdiplus::Color m_SolidColor; Gdiplus::Color m_SolidColor2; Gdiplus::REAL m_SolidAngle; - bool m_AntiAlias; // If true, the line is antialiased + bool m_AntiAlias; // If true, the line is antialiased bool m_Initialized; CMeterWindow* m_MeterWindow; diff --git a/Library/MeterImage.cpp b/Library/MeterImage.cpp index d6e555d9..cda7e073 100644 --- a/Library/MeterImage.cpp +++ b/Library/MeterImage.cpp @@ -61,7 +61,13 @@ void CMeterImage::Initialize() { CMeter::Initialize(); - if (!m_DynamicVariables) LoadImage(true); + if (!m_Measure && !m_DynamicVariables && !m_ImageName.empty()) + { + m_ImageNameResult = m_Path; + m_ImageNameResult += m_ImageName; + m_ImageNameResult = m_MeterWindow->MakePathAbsolute(m_ImageNameResult); + LoadImage(m_ImageNameResult, true); + } } /* @@ -70,9 +76,9 @@ void CMeterImage::Initialize() ** Loads the image from disk ** */ -void CMeterImage::LoadImage(bool bLoadAlways) +void CMeterImage::LoadImage(const std::wstring& imageName, bool bLoadAlways) { - m_Image.LoadImage(m_ImageName, bLoadAlways); + m_Image.LoadImage(imageName, bLoadAlways); if (m_Image.IsLoaded()) { @@ -117,6 +123,12 @@ void CMeterImage::ReadConfig(const WCHAR* section) CConfigParser& parser = m_MeterWindow->GetParser(); + // Check for extra measures + if (!m_Initialized && !m_MeasureName.empty()) + { + ReadMeasureNames(parser, section, m_MeasureNames); + } + m_Path = parser.ReadString(section, L"Path", L""); if (!m_Path.empty()) { @@ -127,22 +139,7 @@ void CMeterImage::ReadConfig(const WCHAR* section) } } - if (!m_Initialized || !m_Measure) - { - std::wstring oldImageName = m_ImageName; - - m_ImageName = parser.ReadString(section, L"ImageName", L""); - if (!m_ImageName.empty()) - { - m_ImageName.insert(0, m_Path); - m_ImageName = m_MeterWindow->MakePathAbsolute(m_ImageName); - } - - if (m_DynamicVariables) - { - m_NeedsReload = (oldImageName != m_ImageName); - } - } + m_ImageName = parser.ReadString(section, L"ImageName", L""); m_PreserveAspectRatio = 0!=parser.ReadInt(section, L"PreserveAspectRatio", 0); m_Tile = 0!=parser.ReadInt(section, L"Tile", 0); @@ -170,32 +167,51 @@ bool CMeterImage::Update() { if (CMeter::Update()) { - if (m_Measure) //read from the measure + if (m_Measure || m_DynamicVariables) { - std::wstring val = m_Measure->GetStringValue(false, 1, 0, false); - if (!val.empty()) + // Store the current values so we know if the image needs to be updated + std::wstring oldResult = m_ImageNameResult; + + if (m_Measure) // read from the measures { - val.insert(0, m_Path); - val = m_MeterWindow->MakePathAbsolute(val); - if (val != m_ImageName) + std::wstring val = m_Measure->GetStringValue(false, 1, 0, false); + + if (m_ImageName.empty()) { - m_ImageName = val; - LoadImage(true); + m_ImageNameResult = val; } else { - LoadImage(false); + std::vector stringValues; + + stringValues.push_back(val); + + // Get the values for the other measures + for (size_t i = 0; i < m_Measures.size(); ++i) + { + stringValues.push_back(m_Measures[i]->GetStringValue(false, 1, 0, false)); + } + + m_ImageNameResult = m_ImageName; + if (!ReplaceMeasures(stringValues, m_ImageNameResult)) + { + // ImageName doesn't contain any measures, so use the result of MeasureName. + m_ImageNameResult = val; + } } } - else if (m_Image.IsLoaded()) + else // read from the skin { - m_Image.DisposeImage(); + m_ImageNameResult = m_ImageName; } - return true; - } - else if (m_DynamicVariables) //read from the skin - { - LoadImage(m_NeedsReload); + + if (!m_ImageNameResult.empty()) + { + m_ImageNameResult.insert(0, m_Path); + m_ImageNameResult = m_MeterWindow->MakePathAbsolute(m_ImageNameResult); + } + + LoadImage(m_ImageNameResult, oldResult != m_ImageNameResult); return true; } } @@ -278,9 +294,32 @@ bool CMeterImage::Draw(Graphics& graphics) */ void CMeterImage::BindMeasure(const std::list& measures) { - // It's ok not to bind image meter to anything - if (!m_MeasureName.empty()) + if (m_MeasureName.empty()) return; // Allow NULL measure binding + + CMeter::BindMeasure(measures); + + std::vector::const_iterator j = m_MeasureNames.begin(); + for (; j != m_MeasureNames.end(); ++j) { - CMeter::BindMeasure(measures); + // Go through the list and check it there is a secondary measures for us + std::list::const_iterator i = measures.begin(); + for( ; i != measures.end(); ++i) + { + if(_wcsicmp((*i)->GetName(), (*j).c_str()) == 0) + { + m_Measures.push_back(*i); + break; + } + } + + if (i == measures.end()) + { + std::wstring error = L"The meter [" + m_Name; + error += L"] cannot be bound with ["; + error += (*j); + error += L"]!"; + throw CError(error, __LINE__, __FILE__); + } } + CMeter::SetAllMeasures(m_Measures); } diff --git a/Library/MeterImage.h b/Library/MeterImage.h index 9de459de..1b9df7d8 100644 --- a/Library/MeterImage.h +++ b/Library/MeterImage.h @@ -36,10 +36,11 @@ public: virtual void BindMeasure(const std::list& measures); protected: - void LoadImage(bool bLoadAlways); + void LoadImage(const std::wstring& imageName, bool bLoadAlways); CTintedImage m_Image; std::wstring m_ImageName; // Name of the image + std::wstring m_ImageNameResult; // Name of the image (as absolute path) std::wstring m_Path; bool m_NeedsReload; @@ -47,6 +48,9 @@ protected: bool m_HeightDefined; bool m_PreserveAspectRatio; // If true, aspect ratio of the image is preserved when the image is scaled bool m_Tile; + + std::vector m_MeasureNames; + std::vector m_Measures; }; #endif diff --git a/Library/MeterString.cpp b/Library/MeterString.cpp index 4039f0f7..abe7da36 100644 --- a/Library/MeterString.cpp +++ b/Library/MeterString.cpp @@ -257,23 +257,7 @@ void CMeterString::ReadConfig(const WCHAR* section) // Check for extra measures if (!m_Initialized && !m_MeasureName.empty()) { - WCHAR tmpName[64]; - int i = 2; - bool loop = true; - do - { - swprintf(tmpName, L"MeasureName%i", i); - std::wstring measure = parser.ReadString(section, tmpName, L""); - if (!measure.empty()) - { - m_MeasureNames.push_back(measure); - } - else - { - loop = false; - } - ++i; - } while(loop); + ReadMeasureNames(parser, section, m_MeasureNames); } m_Color = parser.ReadColor(section, L"FontColor", Color::Black); diff --git a/Library/TintedImage.cpp b/Library/TintedImage.cpp index cc14a193..56f64874 100644 --- a/Library/TintedImage.cpp +++ b/Library/TintedImage.cpp @@ -65,9 +65,11 @@ CTintedImage::CTintedImage(bool disableTransform) : m_DisableTransform(disableTr m_Modified.dwHighDateTime = 0; m_Modified.dwLowDateTime = 0; + m_NeedsCrop = false; m_NeedsTinting = false; m_NeedsTransform = false; + m_CropMode = CROPMODE_TL; m_GreyScale = false; m_Flip = RotateNoneFlipNone; m_Rotate = 0.0f; @@ -166,7 +168,7 @@ void CTintedImage::LoadImage(const std::wstring& imageName, bool bLoadAlways) // Check whether the new image needs tinting (or cropping, flipping, rotating) if (!m_NeedsCrop) { - if (m_Crop.X != -1 || m_Crop.Y != -1 || m_Crop.Width != -1 || m_Crop.Height != -1) + if (m_Crop.Width >= 0 || m_Crop.Height >= 0) { m_NeedsCrop = true; } @@ -268,11 +270,45 @@ void CTintedImage::ApplyCrop() } else { + int imageW = m_Bitmap->GetWidth(); + int imageH = m_Bitmap->GetHeight(); + + int x, y; + + switch (m_CropMode) + { + case CROPMODE_TL: + default: + x = m_Crop.X; + y = m_Crop.Y; + break; + + case CROPMODE_TR: + x = m_Crop.X + imageW; + y = m_Crop.Y; + break; + + case CROPMODE_BR: + x = m_Crop.X + imageW; + y = m_Crop.Y + imageH; + break; + + case CROPMODE_BL: + x = m_Crop.X; + y = m_Crop.Y + imageH; + break; + + case CROPMODE_C: + x = m_Crop.X + (imageW / 2); + y = m_Crop.Y + (imageH / 2); + break; + } + Rect r(0, 0, m_Crop.Width, m_Crop.Height); m_BitmapTint = new Bitmap(r.Width, r.Height, PixelFormat32bppARGB); Graphics graphics(m_BitmapTint); - graphics.DrawImage(m_Bitmap, r, m_Crop.X, m_Crop.Y, r.Width, r.Height, UnitPixel); + graphics.DrawImage(m_Bitmap, r, x, y, r.Width, r.Height, UnitPixel); } } } @@ -444,6 +480,7 @@ void CTintedImage::ReadConfig(CConfigParser& parser, const WCHAR* section) { // Store the current values so we know if the image needs to be tinted or transformed Rect oldCrop = m_Crop; + CROPMODE oldCropMode = m_CropMode; bool oldGreyScale = m_GreyScale; ColorMatrix oldColorMatrix = m_ColorMatrix; RotateFlipType oldFlip = m_Flip; @@ -451,10 +488,58 @@ void CTintedImage::ReadConfig(CConfigParser& parser, const WCHAR* section) if (!m_DisableTransform) { - m_Crop = parser.ReadRect(section, m_ConfigImageCrop.c_str(), Rect(-1,-1,-1,-1)); + m_Crop.X = m_Crop.Y = m_Crop.Width = m_Crop.Height = -1; + m_CropMode = CROPMODE_TL; + + std::wstring crop = parser.ReadString(section, m_ConfigImageCrop.c_str(), L""); + if (!crop.empty()) + { + if (wcschr(crop.c_str(), L',')) + { + WCHAR* parseSz = _wcsdup(crop.c_str()); + WCHAR* token; + + token = wcstok(parseSz, L","); + if (token) + { + m_Crop.X = _wtoi(token); + } + token = wcstok(NULL, L","); + if (token) + { + m_Crop.Y = _wtoi(token); + } + token = wcstok(NULL, L","); + if (token) + { + m_Crop.Width = _wtoi(token); + } + token = wcstok(NULL, L","); + if (token) + { + m_Crop.Height = _wtoi(token); + } + token = wcstok(NULL, L","); + if (token) + { + m_CropMode = (CROPMODE)_wtoi(token); + } + free(parseSz); + } + + if (m_CropMode < CROPMODE_TL || m_CropMode > CROPMODE_C) + { + std::wstring error = m_ConfigImageCrop + L"="; + error += crop; + error += L" (origin) is not valid in meter ["; + error += section; + error += L"]."; + throw CError(error, __LINE__, __FILE__); + } + } } - m_NeedsCrop = (oldCrop.X != m_Crop.X || oldCrop.Y != m_Crop.Y || oldCrop.Width != m_Crop.Width || oldCrop.Height != m_Crop.Height); + m_NeedsCrop = (oldCrop.X != m_Crop.X || oldCrop.Y != m_Crop.Y || oldCrop.Width != m_Crop.Width || oldCrop.Height != m_Crop.Height || oldCropMode != m_CropMode); m_GreyScale = 0!=parser.ReadInt(section, m_ConfigGreyscale.c_str(), 0); diff --git a/Library/TintedImage.h b/Library/TintedImage.h index 4aaf382e..ab909a33 100644 --- a/Library/TintedImage.h +++ b/Library/TintedImage.h @@ -22,6 +22,15 @@ #include "Meter.h" #include "MeterWindow.h" +enum CROPMODE +{ + CROPMODE_TL = 1, + CROPMODE_TR, + CROPMODE_BR, + CROPMODE_BL, + CROPMODE_C +}; + class CTintedImage { public: @@ -77,6 +86,7 @@ protected: bool m_NeedsTransform; Gdiplus::Rect m_Crop; + CROPMODE m_CropMode; bool m_GreyScale; Gdiplus::ColorMatrix m_ColorMatrix; Gdiplus::RotateFlipType m_Flip;