1349 lines
36 KiB
ObjectPascal
1349 lines
36 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: JvArrowBtn.PAS, released on 2002-05-26.
|
|
|
|
The Initial Developer of the Original Code is Peter Thörnqvist [peter3 at sourceforge dot net]
|
|
Portions created by Peter Thörnqvist are Copyright (C) 2002 Peter Thörnqvist.
|
|
All Rights Reserved.
|
|
|
|
Contributor(s):
|
|
|
|
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
|
|
located at http://jvcl.sourceforge.net
|
|
|
|
Description:
|
|
The TJvArrowButton component implements an arrow button like
|
|
the ones used in Office 97: one button and one arrow with
|
|
separate events.
|
|
|
|
Known Issues:
|
|
-----------------------------------------------------------------------------}
|
|
// $Id: JvArrowButton.pas 11043 2006-11-26 07:21:48Z marquardt $
|
|
|
|
unit JvArrowButton;
|
|
|
|
{$I jvcl.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF UNITVERSIONING}
|
|
JclUnitVersioning,
|
|
{$ENDIF UNITVERSIONING}
|
|
Classes, Windows, Messages, Controls, Graphics, Buttons, Menus,
|
|
{$IFDEF HAS_UNIT_TYPES}
|
|
Types,
|
|
{$ENDIF HAS_UNIT_TYPES}
|
|
{$IFDEF VCL}
|
|
CommCtrl,
|
|
{$ENDIF VCL}
|
|
{$IFDEF VisualCLX}
|
|
QImgList,
|
|
{$ENDIF VisualCLX}
|
|
JvComponent, JvTypes;
|
|
|
|
type
|
|
TJvArrowButton = class(TJvGraphicControl)
|
|
private
|
|
FGroupIndex: Integer;
|
|
FGlyph: TObject;
|
|
FDown: Boolean;
|
|
FArrowClick: Boolean;
|
|
FPressBoth: Boolean;
|
|
FArrowWidth: Integer;
|
|
FAllowAllUp: Boolean;
|
|
FLayout: TButtonLayout;
|
|
FSpacing: Integer;
|
|
FFillFont: TFont;
|
|
FMargin: Integer;
|
|
FFlat: Boolean;
|
|
FMouseInControl: Boolean;
|
|
FDropDown: TPopupMenu;
|
|
FDropOnButtonClick: Boolean;
|
|
FOnDrop: TNotifyEvent;
|
|
procedure GlyphChanged(Sender: TObject);
|
|
procedure UpdateExclusive;
|
|
function GetGlyph: TBitmap;
|
|
procedure SetGlyph(Value: TBitmap);
|
|
function GetNumGlyphs: TNumGlyphs;
|
|
procedure SetNumGlyphs(Value: TNumGlyphs);
|
|
procedure SetDown(Value: Boolean);
|
|
procedure SetFlat(Value: Boolean);
|
|
procedure SetAllowAllUp(Value: Boolean);
|
|
procedure SetGroupIndex(Value: Integer);
|
|
procedure SetLayout(Value: TButtonLayout);
|
|
procedure SetSpacing(Value: Integer);
|
|
procedure SetMargin(Value: Integer);
|
|
procedure SetArrowWidth(Value: Integer);
|
|
procedure SetFillFont(Value: TFont);
|
|
procedure UpdateTracking;
|
|
procedure CMButtonPressed(var Msg: TCMButtonPressed); message CM_BUTTONPRESSED;
|
|
{$IFDEF VCL}
|
|
procedure WMLButtonDblClk(var Msg: TWMLButtonDown); message WM_LBUTTONDBLCLK;
|
|
procedure CMSysColorChange(var Msg: TMessage); message CM_SYSCOLORCHANGE;
|
|
{$ENDIF VCL}
|
|
protected
|
|
FState: TButtonState;
|
|
{$IFDEF VCL}
|
|
function GetPalette: HPALETTE; override;
|
|
{$ENDIF VCL}
|
|
procedure Loaded; override;
|
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer); override;
|
|
procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer); override;
|
|
procedure Paint; override;
|
|
procedure MouseEnter(Control: TControl); override;
|
|
procedure MouseLeave(Control: TControl); override;
|
|
|
|
function WantKey(Key: Integer; Shift: TShiftState;
|
|
const KeyText: WideString): Boolean; override;
|
|
procedure EnabledChanged; override;
|
|
procedure FontChanged; override;
|
|
procedure TextChanged; override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
published
|
|
property Align;
|
|
property Action;
|
|
property Anchors;
|
|
property Constraints;
|
|
property AllowAllUp: Boolean read FAllowAllUp write SetAllowAllUp default False;
|
|
property ArrowWidth: Integer read FArrowWidth write SetArrowWidth default 13;
|
|
property GroupIndex: Integer read FGroupIndex write SetGroupIndex default 0;
|
|
property Down: Boolean read FDown write SetDown default False;
|
|
property DropDown: TPopupMenu read FDropDown write FDropDown;
|
|
property DropOnButtonClick: Boolean read FDropOnButtonClick write FDropOnButtonClick default False;
|
|
property Caption;
|
|
property Enabled;
|
|
property Flat: Boolean read FFlat write SetFlat default False;
|
|
property Font;
|
|
property FillFont: TFont read FFillFont write SetFillFont;
|
|
property Glyph: TBitmap read GetGlyph write SetGlyph;
|
|
property Layout: TButtonLayout read FLayout write SetLayout default blGlyphLeft;
|
|
property Margin: Integer read FMargin write SetMargin default -1;
|
|
property NumGlyphs: TNumGlyphs read GetNumGlyphs write SetNumGlyphs default 1;
|
|
property ParentFont default True;
|
|
property ParentShowHint;
|
|
property PressBoth: Boolean read FPressBoth write FPressBoth default True;
|
|
property ShowHint;
|
|
property Spacing: Integer read FSpacing write SetSpacing default 4;
|
|
property Visible;
|
|
property OnDrop: TNotifyEvent read FOnDrop write FOnDrop;
|
|
property OnClick;
|
|
property OnDblClick;
|
|
property OnMouseDown;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
const
|
|
UnitVersioning: TUnitVersionInfo = (
|
|
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_32/run/JvArrowButton.pas $';
|
|
Revision: '$Revision: 11043 $';
|
|
Date: '$Date: 2006-11-26 08:21:48 +0100 (dim., 26 nov. 2006) $';
|
|
LogPath: 'JVCL\run'
|
|
);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
implementation
|
|
|
|
uses
|
|
SysUtils, Consts, Forms,
|
|
JvConsts, JvThemes, JvJCLUtils;
|
|
|
|
type
|
|
TGlyphList = class(TImageList)
|
|
private
|
|
FUsed: TBits;
|
|
FCount: Integer;
|
|
function AllocateIndex: Integer;
|
|
public
|
|
constructor CreateSize(AWidth, AHeight: Integer);
|
|
destructor Destroy; override;
|
|
function AddMasked(Image: TBitmap; MaskColor: TColor): Integer;
|
|
{$IFDEF VisualCLX} override; {$ENDIF}
|
|
procedure Delete(Index: Integer);
|
|
property Count: Integer read FCount;
|
|
end;
|
|
|
|
TGlyphCache = class(TObject)
|
|
private
|
|
FGlyphLists: TList;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
function GetList(AWidth, AHeight: Integer): TGlyphList;
|
|
procedure ReturnList(var List: TGlyphList);
|
|
function Empty: Boolean;
|
|
end;
|
|
|
|
TButtonGlyph = class(TObject)
|
|
private
|
|
FOriginal: TBitmap;
|
|
FGlyphList: TGlyphList;
|
|
FIndexs: array [TButtonState] of Integer;
|
|
FTransparentColor: TColor;
|
|
FNumGlyphs: TNumGlyphs;
|
|
FOnChange: TNotifyEvent;
|
|
procedure GlyphChanged(Sender: TObject);
|
|
procedure SetGlyph(Value: TBitmap);
|
|
procedure SetNumGlyphs(Value: TNumGlyphs);
|
|
procedure Invalidate;
|
|
function CreateButtonGlyph(State: TButtonState): Integer;
|
|
procedure DrawButtonGlyph(Canvas: TCanvas; const GlyphPos: TPoint;
|
|
State: TButtonState; Transparent: Boolean);
|
|
procedure DrawButtonText(Canvas: TCanvas; const Caption: string;
|
|
TextBounds: TRect; State: TButtonState);
|
|
procedure CalcButtonLayout(Canvas: TCanvas; const Client: TRect;
|
|
const Offset: TPoint; const Caption: string; Layout: TButtonLayout;
|
|
Margin, Spacing: Integer; var GlyphPos: TPoint; var TextBounds: TRect);
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
{ return the text rectangle }
|
|
function Draw(Canvas: TCanvas; const Client: TRect; const Offset: TPoint;
|
|
const Caption: string; Layout: TButtonLayout; Margin, Spacing: Integer;
|
|
State: TButtonState; Transparent: Boolean): TRect;
|
|
property Glyph: TBitmap read FOriginal write SetGlyph;
|
|
property NumGlyphs: TNumGlyphs read FNumGlyphs write SetNumGlyphs;
|
|
property OnChange: TNotifyEvent read FOnChange write FOnChange;
|
|
end;
|
|
|
|
procedure DrawLine(Canvas: TCanvas; X, Y, X2, Y2: Integer);
|
|
begin
|
|
Canvas.MoveTo(X, Y);
|
|
Canvas.LineTo(X2, Y2);
|
|
end;
|
|
|
|
// (rom) best move to JCL
|
|
|
|
procedure GrayBitmap(Bmp: TBitmap);
|
|
var
|
|
I, J, W, H: Integer;
|
|
ColT: TColor;
|
|
Col: TColor;
|
|
begin
|
|
if Bmp.Empty then
|
|
Exit;
|
|
|
|
W := Bmp.Width;
|
|
H := Bmp.Height;
|
|
ColT := Bmp.Canvas.Pixels[0, 0];
|
|
|
|
// (rom) speed up by using Scanline
|
|
for I := 0 to W do
|
|
for J := 0 to H do
|
|
begin
|
|
Col := Bmp.Canvas.Pixels[I, J];
|
|
if (Col <> clWhite) and (Col <> ColT) then
|
|
Col := clBlack
|
|
else
|
|
Col := ColT;
|
|
Bmp.Canvas.Pixels[I, J] := Col;
|
|
end;
|
|
end;
|
|
|
|
//=== { TGlyphList } =========================================================
|
|
|
|
constructor TGlyphList.CreateSize(AWidth, AHeight: Integer);
|
|
begin
|
|
inherited CreateSize(AWidth, AHeight);
|
|
FUsed := TBits.Create;
|
|
end;
|
|
|
|
destructor TGlyphList.Destroy;
|
|
begin
|
|
FUsed.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TGlyphList.AllocateIndex: Integer;
|
|
begin
|
|
Result := FUsed.OpenBit;
|
|
if Result >= FUsed.Size then
|
|
begin
|
|
Result := inherited Add(nil, nil);
|
|
FUsed.Size := Result + 1;
|
|
end;
|
|
FUsed[Result] := True;
|
|
end;
|
|
|
|
function TGlyphList.AddMasked(Image: TBitmap; MaskColor: TColor): Integer;
|
|
begin
|
|
Result := AllocateIndex;
|
|
ReplaceMasked(Result, Image, MaskColor);
|
|
Inc(FCount);
|
|
end;
|
|
|
|
procedure TGlyphList.Delete(Index: Integer);
|
|
begin
|
|
if FUsed[Index] then
|
|
begin
|
|
Dec(FCount);
|
|
FUsed[Index] := False;
|
|
end;
|
|
end;
|
|
|
|
//=== { TGlyphCache } ========================================================
|
|
|
|
constructor TGlyphCache.Create;
|
|
begin
|
|
inherited Create;
|
|
FGlyphLists := TList.Create;
|
|
end;
|
|
|
|
destructor TGlyphCache.Destroy;
|
|
begin
|
|
FGlyphLists.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TGlyphCache.GetList(AWidth, AHeight: Integer): TGlyphList;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := FGlyphLists.Count - 1 downto 0 do
|
|
begin
|
|
Result := TGlyphList(FGlyphLists[I]);
|
|
if (AWidth = Result.Width) and (AHeight = Result.Height) then
|
|
Exit;
|
|
end;
|
|
Result := TGlyphList.CreateSize(AWidth, AHeight);
|
|
FGlyphLists.Add(Result);
|
|
end;
|
|
|
|
procedure TGlyphCache.ReturnList(var List: TGlyphList);
|
|
begin
|
|
if (List <> nil) and (List.Count = 0) then
|
|
begin
|
|
FGlyphLists.Remove(List);
|
|
FreeAndNil(List);
|
|
end;
|
|
end;
|
|
|
|
function TGlyphCache.Empty: Boolean;
|
|
begin
|
|
Result := FGlyphLists.Count = 0;
|
|
end;
|
|
|
|
var
|
|
GlyphCache: TGlyphCache = nil;
|
|
Pattern: TBitmap = nil;
|
|
ButtonCount: Integer = 0;
|
|
|
|
//=== { TButtonGlyph } =======================================================
|
|
|
|
procedure CreateBrushPattern;
|
|
var
|
|
X, Y: Integer;
|
|
begin
|
|
Pattern.Free; // (rom) just to be sure
|
|
Pattern := TBitmap.Create;
|
|
Pattern.Width := 8;
|
|
Pattern.Height := 8;
|
|
with Pattern.Canvas do
|
|
begin
|
|
Brush.Style := bsSolid;
|
|
Brush.Color := clBtnFace;
|
|
FillRect(Rect(0, 0, Pattern.Width, Pattern.Height));
|
|
for Y := 0 to 7 do
|
|
for X := 0 to 7 do
|
|
if (Y mod 2) = (X mod 2) then { toggles between even/odd pixles }
|
|
Pixels[X, Y] := clBtnHighlight; { on even/odd rows }
|
|
end;
|
|
end;
|
|
|
|
constructor TButtonGlyph.Create;
|
|
var
|
|
I: TButtonState;
|
|
begin
|
|
inherited Create;
|
|
FOriginal := TBitmap.Create;
|
|
FOriginal.OnChange := GlyphChanged;
|
|
FTransparentColor := clOlive;
|
|
FNumGlyphs := 1;
|
|
for I := Low(I) to High(I) do
|
|
FIndexs[I] := -1;
|
|
if GlyphCache = nil then
|
|
GlyphCache := TGlyphCache.Create;
|
|
end;
|
|
|
|
destructor TButtonGlyph.Destroy;
|
|
begin
|
|
FOriginal.Free;
|
|
Invalidate;
|
|
if Assigned(GlyphCache) and GlyphCache.Empty then
|
|
FreeAndNil(GlyphCache);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TButtonGlyph.Invalidate;
|
|
var
|
|
I: TButtonState;
|
|
begin
|
|
for I := Low(TButtonState) to High(TButtonState) do
|
|
begin
|
|
if FIndexs[I] <> -1 then
|
|
FGlyphList.Delete(FIndexs[I]);
|
|
FIndexs[I] := -1;
|
|
end;
|
|
GlyphCache.ReturnList(FGlyphList);
|
|
end;
|
|
|
|
procedure TButtonGlyph.GlyphChanged(Sender: TObject);
|
|
begin
|
|
if Sender = FOriginal then
|
|
begin
|
|
FTransparentColor := FOriginal.TransparentColor;
|
|
Invalidate;
|
|
if Assigned(FOnChange) then
|
|
FOnChange(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TButtonGlyph.SetGlyph(Value: TBitmap);
|
|
var
|
|
Glyphs: Integer;
|
|
begin
|
|
Invalidate;
|
|
FOriginal.Assign(Value);
|
|
if (Value <> nil) and (Value.Height > 0) then
|
|
begin
|
|
FTransparentColor := Value.TransparentColor;
|
|
if Value.Width mod Value.Height = 0 then
|
|
begin
|
|
Glyphs := Value.Width div Value.Height;
|
|
if Glyphs > 4 then
|
|
Glyphs := 1;
|
|
SetNumGlyphs(Glyphs);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TButtonGlyph.SetNumGlyphs(Value: TNumGlyphs);
|
|
begin
|
|
if (Value <> FNumGlyphs) and (Value > 0) then
|
|
begin
|
|
Invalidate;
|
|
FNumGlyphs := Value;
|
|
GlyphChanged(Glyph);
|
|
end;
|
|
end;
|
|
|
|
function TButtonGlyph.CreateButtonGlyph(State: TButtonState): Integer;
|
|
var
|
|
TmpImage, DDB, MonoBmp: TBitmap;
|
|
IWidth, IHeight: Integer;
|
|
IRect, ORect: TRect;
|
|
I: TButtonState;
|
|
DestDC: HDC;
|
|
begin
|
|
if (State = bsDown) and (NumGlyphs < 3) then
|
|
State := bsUp;
|
|
Result := FIndexs[State];
|
|
if Result <> -1 then
|
|
Exit;
|
|
if (FOriginal.Width = 0) or (FOriginal.Height = 0) then
|
|
Exit;
|
|
IWidth := FOriginal.Width div FNumGlyphs;
|
|
IHeight := FOriginal.Height;
|
|
if FGlyphList = nil then
|
|
begin
|
|
if GlyphCache = nil then
|
|
GlyphCache := TGlyphCache.Create;
|
|
FGlyphList := GlyphCache.GetList(IWidth, IHeight);
|
|
end;
|
|
TmpImage := TBitmap.Create;
|
|
try
|
|
TmpImage.Width := IWidth;
|
|
TmpImage.Height := IHeight;
|
|
IRect := Rect(0, 0, IWidth, IHeight);
|
|
TmpImage.Canvas.Brush.Color := clBtnFace;
|
|
{$IFDEF VCL}
|
|
TmpImage.Palette := CopyPalette(FOriginal.Palette);
|
|
{$ENDIF VCL}
|
|
I := State;
|
|
if Ord(I) >= NumGlyphs then
|
|
I := bsUp;
|
|
ORect := Rect(Ord(I) * IWidth, 0, (Ord(I) + 1) * IWidth, IHeight);
|
|
case State of
|
|
bsUp, bsDown, bsExclusive:
|
|
begin
|
|
TmpImage.Canvas.CopyRect(IRect, FOriginal.Canvas, ORect);
|
|
if FOriginal.TransparentMode = tmFixed then
|
|
FIndexs[State] := FGlyphList.AddMasked(TmpImage, FTransparentColor)
|
|
else
|
|
FIndexs[State] := FGlyphList.AddMasked(TmpImage, clDefault);
|
|
end;
|
|
bsDisabled:
|
|
begin
|
|
MonoBmp := nil;
|
|
DDB := nil;
|
|
try
|
|
MonoBmp := TBitmap.Create;
|
|
DDB := TBitmap.Create;
|
|
DDB.Assign(FOriginal);
|
|
{$IFDEF VCL}
|
|
DDB.HandleType := bmDDB;
|
|
{$ENDIF VCL}
|
|
if NumGlyphs > 1 then
|
|
with TmpImage.Canvas do
|
|
begin { Change white & gray to clBtnHighlight and clBtnShadow }
|
|
CopyRect(IRect, DDB.Canvas, ORect);
|
|
MonoBmp.Monochrome := True;
|
|
MonoBmp.Width := IWidth;
|
|
MonoBmp.Height := IHeight;
|
|
|
|
{ Convert white to clBtnHighlight }
|
|
DDB.Canvas.Brush.Color := clWhite;
|
|
MonoBmp.Canvas.CopyRect(IRect, DDB.Canvas, ORect);
|
|
Brush.Color := clBtnHighlight;
|
|
DestDC := Handle;
|
|
SetTextColor(DestDC, clBlack);
|
|
SetBkColor(DestDC, clWhite);
|
|
BitBlt(DestDC, 0, 0, IWidth, IHeight,
|
|
MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
|
|
|
|
{ Convert gray to clBtnShadow }
|
|
DDB.Canvas.Brush.Color := clGray;
|
|
MonoBmp.Canvas.CopyRect(IRect, DDB.Canvas, ORect);
|
|
Brush.Color := clBtnShadow;
|
|
DestDC := Handle;
|
|
SetTextColor(DestDC, clBlack);
|
|
SetBkColor(DestDC, clWhite);
|
|
BitBlt(DestDC, 0, 0, IWidth, IHeight,
|
|
MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
|
|
|
|
{ Convert transparent color to clBtnFace }
|
|
DDB.Canvas.Brush.Color := ColorToRGB(FTransparentColor);
|
|
MonoBmp.Canvas.CopyRect(IRect, DDB.Canvas, ORect);
|
|
Brush.Color := clBtnFace;
|
|
DestDC := Handle;
|
|
SetTextColor(DestDC, clBlack);
|
|
SetBkColor(DestDC, clWhite);
|
|
BitBlt(DestDC, 0, 0, IWidth, IHeight,
|
|
MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
|
|
end
|
|
else
|
|
begin
|
|
{ Create a disabled version }
|
|
with MonoBmp do
|
|
begin
|
|
Assign(FOriginal);
|
|
GrayBitmap(MonoBmp);
|
|
{$IFDEF VCL}
|
|
HandleType := bmDDB;
|
|
{$ENDIF VCL}
|
|
Canvas.Brush.Color := clBlack;
|
|
Width := IWidth;
|
|
if Monochrome then
|
|
begin
|
|
Canvas.Font.Color := clWhite;
|
|
Monochrome := False;
|
|
Canvas.Brush.Color := clWhite;
|
|
end;
|
|
Monochrome := True;
|
|
end;
|
|
with TmpImage.Canvas do
|
|
begin
|
|
Brush.Color := clBtnFace;
|
|
FillRect(IRect);
|
|
Brush.Color := clBtnHighlight;
|
|
SetTextColor(Handle, clBlack);
|
|
SetBkColor(Handle, clWhite);
|
|
BitBlt(Handle, 1, 1, IWidth, IHeight,
|
|
MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
|
|
Brush.Color := clBtnShadow;
|
|
SetTextColor(Handle, clBlack);
|
|
SetBkColor(Handle, clWhite);
|
|
BitBlt(Handle, 0, 0, IWidth, IHeight,
|
|
MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
|
|
end;
|
|
end;
|
|
finally
|
|
DDB.Free;
|
|
MonoBmp.Free;
|
|
end;
|
|
|
|
FIndexs[State] := FGlyphList.AddMasked(TmpImage, clDefault);
|
|
end;
|
|
end;
|
|
finally
|
|
TmpImage.Free;
|
|
end;
|
|
Result := FIndexs[State];
|
|
FOriginal.Dormant;
|
|
end;
|
|
|
|
procedure TButtonGlyph.DrawButtonGlyph(Canvas: TCanvas; const GlyphPos: TPoint;
|
|
State: TButtonState; Transparent: Boolean);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if (FOriginal = nil) or (FOriginal.Width = 0) or (FOriginal.Height = 0) then
|
|
Exit;
|
|
Index := CreateButtonGlyph(State);
|
|
with GlyphPos do
|
|
{$IFDEF VCL}
|
|
if Transparent or (State = bsExclusive) then
|
|
ImageList_DrawEx(FGlyphList.Handle, Index, Canvas.Handle, X, Y, 0, 0,
|
|
clNone, clNone, ILD_Transparent)
|
|
else
|
|
ImageList_DrawEx(FGlyphList.Handle, Index, Canvas.Handle, X, Y, 0, 0,
|
|
ColorToRGB(clBtnFace), clNone, ILD_Normal);
|
|
{$ENDIF VCL}
|
|
{$IFDEF VisualCLX}
|
|
// (ahuser) transparent not really supported under CLX
|
|
if Transparent or (State = bsExclusive) then
|
|
begin
|
|
FGlyphList.Draw(Canvas, X, Y, Index, itImage, True);
|
|
end
|
|
else
|
|
FGlyphList.Draw(Canvas, X, Y, Index, itImage, True);
|
|
{$ENDIF VisualCLX}
|
|
end;
|
|
|
|
procedure TButtonGlyph.DrawButtonText(Canvas: TCanvas; const Caption: string;
|
|
TextBounds: TRect; State: TButtonState);
|
|
var
|
|
S: string;
|
|
begin
|
|
S := Caption;
|
|
with Canvas do
|
|
begin
|
|
Brush.Style := bsClear;
|
|
if State = bsDisabled then
|
|
begin
|
|
OffsetRect(TextBounds, 1, 1);
|
|
Font.Color := clBtnHighlight;
|
|
DrawText(Canvas, S, -1, TextBounds, 0);
|
|
OffsetRect(TextBounds, -1, -1);
|
|
Font.Color := clBtnShadow;
|
|
DrawText(Canvas, S, -1, TextBounds, 0);
|
|
end
|
|
else
|
|
DrawText(Canvas, S, -1, TextBounds, DT_CENTER or DT_VCENTER or DT_SINGLELINE);
|
|
end;
|
|
end;
|
|
|
|
procedure TButtonGlyph.CalcButtonLayout(Canvas: TCanvas; const Client: TRect;
|
|
const Offset: TPoint; const Caption: string; Layout: TButtonLayout; Margin,
|
|
Spacing: Integer; var GlyphPos: TPoint; var TextBounds: TRect);
|
|
var
|
|
TextPos: TPoint;
|
|
ClientSize, GlyphSize, TextSize: TPoint;
|
|
TotalSize: TPoint;
|
|
S: string;
|
|
begin
|
|
{ calculate the item sizes }
|
|
ClientSize := Point(Client.Right - Client.Left, Client.Bottom -
|
|
Client.Top);
|
|
|
|
if FOriginal <> nil then
|
|
GlyphSize := Point(FOriginal.Width div FNumGlyphs, FOriginal.Height)
|
|
else
|
|
GlyphSize := Point(0, 0);
|
|
|
|
if Length(Caption) > 0 then
|
|
begin
|
|
TextBounds := Rect(0, 0, Client.Right - Client.Left, 0);
|
|
S := Caption;
|
|
DrawText(Canvas, S, -1, TextBounds, DT_CALCRECT);
|
|
TextSize := Point(TextBounds.Right - TextBounds.Left, TextBounds.Bottom -
|
|
TextBounds.Top);
|
|
end
|
|
else
|
|
begin
|
|
TextBounds := Rect(0, 0, 0, 0);
|
|
TextSize := Point(0, 0);
|
|
end;
|
|
|
|
{ If the layout has the glyph on the right or the left, then both the
|
|
text and the glyph are centered vertically. If the glyph is on the top
|
|
or the bottom, then both the text and the glyph are centered horizontally.}
|
|
if Layout in [blGlyphLeft, blGlyphRight] then
|
|
begin
|
|
GlyphPos.Y := (ClientSize.Y - GlyphSize.Y + 1) div 2;
|
|
TextPos.Y := (ClientSize.Y - TextSize.Y + 1) div 2;
|
|
end
|
|
else
|
|
begin
|
|
GlyphPos.X := (ClientSize.X - GlyphSize.X + 1) div 2;
|
|
TextPos.X := (ClientSize.X - TextSize.X + 1) div 2;
|
|
end;
|
|
|
|
{ if there is no text or no bitmap, then Spacing is irrelevant }
|
|
if (TextSize.X = 0) or (GlyphSize.X = 0) then
|
|
Spacing := 0;
|
|
|
|
{ adjust Margin and Spacing }
|
|
if Margin = -1 then
|
|
begin
|
|
if Spacing = -1 then
|
|
begin
|
|
TotalSize := Point(GlyphSize.X + TextSize.X, GlyphSize.Y + TextSize.Y);
|
|
if Layout in [blGlyphLeft, blGlyphRight] then
|
|
Margin := (ClientSize.X - TotalSize.X) div 3
|
|
else
|
|
Margin := (ClientSize.Y - TotalSize.Y) div 3;
|
|
Spacing := Margin;
|
|
end
|
|
else
|
|
begin
|
|
TotalSize := Point(GlyphSize.X + Spacing + TextSize.X, GlyphSize.Y +
|
|
Spacing + TextSize.Y);
|
|
if Layout in [blGlyphLeft, blGlyphRight] then
|
|
Margin := (ClientSize.X - TotalSize.X + 1) div 2
|
|
else
|
|
Margin := (ClientSize.Y - TotalSize.Y + 1) div 2;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if Spacing = -1 then
|
|
begin
|
|
TotalSize := Point(ClientSize.X - (Margin + GlyphSize.X), ClientSize.Y -
|
|
(Margin + GlyphSize.Y));
|
|
if Layout in [blGlyphLeft, blGlyphRight] then
|
|
Spacing := (TotalSize.X - TextSize.X) div 2
|
|
else
|
|
Spacing := (TotalSize.Y - TextSize.Y) div 2;
|
|
end;
|
|
end;
|
|
|
|
case Layout of
|
|
blGlyphLeft:
|
|
begin
|
|
GlyphPos.X := Margin;
|
|
TextPos.X := GlyphPos.X + GlyphSize.X + Spacing;
|
|
end;
|
|
blGlyphRight:
|
|
begin
|
|
GlyphPos.X := ClientSize.X - Margin - GlyphSize.X;
|
|
TextPos.X := GlyphPos.X - Spacing - TextSize.X;
|
|
end;
|
|
blGlyphTop:
|
|
begin
|
|
GlyphPos.Y := Margin;
|
|
TextPos.Y := GlyphPos.Y + GlyphSize.Y + Spacing;
|
|
end;
|
|
blGlyphBottom:
|
|
begin
|
|
GlyphPos.Y := ClientSize.Y - Margin - GlyphSize.Y;
|
|
TextPos.Y := GlyphPos.Y - Spacing - TextSize.Y;
|
|
end;
|
|
end;
|
|
|
|
{ fixup the result variables }
|
|
with GlyphPos do
|
|
begin
|
|
Inc(X, Client.Left + Offset.X);
|
|
Inc(Y, Client.Top + Offset.Y);
|
|
end;
|
|
OffsetRect(TextBounds, TextPos.X + Client.Left + Offset.X,
|
|
TextPos.Y + Client.Top + Offset.X);
|
|
end;
|
|
|
|
function TButtonGlyph.Draw(Canvas: TCanvas; const Client: TRect;
|
|
const Offset: TPoint; const Caption: string; Layout: TButtonLayout;
|
|
Margin, Spacing: Integer; State: TButtonState; Transparent: Boolean): TRect;
|
|
var
|
|
GlyphPos: TPoint;
|
|
begin
|
|
CalcButtonLayout(Canvas, Client, Offset, Caption, Layout, Margin, Spacing,
|
|
GlyphPos, Result);
|
|
DrawButtonGlyph(Canvas, GlyphPos, State, Transparent);
|
|
DrawButtonText(Canvas, Caption, Result, State);
|
|
end;
|
|
|
|
//=== { TJvArrowButton } =====================================================
|
|
|
|
constructor TJvArrowButton.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
SetBounds(0, 0, 42, 25);
|
|
ControlStyle := [csCaptureMouse, csOpaque, csDoubleClicks];
|
|
{$IFDEF VCL}
|
|
IncludeThemeStyle(Self, [csParentBackground]);
|
|
{$ENDIF VCL}
|
|
FGlyph := TButtonGlyph.Create;
|
|
TButtonGlyph(FGlyph).OnChange := GlyphChanged;
|
|
FFillFont := TFont.Create;
|
|
FFillFont.Assign(Font);
|
|
FAllowAllUp := False;
|
|
FArrowWidth := 13;
|
|
FGroupIndex := 0;
|
|
ParentFont := True;
|
|
FDown := False;
|
|
FFlat := False;
|
|
FLayout := blGlyphLeft;
|
|
FMargin := -1;
|
|
FSpacing := 4;
|
|
FPressBoth := True;
|
|
Inc(ButtonCount);
|
|
end;
|
|
|
|
destructor TJvArrowButton.Destroy;
|
|
begin
|
|
TButtonGlyph(FGlyph).Free;
|
|
FFillFont.Free;
|
|
Dec(ButtonCount);
|
|
if ButtonCount = 0 then
|
|
FreeAndNil(Pattern);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvArrowButton.Paint;
|
|
const
|
|
DownStyles: array [Boolean] of Integer = (BDR_RAISEDINNER, BDR_SUNKENOUTER);
|
|
FillStyles: array [Boolean] of Integer = (BF_MIDDLE, 0);
|
|
var
|
|
PaintRect: TRect;
|
|
DrawFlags: Integer;
|
|
Offset: TPoint;
|
|
DivX, DivY: Integer;
|
|
Push: Boolean;
|
|
begin
|
|
if not Enabled then
|
|
FState := bsDisabled
|
|
else
|
|
if FState = bsDisabled then
|
|
begin
|
|
if Down and (GroupIndex <> 0) then
|
|
FState := bsExclusive
|
|
else
|
|
FState := bsUp;
|
|
end;
|
|
if FMouseInControl then
|
|
Canvas.Font := FillFont
|
|
else
|
|
Canvas.Font := Self.Font;
|
|
PaintRect := Rect(0, 0, Width - ArrowWidth, Height);
|
|
|
|
if FArrowClick and not Down then
|
|
FState := bsUp;
|
|
|
|
if not Flat then
|
|
begin
|
|
DrawFlags := DFCS_BUTTONPUSH or DFCS_ADJUSTRECT;
|
|
if (FState in [bsDown, bsExclusive]) then
|
|
DrawFlags := DrawFlags or DFCS_PUSHED;
|
|
if IsMouseOver(Self) then
|
|
DrawFlags := DrawFlags or DFCS_HOT;
|
|
DrawThemedFrameControl(Self, Canvas.Handle, PaintRect, DFC_BUTTON, DrawFlags);
|
|
end
|
|
else
|
|
begin
|
|
if (FState in [bsDown, bsExclusive]) or
|
|
(FMouseInControl and (FState <> bsDisabled)) or
|
|
(csDesigning in ComponentState) then
|
|
DrawEdge(Canvas.Handle, PaintRect, DownStyles[FState in [bsDown, bsExclusive]],
|
|
FillStyles[Flat] or BF_RECT);
|
|
InflateRect(PaintRect, -1, -1);
|
|
end;
|
|
|
|
if FState in [bsDown, bsExclusive] then
|
|
begin
|
|
if (FState = bsExclusive) and (not Flat or not FMouseInControl) then
|
|
begin
|
|
if Pattern = nil then
|
|
CreateBrushPattern;
|
|
Canvas.Brush.Bitmap := Pattern;
|
|
Canvas.FillRect(PaintRect);
|
|
end;
|
|
Offset.X := 1;
|
|
Offset.Y := 1;
|
|
end
|
|
else
|
|
begin
|
|
Offset.X := 0;
|
|
Offset.Y := 0;
|
|
end;
|
|
{ draw image: }
|
|
TButtonGlyph(FGlyph).Draw(Canvas, PaintRect, Offset, Caption, Layout, Margin,
|
|
Spacing, FState, Flat);
|
|
|
|
{ calculate were to put arrow part }
|
|
PaintRect := Rect(Width - ArrowWidth, 0, Width, Height);
|
|
{$IFDEF JVCLThemesEnabled}
|
|
if ThemeServices.ThemesEnabled then
|
|
Dec(PaintRect.Left);
|
|
{$ENDIF JVCLThemesEnabled}
|
|
Push := FArrowClick or (PressBoth and (FState in [bsDown, bsExclusive]));
|
|
if Push then
|
|
begin
|
|
Offset.X := 1;
|
|
Offset.Y := 1;
|
|
end
|
|
else
|
|
begin
|
|
Offset.X := 0;
|
|
Offset.Y := 0;
|
|
end;
|
|
|
|
if not Flat then
|
|
begin
|
|
DrawFlags := DFCS_BUTTONPUSH; // or DFCS_ADJUSTRECT;
|
|
if Push then
|
|
DrawFlags := DrawFlags or DFCS_PUSHED;
|
|
if IsMouseOver(Self) then
|
|
DrawFlags := DrawFlags or DFCS_HOT;
|
|
DrawThemedFrameControl(Self, Canvas.Handle, PaintRect, DFC_BUTTON, DrawFlags);
|
|
end
|
|
else
|
|
if FMouseInControl and Enabled or (csDesigning in ComponentState) then
|
|
DrawEdge(Canvas.Handle, PaintRect, DownStyles[Push],
|
|
FillStyles[Flat] or BF_RECT);
|
|
{ find middle pixel }
|
|
with PaintRect do
|
|
begin
|
|
DivX := Right - Left;
|
|
DivX := DivX div 2;
|
|
DivY := Bottom - Top;
|
|
DivY := DivY div 2;
|
|
Bottom := Bottom - (DivY + DivX div 2) + 1;
|
|
Top := Top + (DivY + DivX div 2) + 1;
|
|
Left := Left + (DivX div 2);
|
|
Right := (Right - DivX div 2);
|
|
end;
|
|
|
|
if not Flat then
|
|
Dec(Offset.X);
|
|
OffsetRect(PaintRect, Offset.X, Offset.Y);
|
|
|
|
if Enabled then
|
|
Canvas.Pen.Color := clBlack
|
|
else
|
|
Canvas.Pen.Color := clBtnShadow;
|
|
|
|
{ Draw arrow }
|
|
while PaintRect.Left < PaintRect.Right + 1 do
|
|
begin
|
|
DrawLine(Canvas, PaintRect.Left, PaintRect.Bottom, PaintRect.Right, PaintRect.Bottom);
|
|
InflateRect(PaintRect, -1, 1);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvArrowButton.UpdateTracking;
|
|
var
|
|
P: TPoint;
|
|
begin
|
|
if Flat then
|
|
if Enabled then
|
|
begin
|
|
GetCursorPos(P);
|
|
FMouseInControl := not (FindDragTarget(P, True) = Self);
|
|
{$IFDEF VCL}
|
|
if FMouseInControl then
|
|
Perform(CM_MOUSELEAVE, 0, 0)
|
|
else
|
|
Perform(CM_MOUSEENTER, 0, 0);
|
|
{$ENDIF VCL}
|
|
{$IFDEF VisualCLX}
|
|
if FMouseInControl then
|
|
MouseLeave(Self)
|
|
else
|
|
MouseEnter(Self);
|
|
{$ENDIF VisualCLX}
|
|
end;
|
|
end;
|
|
|
|
procedure TJvArrowButton.Loaded;
|
|
var
|
|
State: TButtonState;
|
|
begin
|
|
inherited Loaded;
|
|
if Enabled then
|
|
State := bsUp
|
|
else
|
|
State := bsDisabled;
|
|
TButtonGlyph(FGlyph).CreateButtonGlyph(State);
|
|
end;
|
|
|
|
procedure TJvArrowButton.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
Pnt: TPoint;
|
|
{$IFDEF VCL}
|
|
Msg: TMsg;
|
|
{$ENDIF VCL}
|
|
begin
|
|
inherited MouseDown(Button, Shift, X, Y);
|
|
if not Enabled then
|
|
Exit;
|
|
FArrowClick := (X >= Width - ArrowWidth) and (X <= Width) and (Y >= 0) and (Y <= Height) or DropOnButtonClick;
|
|
|
|
if Button = mbLeft then
|
|
begin
|
|
if not Down then
|
|
FState := bsDown
|
|
else
|
|
FState := bsExclusive;
|
|
Repaint; // Invalidate;
|
|
end;
|
|
|
|
if Assigned(FDropDown) and FArrowClick then
|
|
begin
|
|
Pnt := ClientToScreen(Point(0, Height));
|
|
DropDown.Popup(Pnt.X, Pnt.Y);
|
|
{$IFDEF VCL}
|
|
while PeekMessage(Msg, HWND_DESKTOP, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) do
|
|
{nothing};
|
|
if GetCapture <> 0 then
|
|
SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
|
|
{$ENDIF VCL}
|
|
{$IFDEF VisualCLX}
|
|
repeat
|
|
Application.ProcessMessages;
|
|
until IsWindowVisible(DropDown.Handle) = False;
|
|
{$ENDIF VisualCLX}
|
|
end;
|
|
|
|
if FArrowClick then
|
|
if Assigned(FOnDrop) then
|
|
FOnDrop(Self);
|
|
FArrowClick := False;
|
|
Repaint;
|
|
end;
|
|
|
|
procedure TJvArrowButton.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
DoClick: Boolean;
|
|
begin
|
|
inherited MouseUp(Button, Shift, X, Y);
|
|
|
|
if not Enabled then
|
|
begin
|
|
FState := bsUp;
|
|
Repaint;
|
|
end;
|
|
|
|
DoClick := (X >= 0) and (X <= Width - ArrowWidth) and (Y >= 0) and (Y <= Height) and not DropOnButtonClick;
|
|
|
|
if GroupIndex = 0 then
|
|
begin
|
|
{ Redraw face in case mouse is captured }
|
|
FState := bsUp;
|
|
FMouseInControl := False;
|
|
if DoClick and not (FState in [bsExclusive, bsDown]) then
|
|
Invalidate;
|
|
end
|
|
else
|
|
if DoClick then
|
|
begin
|
|
SetDown(not Down);
|
|
if Down then
|
|
Repaint;
|
|
end
|
|
else
|
|
begin
|
|
if Down then
|
|
FState := bsExclusive;
|
|
Repaint;
|
|
end;
|
|
if DoClick then
|
|
Click;
|
|
UpdateTracking;
|
|
Repaint;
|
|
end;
|
|
|
|
{$IFDEF VCL}
|
|
function TJvArrowButton.GetPalette: HPALETTE;
|
|
begin
|
|
Result := Glyph.Palette;
|
|
end;
|
|
{$ENDIF VCL}
|
|
|
|
function TJvArrowButton.GetGlyph: TBitmap;
|
|
begin
|
|
Result := TButtonGlyph(FGlyph).Glyph;
|
|
end;
|
|
|
|
procedure TJvArrowButton.SetGlyph(Value: TBitmap);
|
|
begin
|
|
TButtonGlyph(FGlyph).Glyph := Value;
|
|
Invalidate;
|
|
end;
|
|
|
|
function TJvArrowButton.GetNumGlyphs: TNumGlyphs;
|
|
begin
|
|
Result := TButtonGlyph(FGlyph).NumGlyphs;
|
|
end;
|
|
|
|
procedure TJvArrowButton.SetNumGlyphs(Value: TNumGlyphs);
|
|
begin
|
|
if Value < 0 then
|
|
Value := 1
|
|
else
|
|
if Value > 4 then
|
|
Value := 4;
|
|
if Value <> TButtonGlyph(FGlyph).NumGlyphs then
|
|
begin
|
|
TButtonGlyph(FGlyph).NumGlyphs := Value;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvArrowButton.GlyphChanged(Sender: TObject);
|
|
begin
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TJvArrowButton.UpdateExclusive;
|
|
var
|
|
Msg: TCMButtonPressed;
|
|
begin
|
|
if (GroupIndex <> 0) and (Parent <> nil) then
|
|
begin
|
|
Msg.Msg := CM_BUTTONPRESSED;
|
|
Msg.Index := GroupIndex;
|
|
Msg.Control := Self;
|
|
Msg.Result := 0;
|
|
Parent.Broadcast(Msg);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvArrowButton.SetDown(Value: Boolean);
|
|
begin
|
|
if GroupIndex = 0 then
|
|
Value := False;
|
|
if Value <> FDown then
|
|
begin
|
|
if FDown and (not AllowAllUp) then
|
|
Exit;
|
|
FDown := Value;
|
|
if Value then
|
|
begin
|
|
if FState = bsUp then
|
|
Invalidate;
|
|
FState := bsExclusive
|
|
end
|
|
else
|
|
begin
|
|
FState := bsUp;
|
|
Repaint;
|
|
end;
|
|
if Value then
|
|
UpdateExclusive;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvArrowButton.SetFlat(Value: Boolean);
|
|
begin
|
|
if Value <> FFlat then
|
|
begin
|
|
FFlat := Value;
|
|
if Value then
|
|
ControlStyle := ControlStyle - [csOpaque]
|
|
else
|
|
ControlStyle := ControlStyle + [csOpaque];
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvArrowButton.SetGroupIndex(Value: Integer);
|
|
begin
|
|
if FGroupIndex <> Value then
|
|
begin
|
|
FGroupIndex := Value;
|
|
UpdateExclusive;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvArrowButton.SetLayout(Value: TButtonLayout);
|
|
begin
|
|
if FLayout <> Value then
|
|
begin
|
|
FLayout := Value;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvArrowButton.SetMargin(Value: Integer);
|
|
begin
|
|
if (Value <> FMargin) and (Value >= -1) then
|
|
begin
|
|
FMargin := Value;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvArrowButton.SetArrowWidth(Value: Integer);
|
|
begin
|
|
if FArrowWidth <> Value then
|
|
begin
|
|
FArrowWidth := Value;
|
|
Repaint;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvArrowButton.SetFillFont(Value: TFont);
|
|
begin
|
|
FFillFont.Assign(Value);
|
|
Repaint;
|
|
end;
|
|
|
|
procedure TJvArrowButton.SetSpacing(Value: Integer);
|
|
begin
|
|
if Value <> FSpacing then
|
|
begin
|
|
FSpacing := Value;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvArrowButton.SetAllowAllUp(Value: Boolean);
|
|
begin
|
|
if FAllowAllUp <> Value then
|
|
begin
|
|
FAllowAllUp := Value;
|
|
UpdateExclusive;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvArrowButton.EnabledChanged;
|
|
const
|
|
NewState: array [Boolean] of TButtonState = (bsDisabled, bsUp);
|
|
begin
|
|
inherited EnabledChanged;
|
|
TButtonGlyph(FGlyph).CreateButtonGlyph(NewState[Enabled]);
|
|
UpdateTracking;
|
|
Repaint;
|
|
end;
|
|
|
|
procedure TJvArrowButton.CMButtonPressed(var Msg: TCMButtonPressed);
|
|
var
|
|
Sender: TJvArrowButton;
|
|
{$IFDEF JVCLThemesEnabled}
|
|
R: TRect;
|
|
{$ENDIF JVCLThemesEnabled}
|
|
begin
|
|
if Msg.Index = GroupIndex then
|
|
begin
|
|
Sender := TJvArrowButton(Msg.Control);
|
|
if Sender <> Self then
|
|
begin
|
|
if Sender.Down and Down then
|
|
begin
|
|
FDown := False;
|
|
FState := bsUp;
|
|
{$IFDEF JVCLThemesEnabled}
|
|
if ThemeServices.ThemesEnabled and Enabled and not Flat then
|
|
begin
|
|
R := BoundsRect;
|
|
InvalidateRect(Parent.Handle, @R, True);
|
|
end
|
|
else
|
|
{$ENDIF JVCLThemesEnabled}
|
|
Invalidate;
|
|
end;
|
|
FAllowAllUp := Sender.AllowAllUp;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJvArrowButton.WantKey(Key: Integer; Shift: TShiftState;
|
|
const KeyText: WideString): Boolean;
|
|
begin
|
|
Result := IsAccel(Key, Caption) and Enabled and (Shift * KeyboardShiftStates = [ssAlt]);
|
|
if Result then
|
|
Click
|
|
else
|
|
Result := inherited WantKey(Key, Shift, KeyText);
|
|
end;
|
|
|
|
procedure TJvArrowButton.FontChanged;
|
|
begin
|
|
inherited FontChanged;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TJvArrowButton.TextChanged;
|
|
begin
|
|
inherited TextChanged;
|
|
Invalidate;
|
|
end;
|
|
|
|
{$IFDEF VCL}
|
|
|
|
procedure TJvArrowButton.WMLButtonDblClk(var Msg: TWMLButtonDown);
|
|
begin
|
|
inherited;
|
|
if Down then
|
|
DblClick;
|
|
end;
|
|
|
|
procedure TJvArrowButton.CMSysColorChange(var Msg: TMessage);
|
|
begin
|
|
with TButtonGlyph(FGlyph) do
|
|
begin
|
|
Invalidate;
|
|
CreateButtonGlyph(FState);
|
|
end;
|
|
end;
|
|
|
|
{$ENDIF VCL}
|
|
|
|
procedure TJvArrowButton.MouseEnter(Control: TControl);
|
|
{$IFDEF JVCLThemesEnabled}
|
|
var
|
|
R: TRect;
|
|
{$ENDIF JVCLThemesEnabled}
|
|
begin
|
|
inherited MouseEnter(Control);
|
|
if Flat and not FMouseInControl and Enabled then
|
|
begin
|
|
FMouseInControl := True;
|
|
Repaint;
|
|
end;
|
|
{$IFDEF JVCLThemesEnabled}
|
|
if ThemeServices.ThemesEnabled and Enabled and not Flat then
|
|
begin
|
|
R := BoundsRect;
|
|
InvalidateRect(Parent.Handle, @R, True);
|
|
end;
|
|
{$ENDIF JVCLThemesEnabled}
|
|
end;
|
|
|
|
procedure TJvArrowButton.MouseLeave(Control: TControl);
|
|
{$IFDEF JVCLThemesEnabled}
|
|
var
|
|
R: TRect;
|
|
{$ENDIF JVCLThemesEnabled}
|
|
begin
|
|
inherited MouseLeave(Control);
|
|
if Flat and FMouseInControl and Enabled then
|
|
begin
|
|
FMouseInControl := False;
|
|
Invalidate;
|
|
end;
|
|
{$IFDEF JVCLThemesEnabled}
|
|
if ThemeServices.ThemesEnabled and Enabled and not Flat then
|
|
begin
|
|
R := BoundsRect;
|
|
InvalidateRect(Parent.Handle, @R, True);
|
|
end;
|
|
{$ENDIF JVCLThemesEnabled}
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
initialization
|
|
RegisterUnitVersion(HInstance, UnitVersioning);
|
|
|
|
finalization
|
|
UnregisterUnitVersion(HInstance);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
end.
|
|
|