diff --git a/Library/Library.vcproj b/Library/Library.vcproj
index 5d8caaf2..78f71582 100644
--- a/Library/Library.vcproj
+++ b/Library/Library.vcproj
@@ -1943,6 +1943,51 @@
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2186,6 +2231,10 @@
RelativePath="System.h"
>
+
+
diff --git a/Library/MeterBar.cpp b/Library/MeterBar.cpp
index ecdad50a..fdac2eac 100644
--- a/Library/MeterBar.cpp
+++ b/Library/MeterBar.cpp
@@ -23,7 +23,6 @@
#include "Litestep.h"
#include "Rainmeter.h"
-
using namespace Gdiplus;
extern CRainmeter* Rainmeter;
@@ -34,9 +33,12 @@ extern CRainmeter* Rainmeter;
** The constructor
**
*/
-CMeterBar::CMeterBar(CMeterWindow* meterWindow) : CMeterImage(meterWindow, L"ImageW", L"ImageH"),
+CMeterBar::CMeterBar(CMeterWindow* meterWindow) : CMeter(meterWindow),
m_Color(Color::Green)
{
+ m_Image.SetConfigAttributes(L"BarImage", NULL);
+
+ m_NeedsReload = false;
m_Value = 0.0;
m_Border = 0;
m_Flip = false;
@@ -50,7 +52,6 @@ CMeterBar::CMeterBar(CMeterWindow* meterWindow) : CMeterImage(meterWindow, L"Ima
*/
CMeterBar::~CMeterBar()
{
-
}
/*
@@ -67,23 +68,19 @@ void CMeterBar::Initialize()
// Load the bitmaps if defined
if(!m_ImageName.empty())
{
+ m_Image.LoadImage(m_ImageName, m_NeedsReload);
- LoadImage(false);
-
- if(m_Bitmap)
+ if (m_Image.IsLoaded())
{
- m_W = m_Bitmap->GetWidth();
- m_H = m_Bitmap->GetHeight();
+ Bitmap* bitmap = m_Image.GetImage();
+
+ m_W = bitmap->GetWidth();
+ m_H = bitmap->GetHeight();
}
-
}
- else
+ else if (m_Image.IsLoaded())
{
- if (m_Bitmap)
- {
- delete m_Bitmap;
- m_Bitmap = NULL;
- }
+ m_Image.DisposeImage();
}
}
@@ -101,7 +98,7 @@ void CMeterBar::ReadConfig(const WCHAR* section)
int oldH = m_H;
// Read common configs
- CMeterImage::ReadConfig(section);
+ CMeter::ReadConfig(section);
CConfigParser& parser = m_MeterWindow->GetParser();
@@ -111,6 +108,13 @@ void CMeterBar::ReadConfig(const WCHAR* section)
if (!m_ImageName.empty())
{
m_ImageName = m_MeterWindow->MakePathAbsolute(m_ImageName);
+
+ // Read tinting configs
+ m_Image.ReadConfig(parser, section);
+ }
+ else
+ {
+ m_Image.ClearConfigFlags();
}
m_Border = parser.ReadInt(section, L"BarBorder", 0);
@@ -138,7 +142,10 @@ void CMeterBar::ReadConfig(const WCHAR* section)
if (m_Initialized)
{
- if (oldImageName != m_ImageName || m_NeedsTinting || m_NeedsTransform)
+ m_NeedsReload = (oldImageName != m_ImageName);
+
+ if (m_NeedsReload ||
+ m_Image.IsConfigsChanged())
{
Initialize(); // Reload the image
}
@@ -180,7 +187,7 @@ bool CMeterBar::Draw(Graphics& graphics)
int x = GetX();
int y = GetY();
- Bitmap* drawBitmap = (m_BitmapTint) ? m_BitmapTint : m_Bitmap;
+ Bitmap* drawBitmap = m_Image.GetImage();
if(m_Orientation == VERTICAL)
{
diff --git a/Library/MeterBar.h b/Library/MeterBar.h
index fb1d540a..1f19dd5c 100644
--- a/Library/MeterBar.h
+++ b/Library/MeterBar.h
@@ -19,9 +19,11 @@
#ifndef __METERBAR_H__
#define __METERBAR_H__
-#include "MeterImage.h"
+#include "Meter.h"
+#include "TintedImage.h"
+#include "MeterWindow.h"
-class CMeterBar : public CMeterImage
+class CMeterBar : public CMeter
{
public:
CMeterBar(CMeterWindow* meterWindow);
@@ -39,13 +41,15 @@ private:
VERTICAL
};
+ CTintedImage m_Image;
+ std::wstring m_ImageName; // Name of the bar-image
+ bool m_NeedsReload;
+
Gdiplus::Color m_Color; // Color of the bar
ORIENTATION m_Orientation; // Orientation (i.e. the growth direction)
double m_Value;
int m_Border;
bool m_Flip;
-
-
};
#endif
diff --git a/Library/MeterBitmap.cpp b/Library/MeterBitmap.cpp
index 7e861269..b8c7fcdf 100644
--- a/Library/MeterBitmap.cpp
+++ b/Library/MeterBitmap.cpp
@@ -32,9 +32,12 @@ extern CRainmeter* Rainmeter;
** The constructor
**
*/
-CMeterBitmap::CMeterBitmap(CMeterWindow* meterWindow) : CMeter(meterWindow)
+CMeterBitmap::CMeterBitmap(CMeterWindow* meterWindow) : CMeter(meterWindow),
+ m_Image(true)
{
- m_Bitmap = NULL;
+ m_Image.SetConfigAttributes(L"BitmapImage", NULL);
+
+ m_NeedsReload = false;
m_FrameCount = 1;
m_ZeroFrame = false;
m_Align = ALIGN_LEFT;
@@ -54,7 +57,6 @@ CMeterBitmap::CMeterBitmap(CMeterWindow* meterWindow) : CMeter(meterWindow)
*/
CMeterBitmap::~CMeterBitmap()
{
- if(m_Bitmap != NULL) delete m_Bitmap;
}
/*
@@ -70,20 +72,14 @@ void CMeterBitmap::Initialize()
// Load the bitmaps if defined
if(!m_ImageName.empty())
{
- if (m_Bitmap != NULL) delete m_Bitmap;
- m_Bitmap = new Bitmap(m_ImageName.c_str());
- Status status = m_Bitmap->GetLastStatus();
- if(Ok != status)
- {
- DebugLog(L"Bitmap image not found: %s", m_ImageName.c_str());
+ m_Image.LoadImage(m_ImageName, m_NeedsReload);
- delete m_Bitmap;
- m_Bitmap = NULL;
- }
- else
+ if (m_Image.IsLoaded())
{
- m_W = m_Bitmap->GetWidth();
- m_H = m_Bitmap->GetHeight();
+ Bitmap* bitmap = m_Image.GetImage();
+
+ m_W = bitmap->GetWidth();
+ m_H = bitmap->GetHeight();
if(m_H > m_W)
{
@@ -95,13 +91,9 @@ void CMeterBitmap::Initialize()
}
}
}
- else
+ else if (m_Image.IsLoaded())
{
- if (m_Bitmap)
- {
- delete m_Bitmap;
- m_Bitmap = NULL;
- }
+ m_Image.DisposeImage();
}
}
@@ -187,6 +179,13 @@ void CMeterBitmap::ReadConfig(const WCHAR* section)
if (!m_ImageName.empty())
{
m_ImageName = m_MeterWindow->MakePathAbsolute(m_ImageName);
+
+ // Read tinting configs
+ m_Image.ReadConfig(parser, section);
+ }
+ else
+ {
+ m_Image.ClearConfigFlags();
}
m_FrameCount = parser.ReadInt(section, L"BitmapFrames", 1);
@@ -223,7 +222,10 @@ void CMeterBitmap::ReadConfig(const WCHAR* section)
if (m_Initialized)
{
- if (oldImageName != m_ImageName)
+ m_NeedsReload = (oldImageName != m_ImageName);
+
+ if (m_NeedsReload ||
+ m_Image.IsConfigsChanged())
{
Initialize(); // Reload the image
}
@@ -296,7 +298,9 @@ bool CMeterBitmap::Draw(Graphics& graphics)
int newY, newX;
- if(m_FrameCount == 0 || m_Bitmap == NULL) return false; // Unable to continue
+ if(m_FrameCount == 0 || !m_Image.IsLoaded()) return false; // Unable to continue
+
+ Bitmap* bitmap = m_Image.GetImage();
int x = GetX();
int y = GetY();
@@ -383,7 +387,7 @@ bool CMeterBitmap::Draw(Graphics& graphics)
// DebugLog(L"[%i] Value: %f Frame: %i (Transition = %s)", GetTickCount(), m_Value, frame, m_TransitionStartTicks > 0 ? L"true" : L"false");
- if(m_Bitmap->GetHeight() > m_Bitmap->GetWidth())
+ if(bitmap->GetHeight() > bitmap->GetWidth())
{
newX = 0;
newY = m_H * frame;
@@ -394,7 +398,7 @@ bool CMeterBitmap::Draw(Graphics& graphics)
newY = 0;
}
- graphics.DrawImage(m_Bitmap, r, newX, newY, m_W, m_H, UnitPixel);
+ graphics.DrawImage(bitmap, r, newX, newY, m_W, m_H, UnitPixel);
if (m_FrameCount == 1)
{
value /= 2;
@@ -449,7 +453,7 @@ bool CMeterBitmap::Draw(Graphics& graphics)
// DebugLog(L"[%i] Value: %f Frame: %i (Transition = %s)", GetTickCount(), m_Value, frame, m_TransitionStartTicks > 0 ? L"true" : L"false");
- if(m_Bitmap->GetHeight() > m_Bitmap->GetWidth())
+ if(bitmap->GetHeight() > bitmap->GetWidth())
{
newX = 0;
newY = frame * m_H;
@@ -462,7 +466,7 @@ bool CMeterBitmap::Draw(Graphics& graphics)
// Blit the image
Rect r(x, y, m_W, m_H);
- graphics.DrawImage(m_Bitmap, r, newX, newY, m_W, m_H, UnitPixel);
+ graphics.DrawImage(bitmap, r, newX, newY, m_W, m_H, UnitPixel);
}
return true;
diff --git a/Library/MeterBitmap.h b/Library/MeterBitmap.h
index 31bdaa94..02698390 100644
--- a/Library/MeterBitmap.h
+++ b/Library/MeterBitmap.h
@@ -20,6 +20,7 @@
#define __METERBITMAP_H__
#include "Meter.h"
+#include "TintedImage.h"
#include "MeterWindow.h"
class CMeterBitmap : public CMeter
@@ -37,11 +38,13 @@ public:
virtual bool HasActiveTransition();
private:
+ CTintedImage m_Image;
+ std::wstring m_ImageName; // Name of the image
+ bool m_NeedsReload;
+
bool m_ZeroFrame; // If true, the first frame is only shown when the measured value is zero
int m_FrameCount; // Number of frames in the bitmap
int m_TransitionFrameCount; // Number of transition frames (per one frame) in the bitmap
- Gdiplus::Bitmap* m_Bitmap; // Handle to the bitmap
- std::wstring m_ImageName; // Name of the image
METER_ALIGNMENT m_Align; // Alignment of the bitmaps
bool m_Extend; // If true, bitmaps extend horizontally and are used like numbers
int m_Separation;
diff --git a/Library/MeterButton.cpp b/Library/MeterButton.cpp
index bc1e126e..67789b37 100644
--- a/Library/MeterButton.cpp
+++ b/Library/MeterButton.cpp
@@ -39,13 +39,16 @@ enum BUTTON_STATE
** The constructor
**
*/
-CMeterButton::CMeterButton(CMeterWindow* meterWindow) : CMeter(meterWindow)
+CMeterButton::CMeterButton(CMeterWindow* meterWindow) : CMeter(meterWindow),
+ m_Image(true)
{
+ m_Image.SetConfigAttributes(L"ButtonImage", NULL);
+
for (int i = 0; i < BUTTON_FRAMES; ++i)
{
m_Bitmaps[i] = NULL;
}
- m_Bitmap = NULL;
+ m_NeedsReload = false;
m_State = BUTTON_STATE_NORMAL;
m_Clicked = false;
m_Executable = false;
@@ -61,10 +64,8 @@ CMeterButton::~CMeterButton()
{
for (int i = 0; i < BUTTON_FRAMES; ++i)
{
- if (m_Bitmaps[i] != NULL) delete m_Bitmaps[i];
+ delete m_Bitmaps[i];
}
-
- if (m_Bitmap != NULL) delete m_Bitmap;
}
/*
@@ -77,31 +78,26 @@ void CMeterButton::Initialize()
{
CMeter::Initialize();
+ for (int i = 0; i < BUTTON_FRAMES; ++i)
+ {
+ if (m_Bitmaps[i])
+ {
+ delete m_Bitmaps[i];
+ m_Bitmaps[i] = NULL;
+ }
+ }
+
// Load the bitmaps if defined
if(!m_ImageName.empty())
{
- for (int i = 0; i < BUTTON_FRAMES; ++i)
- {
- if (m_Bitmaps[i] != NULL)
- {
- delete m_Bitmaps[i];
- m_Bitmaps[i] = NULL;
- }
- }
- if (m_Bitmap != NULL) delete m_Bitmap;
- m_Bitmap = new Bitmap(m_ImageName.c_str());
- Status status = m_Bitmap->GetLastStatus();
- if(Ok != status)
- {
- DebugLog(L"Bitmap image not found: %s", m_ImageName.c_str());
+ m_Image.LoadImage(m_ImageName, m_NeedsReload);
- delete m_Bitmap;
- m_Bitmap = NULL;
- }
- else
+ if (m_Image.IsLoaded())
{
- m_W = m_Bitmap->GetWidth();
- m_H = m_Bitmap->GetHeight();
+ Bitmap* bitmap = m_Image.GetImage();
+
+ m_W = bitmap->GetWidth();
+ m_H = bitmap->GetHeight();
if(m_H > m_W)
{
@@ -121,33 +117,21 @@ void CMeterButton::Initialize()
Graphics graphics(&bitmapPart);
Rect r(0, 0, m_W, m_H);
- if(m_Bitmap->GetHeight() > m_Bitmap->GetWidth())
+ if(bitmap->GetHeight() > bitmap->GetWidth())
{
- graphics.DrawImage(m_Bitmap, r, 0, m_H * i, m_W, m_H, UnitPixel);
+ graphics.DrawImage(bitmap, r, 0, m_H * i, m_W, m_H, UnitPixel);
}
else
{
- graphics.DrawImage(m_Bitmap, r, m_W * i, 0, m_W, m_H, UnitPixel);
+ graphics.DrawImage(bitmap, r, m_W * i, 0, m_W, m_H, UnitPixel);
}
m_Bitmaps[i] = new CachedBitmap(&bitmapPart, &graphics);
}
}
}
- else
+ else if (m_Image.IsLoaded())
{
- for (int i = 0; i < BUTTON_FRAMES; ++i)
- {
- if (m_Bitmaps[i])
- {
- delete m_Bitmaps[i];
- m_Bitmaps[i] = NULL;
- }
- }
- if (m_Bitmap)
- {
- delete m_Bitmap;
- m_Bitmap = NULL;
- }
+ m_Image.DisposeImage();
}
}
@@ -173,13 +157,23 @@ void CMeterButton::ReadConfig(const WCHAR* section)
if (!m_ImageName.empty())
{
m_ImageName = m_MeterWindow->MakePathAbsolute(m_ImageName);
+
+ // Read tinting configs
+ m_Image.ReadConfig(parser, section);
+ }
+ else
+ {
+ m_Image.ClearConfigFlags();
}
m_Command = parser.ReadString(section, L"ButtonCommand", L"", false);
if (m_Initialized)
{
- if (oldImageName != m_ImageName)
+ m_NeedsReload = (oldImageName != m_ImageName);
+
+ if (m_NeedsReload ||
+ m_Image.IsConfigsChanged())
{
Initialize(); // Reload the image
}
@@ -262,10 +256,10 @@ bool CMeterButton::HitTest2(int px, int py, bool checkAlpha)
}
// Check transparent pixels
- if (m_Bitmap)
+ if (m_Image.IsLoaded())
{
Color color;
- Status status = m_Bitmap->GetPixel(px - x + m_W * m_State, py - y, &color);
+ Status status = m_Image.GetImage()->GetPixel(px - x + m_W * m_State, py - y, &color);
if (status != Ok || color.GetA() > 0)
{
return true;
diff --git a/Library/MeterButton.h b/Library/MeterButton.h
index 8c85eeba..3d6a7e2b 100644
--- a/Library/MeterButton.h
+++ b/Library/MeterButton.h
@@ -20,6 +20,7 @@
#define __METERBUTTON_H__
#include "Meter.h"
+#include "TintedImage.h"
#include "MeterWindow.h"
#define BUTTON_FRAMES 3
@@ -46,9 +47,11 @@ public:
private:
bool HitTest2(int px, int py, bool checkAlpha);
- Gdiplus::Bitmap* m_Bitmap; // The bitmap
- Gdiplus::CachedBitmap* m_Bitmaps[BUTTON_FRAMES]; // The cached bitmaps
+ CTintedImage m_Image;
std::wstring m_ImageName; // Name of the image
+ bool m_NeedsReload;
+
+ Gdiplus::CachedBitmap* m_Bitmaps[BUTTON_FRAMES]; // The cached bitmaps
std::wstring m_Command; // Command to be executed
int m_State;
bool m_Clicked;
diff --git a/Library/MeterHistogram.cpp b/Library/MeterHistogram.cpp
index 6131bd29..ae22843c 100644
--- a/Library/MeterHistogram.cpp
+++ b/Library/MeterHistogram.cpp
@@ -37,11 +37,15 @@ CMeterHistogram::CMeterHistogram(CMeterWindow* meterWindow) : CMeter(meterWindow
m_SecondaryColor(Color::Red),
m_BothColor(Color::Yellow)
{
+ m_PrimaryImage.SetConfigAttributes(L"PrimaryImage", L"Primary");
+ m_SecondaryImage.SetConfigAttributes(L"SecondaryImage", L"Secondary");
+ m_BothImage.SetConfigAttributes(L"BothImage", L"Both");
+
+ m_PrimaryNeedsReload = false;
+ m_SecondaryNeedsReload = false;
+ m_BothNeedsReload = false;
m_SecondaryMeasure = NULL;
m_MeterPos = 0;
- m_PrimaryBitmap = NULL;
- m_SecondaryBitmap = NULL;
- m_BothBitmap = NULL;
m_PrimaryValues = NULL;
m_SecondaryValues = NULL;
m_Autoscale = false;
@@ -50,7 +54,7 @@ CMeterHistogram::CMeterHistogram(CMeterWindow* meterWindow) : CMeter(meterWindow
m_MinPrimaryValue = 0.0;
m_MaxSecondaryValue = 1.0;
m_MinSecondaryValue = 0.0;
- m_WidthChanged = false;
+ m_WidthChanged = true;
}
/*
@@ -61,35 +65,9 @@ CMeterHistogram::CMeterHistogram(CMeterWindow* meterWindow) : CMeter(meterWindow
*/
CMeterHistogram::~CMeterHistogram()
{
- DisposeImage();
DisposeBuffer();
}
-/*
-** DisposeImage
-**
-** Disposes the image buffers.
-**
-*/
-void CMeterHistogram::DisposeImage()
-{
- if (m_PrimaryBitmap)
- {
- delete m_PrimaryBitmap;
- m_PrimaryBitmap = NULL;
- }
- if (m_SecondaryBitmap)
- {
- delete m_SecondaryBitmap;
- m_SecondaryBitmap = NULL;
- }
- if (m_BothBitmap)
- {
- delete m_BothBitmap;
- m_BothBitmap = NULL;
- }
-}
-
/*
** DisposeBuffer
**
@@ -130,29 +108,25 @@ void CMeterHistogram::Initialize()
{
LSLog(LOG_DEBUG, APPNAME, L"You need to define SecondaryImage and BothImage also!");
- DisposeImage();
+ m_PrimaryImage.DisposeImage();
+ m_SecondaryImage.DisposeImage();
+ m_BothImage.DisposeImage();
}
else
{
// Load the bitmaps if defined
- if(!m_PrimaryImageName.empty())
+ if (!m_PrimaryImageName.empty())
{
- if (m_PrimaryBitmap) delete m_PrimaryBitmap;
- m_PrimaryBitmap = new Bitmap(m_PrimaryImageName.c_str());
- Status status = m_PrimaryBitmap->GetLastStatus();
- if(Ok != status)
- {
- DebugLog(L"PrimaryImage not found: %s", m_PrimaryImageName.c_str());
+ m_PrimaryImage.LoadImage(m_PrimaryImageName, m_PrimaryNeedsReload);
- delete m_PrimaryBitmap;
- m_PrimaryBitmap = NULL;
- }
- else
+ if (m_PrimaryImage.IsLoaded())
{
int oldW = m_W;
- m_W = m_PrimaryBitmap->GetWidth();
- m_H = m_PrimaryBitmap->GetHeight();
+ Bitmap* bitmap = m_PrimaryImage.GetImage();
+
+ m_W = bitmap->GetWidth();
+ m_H = bitmap->GetHeight();
if (oldW != m_W)
{
@@ -160,63 +134,33 @@ void CMeterHistogram::Initialize()
}
}
}
- else
+ else if (m_PrimaryImage.IsLoaded())
{
- if (m_PrimaryBitmap)
- {
- delete m_PrimaryBitmap;
- m_PrimaryBitmap = NULL;
- }
+ m_PrimaryImage.DisposeImage();
}
- if(!m_SecondaryImageName.empty())
+ if (!m_SecondaryImageName.empty())
{
- if (m_SecondaryBitmap) delete m_SecondaryBitmap;
- m_SecondaryBitmap = new Bitmap(m_SecondaryImageName.c_str());
- Status status = m_SecondaryBitmap->GetLastStatus();
- if(Ok != status)
- {
- DebugLog(L"SecondaryImage not found: %s", m_SecondaryImageName.c_str());
-
- delete m_SecondaryBitmap;
- m_SecondaryBitmap = NULL;
- }
+ m_SecondaryImage.LoadImage(m_SecondaryImageName, m_SecondaryNeedsReload);
}
- else
+ else if (m_SecondaryImage.IsLoaded())
{
- if (m_SecondaryBitmap)
- {
- delete m_SecondaryBitmap;
- m_SecondaryBitmap = NULL;
- }
+ m_SecondaryImage.DisposeImage();
}
- if(!m_BothImageName.empty())
+ if (!m_BothImageName.empty())
{
- if (m_BothBitmap) delete m_BothBitmap;
- m_BothBitmap = new Bitmap(m_BothImageName.c_str());
- Status status = m_BothBitmap->GetLastStatus();
- if(Ok != status)
- {
- DebugLog(L"BothImage not found: %s", m_BothImageName.c_str());
-
- delete m_BothBitmap;
- m_BothBitmap = NULL;
- }
+ m_BothImage.LoadImage(m_BothImageName, m_BothNeedsReload);
}
- else
+ else if (m_BothImage.IsLoaded())
{
- if (m_BothBitmap)
- {
- delete m_BothBitmap;
- m_BothBitmap = NULL;
- }
+ m_BothImage.DisposeImage();
}
}
- if ((!m_PrimaryImageName.empty() && !m_PrimaryBitmap) ||
- (!m_SecondaryImageName.empty() && !m_SecondaryBitmap) ||
- (!m_BothImageName.empty() && !m_BothBitmap))
+ if ((!m_PrimaryImageName.empty() && !m_PrimaryImage.IsLoaded()) ||
+ (!m_SecondaryImageName.empty() && !m_SecondaryImage.IsLoaded()) ||
+ (!m_BothImageName.empty() && !m_BothImage.IsLoaded()))
{
DisposeBuffer();
@@ -276,18 +220,39 @@ void CMeterHistogram::ReadConfig(const WCHAR* section)
if (!m_PrimaryImageName.empty())
{
m_PrimaryImageName = m_MeterWindow->MakePathAbsolute(m_PrimaryImageName);
+
+ // Read tinting configs
+ m_PrimaryImage.ReadConfig(parser, section);
+ }
+ else
+ {
+ m_PrimaryImage.ClearConfigFlags();
}
m_SecondaryImageName = parser.ReadString(section, L"SecondaryImage", L"");
if (!m_SecondaryImageName.empty())
{
m_SecondaryImageName = m_MeterWindow->MakePathAbsolute(m_SecondaryImageName);
+
+ // Read tinting configs
+ m_SecondaryImage.ReadConfig(parser, section);
+ }
+ else
+ {
+ m_SecondaryImage.ClearConfigFlags();
}
m_BothImageName = parser.ReadString(section, L"BothImage", L"");
if (!m_BothImageName.empty())
{
m_BothImageName = m_MeterWindow->MakePathAbsolute(m_BothImageName);
+
+ // Read tinting configs
+ m_BothImage.ReadConfig(parser, section);
+ }
+ else
+ {
+ m_BothImage.ClearConfigFlags();
}
m_Autoscale = 0!=parser.ReadInt(section, L"AutoScale", 0);
@@ -309,18 +274,21 @@ void CMeterHistogram::ReadConfig(const WCHAR* section)
m_W = oldW;
m_H = oldH;
- if (oldPrimaryImageName != m_PrimaryImageName ||
- oldSecondaryImageName != m_SecondaryImageName ||
- oldBothImageName != m_BothImageName)
+ m_PrimaryNeedsReload = (oldPrimaryImageName != m_PrimaryImageName);
+ m_SecondaryNeedsReload = (oldSecondaryImageName != m_SecondaryImageName);
+ m_BothNeedsReload = (oldBothImageName != m_BothImageName);
+
+ if (m_PrimaryNeedsReload ||
+ m_SecondaryNeedsReload ||
+ m_BothNeedsReload ||
+ m_PrimaryImage.IsConfigsChanged() ||
+ m_SecondaryImage.IsConfigsChanged() ||
+ m_BothImage.IsConfigsChanged())
{
Initialize(); // Reload the image
}
}
}
- else
- {
- m_WidthChanged = true;
- }
}
/*
@@ -346,8 +314,8 @@ bool CMeterHistogram::Update()
m_MaxPrimaryValue = m_Measure->GetMaxValue();
m_MinPrimaryValue = m_Measure->GetMinValue();
- m_MaxSecondaryValue = 0;
- m_MinSecondaryValue = 0;
+ m_MaxSecondaryValue = 0.0;
+ m_MinSecondaryValue = 0.0;
if (m_SecondaryMeasure)
{
m_MaxSecondaryValue = m_SecondaryMeasure->GetMaxValue();
@@ -421,6 +389,10 @@ bool CMeterHistogram::Draw(Graphics& graphics)
GraphicsPath secondaryPath;
GraphicsPath bothPath;
+ Bitmap* primaryBitmap = m_PrimaryImage.GetImage();
+ Bitmap* secondaryBitmap = m_SecondaryImage.GetImage();
+ Bitmap* bothBitmap = m_BothImage.GetImage();
+
int x = GetX();
int y = GetY();
@@ -434,7 +406,7 @@ bool CMeterHistogram::Draw(Graphics& graphics)
primaryBarHeight = min(m_H, primaryBarHeight);
primaryBarHeight = max(0, primaryBarHeight);
- if (m_SecondaryMeasure != NULL)
+ if (m_SecondaryMeasure)
{
value = (m_MaxSecondaryValue == 0.0) ?
0.0
@@ -447,37 +419,23 @@ bool CMeterHistogram::Draw(Graphics& graphics)
// Check which measured value is higher
int bothBarHeight = min(primaryBarHeight, secondaryBarHeight);
- // Draw image/color for the both lines
+ // Cache image/color rectangle for the both lines
{
Rect& r = (m_Flip) ?
Rect(x + i, y + bothBarHeight, 1, -bothBarHeight)
: Rect(x + i, y + m_H - bothBarHeight, 1, bothBarHeight);
- if (m_BothBitmap)
- {
- graphics.DrawImage(m_BothBitmap, r, i, m_H - bothBarHeight, 1, bothBarHeight, UnitPixel);
- }
- else
- {
- bothPath.AddRectangle(r); // cache
- }
+ bothPath.AddRectangle(r); // cache
}
- // Draw the image/color for the rest
+ // Cache the image/color rectangle for the rest
if (secondaryBarHeight > primaryBarHeight)
{
Rect& r = (m_Flip) ?
Rect(x + i, y + secondaryBarHeight, 1, -(secondaryBarHeight - bothBarHeight))
: Rect(x + i, y + m_H - secondaryBarHeight, 1, secondaryBarHeight - bothBarHeight);
- if (m_SecondaryBitmap)
- {
- graphics.DrawImage(m_SecondaryBitmap, r, i, m_H - secondaryBarHeight, 1, secondaryBarHeight - bothBarHeight, UnitPixel);
- }
- else
- {
- secondaryPath.AddRectangle(r); // cache
- }
+ secondaryPath.AddRectangle(r); // cache
}
else
{
@@ -485,14 +443,7 @@ bool CMeterHistogram::Draw(Graphics& graphics)
Rect(x + i, y + primaryBarHeight, 1, -(primaryBarHeight - bothBarHeight))
: Rect(x + i, y + m_H - primaryBarHeight, 1, primaryBarHeight - bothBarHeight);
- if (m_PrimaryBitmap)
- {
- graphics.DrawImage(m_PrimaryBitmap, r, i, m_H - primaryBarHeight, 1, primaryBarHeight - bothBarHeight, UnitPixel);
- }
- else
- {
- primaryPath.AddRectangle(r); // cache
- }
+ primaryPath.AddRectangle(r); // cache
}
}
else
@@ -501,35 +452,52 @@ bool CMeterHistogram::Draw(Graphics& graphics)
Rect(x + i, y + primaryBarHeight, 1, -primaryBarHeight)
: Rect(x + i, y + m_H - primaryBarHeight, 1, primaryBarHeight);
- if (m_PrimaryBitmap)
- {
- graphics.DrawImage(m_PrimaryBitmap, r, i, m_H - primaryBarHeight, 1, primaryBarHeight, UnitPixel);
- }
- else
- {
- primaryPath.AddRectangle(r); // cache
- }
+ primaryPath.AddRectangle(r); // cache
}
}
// Draw cached rectangles
- if (m_SecondaryMeasure != NULL)
+ if (primaryBitmap)
{
- if (!m_BothBitmap)
+ Rect r(x, y, primaryBitmap->GetWidth(), primaryBitmap->GetHeight());
+
+ graphics.SetClip(&primaryPath);
+ graphics.DrawImage(primaryBitmap, r, 0, 0, r.Width, r.Height, UnitPixel);
+ graphics.ResetClip();
+ }
+ else
+ {
+ SolidBrush brush(m_PrimaryColor);
+ graphics.FillPath(&brush, &primaryPath);
+ }
+ if (m_SecondaryMeasure)
+ {
+ if (secondaryBitmap)
{
- SolidBrush brush(m_BothColor);
- graphics.FillPath(&brush, &bothPath);
+ Rect r(x, y, secondaryBitmap->GetWidth(), secondaryBitmap->GetHeight());
+
+ graphics.SetClip(&secondaryPath);
+ graphics.DrawImage(secondaryBitmap, r, 0, 0, r.Width, r.Height, UnitPixel);
+ graphics.ResetClip();
}
- if (!m_SecondaryBitmap)
+ else
{
SolidBrush brush(m_SecondaryColor);
graphics.FillPath(&brush, &secondaryPath);
}
- }
- if (!m_PrimaryBitmap)
- {
- SolidBrush brush(m_PrimaryColor);
- graphics.FillPath(&brush, &primaryPath);
+ if (bothBitmap)
+ {
+ Rect r(x, y, bothBitmap->GetWidth(), bothBitmap->GetHeight());
+
+ graphics.SetClip(&bothPath);
+ graphics.DrawImage(bothBitmap, r, 0, 0, r.Width, r.Height, UnitPixel);
+ graphics.ResetClip();
+ }
+ else
+ {
+ SolidBrush brush(m_BothColor);
+ graphics.FillPath(&brush, &bothPath);
+ }
}
return true;
diff --git a/Library/MeterHistogram.h b/Library/MeterHistogram.h
index 18aaca16..fef10273 100644
--- a/Library/MeterHistogram.h
+++ b/Library/MeterHistogram.h
@@ -20,6 +20,7 @@
#define __METERHISTOGRAM_H__
#include "Meter.h"
+#include "TintedImage.h"
#include "MeterWindow.h"
class CMeterHistogram : public CMeter
@@ -35,7 +36,6 @@ public:
virtual void BindMeasure(const std::list& measures);
private:
- void DisposeImage();
void DisposeBuffer();
std::wstring m_SecondaryMeasureName; // Name of the secondary measure
@@ -52,9 +52,13 @@ private:
std::wstring m_SecondaryImageName; // Name of the secondary image for bitmap histograms
std::wstring m_BothImageName; // Name of the image for overlapping histograms
- Gdiplus::Bitmap* m_PrimaryBitmap; // The primary bitmap
- Gdiplus::Bitmap* m_SecondaryBitmap; // The secondary bitmap
- Gdiplus::Bitmap* m_BothBitmap; // The overlap bitmap
+ CTintedImage m_PrimaryImage; // The primary bitmap
+ CTintedImage m_SecondaryImage; // The secondary bitmap
+ CTintedImage m_BothImage; // The overlap bitmap
+
+ bool m_PrimaryNeedsReload;
+ bool m_SecondaryNeedsReload;
+ bool m_BothNeedsReload;
double* m_PrimaryValues;
double* m_SecondaryValues;
diff --git a/Library/MeterImage.cpp b/Library/MeterImage.cpp
index 7aeae15d..e2491c82 100644
--- a/Library/MeterImage.cpp
+++ b/Library/MeterImage.cpp
@@ -26,49 +26,18 @@ extern CRainmeter* Rainmeter;
using namespace Gdiplus;
-#define PI 3.14159265f
-
-// GrayScale Matrix
-const Gdiplus::ColorMatrix CMeterImage::c_GreyScaleMatrix = {
- 0.299f, 0.299f, 0.299f, 0.0f, 0.0f,
- 0.587f, 0.587f, 0.587f, 0.0f, 0.0f,
- 0.114f, 0.114f, 0.114f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
-};
-
-const Gdiplus::ColorMatrix CMeterImage::c_IdentifyMatrix = {
- 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
-};
-
/*
** CMeterImage
**
** The constructor
**
*/
-CMeterImage::CMeterImage(CMeterWindow* meterWindow, WCHAR* wName, WCHAR* hName) : CMeter(meterWindow), m_ImageWidthString(wName), m_ImageHeightString(hName),
- m_ColorMatrix(c_IdentifyMatrix)
+CMeterImage::CMeterImage(CMeterWindow* meterWindow) : CMeter(meterWindow)
{
- m_Bitmap = NULL;
- m_BitmapTint = NULL;
m_NeedsReload = false;
- m_NeedsTinting = false;
- m_NeedsTransform = false;
m_WidthDefined = false;
m_HeightDefined = false;
m_PreserveAspectRatio = false;
- m_hBuffer = NULL;
- m_Modified.dwHighDateTime = 0;
- m_Modified.dwLowDateTime = 0;
-
- m_GreyScale = false;
- m_Flip = RotateNoneFlipNone;
- m_Rotate = 0.0f;
}
/*
@@ -79,13 +48,6 @@ CMeterImage::CMeterImage(CMeterWindow* meterWindow, WCHAR* wName, WCHAR* hName)
*/
CMeterImage::~CMeterImage()
{
- if(m_Bitmap != NULL) delete m_Bitmap;
- if(m_BitmapTint != NULL) delete m_BitmapTint;
-
- if (m_hBuffer)
- {
- ::GlobalFree(m_hBuffer);
- }
}
/*
@@ -109,280 +71,36 @@ void CMeterImage::Initialize()
*/
void CMeterImage::LoadImage(bool bLoadAlways)
{
- // Load the bitmap if defined
- if (!m_ImageName.empty())
+ m_Image.LoadImage(m_ImageName, bLoadAlways);
+
+ if (m_Image.IsLoaded())
{
- std::wstring filename = m_ImageName;
+ // Calculate size of the meter
+ Bitmap* bitmap = m_Image.GetImage();
- // Check extension and if it is missing, add .png
- size_t pos = filename.find_last_of(L"\\");
- if (pos == std::wstring::npos) pos = 0;
- if (std::wstring::npos == filename.find(L'.', pos))
- {
- filename += L".png";
- }
+ int imageW = bitmap->GetWidth();
+ int imageH = bitmap->GetHeight();
- // Read the bitmap to memory so that it's not locked by GDI+
- HANDLE fileHandle = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
- if (fileHandle != INVALID_HANDLE_VALUE)
+ if (m_WidthDefined)
{
- // Compare the timestamp and filename to check if the file has been changed (don't load if it's not)
- FILETIME tmpTime;
- GetFileTime(fileHandle, NULL, NULL, &tmpTime);
- if (bLoadAlways || CompareFileTime(&tmpTime, &m_Modified) != 0)
+ if (!m_HeightDefined)
{
- m_Modified = tmpTime;
-
- DWORD imageSize = GetFileSize(fileHandle, 0);
-
- if (imageSize != -1)
- {
- if (m_hBuffer)
- {
- ::GlobalFree(m_hBuffer);
- }
-
- m_hBuffer = ::GlobalAlloc(GMEM_MOVEABLE, imageSize);
- if (m_hBuffer)
- {
- void* pBuffer = ::GlobalLock(m_hBuffer);
- if (pBuffer)
- {
- DWORD readBytes;
- ReadFile(fileHandle, pBuffer, imageSize, &readBytes, NULL);
- ::GlobalUnlock(m_hBuffer);
-
- IStream* pStream = NULL;
- if (::CreateStreamOnHGlobal(m_hBuffer, FALSE, &pStream) == S_OK)
- {
- if (m_Bitmap) delete m_Bitmap;
-
- if (m_BitmapTint)
- {
- delete m_BitmapTint;
- m_BitmapTint = NULL;
- }
-
- m_Bitmap = Bitmap::FromStream(pStream);
- if (m_Bitmap)
- {
- Status status = m_Bitmap->GetLastStatus();
- if(Ok != status)
- {
- DebugLog(L"Unable to create bitmap: %s", filename.c_str());
- delete m_Bitmap;
- m_Bitmap = NULL;
- }
- else
- {
- // Check whether the new image needs tinting (or flipping, rotating)
- if (!m_NeedsTinting)
- {
- if (m_GreyScale || !CompareColorMatrix(m_ColorMatrix, c_IdentifyMatrix))
- {
- m_NeedsTinting = true;
- }
- }
- if (!m_NeedsTransform)
- {
- if (m_Flip != RotateNoneFlipNone || m_Rotate != 0.0f)
- {
- m_NeedsTransform = true;
- }
- }
- }
- }
-
- pStream->Release();
- }
- }
- }
- else
- {
- DebugLog(L"Failed to allocate memory: %i bytes", imageSize);
- }
- }
+ m_H = (imageW == 0) ? 0 : (int)(m_W * imageH / (double)imageW);
}
- CloseHandle(fileHandle);
}
else
{
- DebugLog(L"Unable to load image: %s", filename.c_str());
- }
-
- if (m_Bitmap)
- {
- // We need a copy of the image if has tinting (or flipping, rotating)
- if (m_NeedsTinting || m_NeedsTransform)
+ if (m_HeightDefined)
{
- ApplyTint();
- m_NeedsTinting = false;
-
- ApplyTransform();
- m_NeedsTransform = false;
- }
-
- Bitmap* bitmap = (m_BitmapTint) ? m_BitmapTint : m_Bitmap;
-
- // Calculate size of the meter
- int imageW = bitmap->GetWidth();
- int imageH = bitmap->GetHeight();
-
- if (m_WidthDefined)
- {
- if (!m_HeightDefined)
- {
- m_H = (imageW == 0) ? 0 : m_W * imageH / imageW;
- }
+ m_W = (imageH == 0) ? 0 : (int)(m_H * imageW / (double)imageH);
}
else
{
- if (m_HeightDefined)
- {
- m_W = (imageH == 0) ? 0 : m_H * imageW / imageH;
- }
- else
- {
- m_W = imageW;
- m_H = imageH;
- }
+ m_W = imageW;
+ m_H = imageH;
}
}
}
- else
- {
- if (m_Bitmap)
- {
- delete m_Bitmap;
- m_Bitmap = NULL;
- }
- if (m_BitmapTint)
- {
- delete m_BitmapTint;
- m_BitmapTint = NULL;
- }
- }
-}
-
-/*
-** ApplyTint
-**
-** This will apply the Greyscale matrix and the color tinting.
-**
-*/
-void CMeterImage::ApplyTint()
-{
- ImageAttributes ImgAttr;
- ImgAttr.SetColorMatrix(&m_ColorMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);
-
- if (m_BitmapTint) 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)
- {
- Bitmap* gray = TurnGreyscale();
- 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);
- }
-}
-
-/*
-** TurnGreyscale
-**
-** Turns the image greyscale by applying a greyscale color matrix.
-** Note that the returned bitmap image must be freed by caller.
-**
-*/
-Bitmap* CMeterImage::TurnGreyscale()
-{
- ImageAttributes ImgAttr;
- ImgAttr.SetColorMatrix(&c_GreyScaleMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);
-
- // We need a blank bitmap to paint our greyscale to in case of alpha
- Rect r(0, 0, m_Bitmap->GetWidth(), m_Bitmap->GetHeight());
- Bitmap* bitmap = new Bitmap(r.Width, r.Height, PixelFormat32bppARGB);
-
- Graphics graphics(bitmap);
- graphics.DrawImage(m_Bitmap, r, 0, 0, r.Width, r.Height, UnitPixel, &ImgAttr);
-
- return bitmap;
-}
-
-/*
-** ApplyTransform
-**
-** This will apply the flipping and rotating.
-**
-*/
-void CMeterImage::ApplyTransform()
-{
- if (m_Rotate != 0.0f)
- {
- Bitmap* original = (m_BitmapTint) ? m_BitmapTint : m_Bitmap;
-
- REAL originalW = (REAL)original->GetWidth();
- REAL originalH = (REAL)original->GetHeight();
-
- REAL cos_f = cos(m_Rotate * PI / 180.0f), sin_f = sin(m_Rotate * PI / 180.0f);
-
- REAL transformW = fabs(originalW * cos_f) + fabs(originalH * sin_f);
- REAL transformH = fabs(originalW * sin_f) + fabs(originalH * cos_f);
-
- Bitmap* transform = new Bitmap((int)(transformW + 0.5f), (int)(transformH + 0.5f), PixelFormat32bppARGB);
-
- Graphics graphics(transform);
- graphics.SetPixelOffsetMode(PixelOffsetModeHighQuality);
-
- REAL cx = transformW / 2.0f;
- REAL cy = transformH / 2.0f;
-
- Matrix rotateMatrix;
- rotateMatrix.RotateAt(m_Rotate, PointF(cx, cy));
-
- graphics.SetTransform(&rotateMatrix);
-
- if (m_Flip != RotateNoneFlipNone)
- {
- original->RotateFlip(m_Flip);
- }
-
- RectF r(cx - originalW / 2.0f, cy - originalH / 2.0f, originalW, originalH);
- graphics.DrawImage(original, r, -0.5f, -0.5f, originalW + 1.0f, originalH + 1.0f, UnitPixel); // Makes the anti-aliased edge
-
- if (m_Flip != RotateNoneFlipNone)
- {
- original->RotateFlip(RotateNoneFlipNone);
- }
-
- if (m_BitmapTint) delete m_BitmapTint;
- m_BitmapTint = transform;
- }
- else if (m_Flip != RotateNoneFlipNone)
- {
- Bitmap* original = (m_BitmapTint) ? m_BitmapTint : m_Bitmap;
-
- Rect r(0, 0, original->GetWidth(), original->GetHeight());
- Bitmap* transform = new Bitmap(r.Width, r.Height, PixelFormat32bppARGB);
-
- Graphics graphics(transform);
-
- original->RotateFlip(m_Flip);
-
- graphics.DrawImage(original, r, 0, 0, r.Width, r.Height, UnitPixel);
-
- original->RotateFlip(RotateNoneFlipNone);
-
- if (m_BitmapTint) delete m_BitmapTint;
- m_BitmapTint = transform;
- }
}
/*
@@ -393,12 +111,6 @@ void CMeterImage::ApplyTransform()
*/
void CMeterImage::ReadConfig(const WCHAR* section)
{
- // Store the current values so we know if the image needs to be tinted or transformed
- bool oldGreyScale = m_GreyScale;
- ColorMatrix oldColorMatrix = m_ColorMatrix;
- RotateFlipType oldFlip = m_Flip;
- REAL oldRotate = m_Rotate;
-
// Read common configs
CMeter::ReadConfig(section);
@@ -433,147 +145,17 @@ void CMeterImage::ReadConfig(const WCHAR* section)
m_PreserveAspectRatio = 0!=parser.ReadInt(section, L"PreserveAspectRatio", 0);
- if (-1 != (int)parser.ReadFormula(section, m_ImageWidthString.c_str(), -1))
+ if (-1 != (int)parser.ReadFormula(section, L"W", -1))
{
m_WidthDefined = true;
}
- if (-1 != (int)parser.ReadFormula(section, m_ImageHeightString.c_str(), -1))
+ if (-1 != (int)parser.ReadFormula(section, L"H", -1))
{
m_HeightDefined = true;
}
- m_GreyScale = 0!=parser.ReadInt(section, L"Greyscale", 0);
-
- Color tint = parser.ReadColor(section, L"ImageTint", Color::White);
- int alpha = parser.ReadInt(section, L"ImageAlpha", tint.GetAlpha()); // for backwards compatibility
- alpha = min(255, alpha);
- alpha = max(0, alpha);
-
- if (alpha != tint.GetAlpha())
- {
- tint.SetValue(Color::MakeARGB(alpha, tint.GetRed(), tint.GetGreen(), tint.GetBlue()));
- }
-
- m_ColorMatrix = c_IdentifyMatrix;
-
- // Read in the Color Matrix
- // It has to be read in like this because it crashes when reading over 17 floats
- // at one time. The parser does it fine, but after putting the returned values
- // into the Color Matrix the next time the parser is used it crashes.
- std::vector matrix = parser.ReadFloats(section, L"ColorMatrix1");
- if (matrix.size() == 5)
- {
- for (int i = 0; i < 5; ++i)
- {
- m_ColorMatrix.m[0][i] = matrix[i];
- }
- }
- else
- {
- m_ColorMatrix.m[0][0] = (REAL)tint.GetRed() / 255.0f;
- }
-
- matrix = parser.ReadFloats(section, L"ColorMatrix2");
- if (matrix.size() == 5)
- {
- for(int i = 0; i < 5; ++i)
- {
- m_ColorMatrix.m[1][i] = matrix[i];
- }
- }
- else
- {
- m_ColorMatrix.m[1][1] = (REAL)tint.GetGreen() / 255.0f;
- }
-
- matrix = parser.ReadFloats(section, L"ColorMatrix3");
- if (matrix.size() == 5)
- {
- for(int i = 0; i < 5; ++i)
- {
- m_ColorMatrix.m[2][i] = matrix[i];
- }
- }
- else
- {
- m_ColorMatrix.m[2][2] = (REAL)tint.GetBlue() / 255.0f;
- }
-
- matrix = parser.ReadFloats(section, L"ColorMatrix4");
- if (matrix.size() == 5)
- {
- for(int i = 0; i < 5; ++i)
- {
- m_ColorMatrix.m[3][i] = matrix[i];
- }
- }
- else
- {
- m_ColorMatrix.m[3][3] = (REAL)tint.GetAlpha() / 255.0f;
- }
-
- matrix = parser.ReadFloats(section, L"ColorMatrix5");
- if (matrix.size() == 5)
- {
- for(int i = 0; i < 5; ++i)
- {
- m_ColorMatrix.m[4][i] = matrix[i];
- }
- }
-
- m_NeedsTinting = (oldGreyScale != m_GreyScale || !CompareColorMatrix(oldColorMatrix, m_ColorMatrix));
-
- std::wstring flip = parser.ReadString(section, L"ImageFlip", L"NONE");
-
- if(_wcsicmp(flip.c_str(), L"NONE") == 0)
- {
- m_Flip = RotateNoneFlipNone;
- }
- else if(_wcsicmp(flip.c_str(), L"HORIZONTAL") == 0)
- {
- m_Flip = RotateNoneFlipX;
- }
- else if(_wcsicmp(flip.c_str(), L"VERTICAL") == 0)
- {
- m_Flip = RotateNoneFlipY;
- }
- else if(_wcsicmp(flip.c_str(), L"BOTH") == 0)
- {
- m_Flip = RotateNoneFlipXY;
- }
- else
- {
- std::wstring error = L"ImageFlip=" + flip;
- error += L" is not valid in meter [";
- error += m_Name;
- error += L"].";
- throw CError(error, __LINE__, __FILE__);
- }
-
- m_Rotate = (REAL)parser.ReadFloat(section, L"ImageRotate", 0.0);
-
- m_NeedsTransform = (oldFlip != m_Flip || oldRotate != m_Rotate);
-}
-
-/*
-** CompareColorMatrix
-**
-** Compares the two given color matrices.
-**
-*/
-bool CMeterImage::CompareColorMatrix(const Gdiplus::ColorMatrix& a, const Gdiplus::ColorMatrix& b)
-{
- for (int i = 0; i < 5; ++i)
- {
- for (int j = 0; j < 5; ++j)
- {
- if (a.m[i][j] != b.m[i][j])
- {
- return false;
- }
- }
- }
- return true;
+ // Read tinting configs
+ m_Image.ReadConfig(parser, section);
}
/*
@@ -603,6 +185,10 @@ bool CMeterImage::Update()
LoadImage(false);
}
}
+ else if (m_Image.IsLoaded())
+ {
+ m_Image.DisposeImage();
+ }
return true;
}
else if (m_DynamicVariables) //read from the skin
@@ -624,11 +210,11 @@ bool CMeterImage::Draw(Graphics& graphics)
{
if(!CMeter::Draw(graphics)) return false;
- if (m_Bitmap != NULL)
+ if (m_Image.IsLoaded())
{
- Bitmap* drawBitmap = (m_BitmapTint) ? m_BitmapTint : m_Bitmap;
-
// Copy the image over the doublebuffer
+ Bitmap* drawBitmap = m_Image.GetImage();
+
int x = GetX();
int y = GetY();
int imageW = drawBitmap->GetWidth();
diff --git a/Library/MeterImage.h b/Library/MeterImage.h
index 90fe128b..51dda371 100644
--- a/Library/MeterImage.h
+++ b/Library/MeterImage.h
@@ -20,17 +20,13 @@
#define __METERIMAGE_H__
#include "Meter.h"
+#include "TintedImage.h"
#include "MeterWindow.h"
-namespace Gdiplus
-{
- class Bitmap;
-};
-
class CMeterImage : public CMeter
{
public:
- CMeterImage(CMeterWindow* meterWindow, WCHAR* wName = L"W", WCHAR* hName = L"H");
+ CMeterImage(CMeterWindow* meterWindow);
virtual ~CMeterImage();
virtual void ReadConfig(const WCHAR* section);
@@ -41,34 +37,15 @@ public:
protected:
void LoadImage(bool bLoadAlways);
- bool CompareColorMatrix(const Gdiplus::ColorMatrix& a, const Gdiplus::ColorMatrix& b);
- void ApplyTint();
- Gdiplus::Bitmap* TurnGreyscale();
- void ApplyTransform();
-
- const std::wstring m_ImageWidthString;
- const std::wstring m_ImageHeightString;
- Gdiplus::Bitmap* m_Bitmap; // The bitmap
- Gdiplus::Bitmap* m_BitmapTint; // The bitmap
+ CTintedImage m_Image;
std::wstring m_ImageName; // Name of the image
std::wstring m_Path;
+
bool m_NeedsReload;
- bool m_NeedsTinting;
- bool m_NeedsTransform;
bool m_WidthDefined;
bool m_HeightDefined;
bool m_PreserveAspectRatio; // If true, aspect ratio of the image is preserved when the image is scaled
- HGLOBAL m_hBuffer;
- FILETIME m_Modified;
-
- bool m_GreyScale;
- Gdiplus::ColorMatrix m_ColorMatrix;
- Gdiplus::RotateFlipType m_Flip;
- Gdiplus::REAL m_Rotate;
-
- static const Gdiplus::ColorMatrix c_GreyScaleMatrix;
- static const Gdiplus::ColorMatrix c_IdentifyMatrix;
};
#endif
diff --git a/Library/MeterRotator.cpp b/Library/MeterRotator.cpp
index 6e5e5ab1..2fea4295 100644
--- a/Library/MeterRotator.cpp
+++ b/Library/MeterRotator.cpp
@@ -33,8 +33,9 @@ extern CRainmeter* Rainmeter;
** The constructor
**
*/
-CMeterRotator::CMeterRotator(CMeterWindow* meterWindow) : CMeterImage(meterWindow, L"ImageW", L"ImageH")
+CMeterRotator::CMeterRotator(CMeterWindow* meterWindow) : CMeter(meterWindow)
{
+ m_NeedsReload = false;
m_Value = 0.0;
}
@@ -61,24 +62,11 @@ void CMeterRotator::Initialize()
// Load the bitmaps if defined
if(!m_ImageName.empty())
{
- // Since loading the image redefines the width of the meter we must
- // store the width and height that were defined.
- int Height, Width;
- Height = m_H;
- Width = m_W;
-
- LoadImage(false);
-
- m_W = Width;
- m_H = Height;
+ m_Image.LoadImage(m_ImageName, m_NeedsReload);
}
- else
+ else if (m_Image.IsLoaded())
{
- if (m_Bitmap)
- {
- delete m_Bitmap;
- m_Bitmap = NULL;
- }
+ m_Image.DisposeImage();
}
}
@@ -94,7 +82,7 @@ void CMeterRotator::ReadConfig(const WCHAR* section)
std::wstring oldImageName = m_ImageName;
// Read common configs
- CMeterImage::ReadConfig(section);
+ CMeter::ReadConfig(section);
CConfigParser& parser = m_MeterWindow->GetParser();
@@ -102,6 +90,13 @@ void CMeterRotator::ReadConfig(const WCHAR* section)
if (!m_ImageName.empty())
{
m_ImageName = m_MeterWindow->MakePathAbsolute(m_ImageName);
+
+ // Read tinting configs
+ m_Image.ReadConfig(parser, section);
+ }
+ else
+ {
+ m_Image.ClearConfigFlags();
}
m_OffsetX = parser.ReadFloat(section, L"OffsetX", 0.0);
@@ -112,9 +107,15 @@ void CMeterRotator::ReadConfig(const WCHAR* section)
m_ValueRemainder = parser.ReadInt(section, L"ValueReminder", 0); // Typo
m_ValueRemainder = parser.ReadInt(section, L"ValueRemainder", m_ValueRemainder);
- if (m_Initialized && oldImageName != m_ImageName || m_NeedsTinting || m_NeedsTransform)
+ if (m_Initialized)
{
- Initialize(); // Reload the image
+ m_NeedsReload = (oldImageName != m_ImageName);
+
+ if (m_NeedsReload ||
+ m_Image.IsConfigsChanged())
+ {
+ Initialize(); // Reload the image
+ }
}
}
@@ -155,34 +156,34 @@ bool CMeterRotator::Draw(Graphics& graphics)
{
if(!CMeter::Draw(graphics)) return false;
- // Calculate the center for rotation
- int x = GetX();
- int y = GetY();
-
- REAL cx = (REAL)(x + m_W / 2.0);
- REAL cy = (REAL)(y + m_H / 2.0);
-
- // Calculate the rotation
- REAL angle = (REAL)(m_RotationAngle * m_Value + m_StartAngle);
-
- angle = angle * 180.0f / 3.14159265f; // Convert to degrees
-
- graphics.TranslateTransform(cx, cy);
- graphics.RotateTransform(angle);
- graphics.TranslateTransform((REAL)-m_OffsetX, (REAL)-m_OffsetY);
-
- Bitmap* drawBitmap = (m_BitmapTint) ? m_BitmapTint : m_Bitmap;
-
- if(drawBitmap)
+ if (m_Image.IsLoaded())
{
+ // Calculate the center for rotation
+ int x = GetX();
+ int y = GetY();
+
+ REAL cx = (REAL)(x + m_W / 2.0);
+ REAL cy = (REAL)(y + m_H / 2.0);
+
+ // Calculate the rotation
+ REAL angle = (REAL)(m_RotationAngle * m_Value + m_StartAngle);
+
+ angle = angle * 180.0f / 3.14159265f; // Convert to degrees
+
+ graphics.TranslateTransform(cx, cy);
+ graphics.RotateTransform(angle);
+ graphics.TranslateTransform((REAL)-m_OffsetX, (REAL)-m_OffsetY);
+
+ Bitmap* drawBitmap = m_Image.GetImage();
+
UINT width = drawBitmap->GetWidth();
UINT height = drawBitmap->GetHeight();
// Blit the image
graphics.DrawImage(drawBitmap, 0, 0, width, height);
+
+ graphics.ResetTransform();
}
- graphics.ResetTransform();
return true;
}
-
diff --git a/Library/MeterRotator.h b/Library/MeterRotator.h
index d7876be0..b91aa0b7 100644
--- a/Library/MeterRotator.h
+++ b/Library/MeterRotator.h
@@ -19,9 +19,11 @@
#ifndef __METERROTATOR_H__
#define __METERROTATOR_H__
-#include "MeterImage.h"
+#include "Meter.h"
+#include "TintedImage.h"
+#include "MeterWindow.h"
-class CMeterRotator : public CMeterImage
+class CMeterRotator : public CMeter
{
public:
CMeterRotator(CMeterWindow* meterWindow);
@@ -33,6 +35,9 @@ public:
virtual bool Draw(Gdiplus::Graphics& graphics);
private:
+ CTintedImage m_Image;
+ std::wstring m_ImageName; // Name of the image
+ bool m_NeedsReload;
double m_OffsetX;
double m_OffsetY;
diff --git a/Library/TintedImage.cpp b/Library/TintedImage.cpp
new file mode 100644
index 00000000..9b53eab4
--- /dev/null
+++ b/Library/TintedImage.cpp
@@ -0,0 +1,524 @@
+/*
+ Copyright (C) 2010 Kimmo Pekkola, MattKing, spx
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "StdAfx.h"
+#include "TintedImage.h"
+#include "Error.h"
+#include "Litestep.h"
+
+using namespace Gdiplus;
+
+#define PI 3.14159265f
+
+// GrayScale Matrix
+const Gdiplus::ColorMatrix CTintedImage::c_GreyScaleMatrix = {
+ 0.299f, 0.299f, 0.299f, 0.0f, 0.0f,
+ 0.587f, 0.587f, 0.587f, 0.0f, 0.0f,
+ 0.114f, 0.114f, 0.114f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
+};
+
+const Gdiplus::ColorMatrix CTintedImage::c_IdentifyMatrix = {
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
+};
+
+/*
+** CTintedImage
+**
+** The constructor.
+**
+** If disableTransform is true, following configs are ignored:
+** - ImageRotate
+**
+*/
+CTintedImage::CTintedImage(bool disableTransform) : m_DisableTransform(disableTransform),
+ m_ColorMatrix(c_IdentifyMatrix)
+{
+ SetConfigAttributes(L"Image", L"");
+
+ m_Bitmap = NULL;
+ m_BitmapTint = NULL;
+
+ m_hBuffer = NULL;
+ m_Modified.dwHighDateTime = 0;
+ m_Modified.dwLowDateTime = 0;
+
+ m_NeedsTinting = false;
+ m_NeedsTransform = false;
+
+ m_GreyScale = false;
+ m_Flip = RotateNoneFlipNone;
+ m_Rotate = 0.0f;
+}
+
+/*
+** ~CTintedImage
+**
+** The destructor
+**
+*/
+CTintedImage::~CTintedImage()
+{
+ DisposeImage();
+}
+
+/*
+** DisposeImage
+**
+** Disposes the image buffers.
+**
+*/
+void CTintedImage::DisposeImage()
+{
+ delete m_Bitmap;
+ m_Bitmap = NULL;
+
+ delete m_BitmapTint;
+ m_BitmapTint = NULL;
+
+ if (m_hBuffer)
+ {
+ ::GlobalFree(m_hBuffer);
+ m_hBuffer = NULL;
+ }
+
+ m_Modified.dwHighDateTime = 0;
+ m_Modified.dwLowDateTime = 0;
+}
+
+/*
+** LoadImage
+**
+** Loads the image from disk
+**
+*/
+void CTintedImage::LoadImage(const std::wstring& imageName, bool bLoadAlways)
+{
+ // Load the bitmap if defined
+ if (!imageName.empty())
+ {
+ std::wstring filename = imageName;
+
+ // Check extension and if it is missing, add .png
+ size_t pos = filename.find_last_of(L"\\");
+ if (pos == std::wstring::npos) pos = 0;
+ if (std::wstring::npos == filename.find(L'.', pos))
+ {
+ filename += L".png";
+ }
+
+ // Read the bitmap to memory so that it's not locked by GDI+
+ HANDLE fileHandle = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+ if (fileHandle != INVALID_HANDLE_VALUE)
+ {
+ // Compare the timestamp and filename to check if the file has been changed (don't load if it's not)
+ FILETIME tmpTime;
+ GetFileTime(fileHandle, NULL, NULL, &tmpTime);
+ if (bLoadAlways || CompareFileTime(&tmpTime, &m_Modified) != 0)
+ {
+ DisposeImage();
+ m_Modified = tmpTime;
+
+ DWORD imageSize = GetFileSize(fileHandle, NULL);
+
+ if (imageSize != INVALID_FILE_SIZE)
+ {
+ m_hBuffer = ::GlobalAlloc(GMEM_MOVEABLE, imageSize);
+ if (m_hBuffer)
+ {
+ void* pBuffer = ::GlobalLock(m_hBuffer);
+ if (pBuffer)
+ {
+ DWORD readBytes;
+ ReadFile(fileHandle, pBuffer, imageSize, &readBytes, NULL);
+ ::GlobalUnlock(m_hBuffer);
+
+ IStream* pStream = NULL;
+ if (::CreateStreamOnHGlobal(m_hBuffer, FALSE, &pStream) == S_OK)
+ {
+ m_Bitmap = Bitmap::FromStream(pStream);
+ pStream->Release();
+
+ if (m_Bitmap && Ok == m_Bitmap->GetLastStatus())
+ {
+ // Check whether the new image needs tinting (or flipping, rotating)
+ if (!m_NeedsTinting)
+ {
+ if (m_GreyScale || !CompareColorMatrix(m_ColorMatrix, c_IdentifyMatrix))
+ {
+ m_NeedsTinting = true;
+ }
+ }
+ if (!m_NeedsTransform)
+ {
+ if (m_Flip != RotateNoneFlipNone || m_Rotate != 0.0f)
+ {
+ m_NeedsTransform = true;
+ }
+ }
+ }
+ else // failed
+ {
+ delete m_Bitmap;
+ m_Bitmap = NULL;
+ }
+ }
+ }
+
+ if (!m_Bitmap)
+ {
+ DebugLog(L"Unable to create %s: %s", m_ConfigName.c_str(), filename.c_str());
+ DisposeImage();
+ }
+ }
+ else
+ {
+ DebugLog(L"Unable to allocate memory ( %i bytes ) for %s: %s", imageSize, m_ConfigName.c_str(), filename.c_str());
+ }
+ }
+ else
+ {
+ DebugLog(L"Unable to get %s's file size: %s", m_ConfigName.c_str(), filename.c_str());
+ }
+ }
+ CloseHandle(fileHandle);
+ }
+ else
+ {
+ DebugLog(L"Unable to load %s: %s", m_ConfigName.c_str(), filename.c_str());
+ DisposeImage();
+ }
+
+ if (m_Bitmap)
+ {
+ // We need a copy of the image if has tinting (or flipping, rotating)
+ if (m_NeedsTinting || m_NeedsTransform)
+ {
+ ApplyTint();
+ m_NeedsTinting = false;
+
+ ApplyTransform();
+ m_NeedsTransform = false;
+ }
+ }
+ }
+ else if (IsLoaded())
+ {
+ DisposeImage();
+ }
+}
+
+/*
+** ApplyTint
+**
+** This will apply the Greyscale matrix and the color tinting.
+**
+*/
+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)
+ {
+ 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);
+ }
+}
+
+/*
+** TurnGreyscale
+**
+** Turns the image greyscale by applying a greyscale color matrix.
+** Note that the returned bitmap image must be freed by caller.
+**
+*/
+Bitmap* CTintedImage::TurnGreyscale(Bitmap* source)
+{
+ ImageAttributes ImgAttr;
+ ImgAttr.SetColorMatrix(&c_GreyScaleMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);
+
+ // We need a blank bitmap to paint our greyscale to in case of alpha
+ Rect r(0, 0, source->GetWidth(), source->GetHeight());
+ Bitmap* bitmap = new Bitmap(r.Width, r.Height, PixelFormat32bppARGB);
+
+ Graphics graphics(bitmap);
+ graphics.DrawImage(source, r, 0, 0, r.Width, r.Height, UnitPixel, &ImgAttr);
+
+ return bitmap;
+}
+
+/*
+** ApplyTransform
+**
+** This will apply the flipping and rotating.
+**
+*/
+void CTintedImage::ApplyTransform()
+{
+ if (m_Rotate != 0.0f)
+ {
+ Bitmap* original = (m_BitmapTint) ? m_BitmapTint : m_Bitmap;
+
+ REAL originalW = (REAL)original->GetWidth();
+ REAL originalH = (REAL)original->GetHeight();
+
+ REAL cos_f = cos(m_Rotate * PI / 180.0f), sin_f = sin(m_Rotate * PI / 180.0f);
+
+ REAL transformW = fabs(originalW * cos_f) + fabs(originalH * sin_f);
+ REAL transformH = fabs(originalW * sin_f) + fabs(originalH * cos_f);
+
+ Bitmap* transform = new Bitmap((int)(transformW + 0.5f), (int)(transformH + 0.5f), PixelFormat32bppARGB);
+
+ Graphics graphics(transform);
+ graphics.SetPixelOffsetMode(PixelOffsetModeHighQuality);
+
+ REAL cx = transformW / 2.0f;
+ REAL cy = transformH / 2.0f;
+
+ Matrix rotateMatrix;
+ rotateMatrix.RotateAt(m_Rotate, PointF(cx, cy));
+
+ graphics.SetTransform(&rotateMatrix);
+
+ if (m_Flip != RotateNoneFlipNone)
+ {
+ original->RotateFlip(m_Flip);
+ }
+
+ RectF r(cx - originalW / 2.0f, cy - originalH / 2.0f, originalW, originalH);
+ graphics.DrawImage(original, r, -0.5f, -0.5f, originalW + 1.0f, originalH + 1.0f, UnitPixel); // Makes the anti-aliased edge
+
+ if (m_Flip != RotateNoneFlipNone)
+ {
+ original->RotateFlip(RotateNoneFlipNone);
+ }
+
+ delete m_BitmapTint;
+ m_BitmapTint = transform;
+ }
+ else if (m_Flip != RotateNoneFlipNone)
+ {
+ Bitmap* original = (m_BitmapTint) ? m_BitmapTint : m_Bitmap;
+
+ Rect r(0, 0, original->GetWidth(), original->GetHeight());
+ Bitmap* transform = new Bitmap(r.Width, r.Height, PixelFormat32bppARGB);
+
+ Graphics graphics(transform);
+
+ original->RotateFlip(m_Flip);
+
+ graphics.DrawImage(original, r, 0, 0, r.Width, r.Height, UnitPixel);
+
+ original->RotateFlip(RotateNoneFlipNone);
+
+ delete m_BitmapTint;
+ m_BitmapTint = transform;
+ }
+}
+
+/*
+** SetConfigAttributes
+**
+** Sets own attributes.
+**
+*/
+void CTintedImage::SetConfigAttributes(const WCHAR* name, const WCHAR* prefix)
+{
+ if (name)
+ {
+ m_ConfigName = name;
+ }
+
+ if (prefix)
+ {
+ (m_ConfigGreyscale = prefix) += L"Greyscale";
+ (m_ConfigImageTint = prefix) += L"ImageTint";
+ (m_ConfigImageAlpha = prefix) += L"ImageAlpha";
+ (m_ConfigColorMatrix1 = prefix) += L"ColorMatrix1";
+ (m_ConfigColorMatrix2 = prefix) += L"ColorMatrix2";
+ (m_ConfigColorMatrix3 = prefix) += L"ColorMatrix3";
+ (m_ConfigColorMatrix4 = prefix) += L"ColorMatrix4";
+ (m_ConfigColorMatrix5 = prefix) += L"ColorMatrix5";
+ (m_ConfigImageFlip = prefix) += L"ImageFlip";
+ (m_ConfigImageRotate = prefix) += L"ImageRotate";
+ }
+}
+
+/*
+** ReadConfig
+**
+** Read the meter-specific configs from the ini-file.
+**
+*/
+void CTintedImage::ReadConfig(CConfigParser& parser, const WCHAR* section)
+{
+ // Store the current values so we know if the image needs to be tinted or transformed
+ bool oldGreyScale = m_GreyScale;
+ ColorMatrix oldColorMatrix = m_ColorMatrix;
+ RotateFlipType oldFlip = m_Flip;
+ REAL oldRotate = m_Rotate;
+
+ m_GreyScale = 0!=parser.ReadInt(section, m_ConfigGreyscale.c_str(), 0);
+
+ Color tint = parser.ReadColor(section, m_ConfigImageTint.c_str(), Color::White);
+ int alpha = parser.ReadInt(section, m_ConfigImageAlpha.c_str(), tint.GetAlpha()); // for backwards compatibility
+ alpha = min(255, alpha);
+ alpha = max(0, alpha);
+
+ m_ColorMatrix = c_IdentifyMatrix;
+
+ // Read in the Color Matrix
+ // It has to be read in like this because it crashes when reading over 17 floats
+ // at one time. The parser does it fine, but after putting the returned values
+ // into the Color Matrix the next time the parser is used it crashes.
+ std::vector matrix = parser.ReadFloats(section, m_ConfigColorMatrix1.c_str());
+ if (matrix.size() == 5)
+ {
+ for (int i = 0; i < 5; ++i)
+ {
+ m_ColorMatrix.m[0][i] = matrix[i];
+ }
+ }
+ else
+ {
+ m_ColorMatrix.m[0][0] = (REAL)tint.GetRed() / 255.0f;
+ }
+
+ matrix = parser.ReadFloats(section, m_ConfigColorMatrix2.c_str());
+ if (matrix.size() == 5)
+ {
+ for(int i = 0; i < 5; ++i)
+ {
+ m_ColorMatrix.m[1][i] = matrix[i];
+ }
+ }
+ else
+ {
+ m_ColorMatrix.m[1][1] = (REAL)tint.GetGreen() / 255.0f;
+ }
+
+ matrix = parser.ReadFloats(section, m_ConfigColorMatrix3.c_str());
+ if (matrix.size() == 5)
+ {
+ for(int i = 0; i < 5; ++i)
+ {
+ m_ColorMatrix.m[2][i] = matrix[i];
+ }
+ }
+ else
+ {
+ m_ColorMatrix.m[2][2] = (REAL)tint.GetBlue() / 255.0f;
+ }
+
+ matrix = parser.ReadFloats(section, m_ConfigColorMatrix4.c_str());
+ if (matrix.size() == 5)
+ {
+ for(int i = 0; i < 5; ++i)
+ {
+ m_ColorMatrix.m[3][i] = matrix[i];
+ }
+ }
+ else
+ {
+ m_ColorMatrix.m[3][3] = (REAL)alpha / 255.0f;
+ }
+
+ matrix = parser.ReadFloats(section, m_ConfigColorMatrix5.c_str());
+ if (matrix.size() == 5)
+ {
+ for(int i = 0; i < 5; ++i)
+ {
+ m_ColorMatrix.m[4][i] = matrix[i];
+ }
+ }
+
+ m_NeedsTinting = (oldGreyScale != m_GreyScale || !CompareColorMatrix(oldColorMatrix, m_ColorMatrix));
+
+ std::wstring flip = parser.ReadString(section, m_ConfigImageFlip.c_str(), L"NONE");
+ if(_wcsicmp(flip.c_str(), L"NONE") == 0)
+ {
+ m_Flip = RotateNoneFlipNone;
+ }
+ else if(_wcsicmp(flip.c_str(), L"HORIZONTAL") == 0)
+ {
+ m_Flip = RotateNoneFlipX;
+ }
+ else if(_wcsicmp(flip.c_str(), L"VERTICAL") == 0)
+ {
+ m_Flip = RotateNoneFlipY;
+ }
+ else if(_wcsicmp(flip.c_str(), L"BOTH") == 0)
+ {
+ m_Flip = RotateNoneFlipXY;
+ }
+ else
+ {
+ std::wstring error = m_ConfigImageFlip + L"=";
+ error += flip;
+ error += L" is not valid in meter [";
+ error += section;
+ error += L"].";
+ throw CError(error, __LINE__, __FILE__);
+ }
+
+ if (!m_DisableTransform)
+ {
+ m_Rotate = (REAL)parser.ReadFloat(section, m_ConfigImageRotate.c_str(), 0.0);
+ }
+
+ m_NeedsTransform = (oldFlip != m_Flip || oldRotate != m_Rotate);
+}
+
+/*
+** CompareColorMatrix
+**
+** Compares the two given color matrices.
+**
+*/
+bool CTintedImage::CompareColorMatrix(const Gdiplus::ColorMatrix& a, const Gdiplus::ColorMatrix& b)
+{
+ for (int i = 0; i < 5; ++i)
+ {
+ for (int j = 0; j < 5; ++j)
+ {
+ if (a.m[i][j] != b.m[i][j])
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
diff --git a/Library/TintedImage.h b/Library/TintedImage.h
new file mode 100644
index 00000000..469f8f55
--- /dev/null
+++ b/Library/TintedImage.h
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2010 Kimmo Pekkola, MattKing, spx
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __TINTEDIMAGE_H__
+#define __TINTEDIMAGE_H__
+
+#include "Meter.h"
+#include "MeterWindow.h"
+
+class CTintedImage
+{
+public:
+ CTintedImage(bool disableTransform = false);
+ virtual ~CTintedImage();
+
+ void SetConfigAttributes(const WCHAR* name, const WCHAR* prefix);
+ void ReadConfig(CConfigParser& parser, const WCHAR* section);
+
+ 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; }
+
+ Gdiplus::Bitmap* GetOriginalImage() { return m_Bitmap; }
+ Gdiplus::Bitmap* GetTintedImage() { return m_BitmapTint; }
+ Gdiplus::Bitmap* GetImage() { return (m_BitmapTint) ? m_BitmapTint : m_Bitmap; }
+
+ void DisposeImage();
+ void LoadImage(const std::wstring& imageName, bool bLoadAlways);
+
+protected:
+ void ApplyTint();
+ void ApplyTransform();
+
+ static Gdiplus::Bitmap* TurnGreyscale(Gdiplus::Bitmap* source);
+ static bool CompareColorMatrix(const Gdiplus::ColorMatrix& a, const Gdiplus::ColorMatrix& b);
+
+ Gdiplus::Bitmap* m_Bitmap; // The bitmap
+ Gdiplus::Bitmap* m_BitmapTint; // The tinted bitmap
+
+ HGLOBAL m_hBuffer;
+ FILETIME m_Modified;
+
+ std::wstring m_ConfigName;
+ std::wstring m_ConfigGreyscale;
+ std::wstring m_ConfigImageTint;
+ std::wstring m_ConfigImageAlpha;
+ std::wstring m_ConfigColorMatrix1;
+ std::wstring m_ConfigColorMatrix2;
+ std::wstring m_ConfigColorMatrix3;
+ std::wstring m_ConfigColorMatrix4;
+ std::wstring m_ConfigColorMatrix5;
+ std::wstring m_ConfigImageFlip;
+ std::wstring m_ConfigImageRotate;
+
+ const bool m_DisableTransform;
+
+ bool m_NeedsTinting;
+ bool m_NeedsTransform;
+
+ bool m_GreyScale;
+ Gdiplus::ColorMatrix m_ColorMatrix;
+ Gdiplus::RotateFlipType m_Flip;
+ Gdiplus::REAL m_Rotate;
+
+ static const Gdiplus::ColorMatrix c_GreyScaleMatrix;
+ static const Gdiplus::ColorMatrix c_IdentifyMatrix;
+};
+
+#endif