rainmeter-studio/Library/MeterButton.cpp
spx 64888434c9 - Added !RainmeterWriteKeyValue. (based on MattKing's code)
!RainmeterWriteKeyValue "Section" "Key" "Value" ("FileSpec"), where "FileSpec" is an optional parameter. If FileSpec is not present, the change is automatically done in the currently running skin file. If the bang is executed from command line, FileSpec is required.

- Some improvements of MouseOver/Leave detection.

- Fixed the issue that window dragging brings on MouseLeave if "Show window contents while dragging" is not set.
- Fixed the issue that window dragging can't be begun by dragging the Button.
- Fixed the issue that a reaction of the upper Button penetrates to the lower Buttons or the other window.
2010-08-03 15:10:42 +00:00

359 lines
6.8 KiB
C++

/*
Copyright (C) 2005 Kimmo Pekkola
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 "MeterButton.h"
#include "Measure.h"
#include "Rainmeter.h"
#include "Error.h"
extern CRainmeter* Rainmeter;
using namespace Gdiplus;
enum BUTTON_STATE
{
BUTTON_STATE_NORMAL,
BUTTON_STATE_DOWN,
BUTTON_STATE_HOVER
};
/*
** CMeterButton
**
** The constructor
**
*/
CMeterButton::CMeterButton(CMeterWindow* meterWindow) : CMeter(meterWindow)
{
for (int i = 0; i < BUTTON_FRAMES; ++i)
{
m_Bitmaps[i] = NULL;
}
m_Bitmap = NULL;
m_State = BUTTON_STATE_NORMAL;
m_Clicked = false;
}
/*
** ~CMeterButton
**
** The destructor
**
*/
CMeterButton::~CMeterButton()
{
for (int i = 0; i < BUTTON_FRAMES; ++i)
{
if (m_Bitmaps[i] != NULL) delete m_Bitmaps[i];
}
if (m_Bitmap != NULL) delete m_Bitmap;
}
/*
** Initialize
**
** Load the image and get the dimensions of the meter from it.
**
*/
void CMeterButton::Initialize()
{
CMeter::Initialize();
// 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());
delete m_Bitmap;
m_Bitmap = NULL;
}
else
{
m_W = m_Bitmap->GetWidth();
m_H = m_Bitmap->GetHeight();
if(m_H > m_W)
{
m_H = m_H / BUTTON_FRAMES;
}
else
{
m_W = m_W / BUTTON_FRAMES;
}
// Separate the frames
Graphics desktopGraphics(GetDesktopWindow());
for (int i = 0; i < BUTTON_FRAMES; ++i)
{
Bitmap bitmapPart(m_W, m_H, PixelFormat32bppARGB);
Graphics graphics(&bitmapPart);
Rect r(0, 0, m_W, m_H);
if(m_Bitmap->GetHeight() > m_Bitmap->GetWidth())
{
graphics.DrawImage(m_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);
}
m_Bitmaps[i] = new CachedBitmap(&bitmapPart, &graphics);
}
}
}
else
{
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;
}
}
}
/*
** ReadConfig
**
** Read the meter-specific configs from the ini-file.
**
*/
void CMeterButton::ReadConfig(const WCHAR* section)
{
// Store the current values so we know if the image needs to be updated
std::wstring oldImageName = m_ImageName;
int oldW = m_W;
int oldH = m_H;
// Read common configs
CMeter::ReadConfig(section);
CConfigParser& parser = m_MeterWindow->GetParser();
m_ImageName = parser.ReadString(section, L"ButtonImage", L"");
m_ImageName = m_MeterWindow->MakePathAbsolute(m_ImageName);
m_Command = parser.ReadString(section, L"ButtonCommand", L"", false);
if (m_Initialized)
{
if (oldImageName != m_ImageName)
{
Initialize(); // Reload the image
}
else
{
// Reset to old dimensions
m_W = oldW;
m_H = oldH;
}
}
}
/*
** Update
**
** Updates the value(s) from the measures.
**
*/
bool CMeterButton::Update()
{
return CMeter::Update();
}
/*
** Draw
**
** Draws the meter on the double buffer
**
*/
bool CMeterButton::Draw(Graphics& graphics)
{
if(!CMeter::Draw(graphics)) return false;
if (m_Bitmaps[m_State] == NULL) return false; // Unable to continue
int x = GetX();
int y = GetY();
// Blit the image
graphics.DrawCachedBitmap(m_Bitmaps[m_State], x, y);
return true;
}
/*
** BindMeasure
**
** Overridden method. The meters need not to be bound on anything
**
*/
void CMeterButton::BindMeasure(std::list<CMeasure*>& measures)
{
// It's ok not to bind meter to anything
if (!m_MeasureName.empty())
{
CMeter::BindMeasure(measures);
}
}
/*
** HitTest2
**
** Checks if the given point is inside the button.
**
*/
bool CMeterButton::HitTest2(int px, int py, bool checkAlpha)
{
int x = GetX();
int y = GetY();
if (m_MouseOver &&
px >= x && px < x + m_W &&
py >= y && py < y + m_H)
{
if (checkAlpha)
{
if (m_SolidColor.GetA() > 0 || m_SolidColor2.GetA() > 0)
{
return true;
}
// Check transparent pixels
if (m_Bitmap)
{
Color color;
Status status = m_Bitmap->GetPixel(px - x + m_W * m_State, py - y, &color);
if (status != Ok || color.GetA() > 0)
{
return true;
}
}
else
{
return true;
}
}
else
{
return true;
}
}
return false;
}
bool CMeterButton::MouseUp(POINT pos, CMeterWindow* window)
{
if (m_State == BUTTON_STATE_DOWN)
{
if (window && m_Clicked && HitTest2(pos.x, pos.y, true))
{
// Do a delayed execute or ortherwise !RainmeterRefresh crashes
PostMessage(window->GetWindow(), WM_DELAYED_EXECUTE, (WPARAM)NULL, (LPARAM)m_Command.c_str());
}
m_State = BUTTON_STATE_NORMAL;
m_Clicked = false;
return true;
}
m_Clicked = false;
return false;
}
bool CMeterButton::MouseDown(POINT pos)
{
if (HitTest2(pos.x, pos.y, true))
{
m_State = BUTTON_STATE_DOWN;
m_Clicked = true;
return true;
}
return false;
}
bool CMeterButton::MouseMove(POINT pos)
{
if (m_Clicked == true)
{
if (HitTest2(pos.x, pos.y, true))
{
if (m_State == BUTTON_STATE_NORMAL)
{
m_State = BUTTON_STATE_DOWN;
return true;
}
}
else
{
// If the left button is not down anymore the cliked state needs to be set false
if ((GetKeyState(VK_LBUTTON) & 0x8000) == 0)
{
m_Clicked = false;
}
if (m_State == BUTTON_STATE_DOWN)
{
m_State = BUTTON_STATE_NORMAL;
return true;
}
}
}
else
{
if (HitTest2(pos.x, pos.y, false))
{
if (m_State == BUTTON_STATE_NORMAL)
{
m_State = BUTTON_STATE_HOVER;
return true;
}
}
else
{
if (m_State == BUTTON_STATE_HOVER)
{
m_State = BUTTON_STATE_NORMAL;
return true;
}
}
}
return false;
}