Se forem instalar o componente lembrem-se de acrescentar a linha que está como comentário->
Result:={(csDesigning in ComponentState)}false;
Troque para->
Result:=(csDesigning in ComponentState);
porque se não fizer isso podem ocorrer efeitos indesejáveis durante o tempo de desenho do programa.
O componente é TCaptionButtons derivado de TComponent e existe somente para ser comportado pelo form como sendo componente. Dentro dele existe uma propriedade do tipo TCaptionButtonArray derivada de TCollection, que serve para fazer o controle do componente. E essa por sua vez tem uma coleção da classe TCaptionButton derivada de TCollectionItem compondo os items da coleção que tem como função armazenar os dados de cada botão acrescentado a lista.
Qualquer problema mande MP.
TCaptionButtonArray ->
Propriedades ->
ToBegin: Byte - Indica a índice do primeiro botão da lista, da direita pra esquerda. Default = 4.
HintHideTime: Integer - Tempo em ms que demora para uma Hint associada a algum botão ser ocultada. Default = 5000;
HintShowTime: Integer - Tempo em ms que demora para uma Hint aparecer depois que o mouse estaciona sob a área de um botão. Default = 1300.
property Items[index: Integer]: TCaptionButton - Retorna um TCaptionButton da lista de botões no índice especificado.
property SupportsThemes : boolean - Indica se a versão do Windows suporta Themes.
property XPStyle : byte - Identifica qual tema XP está atualmente sendo usado pela janela: NO_THEME, XP_BLUE, XP_METALLIC ou XP_HOMESTEAD.
Eventos ->
OnThemeChange -> Ocorre quando há mudança de tema para o Form Owner do componente.
Campos ->
Bitmaps: array[1..8] of TBitmap - Bitmaps dos botões em todos os seus 8 possíveis estados quando está sendo feito uso de tema. Esse botões não possuem ícones desenhados.
Bitmaps_:array[1..8] of TBitmap - Bitmaps dos botões em todos os seus 8 possíveis estados quando está sendo feito uso de tema. Esse botões possuem o ícone de minimizar para o Tray.
IconColors : array[1..8] of TColor - Cores dos ícones do botão com o tema usado atualmente em todos os seus 8 estados. Usado para desenhar um ícone no botão.
Lock : Cardinal - Mensagem que a aplicação não deve processar. Se for 0 serão processadas todas as mensagems. Usado para mudar várias propriedades que executam mensagems nos seu métodos de escrita, como WM_NCPAINT, e não ter queda de performance.
Métodos ->
Function add : TCaptionButton; - Cria uma nova instancia de TCaptionButton e adiciona sua referencia a lista.
procedure UnLock; - Seta o campo Lock para 0;
Function GetButtonRect(index : byte; rec : TRect; theme : cardinal; OffSet : integer; XS, YS: integer) : TRect; - Pega o retangulo que um botão correspondente aos parametros fornecidos ocupa atualmente. Onde "index" é o índice do botão na lista, "rec" é o retangulo do form, "theme" é o handle do tema atual, "OffSet" é quantos pixels o botão deve estar deslocado para a esquerda, "XS" é a largura do botão e "YS" é a altura do botão.
Function GetXPStyle(Val : TRGB) : byte; - Retorna a constante que identifica qual tema XP está atualmente sendo usado pela janela mediante fornecimento de uma cor do fundo do botão: NO_THEME, XP_BLUE, XP_METALLIC ou XP_HOMESTEAD. Não é necessário, apenas leia a propriedade XPStyle.
Function RemoveIcon(Bm : TBitmap; FillR : PRect = nil) : TBtnInfo; - Remove o ícone de minimizar do bitmap com o botão devidamente desenhado.
procedure DrawSingleButton(index: integer; DC, stat : cardinal; fast : boolean = true); - Desenha na barra o botão especificado por "index" no Device Context "DC", no estado "stat", com método economico ou não dependendo de "fast".
function Perform(Msg, WParam, LParam : integer) : integer; - Executa a mensagem "Msg" com WParam "WParam", LParam "LParam" e retorna o resultado do processamento da mensagem pelo form ou pelo componente.
procedure UpdateBitmaps; - Atualiza os bitmaps. Usado no caso de a aparencia dos botões mudar.
TCaptionButton ->
Propriedades ->
OwnerDrawed : boolean - Indica se o botão é desenhado pelo Owner. Caso true, um bitmap será passado a um Event Handler para que esse possa desenhar o ícone no botão. Caso false, será desenhado o botão de minimizar para o Tray. Default = false.
Enabled : boolean - Indica se o botão está habilitado. Default = true.
OffSet : integer - Indica a distancia em pixels que o botão deve estar do botão a sua direita. Default = 0.
Visible : boolean - Indica se o botão está visível. Default = true;
Hint : string - Indica o texto que deverá ser mostrado na Hint do botão. Só será mostrada a Hint se a propriedade ShowHint for true.
ShowHint : boolean - Indica se deverá ser mostrada a Hint do Botão. Default = false.
PopUpMenu : TPopUpMenu - Referencia a uma instancia de TPopupMenu que deverá aparecer quando o usuário pressionar o botão direito do mouse.
Eventos ->
OnClick - Ocorre quando o usuário clica no botão.
OnDraw - Ocorre quando é desenhado um botão. Um TBitmap é passado como parametro para esse evento para ser desenhado nele o ícone do botão. O Bitmap inicialmente conterá apenas o fundo do botão.
Campos ->
Rect : TRect - Especifica o retangulo do botão em relação a área não cliente do Form.
State : Cardinal - Especifica o estado atual do botão.
Listagem da Unit do Componente ->
UCaptionButton.Pas
unit UCaptionButton;
{
* Componente CaptionButtons.
* Descrição: Componente que permite adicioncar botões
extras na barra de título suportando XP_THEMES.
* Autor: Thales Pontes Martins.
thalespo@terra.com.br
* Freeware: Este código pode ser ditribuído livremente desde
que sejam mantidas essas informações na íntegra.
* Dezembro de 2006.
}
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, uxtheme, StdCtrls, Menus{, UMessageStr};
const
NO_THEME = byte(0);
XP_BLUE = byte(1);
XP_METALLIC = byte(2);
XP_HOMESTEAD = byte(3);
BT_NORMAL = cardinal(1);
BT_HOT = cardinal(2);
BT_PUSHED = cardinal(3);
BT_DISABLED = cardinal(4);
BT_INORMAL = cardinal(5);
BT_IHOT = cardinal(6);
BT_IPUSHED = cardinal(7);
BT_IDISABLED = cardinal(8);
HTCUSTOMBUTTON = Cardinal(65);
BTTIMERID = cardinal(33998015);
HIDEHINTID = cardinal(99600342);
IconDif = 27;
type
TCaptionButtonDrawEvent = procedure(Sender : TObject; bmp : TBitmap; state, index : cardinal) of object;
TCaptionButtonClickEvent = procedure(Sender : TObject; index : integer) of object;
TCaptionButtonArray = class;
TCaptionButtons = class;
TCaptionButton = class;
TRGB = record
r, g, b, info : byte;
end;
TBtnInfo = record
Rect : TRect;
IconColor : TColor;
end;
TCaptionButtons = class(TComponent)
private
_Buttons : TCaptionButtonArray;
function des : boolean;
public
Constructor Create(AOwner : TComponent); override;
Destructor Destroy; override;
published
Property Buttons : TCaptionButtonArray read _Buttons;
end;
TCaptionButtonArray = class(TCollection)
private
_SupportsThemes, ThemeChanged, DoThEvt : boolean;
ParentWndProc : TWndMethod;
_OnThemeChange : TNotifyEvent;
OwnerForm : TForm;
Owner : TCaptionButtons;
Theme : THANDLE;
_XPStyle : byte;
Selected, Pushed, RPushed, _HintShowTime, _HintHideTime : integer;
_ToBegin : Byte;
DrAux : TBitmap;
BtnH, BtnW : integer;
TimerSet, HintShow, HideSet : Boolean;
HintWindow : THintWindow;
procedure SetToBegin(AValue : byte);
Protected
Function Add : TCaptionButton;
Function GetItem(Index : integer) : TCaptionButton;
Procedure SetItem(Index : Integer; Item : TCaptionButton);
//Messages
procedure ON_WM_NCPAINT(var msg : TMessage);
Procedure ON_WM_NCHITTEST(var msg : TMessage);
procedure ON_WM_NCLBUTTONDOWN(var msg : TMessage);
procedure ON_WM_NCLBUTTONUP(var msg : TMessage);
procedure ON_WM_NCRBUTTONDOWN(var msg : TMessage);
procedure ON_WM_NCRBUTTONUP(var msg : TMessage);
procedure ON_WM_TIMER(var msg : TMessage);
procedure ON_WM_NCMOUSELEAVE(var msg : TMessage);
public
bitmaps, bitmaps_ : array[1..8] of TBitmap;
IconColors : array[1..8] of TColor;
Lock : Cardinal;
constructor Create(AForm : TForm; AOwner : TCaptionButtons);
Destructor Destroy; Override;
procedure WndProc(var msg : TMessage);
procedure UnLock;
Function GetButtonRect(index : byte; rec : TRect; theme : cardinal; OffSet : integer; XS, YS: integer) : TRect;
Function GetXPStyle(Val : TRGB) : byte;
Function RemoveIcon(Bm : TBitmap; FillR : PRect = nil) : TBtnInfo;
procedure DrawSingleButton(index: integer; DC, stat : cardinal; fast : boolean = true);
function Perform(Msg, WParam, LParam : integer) : integer;
procedure UpdateBitmaps;
property Items[Index: Integer]: TCaptionButton read GetItem write SetItem;
property SupportsThemes : boolean read _SupportsThemes;
property XPStyle : byte read _XPStyle;
published
property ToBegin : Byte read _Tobegin write SetToBegin;
property HintHideTime : integer read _HintHideTime write _HintHideTime;
property HintShowTime : integer read _HintShowTime write _HintShowTime;
property OnThemeChange : TNotifyEvent read _OnThemeChange write _OnThemeChange;
end;
TCaptionButton = class(TCollectionItem)
private
_OnClick : TCaptionButtonClickEvent;
_OnDraw : TCaptionButtonDrawEvent;
_OwnerDrawed, _Enabled, _Visible, _ShowHint : Boolean;
_PopUpMenu : TPopUpMenu;
_OffSet : integer;
_Hint : string;
procedure SetOffset(AValue : integer);
procedure SetEnabled(AValue : boolean);
procedure SetVisible(AValue : boolean);
public
Rect : TRect;
State : Cardinal;
Constructor Create(Collection : TCollection); override;
Destructor Destroy; override;
published
property OwnerDrawed : boolean read _OwnerDrawed write _OwnerDrawed;
property Enabled : boolean read _Enabled write SetEnabled;
property OffSet : integer read _OffSet write SetOffSet;
property Visible : boolean read _Visible write SetVisible;
property Hint : string read _Hint write _Hint;
property ShowHint : boolean read _ShowHint write _ShowHint;
property PopUpMenu : TPopUpMenu read _PopUpMenu write _PopUpMenu;
property OnClick : TCaptionButtonClickEvent read _OnClick write _OnClick;
property OnDraw : TCaptionButtonDrawEvent read _OnDraw write _OnDraw;
end;
procedure register;
implementation
//Global fields used in debugging
{var
NTime : cardinal;
mês: TStringList; }
procedure register;
begin
RegisterComponents('Samples',[TCaptionButtons]);
end;
//this is a function that parses a TRect to a string
//Used in debug only
{Function RectToStr(r : TRect) : string;
begin
Result:='L_'+inttostr(r.Left)+' '+
'R_'+inttostr(r.Right)+' '+
'T_'+inttostr(r.Top)+' '+
'B_'+inttostr(r.Bottom);
end;}
//These are the condition functions imitating the C++ ? operator
function s1(cond : boolean;vt,vf:byte) : byte;
begin
if (cond) then result:=vt else result:=vf;
end;
function s4(cond : boolean;vt,vf:Cardinal) : Cardinal;
begin
if (cond) then result:=vt else result:=vf;
end;
function s4_(cond : boolean;vt,vf:Integer) : Integer;
begin
if (cond) then result:=vt else result:=vf;
end;
function sb(cond : boolean;vt,vf:boolean) : boolean;
begin
if (cond) then result:=vt else result:=vf;
end;
constructor TCaptionButtons.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
_Buttons:=TCaptionButtonArray.create(TForm(AOwner),self);
end;
function TCaptionButtons.des : Boolean;
begin
result:={(csDesigning in ComponentState)}false;
//Pay attention, the (csDesigning in ComponentState) expression
//will cause an exception if the component is being created
//in runtime rather than being a installed component.
end;
Destructor TCaptionButtons.Destroy;
begin
_Buttons.Destroy;
inherited Destroy;
end;
Constructor TCaptionButton.Create(Collection: TCollection);
begin
self.Collection:=Collection;
_Enabled:=True;
_Visible:=True;
_OwnerDrawed:=False;
_PopUpMenu:=nil;
_OffSet:=0;
_Hint:='';
_ShowHint:=false;
end;
destructor TCaptionButton.Destroy;
begin
inherited Destroy;
end;
procedure TCaptionButtonArray.UnLock;
begin
Lock:=0;
end;
Constructor TCaptionButtonArray.Create(AForm : TForm; AOwner : TCaptionButtons);
var
i : cardinal;
begin
inherited Create(TCaptionButton);
if (Owner.des) then exit;
ThemeChanged:=True;
Selected:=-1;
Pushed:=-1;
RPushed:=-1;
_ToBegin:=4;
TimerSet:=false;
HintShow:=false;
HideSet:=false;
DoThEvt:=true;
Lock:=0;
_HintHideTime:=5000;
_HintShowTime:=1300;
_OnThemeChange:=nil;
OwnerForm:=AForm;
Owner:=AOwner;
ParentWndProc:=OwnerForm.WindowProc;
ThemeChanged:=True;
_SupportsThemes:=InitThemeLibrary;//indicates if the windows version supports themes
DrAux:=TBitmap.Create;
if _supportsThemes then for I := 1 to 8 do
begin
Bitmaps[i]:=TBitmap.Create;
Bitmaps_[i]:=TBitmap.Create;
end;
HintWindow:=THintWindow.Create(Owner);
HintWindow.Color:=clInfoBk;
OwnerForm.WindowProc:=WndProc;
end;
Destructor TCaptionButtonArray.Destroy;
var
i : cardinal;
begin
if _SupportsThemes then FreeThemeLibrary;
OwnerForm.WindowProc:=ParentWndProc;
DrAux.Destroy;
if _SupportsThemes then for I := 1 to 8 do
begin
Bitmaps[i].Destroy;
Bitmaps_[i].Destroy;
end;
HintWindow.Destroy;
inherited Destroy;
end;
Function TCaptionButtonArray.Add : TCaptionButton;
begin
result:=TCaptionButton(inherited Add);
end;
Function TCaptionButtonArray.GetItem(Index : Integer) : TCaptionButton;
begin
Result:=TCaptionButton(inherited GetItem(Index));
end;
Procedure TCaptionButtonArray.SetItem(Index : integer; Item : TCaptionButton);
begin
inherited SetItem(Index,Item);
end;
function TCaptionButtonArray.Perform(Msg, WParam, LParam: integer) : integer;
var
ms : TMessage;
begin
ms.Msg:=Msg;
ms.WParam:=WParam;
ms.LParam:=LParam;
ms.Result:=0;
WndProc(ms);
result:=ms.Result;
end;
Function TCaptionButtonArray.GetXPStyle(Val : TRGB) : byte;
begin
if (abs(integer(val.b)-((integer(val.r)+integer(val.g)) div 2)) < 30){Must be 17} then
Result:=XP_METALLIC else
begin
if (val.b > s1((val.r>val.g),val.r,val.g)) then Result:=XP_BLUE else result:=XP_HOMESTEAD;
end;
end;
procedure TCaptionButtonArray.UpdateBitmaps;
var
p : PWideChar;
st : string;
r, r2, r3 : TRect;
H, W : Integer;
procedure DoForTheme;
var
i : cardinal;
Aux : TColor;
bm : tbitmap;
icr: TRect;
inf : TBtnInfo;
begin
bm:=TBitmap.Create;
bm.SetSize(r2.Right,r2.Bottom);
DrawThemeBackGround(Theme,bm.canvas.Handle,WP_MINBUTTON,1,r2,nil);
Aux:=bm.Canvas.Pixels[bm.Width div 2,bm.Height div 2];
_XPStyle:=GetXPStyle(TRGB(Aux));
icr:=RemoveIcon(bm).Rect;
for i:=1 to 8 do
begin
bitmaps[i].SetSize(r2.Right,r2.Bottom);
bitmaps[i].Canvas.Brush.Color:=Aux;
bitmaps[i].Canvas.FillRect(r2);
DrawThemeBackGround(Theme,bitmaps[i].Canvas.Handle,WP_MINBUTTON,i,r2,nil);
//In the case u want to remove the corner 3 pixels add the
//following lines that are commented.
bitmaps[i].Canvas.pixels[0,0]:=0;
//bitmaps[i].Canvas.pixels[0,1]:=0;
//bitmaps[i].Canvas.pixels[1,0]:=0;
bitmaps[i].Canvas.pixels[bitmaps[i].Width-1,bitmaps[i].Height-1]:=0;
//bitmaps[i].Canvas.pixels[bitmaps[i].Width-1,bitmaps[i].Height-2]:=0;
//bitmaps[i].Canvas.pixels[bitmaps[i].Width-2,bitmaps[i].Height-1]:=0;
bitmaps[i].Canvas.pixels[bitmaps[i].Width-1,0]:=0;
//bitmaps[i].Canvas.pixels[bitmaps[i].Width-1,1]:=0;
//bitmaps[i].Canvas.pixels[bitmaps[i].Width-2,0]:=0;
bitmaps[i].Canvas.pixels[0,bitmaps[i].Height-1]:=0;
//bitmaps[i].Canvas.pixels[0,bitmaps[i].Height-2]:=0;
//bitmaps[i].Canvas.pixels[1,bitmaps[i].Height-1]:=0;
r:=bounds(0,0,icr.Right-icr.Left,icr.Bottom-icr.Top);
bm.Canvas.CopyRect(r,bitmaps[i].Canvas,icr);
inf:=RemoveIcon(bitmaps[i],@icr);
IconColors[i]:=inf.IconColor;
inf.Rect.Left:=trunc(r2.Right*0.55);
inf.Rect.Right:=trunc(r2.Right*0.82);
bitmaps_[i].Assign(bitmaps[i]);
bitmaps_[i].Canvas.CopyRect(inf.Rect,bm.Canvas,r);
end;
if (_XPStyle = XP_METALLIC) then IconColors[8]:=IconColors[4];
bm.Free;
end;
begin
ThemeChanged:=False;
if not(_SupportsThemes) then
begin
_XPStyle:=NO_THEME;
exit;
end;
if (IsThemeActive) then
begin
st:='Window';
p:=AllocMem((length(st)*2)+2);
StringToWideChar(st,p,(length(st)*2)+2);
Theme:=OpenThemeData(OwnerForm.handle,p);
Freemem(p);
end else Theme:=0;
GetWindowRect(OwnerForm.Handle,r3);
case OwnerForm.BorderStyle of
bsSizeToolWin, bsToolWindow:
begin
H:=GetSystemMetrics(SM_CYSMSIZE);
W:=GetSystemMetrics(SM_CXSMSIZE);
end else
begin
H:=GetSystemMetrics(SM_CYSIZE);
W:=GetSystemMetrics(SM_CXSIZE);
end;
end;
if (Theme <> 0) then W:=H;
r:=GetButtonRect(1,r3,Theme,0,W,H);
r2.Left:=0;
r2.Top:=0;
r2.Right:=r.Right-r.Left;
r2.Bottom:=r.Bottom-r.Top;
DrAux.SetSize(r2.Right,r2.bottom);
if (Theme <> 0) then
begin
DoForTheme;
CloseThemeData(Theme);
end else
begin
_XPStyle:=NO_THEME;
end;
end;
Function TCaptionButtonArray.GetButtonRect(index : byte; rec : TRect; theme : cardinal; OffSet : integer; XS, YS: integer) : TRect;
var
BW, BH, borderx, bordery : integer;
begin
case OwnerForm.BorderStyle of bsSizeable, bsSizeToolWin:
begin
bordery:=GetSystemMetrics(SM_CYSIZEFRAME);
borderx:=GetSystemMetrics(SM_CXSIZEFRAME);
end;
else
begin
bordery:=GetSystemMetrics(SM_CYFIXEDFRAME);
borderx:=GetSystemMetrics(SM_CXFIXEDFRAME);
end;
end;
if (theme <> 0) then
bw:=XS-4
else bw:=XS-2;
bh:=YS-4;
result:=bounds((rec.Right-rec.Left)-borderx-(2*index)-(bw*(index))-OffSet,bordery+2,bw,bh);
end;
Function TCaptionButtonArray.RemoveIcon(Bm : TBitmap; FillR : PRect = nil) : TBtnInfo;
var
ymid, xmid, rmid, dif : integer;
i : cardinal;
Ant, this, fil : TRGB;
rec : trect;
begin
if (FillR = nil) then
begin
ymid:=bm.Height div 2;
xmid:=bm.Width div 2;
for i := ymid to bm.Height - 1 do
begin
TColor(ant):=bm.Canvas.Pixels[xmid,i-1];
TColor(this):=bm.Canvas.Pixels[xmid,i];
dif:=ant.r+ant.g+ant.b;
dec(dif,this.r+this.g+this.b);
if (abs(dif) > IconDif) then
begin
rec.Top:=i;
result.IconColor:=TColor(bm.Canvas.Pixels[xmid,i+1]);
break;
end;
end;
for I := rec.Top+1 to bm.Height-1 do
begin
TColor(ant):=bm.Canvas.Pixels[xmid,i];
TColor(this):=bm.Canvas.Pixels[xmid,i+1];
dif:=ant.r+ant.g+ant.b;
dec(dif,this.r+this.g+this.b);
if (abs(dif) > IconDif) then
begin
rec.bottom:=i+2;
break;
end;
end;
rmid:=(rec.Top+rec.Bottom) div 2;
for I := 3 to bm.width-1 do
begin
TColor(ant):=bm.Canvas.Pixels[i-1,rmid];
TColor(this):=bm.Canvas.Pixels[i,rmid];
dif:=ant.r+ant.g+ant.b;
dec(dif,this.r+this.g+this.b);
if (abs(dif) > IconDif) then
begin
rec.left:=i;
fil:=TRGB(bm.canvas.pixels[i-1,rec.top]);
break;
end;
end;
for I := rec.Left+1 to bm.width-1 do
begin
TColor(ant):=bm.Canvas.Pixels[i,rmid];
TColor(this):=bm.Canvas.Pixels[i+1,rmid];
dif:=ant.r+ant.g+ant.b;
dec(dif,this.r+this.g+this.b);
if (abs(dif) > IconDif) then
begin
rec.right:=i+2;
break;
end;
end;
end;
if (FillR = nil) then
begin
bm.Canvas.Brush.Color:=TColor(fil);
bm.Canvas.FillRect(rec);
result.Rect:=rec;
end
else
begin
bm.Canvas.Brush.Color:=bm.Canvas.Pixels[FillR^.Left-1,(FillR^.Top+FillR^.Bottom) div 2];
Result.IconColor:=bm.Canvas.Pixels[FillR^.Left+2,(FillR^.Top+FillR^.Bottom) div 2];
Result.Rect:=FillR^;
bm.Canvas.FillRect(FillR^);
end;
end;
procedure TCaptionButtonArray.DrawSingleButton(index: integer; DC, stat: Cardinal; fast : boolean = true);
var
btn : TCaptionButton;
aux : cardinal;
r : TRect;
begin
if (index > count-1) then exit;//nothing to do;
btn:=Items[Index];
if not(btn.Visible) then Exit;
if (Fast) then
begin
if (btn.State = stat) then exit;
if (_XPStyle = NO_THEME) then
begin
if (Stat > 4) then dec(stat,4);
case stat of
BT_HOT,BT_IHOT,BT_INORMAL: stat:=BT_NORMAL;
end;
aux:=btn.State;
case aux of
BT_HOT,BT_IHOT,BT_INORMAL: aux:=BT_NORMAL;
end;
if (stat = aux) then exit;
end;
end;
if (_XPStyle <> NO_THEME) then
begin
if btn.OwnerDrawed then
begin
DrAux.Assign(Bitmaps[stat]);
if Assigned(btn.OnDraw) then btn.OnDraw(btn,DrAux,stat,index);
Transparentblt(DC,btn.Rect.Left,btn.Rect.Top,
btn.Rect.Right-btn.Rect.Left,
btn.Rect.bottom-btn.Rect.top,
DrAux.Canvas.Handle,0,0,
btn.Rect.Right-btn.Rect.Left,
btn.Rect.bottom-btn.Rect.top,0);
end else
begin
Transparentblt(DC,btn.Rect.Left,btn.Rect.Top,
btn.Rect.Right-btn.Rect.Left,
btn.Rect.bottom-btn.Rect.top,
Bitmaps_[stat].Canvas.Handle,0,0,
btn.Rect.Right-btn.Rect.Left,
btn.Rect.bottom-btn.Rect.top,0);
end;
end else
begin
if (stat = BT_PUSHED) or (stat = BT_IPUSHED) then
aux:=(DFCS_PUSHED or DFCS_BUTTONPUSH) else
aux:=DFCS_BUTTONPUSH;
DrawFrameControl(DrAux.Canvas.Handle,
bounds(0,0,DrAux.Width,DrAux.Height),DFC_BUTTON,aux);
if btn.OwnerDrawed then
begin
if Assigned(btn.OnDraw) then Btn.OnDraw(btn,DrAux,stat,index);
bitblt(DC,btn.Rect.Left,btn.Rect.Top,
btn.Rect.Right-btn.Rect.Left,
btn.Rect.bottom-btn.Rect.top,
DrAux.Canvas.Handle,0,0,srccopy);
end else
begin
r.Top:=trunc(DrAux.Height*0.65);
r.Bottom:=trunc(DrAux.Height*0.85);
r.Left:=trunc(DrAux.Width*0.55);
r.Right:=trunc(DrAux.Width*0.85);
if (stat = BT_PUSHED) then
begin
inc(r.Top);
inc(r.Bottom);
inc(r.Left);
inc(r.Right);
end;
if (stat = BT_IDISABLED) or (stat = BT_DISABLED) then
begin
inc(r.Right);
inc(r.Bottom);
DrAux.Canvas.Brush.Color:=clwhite;
DrAux.Canvas.FillRect(r);
dec(r.Right);
dec(r.Bottom);
DrAux.Canvas.Brush.Color:=clGrayText;
DrAux.Canvas.FillRect(r);
end else
begin
DrAux.Canvas.Brush.Color:=clbtntext;
DrAux.Canvas.FillRect(r);
end;
bitblt(DC,btn.Rect.Left,btn.Rect.Top,
btn.Rect.Right-btn.Rect.Left,
btn.Rect.bottom-btn.Rect.top,
DrAux.Canvas.Handle,0,0,srccopy);
end;
end;
btn.State:=stat;
end;
//This is the component's WindowProc
procedure TCaptionButtonArray.WndProc(var msg : TMessage);
begin
if (Lock <> 0) then if (Lock = msg.Msg) then exit;
case msg.Msg of
WM_NCPAINT, WM_NCACTIVATE, CM_TEXTCHANGED : ON_WM_NCPAINT(msg);
WM_THEMECHANGED :
begin
ThemeChanged:=true;
ParentWndProc(msg);
end;
WM_NCLBUTTONDOWN : ON_WM_NCLBUTTONDOWN(msg);
WM_NCLBUTTONUP, WM_LBUTTONUP : ON_WM_NCLBUTTONUP(msg);
WM_NCHITTEST : if (Pushed = -1) then ON_WM_NCHITTEST(msg);
WM_MOUSEMOVE : if (Pushed <> -1) then ON_WM_NCHITTEST(msg);
WM_NCRBUTTONDOWN : ON_WM_NCRBUTTONDOWN(msg);
WM_NCRBUTTONUP, WM_RBUTTONUP : ON_WM_NCRBUTTONUP(msg);
WM_TIMER : ON_WM_TIMER(msg);
WM_NCMOUSELEAVE : ON_WM_NCMOUSELEAVE(msg);
else ParentWndProc(msg);
end;
//Debug Begin
//This is for debug only, to display on the form the messages that the
//window receives. Requires unit UMessageStr
(*if (msg.Msg <> WM_NCHITTEST) and
(msg.Msg <> WM_MOUSEMOVE) and
(msg.Msg <> WM_NCMOUSEMOVE)and
(msg.Msg <> WM_SETCURSOR) {and
(msg.Msg <> WM_ENTERIDLE) }
then
begin
mês.Add(mestostr(msg.Msg)+' W = '+IntToHex(msg.WParam,8)+
' L = '+IntToHex(msg.LParam,8)+' R = '+IntToHex(msg.Result,8));
if mês.Count > 59 then mês.Delete(0);
for I := 0 to mês.Count - 1 do
begin
OwnerForm.Canvas.TextOut(4,abs(OwnerForm.Canvas.Font.Height)*i,mês[i]+
' ');
end;
end; *)
//Debug End;
//OwnerForm.Canvas.TextOut(2,30,inttostr(Ntime));
end;
//Messages methods ->
procedure TCaptionButtonArray.ON_WM_NCPAINT(var msg: TMessage);
var
OffSet : integer;
r : TRect;
i, aux, DC : cardinal;
H, W : integer;
pt : TPoint;
begin
ParentWndProc(msg);
OffSet:=0;
H:=GetSystemMetrics(SM_CYSIZE);
W:=GetSystemMetrics(SM_CXSIZE);
if (H <> BtnH) or (W <> BtnW) then
begin
ThemeChanged:=true;
BtnH:=H;
BtnW:=W;
end;
DoThEvt:=ThemeChanged;
if (ThemeChanged) then UpdateBitmaps;
if (_XPStyle <> NO_THEME) then W:=H;
GetWindowRect(OwnerForm.Handle,r);
GetCursorPos(pt);
dec(pt.X,OwnerForm.Left);
dec(pt.Y,OwnerForm.Top);
Selected:=-1;
DC:=GetWindowDC(OwnerForm.Handle);
for i := 0 to Count-1 do
begin
OffSet:=Offset+Items[i].OffSet;
Items[i].Rect:=GetButtonRect(_ToBegin+i,r,Theme,OffSet,W,H);
if PtInRect(Items[i].Rect,pt) then Selected:=i;
Aux:=s4(sb((msg.Msg = WM_NCACTIVATE),(msg.WParam <> 0),(OwnerForm.Active)),0,BT_DISABLED);
inc(Aux,s4(((Selected=Pushed)and(Pushed=integer(i))),BT_PUSHED,s4((Items[i].Enabled),
s4((integer(i) = Selected),BT_HOT,BT_NORMAL),BT_DISABLED)));
if Items[i].Visible then
DrawSingleButton(i,DC,Aux,false);
end;
ReleaseDC(OwnerForm.Handle,DC);
if DoThEvt and Assigned(_OnThemeChange) then
begin
_OnThemeChange(Self);
DoThEvt:=false;
end;
end;
procedure TCaptionButtonArray.ON_WM_NCHITTEST(var msg: TMessage);
var
i, aux, DC : Cardinal;
sel : integer;
pt : TPoint;
begin
if (msg.Msg = WM_NCHITTEST) then
begin
pt.X:=loword(msg.LParam);
pt.Y:=hiword(msg.LParam);
end else GetCursorPos(pt);
dec(pt.x,OwnerForm.Left);
dec(pt.Y,OwnerForm.Top);
sel:=-1;
for i := 0 to Count - 1 do
begin
if (PtInRect(Items[i].Rect,pt)) then sel:=i;
end;
if (sel = -1) or not(Items[sel].Visible) or (msg.Msg = WM_MOUSEMOVE) then ParentWndProc(msg) else
begin
msg.Result:=HTCUSTOMBUTTON;
end;
if (sel <> Selected) then
begin
if HintShow then HintWindow.ReleaseHandle;
DC:=0;
if (Selected <> -1) and (Items[Selected].Enabled) and (Items[selected].Visible) then
begin
DC:=GetWindowDC(OwnerForm.Handle);
aux:=s4((OwnerForm.Active),0,BT_DISABLED);
inc(aux,s4((Items[Selected].Enabled),BT_NORMAL,BT_DISABLED));
DrawSingleButton(Selected,DC,aux);
end;
if (sel <> -1) and (Items[sel].Enabled) and (Items[sel].Visible) and
((Pushed = sel) or (Pushed = -1)) then
begin
if (DC = 0) then DC:=GetWindowDC(OwnerForm.Handle);
aux:=s4((OwnerForm.Active),0,BT_DISABLED);
inc(aux,s4((Pushed = sel),BT_PUSHED,s4((Items[sel].Enabled),BT_HOT,BT_DISABLED)));
DrawSingleButton(sel,DC,aux);
end;
if TimerSet then
begin
KillTimer(OwnerForm.Handle,BTTIMERID);
TimerSet:=false;
end;
if (sel <> -1) and (Items[sel].ShowHint) and (Items[sel].Enabled)
and (Items[sel].Visible) then
begin
SetTimer(OwnerForm.Handle,BTTIMERID,_HintShowTime,nil);
TimerSet:=true;
end;
Selected:=sel;
if (DC <> 0) then ReleaseDC(OwnerForm.Handle,DC);
end{else nothing to do};
if (Selected = -1) and (HintShow) then HintWindow.ReleaseHandle;
end;
procedure TCaptionButtonArray.ON_WM_NCLBUTTONDOWN(var msg: TMessage);
var
DC, aux : Cardinal;
begin
if (Selected = -1) or not(Items[Selected].Visible) or not(Items[Selected].Enabled) then
begin
ParentWndProc(msg);
exit;
end;
Pushed:=Selected;
SetCapture(OwnerForm.Handle);
aux:=s4((OwnerForm.Active),0,BT_DISABLED);
inc(aux,BT_PUSHED);
DC:=GetWindowDC(OwnerForm.Handle);
DrawSingleButton(Pushed,DC,aux);
ReleaseDC(OwnerForm.Handle,DC);
msg.Result:=0;
end;
procedure TCaptionButtonArray.ON_WM_NCLBUTTONUP(var msg: TMessage);
var
DC, aux : Cardinal;
tmp : integer;
begin
DC:=0;
ParentWndProc(msg);
if (Pushed <> -1) then ReleaseCapture;
if (Selected = Pushed) and (Selected <> -1) then
begin
aux:=s4((OwnerForm.Active),0,BT_DISABLED);
inc(aux,BT_HOT);
DC:=GetWindowDC(OwnerForm.Handle);
DrawSingleButton(pushed,DC,aux);
if (Assigned(Items[Pushed].OnClick)) then
begin
tmp:=Pushed;
Pushed:=-1;
Items[tmp].OnClick(Items[tmp],tmp);
Pushed:=tmp;
end;
end else
if (Selected <> -1) then
begin
aux:=s4((OwnerForm.Active),0,BT_DISABLED);
inc(aux,s4(Items[Selected].Enabled,BT_HOT,BT_DISABLED));
if (DC = 0) then DC:=GetWindowDC(OwnerForm.Handle);
DrawSingleButton(Selected,DC,aux);
end;
if (DC <> 0) then ReleaseDC(OwnerForm.Handle,DC);
Pushed:=-1;
end;
procedure TCaptionButtonArray.ON_WM_NCRBUTTONDOWN(var msg: TMessage);
begin
if (Selected <> -1) and (items[Selected].Enabled)
and (Items[Selected].Visible) then
begin
RPushed:=Selected;
SetCapture(OwnerForm.Handle);
msg.Result:=0;
end else if (Selected = -1) or not(Items[selected].Visible)
then ParentWndProc(msg);
end;
procedure TCaptionButtonArray.ON_WM_NCRBUTTONUP(var msg: TMessage);
var
DC, aux : Cardinal;
pt : TPoint;
did : boolean;
begin
did:=false;
if (RPushed <> -1) then ReleaseCapture;
if (Selected = RPushed) and (Selected <> -1) then
begin
if (msg.Msg = WM_NCRBUTTONUP) then
begin
pt.X:=TSmallPoint(msg.LParam).x;
pt.Y:=TSmallPoint(msg.LParam).y;
end else
begin
GetCursorPos(pt);
end;
did:=true;
if (Assigned(Items[RPushed].PopUpMenu)) then Items[RPushed].PopUpMenu.Popup(pt.X,pt.Y);
msg.Result:=0;
end else
begin
if (Selected <> -1) then
begin
aux:=s4((OwnerForm.Active),0,BT_DISABLED);
inc(aux,s4(Items[Selected].Enabled,BT_HOT,BT_DISABLED));
DC:=GetWindowDC(OwnerForm.Handle);
DrawSingleButton(Selected,DC,aux);
ReleaseDC(OwnerForm.Handle,DC);
end;
end;
if ((Selected = -1) or (not Items[selected].Visible)) and not(did) then ParentWndProc(msg);
RPushed:=-1;
end;
procedure TCaptionButtonArray.ON_WM_TIMER(var msg: TMessage);
var
r : TRect;
pt : TPoint;
begin
if (Cardinal(msg.wParam) = BTTIMERID) and (Selected <> -1) then
begin
GetCursorPos(pt);
r.Top:=pt.Y+20;
r.Bottom:=r.Top+abs(HintWindow.Font.Height)+4;
r.Left:=pt.X;
r.Right:=r.Left+HintWindow.Canvas.TextWidth(Items[selected].Hint)+4;
dec(pt.X,OwnerForm.Left);
dec(pt.Y,OwnerForm.Top);
if (PtInRect(Items[Selected].Rect,pt)) then
begin
HintWindow.ActivateHint(r,Items[selected].Hint);
HintShow:=true;
SetTimer(OwnerForm.Handle,HIDEHINTID,_HintHideTime,nil);
HideSet:=True;
end;
msg.Result:=0;
end else if (Cardinal(msg.WParam) = HIDEHINTID) then
begin
if HintShow then HintWindow.ReleaseHandle;
if (HideSet) then
begin
KillTimer(OwnerForm.Handle,HIDEHINTID);
HideSet:=false;
end;
end else ParentWndProc(msg);
if (TimerSet) and (Cardinal(msg.WParam) = BTTIMERID) then
begin
KillTimer(OwnerForm.Handle,BTTIMERID);
TimerSet:=false;
end;
end;
procedure TCaptionButtonArray.ON_WM_NCMOUSELEAVE(var msg: TMessage);
var
DC, aux : cardinal;
pt : TPoint;
begin
GetCursorPos(pt);
dec(pt.X,OwnerForm.Left);
dec(pt.Y,OwnerForm.Top);
if (Selected <> -1) and (Pushed = -1) and (Items[Selected].Enabled)
and not(PtInRect(Items[selected].Rect,pt)) then
begin
aux:=s4(OwnerForm.Active,0,BT_DISABLED);
inc(aux,BT_NORMAL);
DC:=GetWindowDC(OwnerForm.Handle);
DrawSingleButton(Selected,DC,aux);
ReleaseDC(OwnerForm.Handle,DC);
if (TimerSet) then
begin
KillTimer(OwnerForm.Handle,BTTIMERID);
TimerSet:=false;
end;
Selected:=-1;
end;
ParentWndProc(msg);
if HintShow then HintWindow.ReleaseHandle;
end;
// Very boring write methods ->
Procedure TCaptionButtonArray.SetToBegin(AValue: Byte);
begin
if (AValue = _Tobegin) then exit;
_ToBegin:=AValue;
Perform(WM_NCPAINT,1,0);
end;
procedure TCaptionButton.SetOffset(AValue: Integer);
begin
if (AValue = _OffSet) then exit;
_OffSet:=AValue;
TCaptionButtonArray(Collection).Perform(WM_NCPAINT,1,0);
end;
procedure TCaptionButton.SetEnabled(AValue: Boolean);
begin
if (AValue = _Enabled) then exit;
_Enabled:=AValue;
TCaptionButtonArray(Collection).Perform(WM_NCPAINT,1,0);
end;
procedure TCaptionButton.SetVisible(AValue: Boolean);
begin
if (AValue = _Visible) then exit;
_Visible:=AValue;
TCaptionButtonArray(Collection).Perform(WM_NCPAINT,1,0);
end;
//These are the initialization and finalization section required for
//the debug section of the WndProc method. For debug only.
{initialization
mês:=TStringList.Create;
finalization
mês.Destroy; }
end.
Pergunta
Thales Pontes Martins
Aí está o componente para colocar botões extras na barra de título que suporta XP_THEMES.
Se antes quiserem ver o resultado final tem um programa exemplo com código fonte em Delphi 2006(RAR) neste Link.
Tem somente o executável neste Link
Se forem instalar o componente lembrem-se de acrescentar a linha que está como comentário->
Result:={(csDesigning in ComponentState)}false;Troque para-> porque se não fizer isso podem ocorrer efeitos indesejáveis durante o tempo de desenho do programa. O componente é TCaptionButtons derivado de TComponent e existe somente para ser comportado pelo form como sendo componente. Dentro dele existe uma propriedade do tipo TCaptionButtonArray derivada de TCollection, que serve para fazer o controle do componente. E essa por sua vez tem uma coleção da classe TCaptionButton derivada de TCollectionItem compondo os items da coleção que tem como função armazenar os dados de cada botão acrescentado a lista. Qualquer problema mande MP. TCaptionButtonArray -> Propriedades -> ToBegin: Byte - Indica a índice do primeiro botão da lista, da direita pra esquerda. Default = 4. HintHideTime: Integer - Tempo em ms que demora para uma Hint associada a algum botão ser ocultada. Default = 5000; HintShowTime: Integer - Tempo em ms que demora para uma Hint aparecer depois que o mouse estaciona sob a área de um botão. Default = 1300. property Items[index: Integer]: TCaptionButton - Retorna um TCaptionButton da lista de botões no índice especificado. property SupportsThemes : boolean - Indica se a versão do Windows suporta Themes. property XPStyle : byte - Identifica qual tema XP está atualmente sendo usado pela janela: NO_THEME, XP_BLUE, XP_METALLIC ou XP_HOMESTEAD. Eventos -> OnThemeChange -> Ocorre quando há mudança de tema para o Form Owner do componente. Campos -> Bitmaps: array[1..8] of TBitmap - Bitmaps dos botões em todos os seus 8 possíveis estados quando está sendo feito uso de tema. Esse botões não possuem ícones desenhados. Bitmaps_:array[1..8] of TBitmap - Bitmaps dos botões em todos os seus 8 possíveis estados quando está sendo feito uso de tema. Esse botões possuem o ícone de minimizar para o Tray. IconColors : array[1..8] of TColor - Cores dos ícones do botão com o tema usado atualmente em todos os seus 8 estados. Usado para desenhar um ícone no botão. Lock : Cardinal - Mensagem que a aplicação não deve processar. Se for 0 serão processadas todas as mensagems. Usado para mudar várias propriedades que executam mensagems nos seu métodos de escrita, como WM_NCPAINT, e não ter queda de performance. Métodos -> Function add : TCaptionButton; - Cria uma nova instancia de TCaptionButton e adiciona sua referencia a lista. procedure UnLock; - Seta o campo Lock para 0; Function GetButtonRect(index : byte; rec : TRect; theme : cardinal; OffSet : integer; XS, YS: integer) : TRect; - Pega o retangulo que um botão correspondente aos parametros fornecidos ocupa atualmente. Onde "index" é o índice do botão na lista, "rec" é o retangulo do form, "theme" é o handle do tema atual, "OffSet" é quantos pixels o botão deve estar deslocado para a esquerda, "XS" é a largura do botão e "YS" é a altura do botão. Function GetXPStyle(Val : TRGB) : byte; - Retorna a constante que identifica qual tema XP está atualmente sendo usado pela janela mediante fornecimento de uma cor do fundo do botão: NO_THEME, XP_BLUE, XP_METALLIC ou XP_HOMESTEAD. Não é necessário, apenas leia a propriedade XPStyle. Function RemoveIcon(Bm : TBitmap; FillR : PRect = nil) : TBtnInfo; - Remove o ícone de minimizar do bitmap com o botão devidamente desenhado. procedure DrawSingleButton(index: integer; DC, stat : cardinal; fast : boolean = true); - Desenha na barra o botão especificado por "index" no Device Context "DC", no estado "stat", com método economico ou não dependendo de "fast". function Perform(Msg, WParam, LParam : integer) : integer; - Executa a mensagem "Msg" com WParam "WParam", LParam "LParam" e retorna o resultado do processamento da mensagem pelo form ou pelo componente. procedure UpdateBitmaps; - Atualiza os bitmaps. Usado no caso de a aparencia dos botões mudar. TCaptionButton -> Propriedades -> OwnerDrawed : boolean - Indica se o botão é desenhado pelo Owner. Caso true, um bitmap será passado a um Event Handler para que esse possa desenhar o ícone no botão. Caso false, será desenhado o botão de minimizar para o Tray. Default = false. Enabled : boolean - Indica se o botão está habilitado. Default = true. OffSet : integer - Indica a distancia em pixels que o botão deve estar do botão a sua direita. Default = 0. Visible : boolean - Indica se o botão está visível. Default = true; Hint : string - Indica o texto que deverá ser mostrado na Hint do botão. Só será mostrada a Hint se a propriedade ShowHint for true. ShowHint : boolean - Indica se deverá ser mostrada a Hint do Botão. Default = false. PopUpMenu : TPopUpMenu - Referencia a uma instancia de TPopupMenu que deverá aparecer quando o usuário pressionar o botão direito do mouse. Eventos -> OnClick - Ocorre quando o usuário clica no botão. OnDraw - Ocorre quando é desenhado um botão. Um TBitmap é passado como parametro para esse evento para ser desenhado nele o ícone do botão. O Bitmap inicialmente conterá apenas o fundo do botão. Campos -> Rect : TRect - Especifica o retangulo do botão em relação a área não cliente do Form. State : Cardinal - Especifica o estado atual do botão. Listagem da Unit do Componente -> UCaptionButton.Pasunit UCaptionButton; { * Componente CaptionButtons. * Descrição: Componente que permite adicioncar botões extras na barra de título suportando XP_THEMES. * Autor: Thales Pontes Martins. thalespo@terra.com.br * Freeware: Este código pode ser ditribuído livremente desde que sejam mantidas essas informações na íntegra. * Dezembro de 2006. } interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, uxtheme, StdCtrls, Menus{, UMessageStr}; const NO_THEME = byte(0); XP_BLUE = byte(1); XP_METALLIC = byte(2); XP_HOMESTEAD = byte(3); BT_NORMAL = cardinal(1); BT_HOT = cardinal(2); BT_PUSHED = cardinal(3); BT_DISABLED = cardinal(4); BT_INORMAL = cardinal(5); BT_IHOT = cardinal(6); BT_IPUSHED = cardinal(7); BT_IDISABLED = cardinal(8); HTCUSTOMBUTTON = Cardinal(65); BTTIMERID = cardinal(33998015); HIDEHINTID = cardinal(99600342); IconDif = 27; type TCaptionButtonDrawEvent = procedure(Sender : TObject; bmp : TBitmap; state, index : cardinal) of object; TCaptionButtonClickEvent = procedure(Sender : TObject; index : integer) of object; TCaptionButtonArray = class; TCaptionButtons = class; TCaptionButton = class; TRGB = record r, g, b, info : byte; end; TBtnInfo = record Rect : TRect; IconColor : TColor; end; TCaptionButtons = class(TComponent) private _Buttons : TCaptionButtonArray; function des : boolean; public Constructor Create(AOwner : TComponent); override; Destructor Destroy; override; published Property Buttons : TCaptionButtonArray read _Buttons; end; TCaptionButtonArray = class(TCollection) private _SupportsThemes, ThemeChanged, DoThEvt : boolean; ParentWndProc : TWndMethod; _OnThemeChange : TNotifyEvent; OwnerForm : TForm; Owner : TCaptionButtons; Theme : THANDLE; _XPStyle : byte; Selected, Pushed, RPushed, _HintShowTime, _HintHideTime : integer; _ToBegin : Byte; DrAux : TBitmap; BtnH, BtnW : integer; TimerSet, HintShow, HideSet : Boolean; HintWindow : THintWindow; procedure SetToBegin(AValue : byte); Protected Function Add : TCaptionButton; Function GetItem(Index : integer) : TCaptionButton; Procedure SetItem(Index : Integer; Item : TCaptionButton); //Messages procedure ON_WM_NCPAINT(var msg : TMessage); Procedure ON_WM_NCHITTEST(var msg : TMessage); procedure ON_WM_NCLBUTTONDOWN(var msg : TMessage); procedure ON_WM_NCLBUTTONUP(var msg : TMessage); procedure ON_WM_NCRBUTTONDOWN(var msg : TMessage); procedure ON_WM_NCRBUTTONUP(var msg : TMessage); procedure ON_WM_TIMER(var msg : TMessage); procedure ON_WM_NCMOUSELEAVE(var msg : TMessage); public bitmaps, bitmaps_ : array[1..8] of TBitmap; IconColors : array[1..8] of TColor; Lock : Cardinal; constructor Create(AForm : TForm; AOwner : TCaptionButtons); Destructor Destroy; Override; procedure WndProc(var msg : TMessage); procedure UnLock; Function GetButtonRect(index : byte; rec : TRect; theme : cardinal; OffSet : integer; XS, YS: integer) : TRect; Function GetXPStyle(Val : TRGB) : byte; Function RemoveIcon(Bm : TBitmap; FillR : PRect = nil) : TBtnInfo; procedure DrawSingleButton(index: integer; DC, stat : cardinal; fast : boolean = true); function Perform(Msg, WParam, LParam : integer) : integer; procedure UpdateBitmaps; property Items[Index: Integer]: TCaptionButton read GetItem write SetItem; property SupportsThemes : boolean read _SupportsThemes; property XPStyle : byte read _XPStyle; published property ToBegin : Byte read _Tobegin write SetToBegin; property HintHideTime : integer read _HintHideTime write _HintHideTime; property HintShowTime : integer read _HintShowTime write _HintShowTime; property OnThemeChange : TNotifyEvent read _OnThemeChange write _OnThemeChange; end; TCaptionButton = class(TCollectionItem) private _OnClick : TCaptionButtonClickEvent; _OnDraw : TCaptionButtonDrawEvent; _OwnerDrawed, _Enabled, _Visible, _ShowHint : Boolean; _PopUpMenu : TPopUpMenu; _OffSet : integer; _Hint : string; procedure SetOffset(AValue : integer); procedure SetEnabled(AValue : boolean); procedure SetVisible(AValue : boolean); public Rect : TRect; State : Cardinal; Constructor Create(Collection : TCollection); override; Destructor Destroy; override; published property OwnerDrawed : boolean read _OwnerDrawed write _OwnerDrawed; property Enabled : boolean read _Enabled write SetEnabled; property OffSet : integer read _OffSet write SetOffSet; property Visible : boolean read _Visible write SetVisible; property Hint : string read _Hint write _Hint; property ShowHint : boolean read _ShowHint write _ShowHint; property PopUpMenu : TPopUpMenu read _PopUpMenu write _PopUpMenu; property OnClick : TCaptionButtonClickEvent read _OnClick write _OnClick; property OnDraw : TCaptionButtonDrawEvent read _OnDraw write _OnDraw; end; procedure register; implementation //Global fields used in debugging {var NTime : cardinal; mês: TStringList; } procedure register; begin RegisterComponents('Samples',[TCaptionButtons]); end; //this is a function that parses a TRect to a string //Used in debug only {Function RectToStr(r : TRect) : string; begin Result:='L_'+inttostr(r.Left)+' '+ 'R_'+inttostr(r.Right)+' '+ 'T_'+inttostr(r.Top)+' '+ 'B_'+inttostr(r.Bottom); end;} //These are the condition functions imitating the C++ ? operator function s1(cond : boolean;vt,vf:byte) : byte; begin if (cond) then result:=vt else result:=vf; end; function s4(cond : boolean;vt,vf:Cardinal) : Cardinal; begin if (cond) then result:=vt else result:=vf; end; function s4_(cond : boolean;vt,vf:Integer) : Integer; begin if (cond) then result:=vt else result:=vf; end; function sb(cond : boolean;vt,vf:boolean) : boolean; begin if (cond) then result:=vt else result:=vf; end; constructor TCaptionButtons.Create(AOwner: TComponent); begin inherited Create(AOwner); _Buttons:=TCaptionButtonArray.create(TForm(AOwner),self); end; function TCaptionButtons.des : Boolean; begin result:={(csDesigning in ComponentState)}false; //Pay attention, the (csDesigning in ComponentState) expression //will cause an exception if the component is being created //in runtime rather than being a installed component. end; Destructor TCaptionButtons.Destroy; begin _Buttons.Destroy; inherited Destroy; end; Constructor TCaptionButton.Create(Collection: TCollection); begin self.Collection:=Collection; _Enabled:=True; _Visible:=True; _OwnerDrawed:=False; _PopUpMenu:=nil; _OffSet:=0; _Hint:=''; _ShowHint:=false; end; destructor TCaptionButton.Destroy; begin inherited Destroy; end; procedure TCaptionButtonArray.UnLock; begin Lock:=0; end; Constructor TCaptionButtonArray.Create(AForm : TForm; AOwner : TCaptionButtons); var i : cardinal; begin inherited Create(TCaptionButton); if (Owner.des) then exit; ThemeChanged:=True; Selected:=-1; Pushed:=-1; RPushed:=-1; _ToBegin:=4; TimerSet:=false; HintShow:=false; HideSet:=false; DoThEvt:=true; Lock:=0; _HintHideTime:=5000; _HintShowTime:=1300; _OnThemeChange:=nil; OwnerForm:=AForm; Owner:=AOwner; ParentWndProc:=OwnerForm.WindowProc; ThemeChanged:=True; _SupportsThemes:=InitThemeLibrary;//indicates if the windows version supports themes DrAux:=TBitmap.Create; if _supportsThemes then for I := 1 to 8 do begin Bitmaps[i]:=TBitmap.Create; Bitmaps_[i]:=TBitmap.Create; end; HintWindow:=THintWindow.Create(Owner); HintWindow.Color:=clInfoBk; OwnerForm.WindowProc:=WndProc; end; Destructor TCaptionButtonArray.Destroy; var i : cardinal; begin if _SupportsThemes then FreeThemeLibrary; OwnerForm.WindowProc:=ParentWndProc; DrAux.Destroy; if _SupportsThemes then for I := 1 to 8 do begin Bitmaps[i].Destroy; Bitmaps_[i].Destroy; end; HintWindow.Destroy; inherited Destroy; end; Function TCaptionButtonArray.Add : TCaptionButton; begin result:=TCaptionButton(inherited Add); end; Function TCaptionButtonArray.GetItem(Index : Integer) : TCaptionButton; begin Result:=TCaptionButton(inherited GetItem(Index)); end; Procedure TCaptionButtonArray.SetItem(Index : integer; Item : TCaptionButton); begin inherited SetItem(Index,Item); end; function TCaptionButtonArray.Perform(Msg, WParam, LParam: integer) : integer; var ms : TMessage; begin ms.Msg:=Msg; ms.WParam:=WParam; ms.LParam:=LParam; ms.Result:=0; WndProc(ms); result:=ms.Result; end; Function TCaptionButtonArray.GetXPStyle(Val : TRGB) : byte; begin if (abs(integer(val.b)-((integer(val.r)+integer(val.g)) div 2)) < 30){Must be 17} then Result:=XP_METALLIC else begin if (val.b > s1((val.r>val.g),val.r,val.g)) then Result:=XP_BLUE else result:=XP_HOMESTEAD; end; end; procedure TCaptionButtonArray.UpdateBitmaps; var p : PWideChar; st : string; r, r2, r3 : TRect; H, W : Integer; procedure DoForTheme; var i : cardinal; Aux : TColor; bm : tbitmap; icr: TRect; inf : TBtnInfo; begin bm:=TBitmap.Create; bm.SetSize(r2.Right,r2.Bottom); DrawThemeBackGround(Theme,bm.canvas.Handle,WP_MINBUTTON,1,r2,nil); Aux:=bm.Canvas.Pixels[bm.Width div 2,bm.Height div 2]; _XPStyle:=GetXPStyle(TRGB(Aux)); icr:=RemoveIcon(bm).Rect; for i:=1 to 8 do begin bitmaps[i].SetSize(r2.Right,r2.Bottom); bitmaps[i].Canvas.Brush.Color:=Aux; bitmaps[i].Canvas.FillRect(r2); DrawThemeBackGround(Theme,bitmaps[i].Canvas.Handle,WP_MINBUTTON,i,r2,nil); //In the case u want to remove the corner 3 pixels add the //following lines that are commented. bitmaps[i].Canvas.pixels[0,0]:=0; //bitmaps[i].Canvas.pixels[0,1]:=0; //bitmaps[i].Canvas.pixels[1,0]:=0; bitmaps[i].Canvas.pixels[bitmaps[i].Width-1,bitmaps[i].Height-1]:=0; //bitmaps[i].Canvas.pixels[bitmaps[i].Width-1,bitmaps[i].Height-2]:=0; //bitmaps[i].Canvas.pixels[bitmaps[i].Width-2,bitmaps[i].Height-1]:=0; bitmaps[i].Canvas.pixels[bitmaps[i].Width-1,0]:=0; //bitmaps[i].Canvas.pixels[bitmaps[i].Width-1,1]:=0; //bitmaps[i].Canvas.pixels[bitmaps[i].Width-2,0]:=0; bitmaps[i].Canvas.pixels[0,bitmaps[i].Height-1]:=0; //bitmaps[i].Canvas.pixels[0,bitmaps[i].Height-2]:=0; //bitmaps[i].Canvas.pixels[1,bitmaps[i].Height-1]:=0; r:=bounds(0,0,icr.Right-icr.Left,icr.Bottom-icr.Top); bm.Canvas.CopyRect(r,bitmaps[i].Canvas,icr); inf:=RemoveIcon(bitmaps[i],@icr); IconColors[i]:=inf.IconColor; inf.Rect.Left:=trunc(r2.Right*0.55); inf.Rect.Right:=trunc(r2.Right*0.82); bitmaps_[i].Assign(bitmaps[i]); bitmaps_[i].Canvas.CopyRect(inf.Rect,bm.Canvas,r); end; if (_XPStyle = XP_METALLIC) then IconColors[8]:=IconColors[4]; bm.Free; end; begin ThemeChanged:=False; if not(_SupportsThemes) then begin _XPStyle:=NO_THEME; exit; end; if (IsThemeActive) then begin st:='Window'; p:=AllocMem((length(st)*2)+2); StringToWideChar(st,p,(length(st)*2)+2); Theme:=OpenThemeData(OwnerForm.handle,p); Freemem(p); end else Theme:=0; GetWindowRect(OwnerForm.Handle,r3); case OwnerForm.BorderStyle of bsSizeToolWin, bsToolWindow: begin H:=GetSystemMetrics(SM_CYSMSIZE); W:=GetSystemMetrics(SM_CXSMSIZE); end else begin H:=GetSystemMetrics(SM_CYSIZE); W:=GetSystemMetrics(SM_CXSIZE); end; end; if (Theme <> 0) then W:=H; r:=GetButtonRect(1,r3,Theme,0,W,H); r2.Left:=0; r2.Top:=0; r2.Right:=r.Right-r.Left; r2.Bottom:=r.Bottom-r.Top; DrAux.SetSize(r2.Right,r2.bottom); if (Theme <> 0) then begin DoForTheme; CloseThemeData(Theme); end else begin _XPStyle:=NO_THEME; end; end; Function TCaptionButtonArray.GetButtonRect(index : byte; rec : TRect; theme : cardinal; OffSet : integer; XS, YS: integer) : TRect; var BW, BH, borderx, bordery : integer; begin case OwnerForm.BorderStyle of bsSizeable, bsSizeToolWin: begin bordery:=GetSystemMetrics(SM_CYSIZEFRAME); borderx:=GetSystemMetrics(SM_CXSIZEFRAME); end; else begin bordery:=GetSystemMetrics(SM_CYFIXEDFRAME); borderx:=GetSystemMetrics(SM_CXFIXEDFRAME); end; end; if (theme <> 0) then bw:=XS-4 else bw:=XS-2; bh:=YS-4; result:=bounds((rec.Right-rec.Left)-borderx-(2*index)-(bw*(index))-OffSet,bordery+2,bw,bh); end; Function TCaptionButtonArray.RemoveIcon(Bm : TBitmap; FillR : PRect = nil) : TBtnInfo; var ymid, xmid, rmid, dif : integer; i : cardinal; Ant, this, fil : TRGB; rec : trect; begin if (FillR = nil) then begin ymid:=bm.Height div 2; xmid:=bm.Width div 2; for i := ymid to bm.Height - 1 do begin TColor(ant):=bm.Canvas.Pixels[xmid,i-1]; TColor(this):=bm.Canvas.Pixels[xmid,i]; dif:=ant.r+ant.g+ant.b; dec(dif,this.r+this.g+this.b); if (abs(dif) > IconDif) then begin rec.Top:=i; result.IconColor:=TColor(bm.Canvas.Pixels[xmid,i+1]); break; end; end; for I := rec.Top+1 to bm.Height-1 do begin TColor(ant):=bm.Canvas.Pixels[xmid,i]; TColor(this):=bm.Canvas.Pixels[xmid,i+1]; dif:=ant.r+ant.g+ant.b; dec(dif,this.r+this.g+this.b); if (abs(dif) > IconDif) then begin rec.bottom:=i+2; break; end; end; rmid:=(rec.Top+rec.Bottom) div 2; for I := 3 to bm.width-1 do begin TColor(ant):=bm.Canvas.Pixels[i-1,rmid]; TColor(this):=bm.Canvas.Pixels[i,rmid]; dif:=ant.r+ant.g+ant.b; dec(dif,this.r+this.g+this.b); if (abs(dif) > IconDif) then begin rec.left:=i; fil:=TRGB(bm.canvas.pixels[i-1,rec.top]); break; end; end; for I := rec.Left+1 to bm.width-1 do begin TColor(ant):=bm.Canvas.Pixels[i,rmid]; TColor(this):=bm.Canvas.Pixels[i+1,rmid]; dif:=ant.r+ant.g+ant.b; dec(dif,this.r+this.g+this.b); if (abs(dif) > IconDif) then begin rec.right:=i+2; break; end; end; end; if (FillR = nil) then begin bm.Canvas.Brush.Color:=TColor(fil); bm.Canvas.FillRect(rec); result.Rect:=rec; end else begin bm.Canvas.Brush.Color:=bm.Canvas.Pixels[FillR^.Left-1,(FillR^.Top+FillR^.Bottom) div 2]; Result.IconColor:=bm.Canvas.Pixels[FillR^.Left+2,(FillR^.Top+FillR^.Bottom) div 2]; Result.Rect:=FillR^; bm.Canvas.FillRect(FillR^); end; end; procedure TCaptionButtonArray.DrawSingleButton(index: integer; DC, stat: Cardinal; fast : boolean = true); var btn : TCaptionButton; aux : cardinal; r : TRect; begin if (index > count-1) then exit;//nothing to do; btn:=Items[Index]; if not(btn.Visible) then Exit; if (Fast) then begin if (btn.State = stat) then exit; if (_XPStyle = NO_THEME) then begin if (Stat > 4) then dec(stat,4); case stat of BT_HOT,BT_IHOT,BT_INORMAL: stat:=BT_NORMAL; end; aux:=btn.State; case aux of BT_HOT,BT_IHOT,BT_INORMAL: aux:=BT_NORMAL; end; if (stat = aux) then exit; end; end; if (_XPStyle <> NO_THEME) then begin if btn.OwnerDrawed then begin DrAux.Assign(Bitmaps[stat]); if Assigned(btn.OnDraw) then btn.OnDraw(btn,DrAux,stat,index); Transparentblt(DC,btn.Rect.Left,btn.Rect.Top, btn.Rect.Right-btn.Rect.Left, btn.Rect.bottom-btn.Rect.top, DrAux.Canvas.Handle,0,0, btn.Rect.Right-btn.Rect.Left, btn.Rect.bottom-btn.Rect.top,0); end else begin Transparentblt(DC,btn.Rect.Left,btn.Rect.Top, btn.Rect.Right-btn.Rect.Left, btn.Rect.bottom-btn.Rect.top, Bitmaps_[stat].Canvas.Handle,0,0, btn.Rect.Right-btn.Rect.Left, btn.Rect.bottom-btn.Rect.top,0); end; end else begin if (stat = BT_PUSHED) or (stat = BT_IPUSHED) then aux:=(DFCS_PUSHED or DFCS_BUTTONPUSH) else aux:=DFCS_BUTTONPUSH; DrawFrameControl(DrAux.Canvas.Handle, bounds(0,0,DrAux.Width,DrAux.Height),DFC_BUTTON,aux); if btn.OwnerDrawed then begin if Assigned(btn.OnDraw) then Btn.OnDraw(btn,DrAux,stat,index); bitblt(DC,btn.Rect.Left,btn.Rect.Top, btn.Rect.Right-btn.Rect.Left, btn.Rect.bottom-btn.Rect.top, DrAux.Canvas.Handle,0,0,srccopy); end else begin r.Top:=trunc(DrAux.Height*0.65); r.Bottom:=trunc(DrAux.Height*0.85); r.Left:=trunc(DrAux.Width*0.55); r.Right:=trunc(DrAux.Width*0.85); if (stat = BT_PUSHED) then begin inc(r.Top); inc(r.Bottom); inc(r.Left); inc(r.Right); end; if (stat = BT_IDISABLED) or (stat = BT_DISABLED) then begin inc(r.Right); inc(r.Bottom); DrAux.Canvas.Brush.Color:=clwhite; DrAux.Canvas.FillRect(r); dec(r.Right); dec(r.Bottom); DrAux.Canvas.Brush.Color:=clGrayText; DrAux.Canvas.FillRect(r); end else begin DrAux.Canvas.Brush.Color:=clbtntext; DrAux.Canvas.FillRect(r); end; bitblt(DC,btn.Rect.Left,btn.Rect.Top, btn.Rect.Right-btn.Rect.Left, btn.Rect.bottom-btn.Rect.top, DrAux.Canvas.Handle,0,0,srccopy); end; end; btn.State:=stat; end; //This is the component's WindowProc procedure TCaptionButtonArray.WndProc(var msg : TMessage); begin if (Lock <> 0) then if (Lock = msg.Msg) then exit; case msg.Msg of WM_NCPAINT, WM_NCACTIVATE, CM_TEXTCHANGED : ON_WM_NCPAINT(msg); WM_THEMECHANGED : begin ThemeChanged:=true; ParentWndProc(msg); end; WM_NCLBUTTONDOWN : ON_WM_NCLBUTTONDOWN(msg); WM_NCLBUTTONUP, WM_LBUTTONUP : ON_WM_NCLBUTTONUP(msg); WM_NCHITTEST : if (Pushed = -1) then ON_WM_NCHITTEST(msg); WM_MOUSEMOVE : if (Pushed <> -1) then ON_WM_NCHITTEST(msg); WM_NCRBUTTONDOWN : ON_WM_NCRBUTTONDOWN(msg); WM_NCRBUTTONUP, WM_RBUTTONUP : ON_WM_NCRBUTTONUP(msg); WM_TIMER : ON_WM_TIMER(msg); WM_NCMOUSELEAVE : ON_WM_NCMOUSELEAVE(msg); else ParentWndProc(msg); end; //Debug Begin //This is for debug only, to display on the form the messages that the //window receives. Requires unit UMessageStr (*if (msg.Msg <> WM_NCHITTEST) and (msg.Msg <> WM_MOUSEMOVE) and (msg.Msg <> WM_NCMOUSEMOVE)and (msg.Msg <> WM_SETCURSOR) {and (msg.Msg <> WM_ENTERIDLE) } then begin mês.Add(mestostr(msg.Msg)+' W = '+IntToHex(msg.WParam,8)+ ' L = '+IntToHex(msg.LParam,8)+' R = '+IntToHex(msg.Result,8)); if mês.Count > 59 then mês.Delete(0); for I := 0 to mês.Count - 1 do begin OwnerForm.Canvas.TextOut(4,abs(OwnerForm.Canvas.Font.Height)*i,mês[i]+ ' '); end; end; *) //Debug End; //OwnerForm.Canvas.TextOut(2,30,inttostr(Ntime)); end; //Messages methods -> procedure TCaptionButtonArray.ON_WM_NCPAINT(var msg: TMessage); var OffSet : integer; r : TRect; i, aux, DC : cardinal; H, W : integer; pt : TPoint; begin ParentWndProc(msg); OffSet:=0; H:=GetSystemMetrics(SM_CYSIZE); W:=GetSystemMetrics(SM_CXSIZE); if (H <> BtnH) or (W <> BtnW) then begin ThemeChanged:=true; BtnH:=H; BtnW:=W; end; DoThEvt:=ThemeChanged; if (ThemeChanged) then UpdateBitmaps; if (_XPStyle <> NO_THEME) then W:=H; GetWindowRect(OwnerForm.Handle,r); GetCursorPos(pt); dec(pt.X,OwnerForm.Left); dec(pt.Y,OwnerForm.Top); Selected:=-1; DC:=GetWindowDC(OwnerForm.Handle); for i := 0 to Count-1 do begin OffSet:=Offset+Items[i].OffSet; Items[i].Rect:=GetButtonRect(_ToBegin+i,r,Theme,OffSet,W,H); if PtInRect(Items[i].Rect,pt) then Selected:=i; Aux:=s4(sb((msg.Msg = WM_NCACTIVATE),(msg.WParam <> 0),(OwnerForm.Active)),0,BT_DISABLED); inc(Aux,s4(((Selected=Pushed)and(Pushed=integer(i))),BT_PUSHED,s4((Items[i].Enabled), s4((integer(i) = Selected),BT_HOT,BT_NORMAL),BT_DISABLED))); if Items[i].Visible then DrawSingleButton(i,DC,Aux,false); end; ReleaseDC(OwnerForm.Handle,DC); if DoThEvt and Assigned(_OnThemeChange) then begin _OnThemeChange(Self); DoThEvt:=false; end; end; procedure TCaptionButtonArray.ON_WM_NCHITTEST(var msg: TMessage); var i, aux, DC : Cardinal; sel : integer; pt : TPoint; begin if (msg.Msg = WM_NCHITTEST) then begin pt.X:=loword(msg.LParam); pt.Y:=hiword(msg.LParam); end else GetCursorPos(pt); dec(pt.x,OwnerForm.Left); dec(pt.Y,OwnerForm.Top); sel:=-1; for i := 0 to Count - 1 do begin if (PtInRect(Items[i].Rect,pt)) then sel:=i; end; if (sel = -1) or not(Items[sel].Visible) or (msg.Msg = WM_MOUSEMOVE) then ParentWndProc(msg) else begin msg.Result:=HTCUSTOMBUTTON; end; if (sel <> Selected) then begin if HintShow then HintWindow.ReleaseHandle; DC:=0; if (Selected <> -1) and (Items[Selected].Enabled) and (Items[selected].Visible) then begin DC:=GetWindowDC(OwnerForm.Handle); aux:=s4((OwnerForm.Active),0,BT_DISABLED); inc(aux,s4((Items[Selected].Enabled),BT_NORMAL,BT_DISABLED)); DrawSingleButton(Selected,DC,aux); end; if (sel <> -1) and (Items[sel].Enabled) and (Items[sel].Visible) and ((Pushed = sel) or (Pushed = -1)) then begin if (DC = 0) then DC:=GetWindowDC(OwnerForm.Handle); aux:=s4((OwnerForm.Active),0,BT_DISABLED); inc(aux,s4((Pushed = sel),BT_PUSHED,s4((Items[sel].Enabled),BT_HOT,BT_DISABLED))); DrawSingleButton(sel,DC,aux); end; if TimerSet then begin KillTimer(OwnerForm.Handle,BTTIMERID); TimerSet:=false; end; if (sel <> -1) and (Items[sel].ShowHint) and (Items[sel].Enabled) and (Items[sel].Visible) then begin SetTimer(OwnerForm.Handle,BTTIMERID,_HintShowTime,nil); TimerSet:=true; end; Selected:=sel; if (DC <> 0) then ReleaseDC(OwnerForm.Handle,DC); end{else nothing to do}; if (Selected = -1) and (HintShow) then HintWindow.ReleaseHandle; end; procedure TCaptionButtonArray.ON_WM_NCLBUTTONDOWN(var msg: TMessage); var DC, aux : Cardinal; begin if (Selected = -1) or not(Items[Selected].Visible) or not(Items[Selected].Enabled) then begin ParentWndProc(msg); exit; end; Pushed:=Selected; SetCapture(OwnerForm.Handle); aux:=s4((OwnerForm.Active),0,BT_DISABLED); inc(aux,BT_PUSHED); DC:=GetWindowDC(OwnerForm.Handle); DrawSingleButton(Pushed,DC,aux); ReleaseDC(OwnerForm.Handle,DC); msg.Result:=0; end; procedure TCaptionButtonArray.ON_WM_NCLBUTTONUP(var msg: TMessage); var DC, aux : Cardinal; tmp : integer; begin DC:=0; ParentWndProc(msg); if (Pushed <> -1) then ReleaseCapture; if (Selected = Pushed) and (Selected <> -1) then begin aux:=s4((OwnerForm.Active),0,BT_DISABLED); inc(aux,BT_HOT); DC:=GetWindowDC(OwnerForm.Handle); DrawSingleButton(pushed,DC,aux); if (Assigned(Items[Pushed].OnClick)) then begin tmp:=Pushed; Pushed:=-1; Items[tmp].OnClick(Items[tmp],tmp); Pushed:=tmp; end; end else if (Selected <> -1) then begin aux:=s4((OwnerForm.Active),0,BT_DISABLED); inc(aux,s4(Items[Selected].Enabled,BT_HOT,BT_DISABLED)); if (DC = 0) then DC:=GetWindowDC(OwnerForm.Handle); DrawSingleButton(Selected,DC,aux); end; if (DC <> 0) then ReleaseDC(OwnerForm.Handle,DC); Pushed:=-1; end; procedure TCaptionButtonArray.ON_WM_NCRBUTTONDOWN(var msg: TMessage); begin if (Selected <> -1) and (items[Selected].Enabled) and (Items[Selected].Visible) then begin RPushed:=Selected; SetCapture(OwnerForm.Handle); msg.Result:=0; end else if (Selected = -1) or not(Items[selected].Visible) then ParentWndProc(msg); end; procedure TCaptionButtonArray.ON_WM_NCRBUTTONUP(var msg: TMessage); var DC, aux : Cardinal; pt : TPoint; did : boolean; begin did:=false; if (RPushed <> -1) then ReleaseCapture; if (Selected = RPushed) and (Selected <> -1) then begin if (msg.Msg = WM_NCRBUTTONUP) then begin pt.X:=TSmallPoint(msg.LParam).x; pt.Y:=TSmallPoint(msg.LParam).y; end else begin GetCursorPos(pt); end; did:=true; if (Assigned(Items[RPushed].PopUpMenu)) then Items[RPushed].PopUpMenu.Popup(pt.X,pt.Y); msg.Result:=0; end else begin if (Selected <> -1) then begin aux:=s4((OwnerForm.Active),0,BT_DISABLED); inc(aux,s4(Items[Selected].Enabled,BT_HOT,BT_DISABLED)); DC:=GetWindowDC(OwnerForm.Handle); DrawSingleButton(Selected,DC,aux); ReleaseDC(OwnerForm.Handle,DC); end; end; if ((Selected = -1) or (not Items[selected].Visible)) and not(did) then ParentWndProc(msg); RPushed:=-1; end; procedure TCaptionButtonArray.ON_WM_TIMER(var msg: TMessage); var r : TRect; pt : TPoint; begin if (Cardinal(msg.wParam) = BTTIMERID) and (Selected <> -1) then begin GetCursorPos(pt); r.Top:=pt.Y+20; r.Bottom:=r.Top+abs(HintWindow.Font.Height)+4; r.Left:=pt.X; r.Right:=r.Left+HintWindow.Canvas.TextWidth(Items[selected].Hint)+4; dec(pt.X,OwnerForm.Left); dec(pt.Y,OwnerForm.Top); if (PtInRect(Items[Selected].Rect,pt)) then begin HintWindow.ActivateHint(r,Items[selected].Hint); HintShow:=true; SetTimer(OwnerForm.Handle,HIDEHINTID,_HintHideTime,nil); HideSet:=True; end; msg.Result:=0; end else if (Cardinal(msg.WParam) = HIDEHINTID) then begin if HintShow then HintWindow.ReleaseHandle; if (HideSet) then begin KillTimer(OwnerForm.Handle,HIDEHINTID); HideSet:=false; end; end else ParentWndProc(msg); if (TimerSet) and (Cardinal(msg.WParam) = BTTIMERID) then begin KillTimer(OwnerForm.Handle,BTTIMERID); TimerSet:=false; end; end; procedure TCaptionButtonArray.ON_WM_NCMOUSELEAVE(var msg: TMessage); var DC, aux : cardinal; pt : TPoint; begin GetCursorPos(pt); dec(pt.X,OwnerForm.Left); dec(pt.Y,OwnerForm.Top); if (Selected <> -1) and (Pushed = -1) and (Items[Selected].Enabled) and not(PtInRect(Items[selected].Rect,pt)) then begin aux:=s4(OwnerForm.Active,0,BT_DISABLED); inc(aux,BT_NORMAL); DC:=GetWindowDC(OwnerForm.Handle); DrawSingleButton(Selected,DC,aux); ReleaseDC(OwnerForm.Handle,DC); if (TimerSet) then begin KillTimer(OwnerForm.Handle,BTTIMERID); TimerSet:=false; end; Selected:=-1; end; ParentWndProc(msg); if HintShow then HintWindow.ReleaseHandle; end; // Very boring write methods -> Procedure TCaptionButtonArray.SetToBegin(AValue: Byte); begin if (AValue = _Tobegin) then exit; _ToBegin:=AValue; Perform(WM_NCPAINT,1,0); end; procedure TCaptionButton.SetOffset(AValue: Integer); begin if (AValue = _OffSet) then exit; _OffSet:=AValue; TCaptionButtonArray(Collection).Perform(WM_NCPAINT,1,0); end; procedure TCaptionButton.SetEnabled(AValue: Boolean); begin if (AValue = _Enabled) then exit; _Enabled:=AValue; TCaptionButtonArray(Collection).Perform(WM_NCPAINT,1,0); end; procedure TCaptionButton.SetVisible(AValue: Boolean); begin if (AValue = _Visible) then exit; _Visible:=AValue; TCaptionButtonArray(Collection).Perform(WM_NCPAINT,1,0); end; //These are the initialization and finalization section required for //the debug section of the WndProc method. For debug only. {initialization mês:=TStringList.Create; finalization mês.Destroy; } end.Espero que seja útil.
Abraços.
Editado por Thales Pontes MartinsLink para o comentário
Compartilhar em outros sites
2 respostass a esta questão
Posts Recomendados
Participe da discussão
Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.