From 96c81ac516583dc4ddc5c607d3c60a96beaf7899 Mon Sep 17 00:00:00 2001 From: spx Date: Sat, 4 Dec 2010 15:07:28 +0000 Subject: [PATCH] - Added BackgroundMode=4 for tiling background image. - Added tinting functions for Background. - Added "ImageCrop" option to Meter=IMAGE/BAR/HISTOGRAM/ROTATOR and Background. - Added "Tile" option to Meter=IMAGE. - Some code cleanups. --- Library/ConfigParser.cpp | 90 +++++++++++++++ Library/ConfigParser.h | 5 + Library/Meter.cpp | 40 ++++--- Library/MeterHistogram.cpp | 9 +- Library/MeterImage.cpp | 73 +++++++----- Library/MeterImage.h | 1 + Library/MeterLine.cpp | 10 +- Library/MeterString.cpp | 9 +- Library/MeterWindow.cpp | 224 +++++++++++++++++++------------------ Library/MeterWindow.h | 3 +- Library/Rainmeter.cpp | 8 +- Library/TintedImage.cpp | 115 ++++++++++++++----- Library/TintedImage.h | 8 +- 13 files changed, 395 insertions(+), 200 deletions(-) diff --git a/Library/ConfigParser.cpp b/Library/ConfigParser.cpp index efc78f8b..a9dbdb14 100644 --- a/Library/ConfigParser.cpp +++ b/Library/ConfigParser.cpp @@ -672,6 +672,12 @@ const std::wstring& CConfigParser::ReadString(LPCTSTR section, LPCTSTR key, LPCT return result; } +bool CConfigParser::IsValueDefined(LPCTSTR section, LPCTSTR key) +{ + ReadString(section, key, L"", false); + return !m_LastDefaultUsed; +} + void CConfigParser::AddMeasure(CMeasure* pMeasure) { if (pMeasure) @@ -775,6 +781,20 @@ Color CConfigParser::ReadColor(LPCTSTR section, LPCTSTR key, const Color& defVal return (m_LastDefaultUsed) ? defValue : ParseColor(result.c_str()); } +Rect CConfigParser::ReadRect(LPCTSTR section, LPCTSTR key, const Rect& defValue) +{ + const std::wstring& result = ReadString(section, key, L""); + + return (m_LastDefaultUsed) ? defValue : ParseRect(result.c_str()); +} + +RECT CConfigParser::ReadRECT(LPCTSTR section, LPCTSTR key, const RECT& defValue) +{ + const std::wstring& result = ReadString(section, key, L""); + + return (m_LastDefaultUsed) ? defValue : ParseRECT(result.c_str()); +} + /* ** Tokenize ** @@ -929,6 +949,76 @@ Color CConfigParser::ParseColor(LPCTSTR string) return Color(A, R, G, B); } +/* +** Parse4 +** +** 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) +{ + if (wcschr(string, L',') != NULL) + { + WCHAR* parseSz = _wcsdup(string); + WCHAR* token; + + token = wcstok(parseSz, L","); + if (token != NULL) + { + v1 = _wtoi(token); + } + token = wcstok( NULL, L","); + if (token != NULL) + { + v2 = _wtoi(token); + } + token = wcstok( NULL, L","); + if (token != NULL) + { + v3 = _wtoi(token); + } + token = wcstok( NULL, L","); + if (token != NULL) + { + v4 = _wtoi(token); + } + free(parseSz); + + return true; + } + + return false; +} + +/* +** ParseRect +** +** This is a helper method that parses the Gdiplus::Rect values from the given string. +** The rect can be supplied as four comma separated values (X/Y/Width/Height). +** +*/ +Rect CConfigParser::ParseRect(LPCTSTR string) +{ + Rect r; + Parse4(string, r.X, r.Y, r.Width, r.Height); + return r; +} + +/* +** ParseRECT +** +** This is a helper method that parses the RECT values from the given string. +** The rect can be supplied as four comma separated values (left/top/right/bottom). +** +*/ +RECT CConfigParser::ParseRECT(LPCTSTR string) +{ + RECT r = {0}; + Parse4(string, r.left, r.top, r.right, r.bottom); + return r; +} + //============================================================================== /** ** Reads the given ini file and fills the m_Values and m_Keys maps. diff --git a/Library/ConfigParser.h b/Library/ConfigParser.h index 8d6792d7..82cecc2f 100644 --- a/Library/ConfigParser.h +++ b/Library/ConfigParser.h @@ -52,10 +52,13 @@ public: void ResetMonitorVariables(CMeterWindow* meterWindow = NULL); const std::wstring& ReadString(LPCTSTR section, LPCTSTR key, LPCTSTR defValue, bool bReplaceMeasures = true); + bool IsValueDefined(LPCTSTR section, LPCTSTR key); double ReadFloat(LPCTSTR section, LPCTSTR key, double defValue); double ReadFormula(LPCTSTR section, LPCTSTR key, double defValue); int ReadInt(LPCTSTR section, LPCTSTR key, int defValue); Gdiplus::Color ReadColor(LPCTSTR section, LPCTSTR key, const Gdiplus::Color& defValue); + Gdiplus::Rect ReadRect(LPCTSTR section, LPCTSTR key, const Gdiplus::Rect& defValue); + RECT ReadRECT(LPCTSTR section, LPCTSTR key, const RECT& defValue); std::vector ReadFloats(LPCTSTR section, LPCTSTR key); const std::wstring& GetFilename() { return m_Filename; } @@ -67,6 +70,8 @@ public: static std::vector Tokenize(const std::wstring& str, const std::wstring& delimiters); static double ParseDouble(const std::wstring& string, double defValue, bool rejectExp = false); static Gdiplus::Color ParseColor(LPCTSTR string); + static Gdiplus::Rect ParseRect(LPCTSTR string); + static RECT ParseRECT(LPCTSTR string); static void ClearMultiMonitorVariables() { c_MonitorVariables.clear(); } static void UpdateWorkareaVariables() { SetMultiMonitorVariables(false); } diff --git a/Library/Meter.cpp b/Library/Meter.cpp index e8d04af8..1fff5132 100644 --- a/Library/Meter.cpp +++ b/Library/Meter.cpp @@ -375,6 +375,11 @@ void CMeter::ReadConfig(const WCHAR* section) } } + if (!m_Initialized) + { + m_MeasureName = parser.ReadString(section, L"MeasureName", L""); + } + m_SolidBevel = (BEVELTYPE)parser.ReadInt(section, L"BevelType", BEVELTYPE_NONE); m_SolidColor = parser.ReadColor(section, L"SolidColor", Color(0, 0, 0, 0)); @@ -407,8 +412,6 @@ void CMeter::ReadConfig(const WCHAR* section) m_ToolTipType = 0!=parser.ReadInt(section, L"ToolTipType", 0); m_ToolTipHidden = 0!=parser.ReadInt(section, L"ToolTipHidden", m_ToolTipHidden); - m_MeasureName = parser.ReadString(section, L"MeasureName", L""); - UINT updateDivider = parser.ReadInt(section, L"UpdateDivider", 1); if (updateDivider != m_UpdateDivider) { @@ -575,25 +578,28 @@ void CMeter::SetAllMeasures(const std::vector& measures) */ void CMeter::ReplaceMeasures(const std::vector& stringValues, std::wstring& str) { - WCHAR buffer[64]; - - // Create the actual text (i.e. replace %1, %2, .. with the measure texts) - for (size_t i = stringValues.size(); i > 0; --i) + if (str.find(L'%') != std::wstring::npos) { - wsprintf(buffer, L"%%%i", i); + WCHAR buffer[64]; - size_t start = 0; - size_t pos = std::wstring::npos; - - do + // Create the actual text (i.e. replace %1, %2, .. with the measure texts) + for (size_t i = stringValues.size(); i > 0; --i) { - pos = str.find(buffer, start); - if (pos != std::wstring::npos) + wsprintf(buffer, L"%%%i", i); + + size_t start = 0; + size_t pos = std::wstring::npos; + + do { - str.replace(str.begin() + pos, str.begin() + pos + wcslen(buffer), stringValues[i - 1]); - start = pos + stringValues[i - 1].length(); - } - } while(pos != std::wstring::npos); + pos = str.find(buffer, start); + if (pos != std::wstring::npos) + { + str.replace(str.begin() + pos, str.begin() + pos + wcslen(buffer), stringValues[i - 1]); + start = pos + stringValues[i - 1].length(); + } + } while(pos != std::wstring::npos); + } } } diff --git a/Library/MeterHistogram.cpp b/Library/MeterHistogram.cpp index ad3945a8..451a1a78 100644 --- a/Library/MeterHistogram.cpp +++ b/Library/MeterHistogram.cpp @@ -210,10 +210,13 @@ void CMeterHistogram::ReadConfig(const WCHAR* section) m_SecondaryColor = parser.ReadColor(section, L"SecondaryColor", Color::Red); m_BothColor = parser.ReadColor(section, L"BothColor", Color::Yellow); - m_SecondaryMeasureName = parser.ReadString(section, L"MeasureName2", L""); - if (m_SecondaryMeasureName.empty()) + if (!m_Initialized && !m_MeasureName.empty()) { - m_SecondaryMeasureName = parser.ReadString(section, L"SecondaryMeasureName", L""); + m_SecondaryMeasureName = parser.ReadString(section, L"MeasureName2", L""); + if (m_SecondaryMeasureName.empty()) + { + m_SecondaryMeasureName = parser.ReadString(section, L"SecondaryMeasureName", L""); + } } m_PrimaryImageName = parser.ReadString(section, L"PrimaryImage", L""); diff --git a/Library/MeterImage.cpp b/Library/MeterImage.cpp index e2491c82..d6e555d9 100644 --- a/Library/MeterImage.cpp +++ b/Library/MeterImage.cpp @@ -38,6 +38,7 @@ CMeterImage::CMeterImage(CMeterWindow* meterWindow) : CMeter(meterWindow) m_WidthDefined = false; m_HeightDefined = false; m_PreserveAspectRatio = false; + m_Tile = false; } /* @@ -85,14 +86,14 @@ void CMeterImage::LoadImage(bool bLoadAlways) { if (!m_HeightDefined) { - m_H = (imageW == 0) ? 0 : (int)(m_W * imageH / (double)imageW); + m_H = (imageW == 0) ? 0 : (m_Tile) ? imageH : (int)(m_W * imageH / (double)imageW); } } else { if (m_HeightDefined) { - m_W = (imageH == 0) ? 0 : (int)(m_H * imageW / (double)imageH); + m_W = (imageH == 0) ? 0 : (m_Tile) ? imageW : (int)(m_H * imageW / (double)imageH); } else { @@ -144,12 +145,13 @@ void CMeterImage::ReadConfig(const WCHAR* section) } m_PreserveAspectRatio = 0!=parser.ReadInt(section, L"PreserveAspectRatio", 0); + m_Tile = 0!=parser.ReadInt(section, L"Tile", 0); - if (-1 != (int)parser.ReadFormula(section, L"W", -1)) + if (parser.IsValueDefined(section, L"W")) { m_WidthDefined = true; } - if (-1 != (int)parser.ReadFormula(section, L"H", -1)) + if (parser.IsValueDefined(section, L"H")) { m_HeightDefined = true; } @@ -215,43 +217,54 @@ bool CMeterImage::Draw(Graphics& graphics) // Copy the image over the doublebuffer Bitmap* drawBitmap = m_Image.GetImage(); - int x = GetX(); - int y = GetY(); int imageW = drawBitmap->GetWidth(); int imageH = drawBitmap->GetHeight(); - int drawW, drawH; + if (imageW == 0 || imageH == 0 || m_W == 0 || m_H == 0) return true; - if (m_PreserveAspectRatio) + int x = GetX(); + int y = GetY(); + + int drawW = m_W; + int drawH = m_H; + + ImageAttributes imgAttr; + bool useImgAttr = false; + + if (m_Tile) { - if (imageW == 0 || imageH == 0 || m_W == 0 || m_H == 0) return true; + imageW = m_W; + imageH = m_H; - REAL imageRatio = imageW / (REAL)imageH; - REAL meterRatio = m_W / (REAL)m_H; - - if (imageRatio >= meterRatio) - { - drawW = m_W; - drawH = m_W * imageH / imageW; - } - else - { - drawW = m_H * imageW / imageH; - drawH = m_H; - } - - // Centering - x += (m_W - drawW) / 2; - y += (m_H - drawH) / 2; + imgAttr.SetWrapMode(WrapModeTile); + useImgAttr = true; } - else + else if (m_PreserveAspectRatio) { - drawW = m_W; - drawH = m_H; + if (m_WidthDefined && m_HeightDefined) + { + REAL imageRatio = imageW / (REAL)imageH; + REAL meterRatio = m_W / (REAL)m_H; + + if (imageRatio >= meterRatio) + { + drawW = m_W; + drawH = m_W * imageH / imageW; + } + else + { + drawW = m_H * imageW / imageH; + drawH = m_H; + } + + // Centering + x += (m_W - drawW) / 2; + y += (m_H - drawH) / 2; + } } Rect r(x, y, drawW, drawH); - graphics.DrawImage(drawBitmap, r, 0, 0, imageW, imageH, UnitPixel); + graphics.DrawImage(drawBitmap, r, 0, 0, imageW, imageH, UnitPixel, (useImgAttr) ? &imgAttr : NULL); } return true; diff --git a/Library/MeterImage.h b/Library/MeterImage.h index 51dda371..9de459de 100644 --- a/Library/MeterImage.h +++ b/Library/MeterImage.h @@ -46,6 +46,7 @@ protected: bool m_WidthDefined; bool m_HeightDefined; bool m_PreserveAspectRatio; // If true, aspect ratio of the image is preserved when the image is scaled + bool m_Tile; }; #endif diff --git a/Library/MeterLine.cpp b/Library/MeterLine.cpp index 24cb959f..59ecdaa7 100644 --- a/Library/MeterLine.cpp +++ b/Library/MeterLine.cpp @@ -109,7 +109,6 @@ void CMeterLine::ReadConfig(const WCHAR* section) m_Colors.clear(); m_ScaleValues.clear(); - m_MeasureNames.clear(); for (int i = 0; i < lineCount; ++i) { @@ -135,10 +134,13 @@ void CMeterLine::ReadConfig(const WCHAR* section) m_ScaleValues.push_back(parser.ReadFloat(section, tmpName, 1.0)); - if (i != 0) + if (!m_Initialized && !m_MeasureName.empty()) { - swprintf(tmpName, L"MeasureName%i", i + 1); - m_MeasureNames.push_back(parser.ReadString(section, tmpName, L"")); + if (i != 0) + { + swprintf(tmpName, L"MeasureName%i", i + 1); + m_MeasureNames.push_back(parser.ReadString(section, tmpName, L"")); + } } } diff --git a/Library/MeterString.cpp b/Library/MeterString.cpp index 9a636591..4039f0f7 100644 --- a/Library/MeterString.cpp +++ b/Library/MeterString.cpp @@ -244,8 +244,6 @@ void CMeterString::Initialize() */ void CMeterString::ReadConfig(const WCHAR* section) { - WCHAR tmpName[64]; - // Store the current font values so we know if the font needs to be updated std::wstring oldFontFace = m_FontFace; int oldFontSize = m_FontSize; @@ -256,11 +254,10 @@ void CMeterString::ReadConfig(const WCHAR* section) CConfigParser& parser = m_MeterWindow->GetParser(); - m_MeasureNames.clear(); - // Check for extra measures - if (!m_MeasureName.empty()) + if (!m_Initialized && !m_MeasureName.empty()) { + WCHAR tmpName[64]; int i = 2; bool loop = true; do @@ -415,7 +412,7 @@ void CMeterString::ReadConfig(const WCHAR* section) throw CError(error, __LINE__, __FILE__); } - if (-1 != (int)parser.ReadFormula(section, L"W", -1) && -1 != (int)parser.ReadFormula(section, L"H", -1)) + if (parser.IsValueDefined(section, L"W") && parser.IsValueDefined(section, L"H")) { m_DimensionsDefined = true; } diff --git a/Library/MeterWindow.cpp b/Library/MeterWindow.cpp index 193768e4..87b791a3 100644 --- a/Library/MeterWindow.cpp +++ b/Library/MeterWindow.cpp @@ -30,6 +30,7 @@ #include "MeasureNet.h" #include "MeasurePlugin.h" #include "MeterButton.h" +#include "TintedImage.h" using namespace Gdiplus; @@ -1735,21 +1736,13 @@ bool CMeterWindow::ReadSkin() m_BackgroundName = m_Parser.ReadString(L"Rainmeter", L"Background", L""); m_BackgroundName = MakePathAbsolute(m_BackgroundName); - std::wstring margins = m_Parser.ReadString(L"Rainmeter", L"BackgroundMargins", L"0, 0, 0, 0"); - int left = 0, top = 0, right = 0, bottom = 0; - swscanf(margins.c_str(), L"%i, %i, %i, %i", &left, &top, &right, &bottom); - m_BackgroundMargins.X = left; - m_BackgroundMargins.Width = right - left; - m_BackgroundMargins.Y = top; - m_BackgroundMargins.Height = bottom - top; + m_BackgroundMargins = m_Parser.ReadRect(L"Rainmeter", L"BackgroundMargins", Rect(0,0,0,0)); + m_BackgroundMargins.Width -= m_BackgroundMargins.X; + m_BackgroundMargins.Height -= m_BackgroundMargins.Y; - margins = m_Parser.ReadString(L"Rainmeter", L"DragMargins", L"0, 0, 0, 0"); - left = 0, top = 0, right = 0, bottom = 0; - swscanf(margins.c_str(), L"%i, %i, %i, %i", &left, &top, &right, &bottom); - m_DragMargins.X = left; - m_DragMargins.Width = right - left; - m_DragMargins.Y = top; - m_DragMargins.Height = bottom - top; + m_DragMargins = m_Parser.ReadRect(L"Rainmeter", L"DragMargins", Rect(0,0,0,0)); + m_DragMargins.Width -= m_DragMargins.X; + m_DragMargins.Height -= m_DragMargins.Y; m_BackgroundMode = (BGMODE)m_Parser.ReadInt(L"Rainmeter", L"BackgroundMode", BGMODE_IMAGE); m_SolidBevel = (BEVELTYPE)m_Parser.ReadInt(L"Rainmeter", L"BevelType", BEVELTYPE_NONE); @@ -1760,7 +1753,7 @@ bool CMeterWindow::ReadSkin() m_DynamicWindowSize = 0!=m_Parser.ReadInt(L"Rainmeter", L"DynamicWindowSize", 0); - if ((m_BackgroundMode == BGMODE_IMAGE || m_BackgroundMode == BGMODE_SCALED_IMAGE) && m_BackgroundName.empty()) + if ((m_BackgroundMode == BGMODE_IMAGE || m_BackgroundMode == BGMODE_SCALED_IMAGE || m_BackgroundMode == BGMODE_TILED_IMAGE) && m_BackgroundName.empty()) { m_BackgroundMode = BGMODE_COPY; } @@ -2106,17 +2099,16 @@ bool CMeterWindow::ResizeWindow(bool reset) m_Background = NULL; } - if ((m_BackgroundMode == BGMODE_IMAGE || m_BackgroundMode == BGMODE_SCALED_IMAGE) && !m_BackgroundName.empty()) + if ((m_BackgroundMode == BGMODE_IMAGE || m_BackgroundMode == BGMODE_SCALED_IMAGE || m_BackgroundMode == BGMODE_TILED_IMAGE) && !m_BackgroundName.empty()) { // Load the background - m_Background = new Bitmap(m_BackgroundName.c_str()); - Status status = m_Background->GetLastStatus(); - if(Ok != status) + CTintedImage tintedBackground; + tintedBackground.SetConfigAttributes(L"Background", NULL); + tintedBackground.ReadConfig(m_Parser, L"Rainmeter"); + tintedBackground.LoadImage(m_BackgroundName, true); + + if (!tintedBackground.IsLoaded()) { - std::wstring err = L"Unable to load background: " + m_BackgroundName; - MessageBox(m_Window, err.c_str(), APPNAME, MB_OK | MB_TOPMOST | MB_ICONEXCLAMATION); - delete m_Background; - m_Background = NULL; m_BackgroundSize.cx = 0; m_BackgroundSize.cy = 0; @@ -2125,81 +2117,99 @@ bool CMeterWindow::ResizeWindow(bool reset) } else { + Bitmap* tempBackground = tintedBackground.GetImage(); + // Calculate the window dimensions - m_BackgroundSize.cx = m_Background->GetWidth(); - m_BackgroundSize.cy = m_Background->GetHeight(); + m_BackgroundSize.cx = tempBackground->GetWidth(); + m_BackgroundSize.cy = tempBackground->GetHeight(); - w = max(w, m_BackgroundSize.cx); - h = max(h, m_BackgroundSize.cy); - - if (m_BackgroundMode == BGMODE_SCALED_IMAGE) + if (m_BackgroundMode == BGMODE_IMAGE) { + m_Background = tempBackground->Clone(0, 0, m_BackgroundSize.cx, m_BackgroundSize.cy, PixelFormat32bppARGB); + } + else + { + w = max(w, m_BackgroundSize.cx); + h = max(h, m_BackgroundSize.cy); + // Scale the background to fill the whole window - Bitmap* scaledBackground = new Bitmap(w, h, PixelFormat32bppARGB); + Bitmap* background = new Bitmap(w, h, PixelFormat32bppARGB); - Graphics graphics(scaledBackground); + Graphics graphics(background); - if (m_BackgroundMargins.GetTop() > 0) + if (m_BackgroundMode == BGMODE_SCALED_IMAGE) { - if (m_BackgroundMargins.GetLeft() > 0) + RECT m = {m_BackgroundMargins.GetLeft(), m_BackgroundMargins.GetTop(), m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetBottom()}; + + if (m.top > 0) { - // Top-Left - Rect r(0, 0, m_BackgroundMargins.GetLeft(), m_BackgroundMargins.GetTop()); - graphics.DrawImage(m_Background, r, 0, 0, m_BackgroundMargins.GetLeft(), m_BackgroundMargins.GetTop(), UnitPixel); + if (m.left > 0) + { + // Top-Left + Rect r(0, 0, m.left, m.top); + graphics.DrawImage(tempBackground, r, 0, 0, m.left, m.top, UnitPixel); + } + + // Top + Rect r(m.left, 0, w - m.left - m.right, m.top); + graphics.DrawImage(tempBackground, r, m.left, 0, m_BackgroundSize.cx - m.left - m.right, m.top, UnitPixel); + + if (m.right > 0) + { + // Top-Right + Rect r(w - m.right, 0, m.right, m.top); + graphics.DrawImage(tempBackground, r, m_BackgroundSize.cx - m.right, 0, m.right, m.top, UnitPixel); + } } - // Top - Rect r(m_BackgroundMargins.GetLeft(), 0, w - m_BackgroundMargins.GetLeft() - m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetTop()); - graphics.DrawImage(m_Background, r, m_BackgroundMargins.GetLeft(), 0, m_Background->GetWidth() - m_BackgroundMargins.GetLeft() - m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetTop(), UnitPixel); - - if (m_BackgroundMargins.GetRight() > 0) + if (m.left > 0) { - // Top-Right - Rect r(w - m_BackgroundMargins.GetRight(), 0, m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetTop()); - graphics.DrawImage(m_Background, r, m_Background->GetWidth() - m_BackgroundMargins.GetRight(), 0, m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetTop(), UnitPixel); + // Left + Rect r(0, m.top, m.left, h - m.top - m.bottom); + graphics.DrawImage(tempBackground, r, 0, m.top, m.left, m_BackgroundSize.cy - m.top - m.bottom, UnitPixel); + } + + // Center + Rect r(m.left, m.top, w - m.left - m.right, h - m.top - m.bottom); + graphics.DrawImage(tempBackground, r, m.left, m.top, m_BackgroundSize.cx - m.left - m.right, m_BackgroundSize.cy - m.top - m.bottom, UnitPixel); + + if (m.right > 0) + { + // Right + Rect r(w - m.right, m.top, m.right, h - m.top - m.bottom); + graphics.DrawImage(tempBackground, r, m_BackgroundSize.cx - m.right, m.top, m.right, m_BackgroundSize.cy - m.top - m.bottom, UnitPixel); + } + + if (m.bottom > 0) + { + if (m.left > 0) + { + // Bottom-Left + Rect r(0, h - m.bottom, m.left, m.bottom); + graphics.DrawImage(tempBackground, r, 0, m_BackgroundSize.cy - m.bottom, m.left, m.bottom, UnitPixel); + } + // Bottom + Rect r(m.left, h - m.bottom, w - m.left - m.right, m.bottom); + graphics.DrawImage(tempBackground, r, m.left, m_BackgroundSize.cy - m.bottom, m_BackgroundSize.cx - m.left - m.right, m.bottom, UnitPixel); + + if (m.right > 0) + { + // Bottom-Right + Rect r(w - m.right, h - m.bottom, m.right, m.bottom); + graphics.DrawImage(tempBackground, r, m_BackgroundSize.cx - m.right, m_BackgroundSize.cy - m.bottom, m.right, m.bottom, UnitPixel); + } } } - - if (m_BackgroundMargins.GetLeft() > 0) + else { - // Left - Rect r(0, m_BackgroundMargins.GetTop(), m_BackgroundMargins.GetLeft(), h - m_BackgroundMargins.GetTop() - m_BackgroundMargins.GetBottom()); - graphics.DrawImage(m_Background, r, 0, m_BackgroundMargins.GetTop(), m_BackgroundMargins.GetLeft(), m_Background->GetHeight() - m_BackgroundMargins.GetTop() - m_BackgroundMargins.GetBottom(), UnitPixel); + ImageAttributes imgAttr; + imgAttr.SetWrapMode(WrapModeTile); + + Rect r(0, 0, w, h); + graphics.DrawImage(tempBackground, r, 0, 0, w, h, UnitPixel, &imgAttr); } - // Center - Rect r(m_BackgroundMargins.GetLeft(), m_BackgroundMargins.GetTop(), w - m_BackgroundMargins.GetLeft() - m_BackgroundMargins.GetRight(), h - m_BackgroundMargins.GetTop() - m_BackgroundMargins.GetBottom()); - graphics.DrawImage(m_Background, r, m_BackgroundMargins.GetLeft(), m_BackgroundMargins.GetTop(), m_Background->GetWidth() - m_BackgroundMargins.GetLeft() - m_BackgroundMargins.GetRight(), m_Background->GetHeight() - m_BackgroundMargins.GetTop() - m_BackgroundMargins.GetBottom(), UnitPixel); - - if (m_BackgroundMargins.GetRight() > 0) - { - // Right - Rect r(w - m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetTop(), m_BackgroundMargins.GetRight(), h - m_BackgroundMargins.GetTop() - m_BackgroundMargins.GetBottom()); - graphics.DrawImage(m_Background, r, m_Background->GetWidth() - m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetTop(), m_BackgroundMargins.GetRight(), m_Background->GetHeight() - m_BackgroundMargins.GetTop() - m_BackgroundMargins.GetBottom(), UnitPixel); - } - - if (m_BackgroundMargins.GetBottom() > 0) - { - if (m_BackgroundMargins.GetLeft() > 0) - { - // Bottom-Left - Rect r(0, h - m_BackgroundMargins.GetBottom(), m_BackgroundMargins.GetLeft(), m_BackgroundMargins.GetBottom()); - graphics.DrawImage(m_Background, r, 0, m_Background->GetHeight() - m_BackgroundMargins.GetBottom(), m_BackgroundMargins.GetLeft(), m_BackgroundMargins.GetBottom(), UnitPixel); - } - // Bottom - Rect r(m_BackgroundMargins.GetLeft(), h - m_BackgroundMargins.GetBottom(), w - m_BackgroundMargins.GetLeft() - m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetBottom()); - graphics.DrawImage(m_Background, r, m_BackgroundMargins.GetLeft(), m_Background->GetHeight() - m_BackgroundMargins.GetBottom(), m_Background->GetWidth() - m_BackgroundMargins.GetLeft() - m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetBottom(), UnitPixel); - - if (m_BackgroundMargins.GetRight() > 0) - { - // Bottom-Right - Rect r(w - m_BackgroundMargins.GetRight(), h - m_BackgroundMargins.GetBottom(), m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetBottom()); - graphics.DrawImage(m_Background, r, m_Background->GetWidth() - m_BackgroundMargins.GetRight(), m_Background->GetHeight() - m_BackgroundMargins.GetBottom(), m_BackgroundMargins.GetRight(), m_BackgroundMargins.GetBottom(), UnitPixel); - } - } - - delete m_Background; - m_Background = scaledBackground; + m_Background = background; } // Get the size form the background bitmap @@ -2239,34 +2249,36 @@ bool CMeterWindow::ResizeWindow(bool reset) } else { - // Create a solid color bitmap for the background - m_Background = new Bitmap(m_WindowW, m_WindowH, PixelFormat32bppARGB); - Graphics graphics(m_Background); - - if (m_SolidColor.GetValue() == m_SolidColor2.GetValue()) + if (m_WindowW != 0 && m_WindowH != 0) { - SolidBrush solid(m_SolidColor); - graphics.FillRectangle(&solid, 0, 0, m_WindowW, m_WindowH); - } - else - { - Rect r(0, 0, m_WindowW, m_WindowH); - LinearGradientBrush gradient(r, m_SolidColor, m_SolidColor2, m_SolidAngle, TRUE); - graphics.FillRectangle(&gradient, r); - } + // Create a solid color bitmap for the background + m_Background = new Bitmap(m_WindowW, m_WindowH, PixelFormat32bppARGB); + Graphics graphics(m_Background); - if (m_SolidBevel != BEVELTYPE_NONE) - { - Pen light(Color(255, 255, 255, 255)); - Pen dark(Color(255, 0, 0, 0)); - - if (m_SolidBevel == BEVELTYPE_DOWN) + if (m_SolidColor.GetValue() == m_SolidColor2.GetValue()) { - light.SetColor(Color(255, 0, 0, 0)); - dark.SetColor(Color(255, 255, 255, 255)); + graphics.Clear(m_SolidColor); + } + else + { + Rect r(0, 0, m_WindowW, m_WindowH); + LinearGradientBrush gradient(r, m_SolidColor, m_SolidColor2, m_SolidAngle, TRUE); + graphics.FillRectangle(&gradient, r); + } + + if (m_SolidBevel != BEVELTYPE_NONE) + { + Pen light(Color(255, 255, 255, 255)); + Pen dark(Color(255, 0, 0, 0)); + + if (m_SolidBevel == BEVELTYPE_DOWN) + { + light.SetColor(Color(255, 0, 0, 0)); + dark.SetColor(Color(255, 255, 255, 255)); + } + Rect rect(0, 0, m_WindowW, m_WindowH); + CMeter::DrawBevel(graphics, rect, light, dark); } - Rect rect(0, 0, m_WindowW, m_WindowH); - CMeter::DrawBevel(graphics, rect, light, dark); } } } diff --git a/Library/MeterWindow.h b/Library/MeterWindow.h index acb61cf1..f8994a62 100644 --- a/Library/MeterWindow.h +++ b/Library/MeterWindow.h @@ -77,7 +77,8 @@ enum BGMODE BGMODE_IMAGE = 0, BGMODE_COPY, BGMODE_SOLID, - BGMODE_SCALED_IMAGE + BGMODE_SCALED_IMAGE, + BGMODE_TILED_IMAGE }; enum HIDEMODE diff --git a/Library/Rainmeter.cpp b/Library/Rainmeter.cpp index aa0651bf..a6d8997f 100644 --- a/Library/Rainmeter.cpp +++ b/Library/Rainmeter.cpp @@ -2843,9 +2843,7 @@ void CRainmeter::ReadGeneralSettings(const std::wstring& iniFile) std::wstring area = parser.ReadString(L"Rainmeter", L"DesktopWorkArea", L""); if (!area.empty()) { - RECT r; - swscanf(area.c_str(), L"%i,%i,%i,%i", &r.left, &r.top, &r.right, &r.bottom); - m_DesktopWorkAreas[0] = r; + m_DesktopWorkAreas[0] = parser.ParseRECT(area.c_str()); m_DesktopWorkAreaChanged = true; } @@ -2856,9 +2854,7 @@ void CRainmeter::ReadGeneralSettings(const std::wstring& iniFile) area = parser.ReadString(L"Rainmeter", buffer, L""); if (!area.empty()) { - RECT r; - swscanf(area.c_str(), L"%i,%i,%i,%i", &r.left, &r.top, &r.right, &r.bottom); - m_DesktopWorkAreas[i] = r; + m_DesktopWorkAreas[i] = parser.ParseRECT(area.c_str()); m_DesktopWorkAreaChanged = true; } } diff --git a/Library/TintedImage.cpp b/Library/TintedImage.cpp index 9b53eab4..cc14a193 100644 --- a/Library/TintedImage.cpp +++ b/Library/TintedImage.cpp @@ -48,10 +48,12 @@ const Gdiplus::ColorMatrix CTintedImage::c_IdentifyMatrix = { ** The constructor. ** ** If disableTransform is true, following configs are ignored: +** - ImageCrop ** - ImageRotate ** */ CTintedImage::CTintedImage(bool disableTransform) : m_DisableTransform(disableTransform), + m_Crop(-1, -1, -1, -1), m_ColorMatrix(c_IdentifyMatrix) { SetConfigAttributes(L"Image", L""); @@ -161,7 +163,14 @@ void CTintedImage::LoadImage(const std::wstring& imageName, bool bLoadAlways) if (m_Bitmap && Ok == m_Bitmap->GetLastStatus()) { - // Check whether the new image needs tinting (or flipping, rotating) + // 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) + { + m_NeedsCrop = true; + } + } if (!m_NeedsTinting) { if (m_GreyScale || !CompareColorMatrix(m_ColorMatrix, c_IdentifyMatrix)) @@ -212,12 +221,27 @@ void CTintedImage::LoadImage(const std::wstring& imageName, bool bLoadAlways) if (m_Bitmap) { // We need a copy of the image if has tinting (or flipping, rotating) - if (m_NeedsTinting || m_NeedsTransform) + if (m_NeedsCrop || m_NeedsTinting || m_NeedsTransform) { - ApplyTint(); - m_NeedsTinting = false; + if (m_BitmapTint) + { + delete m_BitmapTint; + m_BitmapTint = NULL; + } - ApplyTransform(); + if (m_Bitmap->GetWidth() > 0 && m_Bitmap->GetHeight() > 0) + { + ApplyCrop(); + + if (!m_BitmapTint || (m_BitmapTint->GetWidth() > 0 && m_BitmapTint->GetHeight() > 0)) + { + ApplyTint(); + ApplyTransform(); + } + } + + m_NeedsCrop = false; + m_NeedsTinting = false; m_NeedsTransform = false; } } @@ -228,6 +252,31 @@ void CTintedImage::LoadImage(const std::wstring& imageName, bool bLoadAlways) } } +/* +** ApplyCrop +** +** This will apply the cropping. +** +*/ +void CTintedImage::ApplyCrop() +{ + if (m_Crop.Width >= 0 && m_Crop.Height >= 0) + { + if (m_Crop.Width == 0 || m_Crop.Height == 0) + { + m_BitmapTint = new Bitmap(0, 0, PixelFormat32bppARGB); // create dummy bitmap + } + else + { + 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); + } + } +} + /* ** ApplyTint ** @@ -236,25 +285,32 @@ void CTintedImage::LoadImage(const std::wstring& imageName, bool bLoadAlways) */ void CTintedImage::ApplyTint() { - ImageAttributes ImgAttr; - ImgAttr.SetColorMatrix(&m_ColorMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap); - - delete m_BitmapTint; - - Rect r(0, 0, m_Bitmap->GetWidth(), m_Bitmap->GetHeight()); - m_BitmapTint = new Bitmap(r.Width, r.Height, PixelFormat32bppARGB); - - Graphics graphics(m_BitmapTint); - - if (m_GreyScale) + if (m_GreyScale || !CompareColorMatrix(m_ColorMatrix, c_IdentifyMatrix)) { - Bitmap* gray = TurnGreyscale(m_Bitmap); - graphics.DrawImage(gray, r, 0, 0, r.Width, r.Height, UnitPixel, &ImgAttr); - delete gray; - } - else - { - graphics.DrawImage(m_Bitmap, r, 0, 0, r.Width, r.Height, UnitPixel, &ImgAttr); + Bitmap* original = GetImage(); + + ImageAttributes ImgAttr; + ImgAttr.SetColorMatrix(&m_ColorMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap); + + Rect r(0, 0, original->GetWidth(), original->GetHeight()); + + Bitmap* tint = new Bitmap(r.Width, r.Height, PixelFormat32bppARGB); + + Graphics graphics(tint); + + if (m_GreyScale) + { + Bitmap* gray = TurnGreyscale(original); + graphics.DrawImage(gray, r, 0, 0, r.Width, r.Height, UnitPixel, &ImgAttr); + delete gray; + } + else + { + graphics.DrawImage(original, r, 0, 0, r.Width, r.Height, UnitPixel, &ImgAttr); + } + + delete m_BitmapTint; + m_BitmapTint = tint; } } @@ -290,7 +346,7 @@ void CTintedImage::ApplyTransform() { if (m_Rotate != 0.0f) { - Bitmap* original = (m_BitmapTint) ? m_BitmapTint : m_Bitmap; + Bitmap* original = GetImage(); REAL originalW = (REAL)original->GetWidth(); REAL originalH = (REAL)original->GetHeight(); @@ -331,7 +387,7 @@ void CTintedImage::ApplyTransform() } else if (m_Flip != RotateNoneFlipNone) { - Bitmap* original = (m_BitmapTint) ? m_BitmapTint : m_Bitmap; + Bitmap* original = GetImage(); Rect r(0, 0, original->GetWidth(), original->GetHeight()); Bitmap* transform = new Bitmap(r.Width, r.Height, PixelFormat32bppARGB); @@ -364,6 +420,7 @@ void CTintedImage::SetConfigAttributes(const WCHAR* name, const WCHAR* prefix) if (prefix) { + (m_ConfigImageCrop = prefix) += L"ImageCrop"; (m_ConfigGreyscale = prefix) += L"Greyscale"; (m_ConfigImageTint = prefix) += L"ImageTint"; (m_ConfigImageAlpha = prefix) += L"ImageAlpha"; @@ -386,11 +443,19 @@ void CTintedImage::SetConfigAttributes(const WCHAR* name, const WCHAR* prefix) 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; bool oldGreyScale = m_GreyScale; ColorMatrix oldColorMatrix = m_ColorMatrix; RotateFlipType oldFlip = m_Flip; REAL oldRotate = m_Rotate; + if (!m_DisableTransform) + { + m_Crop = parser.ReadRect(section, m_ConfigImageCrop.c_str(), Rect(-1,-1,-1,-1)); + } + + m_NeedsCrop = (oldCrop.X != m_Crop.X || oldCrop.Y != m_Crop.Y || oldCrop.Width != m_Crop.Width || oldCrop.Height != m_Crop.Height); + m_GreyScale = 0!=parser.ReadInt(section, m_ConfigGreyscale.c_str(), 0); Color tint = parser.ReadColor(section, m_ConfigImageTint.c_str(), Color::White); diff --git a/Library/TintedImage.h b/Library/TintedImage.h index 469f8f55..4aaf382e 100644 --- a/Library/TintedImage.h +++ b/Library/TintedImage.h @@ -33,8 +33,8 @@ public: bool IsLoaded() { return (m_Bitmap != NULL); } bool IsTinted() { return (m_BitmapTint != NULL); } - bool IsConfigsChanged() { return m_NeedsTinting || m_NeedsTransform; } - void ClearConfigFlags() { m_NeedsTinting = m_NeedsTransform = false; } + bool IsConfigsChanged() { return m_NeedsCrop || m_NeedsTinting || m_NeedsTransform; } + void ClearConfigFlags() { m_NeedsCrop = m_NeedsTinting = m_NeedsTransform = false; } Gdiplus::Bitmap* GetOriginalImage() { return m_Bitmap; } Gdiplus::Bitmap* GetTintedImage() { return m_BitmapTint; } @@ -44,6 +44,7 @@ public: void LoadImage(const std::wstring& imageName, bool bLoadAlways); protected: + void ApplyCrop(); void ApplyTint(); void ApplyTransform(); @@ -57,6 +58,7 @@ protected: FILETIME m_Modified; std::wstring m_ConfigName; + std::wstring m_ConfigImageCrop; std::wstring m_ConfigGreyscale; std::wstring m_ConfigImageTint; std::wstring m_ConfigImageAlpha; @@ -70,9 +72,11 @@ protected: const bool m_DisableTransform; + bool m_NeedsCrop; bool m_NeedsTinting; bool m_NeedsTransform; + Gdiplus::Rect m_Crop; bool m_GreyScale; Gdiplus::ColorMatrix m_ColorMatrix; Gdiplus::RotateFlipType m_Flip;