类似MSN的提示窗口
unit TaskbarNotifier;
// By John O'Byrne - 05 July 2002
{ Translated from cpp to Delphi by Ian Boyd
Source .cpp code taken from eMule}
{ Sample Usage:
FTaskbarNotifier := TTaskbarNotifier.CreateParented(Application.Handle);
FTaskbarNotifier.Skin.LoadFromResourceName(hInstance, 'taskbarNotifier');
FTaskbarNotifier.FontNormal.Color := clWhite;
FTaskbarNotifier.FontSelected.Color := clWhite;
FTaskbarNotifier.TextRect := Rect(3, 43, 213, 83);
FTaskbarNotifier.Show('', 0);
FTaskbarNotifier.Free;
}
interface
//{$INCLUDE compilers.inc}
uses
Messages, Windows, Graphics, Controls, Classes
{$IFDEF DELPHI7_UP}, Types{$ENDIF};
{$IFNDEF DELPHI7_UP}
type
TByteDynArray = array of Byte;
{$ENDIF}
const
WFTASKBARNOTIFIERCLICKED = WM_USER+123;
TN_TEXT_NORMAL = $0000;
TN_TEXT_BOLD = $0001;
TN_TEXT_ITALIC = $0002;
TN_TEXT_UNDERLINE = $0004;
TBN_NULL = 0;
TBN_CHAT = 1;
TBN_DLOAD = 2;
TBN_LOG = 3;
TBN_IMPORTANTEVENT = 4;
WM_MOUSEHOVER = $2A1;
WM_MOUSELEAVE = $2A3;
type
TAnimationStatus = Integer;
const
IDT_HIDDEN = 0;
IDT_APPEARING = 1;
IDT_WAITING = 2;
IDT_DISAPPEARING = 3;
type
TTaskbarNotifier = class(TCustomControl)
private
FTransparent: Boolean;
FTransparentColor: TColor;
procedure SetTransparent(const Value: Boolean);
procedure SetTransparentColor(const Value: TColor);
procedure BackgroundChanged;
// function CreateRgnFromBitmap(hBmp: HBITMAP; color: TColor): HRGN;
protected
FNormalFont: TFont;
FSelectedFont: TFont;
FNormalTextColor: TColor;
FSelectedTextColor: TColor;
FHandCursor: HCURSOR;
FSkinBackground: TBitmap;
FSkinRegion: HRGN;
FBitmapHeight: Integer;
FBitmapWidth: Integer;
FTextRect: TRect;
FTextFormat: Longint;
FMouseIsOver: Boolean;
FAnimStatus: TAnimationStatus;
FTaskbarPlacement: Integer;
FTimerPrecision: Integer;
FTimeToStay: Integer;
FShowEvents: Integer;
FHideEvents: Integer;
FCurrentPosX: Integer;
FCurrentPosY: Integer;
FCurrentWidth: Integer;
FCurrentHeight: Integer;
FIncrementShow: Integer;
FIncrementHide: Integer;
{Taskbar Notifier}
FActiveMessageType: Integer;
FMessageTypeClicked: Integer;
(*
FTimeToShow: Integer;
FTimeToHide: Integer;
FDelayBetweenShowEvents: Integer;
FDelayBetweenHideEvents: Integer;
FStartPosX: Integer;
FStartPosY: Integer;
FIncrement: Integer;
*)
function Get24BitPixels(pBitmap: HBITMAP;
var wWidth: WORD; var wHeight: WORD): TByteDynArray;
function GenerateRegion(Bitmap: HBITMAP; red, green, Blue: Byte): HRGN;
procedure CreateParams(var Params: TCreateParams); override;
procedure WMTimer(var Msg: TWMTimer); message WM_TIMER;
procedure OnSkinBackgroundChange(Sender: TObject);
procedure Paint; override;
{TCustomControl's new handler for WM_PAINT messages}
{ Message Handlers }
procedure WMMouseMove(var Message: TWMMouseMove); message WM_MOUSEMOVE;
procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
procedure WMMouseHover(var Message: TMessage); message WM_MOUSEHOVER;
procedure WMMouseLeave(var Message: TMessage); message WM_MOUSELEAVE;
procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure WMSetCursor(var Message: TWMSetCursor); message WM_SETCURSOR;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Show(const szCaption: string; MessageType: Integer;
dwTimeToShow: Integer=500; dwTimeToStay: Integer=5000;
dwTimeToHide: Integer=500; nIncrement: Integer=1); overload;
procedure Hide;
function SetSkin(nBitmapID: UINT; red: SmallInt=-1; green:
SmallInt=-1; blue: SmallInt=-1): Boolean; overload;
function SetSkin(const szFileName: string; red: SmallInt=-1; green:
SmallInt=-1; blue: SmallInt=-1): Boolean; overload;
property FontNormal: TFont read FNormalFont;
property FontSelected: TFont read FSelectedFont;
property TextRect: TRect read FTextRect write FTextRect;
property TransparentColor: TColor read FTransparentColor write
SetTransparentColor;
property Transparent: Boolean read FTransparent write SetTransparent;
property Skin: TBitmap read FSkinBackground;
property AnimationStatus: TAnimationStatus read FAnimStatus;
{
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg LRESULT OnMouseHover(WPARAM w, LPARAM l);
afx_msg LRESULT OnMouseLeave(WPARAM w, LPARAM l);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnPaint();
afx_msg void OnTimer(UINT nIDEvent);
}
end;
implementation
uses
SysUtils, ShellAPI, Math, Dialogs;
const
TASKBAR_ON_TOP = 1;
TASKBAR_ON_LEFT = 2;
TASKBAR_ON_RIGHT = 3;
TASKBAR_ON_BOTTOM = 4;
TASKBAR_X_TOLERANCE = 40;
TASKBAR_Y_TOLERANCE = 40;
function NearlyEqual(a, b, epsilon: Integer): Boolean;
begin
Result := Abs(a-b) < (epsilon / 2);
end;
constructor TTaskbarNotifier.Create(AOwner: TComponent);
var
osvi: OSVERSIONINFO;
begin
inherited Create(AOwner);
if ParentWindow = 0 then
raise Exception.Create('Must create TTaskbarNotifier with.CreateParented(ParentHandle)');
FTaskbarPlacement := ABE_BOTTOM;
FAnimStatus := IDT_HIDDEN;
FTextFormat := DT_MODIFYSTRING or DT_WORDBREAK or DT_PATH_ELLIPSIS or
DT_END_ELLIPSIS; // Default Text format (see DrawText in the win32 API for the different values)
FHandCursor := LoadCursor(0, MAKEINTRESOURCE(32649)); // System Hand Cursor
FSkinBackground := TBitmap.Create;
FSkinBackground.OnChange := OnSkinBackgroundChange;
FTransparentColor := clFuchsia;
FTransparent := True;
{Normal text}
FNormalFont := TFont.Create;
FNormalFont.Color := rgb(133, 146, 181);
{Selected Text}
FSelectedFont := TFont.Create;
FSelectedFont.Style := FSelectedFont.Style + [fsUnderline];
FSelectedFont.Color := rgb(10, 36, 106);
// If running on NT, timer precision is 10 ms, if not timer precision is 50ms
osvi.dwOSVersionInfoSize := SizeOf(OSVERSIONINFO);
GetVersionEx(osvi);
if (osvi.dwPlatformId = VER_PLATFORM_WIN32_NT) then
FTimerPrecision := 10
else
FTimerPrecision := 50;
end;
destructor TTaskbarNotifier.Destroy;
begin
// No need to delete the HRGN, SetWindowRgn() owns it after being called
FSkinBackground.Free;
FNormalFont.Free;
FSelectedFont.Free;
inherited Destroy;
end;
function TTaskbarNotifier.SetSkin(nBitmapID: UINT; red: SmallInt; green:
SmallInt; blue: SmallInt): Boolean;
begin
FSkinBackground.Handle := nBitmapID;
Result := True;
end;
function TTaskbarNotifier.SetSkin(const szFileName: string;
red: SmallInt; green: SmallInt; blue: SmallInt): Boolean;
begin
FSkinBackground.LoadFromFile(szFilename);
Result := True;
end;
procedure TTaskbarNotifier.Show(const szCaption: string; MessageType:
Integer;
dwTimeToShow: Integer; dwTimeToStay: Integer; dwTimeToHide: Integer;
nIncrement: Integer);
var
nScreenWidth: Cardinal;
// nScreenHeight: Cardinal;
nEvents: Integer;
nBitmapSize: Integer;
rcTaskbar: TRect;
hWndTaskbar: HWND;
begin
if (FBitmapWidth = 0) or (FBitmapHeight = 0) then
Exit;
Caption := szCaption;
FTimeToStay := dwTimeToStay;
nScreenWidth := GetSystemMetrics(SM_CXSCREEN);
// nScreenHeight := GetSystemMetrics(SM_CYSCREEN);
hWndTaskbar := FindWindow('Shell_TrayWnd', nil);
GetWindowRect(hWndTaskbar, rcTaskbar);
{Daniel Lohmann: Calculate taskbar position from its window rect. However,
on XP it may be that the taskbar is slightly larger or smaller than the
screen size. Therefore we allow some tolerance here.
}
if NearlyEqual(rcTaskbar.Left, 0, TASKBAR_X_TOLERANCE) and
NearlyEqual(rcTaskbar.Right, nScreenWidth, TASKBAR_X_TOLERANCE) then
begin
// Taskbar is on top or on bottom
if NearlyEqual(rcTaskbar.Top, 0, TASKBAR_Y_TOLERANCE) then
FTaskbarPlacement := ABE_TOP
else
FTaskbarPlacement := ABE_BOTTOM;
nBitmapSize := FBitmapHeight;
end
else
begin
// Taskbar is on left or on right
if NearlyEqual(rcTaskbar.Left, 0, TASKBAR_X_TOLERANCE) then
FTaskbarPlacement := ABE_LEFT
else
FTaskbarPlacement := ABE_RIGHT;
nBitmapSize := FBitmapWidth;
end;
// We calculate the pixel increment and the timer value for the showing animation
if (dwTimeToShow > FTimerPrecision) then
begin
nEvents := min((dwTimeToShow div FTimerPrecision div 2), nBitmapSize);
//<<-- enkeyDEV(Ottavio84) -Reduced frames of a half-
FShowEvents := dwTimeToShow div nEvents;
FIncrementShow := nBitmapSize div nEvents;
end
else
begin
FShowEvents := FTimerPrecision;
FIncrementShow := nBitmapSize;
end;
// We calculate the pixel increment and the timer value for the hiding animation
if dwTimeToHide > FTimerPrecision then
begin
nEvents := min((dwTimeToHide div FTimerPrecision div 2), nBitmapSize);
//<<-- enkeyDEV(Ottavio84) -Reduced frames of a half-
FHideEvents := dwTimeToHide div nEvents;
FIncrementHide := nBitmapSize div nEvents;
end
else
begin
FShowEvents := FTimerPrecision;
FIncrementHide := nBitmapSize;
end;
case FAnimStatus of
IDT_HIDDEN:
begin
case FTaskbarPlacement of
ABE_RIGHT:
begin
FCurrentPosX := rcTaskbar.Left;
FCurrentPosY := rcTaskbar.Bottom - FBitmapHeight;
FCurrentWidth := 0;
FCurrentHeight := FBitmapHeight;
end;
ABE_LEFT:
begin
FCurrentPosX := rcTaskbar.Right;
FCurrentPosY := rcTaskbar.Bottom - FBitmapHeight;
FCurrentWidth := 0;
FCurrentHeight := FBitmapHeight;
end;
ABE_TOP:
begin
FCurrentPosX := rcTaskbar.Right - FBitmapWidth;
FCurrentPosY := rcTaskbar.Bottom;
FCurrentWidth := FBitmapWidth;
FCurrentHeight := 0;
end;
else //ABE_BOTTOM
// Taskbar is on the bottom or Invisible
FCurrentPosX := rcTaskbar.Right - FBitmapWidth;
FCurrentPosY := rcTaskbar.Top;
FCurrentWidth := FBitmapWidth;
FCurrentHeight := 0;
end;
ShowWindow(Handle, SW_SHOWNOACTIVATE);
FActiveMessageType := MessageType;
//<<--enkeyDEV(kei-kun) -TaskbarNotifier-
SetTimer(Handle, IDT_APPEARING, FShowEvents, nil);
end;
IDT_APPEARING:
Repaint; //RedrawWindow;
IDT_WAITING:
begin
Repaint;{RedrawWindow;}
KillTimer(Handle, IDT_WAITING);
SetTimer(Handle, IDT_WAITING, FTimeToStay, nil);
end;
IDT_DISAPPEARING:
begin
KillTimer(Handle, IDT_DISAPPEARING);
SetTimer(Handle, IDT_WAITING, FTimeToStay, nil);
case FTaskbarPlacement of
ABE_RIGHT:
begin
FCurrentPosX := rcTaskbar.Left - FBitmapWidth;
FCurrentWidth := FBitmapWidth;
end;
ABE_LEFT:
begin
FCurrentPosX := rcTaskbar.Right;
FCurrentWidth := FBitmapWidth;
end;
ABE_TOP:
begin
FCurrentPosY := rcTaskbar.Bottom;
FCurrentHeight := FBitmapHeight;
end;
else //ABE_BOTTOM
FCurrentPosY := rcTaskbar.Top - FBitmapHeight;
FCurrentHeight := FBitmapHeight;
end;
SetWindowPos(Handle, HWND_TOPMOST, FCurrentPosX, FCurrentPosY,
FCurrentWidth, FCurrentHeight, SWP_NOACTIVATE);
Repaint; //RedrawWindow;
end;
end
end;
procedure TTaskbarNotifier.Hide;
begin
case FAnimStatus of
IDT_APPEARING: KillTimer(Handle, IDT_APPEARING);
IDT_WAITING: KillTimer(Handle, IDT_WAITING);
IDT_DISAPPEARING: KillTimer(Handle, IDT_DISAPPEARING);
end;
MoveWindow(Handle, 0, 0, 0, 0, True); { TODO : Last parameter, Repaint.
What is the implied value in MFC? }
ShowWindow(Handle, SW_HIDE);
FAnimStatus := IDT_HIDDEN;
FActiveMessageType := TBN_NULL; //<<--enkeyDEV(kei-kun) -TaskbarNotifier-
end;
function TTaskbarNotifier.GenerateRegion(Bitmap: HBITMAP; red, green, Blue:
Byte): HRGN;
var
wBmpWidth,wBmpHeight: WORD;
Rgn, TmpRgn: HRGN;
p, x, y: Integer;
jRed, jGreen, jBlue: Byte;
Pixels: TByteDynArray;
begin
// 24bit pixels from the bitmap
Pixels := Get24BitPixels(Bitmap, wBmpWidth, wBmpHeight);
// if (!pPixels) return NULL;
// create our working region
Rgn := CreateRectRgn(0, 0, wBmpWidth, wBmpHeight);
if Rgn=0 then
begin
{delete pPixels;}
Result := 0;
Exit;
end;
p := 0;
for y := 0 to wBmpHeight-1 do
begin
for x := 0 to wBmpWidth-1 do
begin
jRed := Pixels[p+2];
jGreen := Pixels[p+1];
jBlue := Pixels[p+0];
if (jRed=red) and (jGreen=green) and (jBlue=blue) then
begin
// remove transparent color from region
TmpRgn := CreateRectRgn(x, y, x+1, y+1);
CombineRgn(Rgn, Rgn, TmpRgn, RGN_XOR);
DeleteObject(TmpRgn);
end;
// next pixel
Inc(p, 3);
end;
end;
// release pixels
// delete pPixels;
// return the region
Result := Rgn;
end;
function TTaskbarNotifier.Get24BitPixels(pBitmap: HBITMAP;
var wWidth: WORD; var wHeight: WORD): TByteDynArray;
var
bmpBmp: BITMAP;
pbmiInfo: PBITMAPINFO;
bmiInfo: BITMAPINFO;
wBmpWidth, wBmpHeight: WORD;
dc: HDC;
iRes: Integer;
begin
GetObject(pBitmap, SizeOf(bmpBmp), @bmpBmp);
pbmiInfo := @bmpBmp;
wBmpWidth := pbmiInfo.bmiHeader.biWidth;
Dec(wBmpWidth, wBmpWidth mod 4);
wBmpHeight := pbmiInfo.bmiHeader.biHeight;
wWidth := wBmpWidth;
wHeight := wBmpHeight;
try
SetLength(Result, wBmpWidth*wBmpHeight*3);
except
Result := nil;
Exit;
end;
dc := GetWindowDC(Handle);
try
bmiInfo.bmiHeader.biSize := SizeOf(BITMAPINFOHEADER);
bmiInfo.bmiHeader.biWidth := wBmpWidth;
bmiInfo.bmiHeader.biHeight := -wBmpHeight;
bmiInfo.bmiHeader.biPlanes := 1;
bmiInfo.bmiHeader.biBitCount := 24;
bmiInfo.bmiHeader.biCompression := BI_RGB;
bmiInfo.bmiHeader.biSizeImage := wBmpWidth*wBmpHeight*3;
bmiInfo.bmiHeader.biXPelsPerMeter := 0;
bmiInfo.bmiHeader.biYPelsPerMeter := 0;
bmiInfo.bmiHeader.biClrUsed := 0;
bmiInfo.bmiHeader.biClrImportant := 0;
// get pixels from the original bitmap converted to 24bits
iRes := GetDIBits(dc, pBitmap, 0, wBmpHeight, @Result[0], bmiInfo,
DIB_RGB_COLORS);
finally
// release the device context
ReleaseDC(0, dc);
end;
// if failed, cancel the operation.
if iRes = 0 then
begin
SetLength(Result, 0);
Result := nil;
Exit;
end;
// return the pixel array
end;
(*
function TTaskbarNotifier.CreateRgnFromBitmap(hBmp: HBITMAP; color: TColor):
HRGN;
type
TRectArray = array of TRect;
PRectArray = ^TRectArray;
var
bm: BITMAP;
dcBmp: HDC;
hOldBitmap: HGDIOBJ;
RDHDR: Integer;
MAXBUF: Integer;
i, j: Integer; // current position in mask image
first: Integer; // left position of current scan line
wasfirst: Boolean; // set when if mask was found in current scan line
isMask: Boolean; // set when current color is mask color
pRgnData: PRgnDataHeader;
Rects: PRectArray;
begin
// this code is written by Davide Pizzolato
if hBmp = 0 then
begin
Result := 0;
Exit;
end;
GetObject(hBmp, SizeOf(BITMAP), @bm ); // get bitmap attributes
dcBmp := CreateCompatibleDC(GetDC(Handle)); //Creates a memory device
context for the bitmap
hOldBitmap := SelectObject(dcBmp, hBmp); //selects the bitmap in the device
context
RDHDR := SizeOf(RGNDATAHEADER);
MAXBUF := 40; // size of one block in RECTs
// (i.e. MAXBUF*sizeof(RECT) in bytes)
// LPRECT pRects;
// DWORD cBlocks = 0; // number of allocated blocks
first := 0; // left position of current scan line
// where mask was found
wasfirst := False; // set when if mask was found in current scan line
// allocate memory for region data
// pRgnData := new BYTE[ RDHDR + ++cBlocks * MAXBUF * sizeof(RECT) ];
memset( pRgnData, 0, RDHDR + cBlocks * MAXBUF * sizeof(RECT) );
// fill it by default
pRgnData.dwSize := RDHDR;
pRgnData.iType := RDH_RECTANGLES;
pRgnData.nCount := 0;
for i := 0 to bm.bmHeight-1 do
begin
for j := 0 to bm.bmWidth-1 do
begin
// get color
ismask := (dcBmp.GetPixel(j,bm.bmHeight-i-1) != color);
// place part of scan line as RECT region if transparent color found
//after mask color or mask color found at the end of mask image
if wasfirst and (
(ismask and (j = (bm.bmWidth-1))) or
(ismask xor (j < bm.bmWidth))) then
begin
// get offset to RECT array in RGNDATA buffer
pRects := Inc(pRgnData, RDHDR);
// save current RECT
pRects[ pRgnData->nCount++ ] = CRect( first, bm.bmHeight - i - 1,
j+(j==(bm.bmWidth-1)), bm.bmHeight - i );
// if buffer full reallocate it
if ( pRgnData->nCount >= cBlocks * MAXBUF ) then
begin
LPBYTE pRgnDataNew = new BYTE[ RDHDR + ++cBlocks * MAXBUF *
sizeof(RECT) ];
memcpy( pRgnDataNew, pRgnData, RDHDR + (cBlocks - 1) * MAXBUF *
sizeof(RECT) );
delete pRgnData;
pRgnData = (RGNDATAHEADER* )pRgnDataNew;
end;
wasfirst = false;
end
else if ( !wasfirst && ismask ) then
begin // set wasfirst when mask is found
first = j;
wasfirst = true;
end;
end;
dcBmp.SelectObject(hOldBitmap); //restore default object
dcBmp.DeleteDC(); //release the bitmap
// create region
{ Under WinNT the ExtCreateRegion returns NULL (by Fable@aramszu.net) }
// HRGN hRgn = ExtCreateRegion( NULL, RDHDR + pRgnData->nCount *
sizeof(RECT), (LPRGNDATA)pRgnData );
{ ExtCreateRegion replacement { }
HRGN hRgn=CreateRectRgn(0, 0, 0, 0);
ASSERT( hRgn!=NULL );
pRects = (LPRECT)((LPBYTE)pRgnData + RDHDR);
for (i=0; i<(int)pRgnData->nCount; i++) do
begin
HRGN hr=CreateRectRgn(pRects[i].left, pRects[i].top, pRects[i].right,
pRects[i].bottom);
VERIFY(CombineRgn(hRgn, hRgn, hr, RGN_OR)!=ERROR);
if (hr) then
DeleteObject(hr);
end;
ASSERT( hRgn!=NULL );
{ } ExtCreateRegion replacement }
delete pRgnData;
return hRgn;
end;
end;
*)
procedure TTaskbarNotifier.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.Style := WS_POPUP;
Params.ExStyle := WS_EX_TOPMOST;
Params.X := 0;
Params.Y := 0;
Params.Width := 0;
Params.Height := 0;
{Window Class}
Params.WindowClass.style := CS_DBLCLKS or CS_SAVEBITS;
Params.WindowClass.hIcon := 0;
Params.WindowClass.hCursor := LoadCursor(0, IDC_ARROW);
Params.WindowClass.hbrBackground := COLOR_WINDOW+1;
end;
procedure TTaskbarNotifier.OnSkinBackgroundChange(Sender: TObject);
begin
BackgroundChanged;
end;
procedure TTaskbarNotifier.SetTransparent(const Value: Boolean);
begin
if FTransparent <> Value then
begin
FTransparent := Value;
BackgroundChanged;
end;
end;
procedure TTaskbarNotifier.SetTransparentColor(const Value: TColor);
begin
if FTransparentColor <> Value then
begin
FTransparentColor := Value;
BackgroundChanged;
end;
end;
procedure TTaskbarNotifier.BackgroundChanged;
var
bm: BITMAP;
red, green, blue: Byte;
dwResult: Integer;
begin
ZeroMemory(@bm, SizeOf(bm));
if FSkinBackground.Handle = 0 then
Exit;
dwResult := GetObject(FSkinBackground.Handle, SizeOf(bm), @bm);
if dwResult = 0 then
begin
// MessageDlg('Could not get new Skin object: '+#13#10+
// SysErrorMessage(GetLastError), mtError, [mbOk], 0);
Beep;
Exit;
end;
FBitmapWidth := bm.bmWidth;
FBitmapHeight := bm.bmHeight;
FTextRect := rect(0, 0, bm.bmWidth, bm.bmHeight);
if FTransparent then
begin
red := (FTransparentColor shr 16) and $FF;
green := (FTransparentColor shr 8) and $FF;
blue := (FTransparentColor) and $FF;
// No need to delete the HRGN, SetWindowRgn() owns it after being called
FSkinRegion := GenerateRegion(FSkinBackground.Handle,
red, green, blue);
SetWindowRgn(Handle, FSkinRegion, True);
end;
end;
{
BEGIN_MESSAGE_MAP(TTaskbarNotifier, CWnd)
ON_WFCREATE()
ON_WFMOUSEMOVE()
ON_WFDESTROY()
ON_WFERASEBKGND()
ON_WFPAINT()
ON_MESSAGE(WFMOUSELEAVE, OnMouseLeave)
ON_MESSAGE(WFMOUSEHOVER, OnMouseHover)
ON_WFSETCURSOR()
ON_WFLBUTTONUP()
ON_WFTIMER()
END_MESSAGE_MAP()
}
{ TTaskbarNotifier message handlers }
procedure TTaskbarNotifier.WMMouseMove(var Message: TWMMouseMove);
var
MouseEvent: TTrackMouseEvent;
begin
MouseEvent.cbSize := SizeOf(TTrackMouseEvent);
MouseEvent.dwFlags := TME_LEAVE or TME_HOVER;
MouseEvent.hwndTrack := Handle;
MouseEvent.dwHoverTime := 1;
TrackMouseEvent(MouseEvent);
inherited;
end;
procedure TTaskbarNotifier.WMLButtonUp(var Message: TWMLButtonUp);
begin
FMessageTypeClicked := FActiveMessageType;
PostMessage(ParentWindow, WFTASKBARNOTIFIERCLICKED, 0, 0);
inherited;
end;
procedure TTaskbarNotifier.WMMouseHover(var Message: TMessage);
begin
if FAnimStatus = IDT_WAITING then
KillTimer(Handle, IDT_WAITING);
if not FMouseIsOver then
begin
FMouseIsOver := True;
Repaint; //RedrawWindow;
if FAnimStatus = IDT_DISAPPEARING then
begin
KillTimer(Handle, IDT_DISAPPEARING);
FAnimStatus := IDT_APPEARING;
SetTimer(Handle, IDT_APPEARING, FShowEvents, nil);
end;
end;
Message.Result := 0;
end;
procedure TTaskbarNotifier.WMMouseLeave(var Message: TMessage);
begin
if FMouseIsOver then
begin
FMouseIsOver := False;
if FAnimStatus = IDT_WAITING then
SetTimer(Handle, IDT_WAITING, FTimeToStay, nil);
Repaint;
end;
Message.Result := 0;
end;
procedure TTaskbarNotifier.WMEraseBkgnd(var Message: TWmEraseBkgnd);
var
memDC: hDC;
OldBitmap: HGDIOBJ;
begin
memDC := CreateCompatibleDC(Message.DC);
OldBitmap := SelectObject(memDC, FSkinBackground.Handle);
BitBlt(Message.DC, 0, 0, FCurrentWidth, FCurrentHeight, memDC, 0, 0,
SRCCOPY);
SelectObject(memDC, OldBitmap);
Message.Result := -1;
end;
procedure TTaskbarNotifier.WMPaint(var Message: TWMPaint);
{var
dc: HDC; //CPaintDC dc(this);
rcClient: TRect;
pOldFont: TFont;// CFont *pOldFont;
szBuffer: string; //char *szBuffer;
}
begin
inherited;
Exit;
(*
dc := GetDC(Handle);
if FMouseIsOver then
begin
SetTextColor(dc, FFontSelected.Color and $00FFFFFF); todo
pOldFont := SelectObject(dc, FFontSelected.Handle); todo
end
else
begin
SetTextColor(dc, FFontNormal.Color and $00FFFFFF); todo
pOldFont := SelectObject(dc, FFontNormal.Handle); todo
end;
TCanvas
SetBkMode(dc, Windows.TRANSPARENT);
InflateRect(rcClient, -1, -20);
DrawText(dc, PChar(Caption), -1, FTextRect, FTextFormat);
SelectObject(dc, pOldFont);
*)
end;
procedure TTaskbarNotifier.WMSetCursor(var Message: TWMSetCursor);
begin
if Message.HitTest = HTCLIENT then
begin
SetCursor(FHandCursor);
Message.Result := -1; //True
end;
end;
procedure TTaskbarNotifier.WMTimer(var Msg: TWMTimer);
begin
case Msg.TimerID of
IDT_APPEARING:
begin
FAnimStatus := IDT_APPEARING;
case FTaskbarPlacement of
ABE_BOTTOM:
begin
if (FCurrentHeight < FBitmapHeight) then
begin
Dec(FCurrentPosY, FIncrementShow);
Inc(FCurrentHeight, FIncrementShow);
end
else
begin
KillTimer(Handle, IDT_APPEARING);
SetTimer(Handle, IDT_WAITING, FTimeToStay, nil);
FAnimStatus := IDT_WAITING;
end;
end;
ABE_TOP:
begin
if (FCurrentHeight < FBitmapHeight) then
Inc(FCurrentHeight, FIncrementShow)
else
begin
KillTimer(Handle, IDT_APPEARING);
SetTimer(Handle, IDT_WAITING, FTimeToStay, nil);
FAnimStatus := IDT_WAITING;
end;
end;
ABE_LEFT:
begin
if (FCurrentWidth < FBitmapWidth) then
Inc(FCurrentWidth, FIncrementShow)
else
begin
KillTimer(Handle, IDT_APPEARING);
SetTimer(Handle, IDT_WAITING, FTimeToStay, nil);
FAnimStatus := IDT_WAITING;
end;
end;
ABE_RIGHT:
begin
if (FCurrentWidth < FBitmapWidth) then
begin
Dec(FCurrentPosX, FIncrementShow);
Inc(FCurrentWidth, FIncrementShow);
end
else
begin
KillTimer(Handle, IDT_APPEARING);
SetTimer(Handle, IDT_WAITING, FTimeToStay, nil);
FAnimStatus := IDT_WAITING;
end;
end;
end;
SetWindowPos(Handle, HWND_TOPMOST, FCurrentPosX, FCurrentPosY,
FCurrentWidth, FCurrentHeight, SWP_NOACTIVATE);
//RedrawWindow();
end;
IDT_WAITING:
begin
KillTimer(Handle, IDT_WAITING);
SetTimer(Handle, IDT_DISAPPEARING, FHideEvents, nil);
end;
IDT_DISAPPEARING:
begin
FAnimStatus := IDT_DISAPPEARING;
case FTaskbarPlacement of
ABE_BOTTOM:
begin
if (FCurrentHeight > 0) then
begin
Inc(FCurrentPosY, FIncrementHide);
Dec(FCurrentHeight, FIncrementHide);
end
else
begin
KillTimer(Handle, IDT_DISAPPEARING);
Hide;
end;
end;
ABE_TOP:
begin
if (FCurrentHeight > 0) then
Dec(FCurrentHeight, FIncrementHide)
else
begin
KillTimer(Handle, IDT_DISAPPEARING);
Hide;
end;
end;
ABE_LEFT:
begin
if (FCurrentWidth > 0) then
Dec(FCurrentWidth, FIncrementHide)
else
begin
KillTimer(Handle, IDT_DISAPPEARING);
Hide;
end;
end;
ABE_RIGHT:
begin
if (FCurrentWidth > 0) then
begin
Inc(FCurrentPosX, FIncrementHide);
Dec(FCurrentWidth, FIncrementHide);
end
else
begin
KillTimer(Handle, IDT_DISAPPEARING);
Hide;
end;
end;
end;
SetWindowPos(Handle, HWND_TOPMOST, FCurrentPosX, FCurrentPosY,
FCurrentWidth, FCurrentHeight, SWP_NOACTIVATE);
end;
end;
Msg.Result := 0;
end;
procedure TTaskbarNotifier.Paint;
var
rcText: TRect;
begin
if FMouseIsOver then
Canvas.Font.Assign(FSelectedFont)
else
Canvas.Font.Assign(FNormalFont);
Canvas.Brush.Style := bsClear;
rcText := FTextRect;
DrawText(Canvas.Handle, PChar(Caption), -1, rcText, FTextFormat);
// Canvas.TextRect(rcClient, rcClient.Left, rcClient.Top, Caption);
end;
end.