home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 September
/
Chip_2001-09_cd1.bin
/
zkuste
/
delphi
/
kolekce
/
d6
/
RX275D6.ZIP
/
Units
/
RxCtrls.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
2001-06-24
|
150KB
|
5,127 lines
{*******************************************************}
{ }
{ Delphi VCL Extensions (RX) }
{ }
{ Copyright (c) 1995, 1996 AO ROSNO }
{ Copyright (c) 1997, 1998 Master-Bank }
{ }
{*******************************************************}
unit RXCtrls;
{$I RX.INC}
{$W-,T-}
interface
uses Windows, Registry, RTLConsts, Messages, Classes, Controls, Graphics, StdCtrls, ExtCtrls, Forms,
Buttons, Menus, RxTimer, RxConst, IniFiles, Placemnt;
type
TPositiveInt = 1..MaxInt;
{ TTextListBox }
TTextListBox = class(TCustomListBox)
private
FMaxWidth: Integer;
{$IFNDEF WIN32}
FTabWidth: Integer;
procedure SetTabWidth(Value: Integer);
{$ENDIF}
procedure ResetHorizontalExtent;
procedure SetHorizontalExtent;
function GetItemWidth(Index: Integer): Integer;
protected
{$IFNDEF WIN32}
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
{$ENDIF}
procedure WndProc(var Message: TMessage); override;
published
property Align;
property BorderStyle;
property Color;
property Ctl3D;
property DragCursor;
property DragMode;
property Enabled;
property ExtendedSelect;
property Font;
property IntegralHeight;
{$IFDEF RX_D4}
property Anchors;
property BiDiMode;
property Constraints;
property DragKind;
property ParentBiDiMode;
{$ENDIF}
{$IFDEF WIN32}
{$IFNDEF VER90}
property ImeMode;
property ImeName;
{$ENDIF}
{$ENDIF}
property ItemHeight;
property Items;
property MultiSelect;
property ParentColor;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Sorted;
property TabOrder;
property TabStop;
{$IFDEF WIN32}
property TabWidth;
{$ELSE}
property TabWidth: Integer read FTabWidth write SetTabWidth default 0;
{$ENDIF}
property Visible;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
{$IFDEF WIN32}
property OnStartDrag;
{$ENDIF}
{$IFDEF RX_D5}
property OnContextPopup;
{$ENDIF}
{$IFDEF RX_D4}
property OnMouseWheelDown;
property OnMouseWheelUp;
property OnEndDock;
property OnStartDock;
{$ENDIF}
end;
{ TRxCustomListBox }
TGetItemWidthEvent = procedure(Control: TWinControl; Index: Integer;
var Width: Integer) of object;
TRxCustomListBox = class(TWinControl)
private
FItems: TStrings;
FBorderStyle: TBorderStyle;
FCanvas: TCanvas;
FColumns: Integer;
FItemHeight: Integer;
FStyle: TListBoxStyle;
FIntegralHeight: Boolean;
FMultiSelect: Boolean;
FSorted: Boolean;
FExtendedSelect: Boolean;
FTabWidth: Integer;
FSaveItems: TStringList;
FSaveTopIndex: Integer;
FSaveItemIndex: Integer;
FAutoScroll: Boolean;
FGraySelection: Boolean;
FMaxItemWidth: Integer;
FOnDrawItem: TDrawItemEvent;
FOnMeasureItem: TMeasureItemEvent;
FOnGetItemWidth: TGetItemWidthEvent;
procedure ResetHorizontalExtent;
procedure SetHorizontalExtent;
function GetAutoScroll: Boolean;
function GetItemHeight: Integer; virtual;
function GetItemIndex: Integer;
function GetSelCount: Integer;
function GetSelected(Index: Integer): Boolean;
function GetTopIndex: Integer;
procedure SetAutoScroll(Value: Boolean);
procedure SetBorderStyle(Value: TBorderStyle);
procedure SetColumnWidth;
procedure SetColumns(Value: Integer);
procedure SetExtendedSelect(Value: Boolean);
procedure SetIntegralHeight(Value: Boolean);
procedure SetItemHeight(Value: Integer);
procedure SetItemIndex(Value: Integer);
procedure SetMultiSelect(Value: Boolean);
procedure SetSelected(Index: Integer; Value: Boolean);
procedure SetSorted(Value: Boolean);
procedure SetStyle(Value: TListBoxStyle);
procedure SetTabWidth(Value: Integer);
procedure SetTopIndex(Value: Integer);
procedure SetGraySelection(Value: Boolean);
procedure SetOnDrawItem(Value: TDrawItemEvent);
procedure SetOnGetItemWidth(Value: TGetItemWidthEvent);
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
procedure CNMeasureItem(var Message: TWMMeasureItem); message CN_MEASUREITEM;
procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
procedure WMNCHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST;
procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
{$IFDEF WIN32}
procedure CMCtl3DChanged(var Message: TMessage); message CM_CTL3DCHANGED;
{$ENDIF}
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure DestroyWnd; override;
function CreateItemList: TStrings; virtual;
function GetItemWidth(Index: Integer): Integer; virtual;
procedure WndProc(var Message: TMessage); override;
procedure DragCanceled; override;
procedure DrawItem(Index: Integer; Rect: TRect;
State: TOwnerDrawState); virtual;
procedure MeasureItem(Index: Integer; var Height: Integer); virtual;
function GetItemData(Index: Integer): Longint; dynamic;
procedure SetItemData(Index: Integer; AData: LongInt); dynamic;
procedure SetItems(Value: TStrings); virtual;
procedure ResetContent; dynamic;
procedure DeleteString(Index: Integer); dynamic;
property AutoScroll: Boolean read GetAutoScroll write SetAutoScroll default False;
property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle;
property Columns: Integer read FColumns write SetColumns default 0;
property ExtendedSelect: Boolean read FExtendedSelect write SetExtendedSelect default True;
property GraySelection: Boolean read FGraySelection write SetGraySelection default False;
property IntegralHeight: Boolean read FIntegralHeight write SetIntegralHeight default False;
property ItemHeight: Integer read GetItemHeight write SetItemHeight;
property MultiSelect: Boolean read FMultiSelect write SetMultiSelect default False;
property ParentColor default False;
property Sorted: Boolean read FSorted write SetSorted default False;
property Style: TListBoxStyle read FStyle write SetStyle default lbStandard;
property TabWidth: Integer read FTabWidth write SetTabWidth default 0;
property OnDrawItem: TDrawItemEvent read FOnDrawItem write SetOnDrawItem;
property OnMeasureItem: TMeasureItemEvent read FOnMeasureItem write FOnMeasureItem;
property OnGetItemWidth: TGetItemWidthEvent read FOnGetItemWidth write SetOnGetItemWidth;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Clear;
procedure DefaultDrawText(X, Y: Integer; const S: string);
function ItemAtPos(Pos: TPoint; Existing: Boolean): Integer;
function ItemRect(Index: Integer): TRect;
property Canvas: TCanvas read FCanvas;
property Items: TStrings read FItems write SetItems;
property ItemIndex: Integer read GetItemIndex write SetItemIndex;
property SelCount: Integer read GetSelCount;
property Selected[Index: Integer]: Boolean read GetSelected write SetSelected;
property TopIndex: Integer read GetTopIndex write SetTopIndex;
published
property TabStop default True;
end;
{ TRxCheckListBox }
TCheckKind = (ckCheckBoxes, ckRadioButtons, ckCheckMarks);
TChangeStateEvent = procedure (Sender: TObject; Index: Integer) of object;
TRxCheckListBox = class(TRxCustomListBox)
private
FAllowGrayed: Boolean;
FCheckKind: TCheckKind;
FSaveStates: TList;
FDrawBitmap: TBitmap;
FCheckWidth, FCheckHeight: Integer;
FReserved: Integer;
FInUpdateStates: Boolean;
FIniLink: TIniLink;
FOnClickCheck: TNotifyEvent;
FOnStateChange: TChangeStateEvent;
procedure ResetItemHeight;
function GetItemHeight: Integer; override;
procedure DrawCheck(R: TRect; AState: TCheckBoxState; Enabled: Boolean);
procedure SetCheckKind(Value: TCheckKind);
procedure SetChecked(Index: Integer; AChecked: Boolean);
function GetChecked(Index: Integer): Boolean;
procedure SetState(Index: Integer; AState: TCheckBoxState);
function GetState(Index: Integer): TCheckBoxState;
procedure SetItemEnabled(Index: Integer; Value: Boolean);
function GetItemEnabled(Index: Integer): Boolean;
function GetAllowGrayed: Boolean;
procedure ToggleClickCheck(Index: Integer);
procedure InvalidateCheck(Index: Integer);
procedure InvalidateItem(Index: Integer);
function CreateCheckObject(Index: Integer): TObject;
function FindCheckObject(Index: Integer): TObject;
function GetCheckObject(Index: Integer): TObject;
function IsCheckObject(Index: Integer): Boolean;
procedure ReadVersion(Reader: TReader);
procedure WriteVersion(Writer: TWriter);
procedure ReadCheckData(Reader: TReader);
procedure WriteCheckData(Writer: TWriter);
procedure InternalSaveStates(IniFile: TObject; const Section: string);
procedure InternalRestoreStates(IniFile: TObject; const Section: string);
function GetStorage: TFormPlacement;
procedure SetStorage(Value: TFormPlacement);
procedure IniSave(Sender: TObject);
procedure IniLoad(Sender: TObject);
procedure UpdateCheckStates;
function GetCheckedIndex: Integer;
procedure SetCheckedIndex(Value: Integer);
procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
protected
function CreateItemList: TStrings; override;
procedure DrawItem(Index: Integer; Rect: TRect;
State: TOwnerDrawState); override;
procedure DefineProperties(Filer: TFiler); override;
function GetItemWidth(Index: Integer): Integer; override;
function GetItemData(Index: Integer): LongInt; override;
procedure SetItemData(Index: Integer; AData: LongInt); override;
procedure KeyPress(var Key: Char); override;
procedure Loaded; override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure ResetContent; override;
procedure DeleteString(Index: Integer); override;
procedure ClickCheck; dynamic;
procedure ChangeItemState(Index: Integer); dynamic;
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure DestroyWnd; override;
procedure WMDestroy(var Msg: TWMDestroy); message WM_DESTROY;
function GetCheckWidth: Integer;
procedure SetItems(Value: TStrings); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
{$IFDEF WIN32}
procedure SaveStatesReg(IniFile: TRegIniFile);
procedure RestoreStatesReg(IniFile: TRegIniFile);
{$ENDIF WIN32}
procedure SaveStates(IniFile: TIniFile);
procedure RestoreStates(IniFile: TIniFile);
procedure ApplyState(AState: TCheckBoxState; EnabledOnly: Boolean);
property Checked[Index: Integer]: Boolean read GetChecked write SetChecked;
property State[Index: Integer]: TCheckBoxState read GetState write SetState;
property EnabledItem[Index: Integer]: Boolean read GetItemEnabled write SetItemEnabled;
published
property AllowGrayed: Boolean read GetAllowGrayed write FAllowGrayed default False;
property CheckKind: TCheckKind read FCheckKind write SetCheckKind default ckCheckBoxes;
property CheckedIndex: Integer read GetCheckedIndex write SetCheckedIndex default -1;
property IniStorage: TFormPlacement read GetStorage write SetStorage;
property Align;
property AutoScroll default True;
property BorderStyle;
property Color;
property Columns;
property Ctl3D;
property DragCursor;
property DragMode;
property Enabled;
property ExtendedSelect;
property Font;
property GraySelection;
{$IFDEF RX_D4}
property Anchors;
property BiDiMode;
property Constraints;
property DragKind;
property ParentBiDiMode;
{$ENDIF}
{$IFDEF WIN32}
{$IFNDEF VER90}
property ImeMode;
property ImeName;
{$ENDIF}
{$ENDIF}
property IntegralHeight;
property ItemHeight;
property Items stored False;
property MultiSelect;
property ParentColor;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Sorted;
property Style;
property TabOrder;
property TabWidth;
property Visible;
property OnStateChange: TChangeStateEvent read FOnStateChange write FOnStateChange;
property OnClickCheck: TNotifyEvent read FOnClickCheck write FOnClickCheck;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnDrawItem;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnGetItemWidth;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMeasureItem;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
{$IFDEF WIN32}
property OnStartDrag;
{$ENDIF}
{$IFDEF RX_D5}
property OnContextPopup;
{$ENDIF}
{$IFDEF RX_D4}
property OnMouseWheelDown;
property OnMouseWheelUp;
property OnEndDock;
property OnStartDock;
{$ENDIF}
end;
const
clbDefaultState = cbUnchecked;
clbDefaultEnabled = True;
{ TRxCustomLabel }
type
TShadowPosition = (spLeftTop, spLeftBottom, spRightBottom, spRightTop);
{$IFNDEF RX_D3}
TTextLayout = (tlTop, tlCenter, tlBottom);
{$ENDIF}
TRxCustomLabel = class(TGraphicControl)
private
FFocusControl: TWinControl;
FAlignment: TAlignment;
FAutoSize: Boolean;
FLayout: TTextLayout;
FShadowColor: TColor;
FShadowSize: Byte;
FShadowPos: TShadowPosition;
FWordWrap: Boolean;
FShowAccelChar: Boolean;
FShowFocus: Boolean;
FFocused: Boolean;
FMouseInControl: Boolean;
FDragging: Boolean;
FLeftMargin: Integer;
FRightMargin: Integer;
FOnMouseEnter: TNotifyEvent;
FOnMouseLeave: TNotifyEvent;
procedure DoDrawText(var Rect: TRect; Flags: Word);
function GetTransparent: Boolean;
procedure UpdateTracking;
procedure SetAlignment(Value: TAlignment);
procedure SetAutoSize(Value: Boolean);
procedure SetFocusControl(Value: TWinControl);
procedure SetLayout(Value: TTextLayout);
procedure SetLeftMargin(Value: Integer);
procedure SetRightMargin(Value: Integer);
procedure SetShadowColor(Value: TColor);
procedure SetShadowSize(Value: Byte);
procedure SetShadowPos(Value: TShadowPosition);
procedure SetShowAccelChar(Value: Boolean);
procedure SetTransparent(Value: Boolean);
procedure SetWordWrap(Value: Boolean);
procedure SetShowFocus(Value: Boolean);
procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
procedure CMFocusChanged(var Message: TCMFocusChanged); message CM_FOCUSCHANGED;
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
procedure CMVisibleChanged(var Message: TMessage); message CM_VISIBLECHANGED;
procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
procedure WMRButtonUp(var Message: TWMRButtonUp); message WM_RBUTTONUP;
protected
procedure AdjustBounds;
function GetDefaultFontColor: TColor; virtual;
function GetLabelCaption: string; virtual;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure Paint; override;
procedure MouseEnter; dynamic;
procedure MouseLeave; dynamic;
property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
property AutoSize: Boolean read FAutoSize write SetAutoSize default True;
property FocusControl: TWinControl read FFocusControl write SetFocusControl;
property Layout: TTextLayout read FLayout write SetLayout default tlTop;
property LeftMargin: Integer read FLeftMargin write SetLeftMargin default 0;
property RightMargin: Integer read FRightMargin write SetRightMargin default 0;
property ShadowColor: TColor read FShadowColor write SetShadowColor default clBtnHighlight;
property ShadowSize: Byte read FShadowSize write SetShadowSize default 1;
property ShadowPos: TShadowPosition read FShadowPos write SetShadowPos default spLeftTop;
property ShowAccelChar: Boolean read FShowAccelChar write SetShowAccelChar default True;
property ShowFocus: Boolean read FShowFocus write SetShowFocus default False;
property Transparent: Boolean read GetTransparent write SetTransparent default False;
property WordWrap: Boolean read FWordWrap write SetWordWrap default False;
property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
public
constructor Create(AOwner: TComponent); override;
property Canvas;
property MouseInControl: Boolean read FMouseInControl;
end;
{ TRxLabel }
TRxLabel = class(TRxCustomLabel)
published
property Align;
property Alignment;
property AutoSize;
property Caption;
property Color;
property DragCursor;
property DragMode;
property Enabled;
property FocusControl;
property Font;
{$IFDEF RX_D4}
property Anchors;
property BiDiMode;
property Constraints;
property DragKind;
property ParentBiDiMode;
{$ENDIF}
property Layout;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShadowColor;
property ShadowSize;
property ShadowPos;
property ShowAccelChar;
property ShowFocus;
property ShowHint;
property Transparent;
property Visible;
property WordWrap;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnMouseEnter;
property OnMouseLeave;
{$IFDEF WIN32}
property OnStartDrag;
{$ENDIF}
{$IFDEF RX_D5}
property OnContextPopup;
{$ENDIF}
{$IFDEF RX_D4}
property OnEndDock;
property OnStartDock;
{$ENDIF}
end;
{ TSecretPanel }
TGlyphLayout = (glGlyphLeft, glGlyphRight, glGlyphTop, glGlyphBottom);
TScrollDirection = (sdVertical, sdHorizontal);
TPanelDrawEvent = procedure(Sender: TObject; Canvas: TCanvas;
Rect: TRect) of object;
TSecretPanel = class(TCustomPanel)
private
FActive: Boolean;
FAlignment: TAlignment;
FLines: TStrings;
FCycled: Boolean;
FScrollCnt: Integer;
FMaxScroll: Integer;
FTxtDivider: Byte;
FFirstLine: Integer;
FTimer: TRxTimer;
FTxtRect: TRect;
FPaintRect: TRect;
FGlyphOrigin: TPoint;
FMemoryImage: TBitmap;
FGlyph: TBitmap;
FHiddenList: TList;
FTextStyle: TPanelBevel;
FDirection: TScrollDirection;
FGlyphLayout: TGlyphLayout;
FOnPaintClient: TPanelDrawEvent;
FOnStartPlay: TNotifyEvent;
FOnStopPlay: TNotifyEvent;
{$IFDEF RX_D3}
FAsyncDrawing: Boolean;
procedure SetAsyncDrawing(Value: Boolean);
{$ENDIF}
function GetInflateWidth: Integer;
function GetInterval: Cardinal;
procedure SetInterval(Value: Cardinal);
procedure SetGlyph(Value: TBitmap);
procedure SetLines(Value: TStrings);
procedure SetActive(Value: Boolean);
procedure SetAlignment(Value: TAlignment);
procedure SetGlyphLayout(Value: TGlyphLayout);
procedure SetTextStyle(Value: TPanelBevel);
procedure SetDirection(Value: TScrollDirection);
procedure RecalcDrawRect;
procedure PaintGlyph;
procedure PaintText;
procedure UpdateMemoryImage;
procedure GlyphChanged(Sender: TObject);
procedure LinesChanged(Sender: TObject);
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
procedure WMSize(var Message: TMessage); message WM_SIZE;
protected
procedure AlignControls(AControl: TControl; var Rect: TRect); override;
procedure Paint; override;
procedure PaintClient(Canvas: TCanvas; Rect: TRect); virtual;
procedure TimerExpired(Sender: TObject); virtual;
procedure StartPlay; dynamic;
procedure StopPlay; dynamic;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Play;
procedure Stop;
property Canvas;
published
{$IFDEF RX_D3}
property AsyncDrawing: Boolean read FAsyncDrawing write SetAsyncDrawing default True;
{$ENDIF}
property Active: Boolean read FActive write SetActive default False;
property Alignment: TAlignment read FAlignment write SetAlignment default taCenter;
property Cycled: Boolean read FCycled write FCycled default False;
property Glyph: TBitmap read FGlyph write SetGlyph;
property GlyphLayout: TGlyphLayout read FGlyphLayout write SetGlyphLayout
default glGlyphLeft;
property Interval: Cardinal read GetInterval write SetInterval default 30;
property Lines: TStrings read FLines write SetLines;
property ScrollDirection: TScrollDirection read FDirection write SetDirection
default sdVertical;
property TextStyle: TPanelBevel read FTextStyle write SetTextStyle default bvNone;
{$IFDEF RX_D4}
property Anchors;
property BiDiMode;
property Constraints;
property DragKind;
property ParentBiDiMode;
{$ENDIF}
property Align;
property BevelInner;
property BevelOuter default bvLowered;
property BevelWidth;
property BorderWidth;
property BorderStyle;
property DragCursor;
property DragMode;
property Color;
property Ctl3D;
property Font;
property ParentColor;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property TabOrder;
property TabStop;
property Visible;
property OnPaintClient: TPanelDrawEvent read FOnPaintClient write FOnPaintClient;
property OnStartPlay: TNotifyEvent read FOnStartPlay write FOnStartPlay;
property OnStopPlay: TNotifyEvent read FOnStopPlay write FOnStopPlay;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
{$IFDEF WIN32}
property OnStartDrag;
{$ENDIF}
{$IFDEF RX_D5}
property OnContextPopup;
{$ENDIF}
{$IFDEF RX_D4}
property OnEndDock;
property OnStartDock;
{$ENDIF}
property OnResize;
end;
{ TRxSpeedButton }
TRxNumGlyphs = 1..5;
TRxDropDownMenuPos = (dmpBottom, dmpRight);
TRxButtonState = (rbsUp, rbsDisabled, rbsDown, rbsExclusive, rbsInactive);
TRxSpeedButton = class(TGraphicControl)
private
FGroupIndex: Integer;
FStyle: TButtonStyle;
FGlyph: Pointer;
FDrawImage: TBitmap;
FDown: Boolean;
FDragging: Boolean;
FFlat: Boolean;
FMouseInControl: Boolean;
FAllowAllUp: Boolean;
FLayout: TButtonLayout;
FSpacing: Integer;
FMargin: Integer;
FModalResult: TModalResult;
FTransparent: Boolean;
FMarkDropDown: Boolean;
FDropDownMenu: TPopupMenu;
FMenuPosition: TRxDropDownMenuPos;
FInactiveGrayed: Boolean;
FMenuTracking: Boolean;
FRepeatTimer: TTimer;
FAllowTimer: Boolean;
FInitRepeatPause: Word;
FRepeatPause: Word;
FOnMouseEnter: TNotifyEvent;
FOnMouseLeave: TNotifyEvent;
procedure GlyphChanged(Sender: TObject);
procedure UpdateExclusive;
function GetGlyph: TBitmap;
procedure SetGlyph(Value: TBitmap);
function GetNumGlyphs: TRxNumGlyphs;
procedure SetNumGlyphs(Value: TRxNumGlyphs);
function GetWordWrap: Boolean;
procedure SetWordWrap(Value: Boolean);
function GetAlignment: TAlignment;
procedure SetAlignment(Value: TAlignment);
procedure SetDown(Value: Boolean);
procedure SetAllowAllUp(Value: Boolean);
procedure SetGroupIndex(Value: Integer);
procedure SetLayout(Value: TButtonLayout);
procedure SetSpacing(Value: Integer);
procedure SetMargin(Value: Integer);
procedure SetDropDownMenu(Value: TPopupMenu);
procedure SetFlat(Value: Boolean);
procedure SetStyle(Value: TButtonStyle);
procedure SetInactiveGrayed(Value: Boolean);
procedure SetTransparent(Value: Boolean);
procedure SetMarkDropDown(Value: Boolean);
procedure TimerExpired(Sender: TObject);
procedure SetAllowTimer(Value: Boolean);
function CheckMenuDropDown(const Pos: TSmallPoint;
Manual: Boolean): Boolean;
procedure DoMouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
procedure CMButtonPressed(var Message: TMessage); message CM_RXBUTTONPRESSED;
procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
procedure CMSysColorChange(var Message: TMessage); message CM_SYSCOLORCHANGE;
procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
procedure CMVisibleChanged(var Message: TMessage); message CM_VISIBLECHANGED;
procedure WMLButtonDblClk(var Message: TWMLButtonDown); message WM_LBUTTONDBLCLK;
procedure WMMouseMove(var Message: TMessage); message WM_MOUSEMOVE;
procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
procedure WMRButtonUp(var Message: TWMRButtonUp); message WM_RBUTTONUP;
protected
FState: TRxButtonState;
{$IFDEF RX_D4}
procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); override;
{$ENDIF}
function GetDropDownMenuPos: TPoint;
function GetPalette: HPALETTE; override;
procedure Paint; override;
procedure Loaded; override;
procedure PaintGlyph(Canvas: TCanvas; ARect: TRect; AState: TRxButtonState;
DrawMark: Boolean); virtual;
procedure MouseEnter; dynamic;
procedure MouseLeave; dynamic;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
property ButtonGlyph: Pointer read FGlyph;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure ButtonClick;
function CheckBtnMenuDropDown: Boolean;
procedure Click; override;
procedure UpdateTracking;
published
{$IFDEF RX_D4}
property Action;
property Anchors;
property BiDiMode;
property Constraints;
property DragKind;
property ParentBiDiMode;
{$ENDIF}
property Alignment: TAlignment read GetAlignment write SetAlignment default taCenter;
property AllowAllUp: Boolean read FAllowAllUp write SetAllowAllUp default False;
property AllowTimer: Boolean read FAllowTimer write SetAllowTimer default False;
property GroupIndex: Integer read FGroupIndex write SetGroupIndex default 0;
{ Ensure group index is declared before Down }
property Down: Boolean read FDown write SetDown default False;
property DropDownMenu: TPopupMenu read FDropDownMenu write SetDropDownMenu;
property MenuPosition: TRxDropDownMenuPos read FMenuPosition write FMenuPosition
default dmpBottom;
property Caption;
property DragCursor;
property DragMode;
property Enabled;
property Flat: Boolean read FFlat write SetFlat default False;
property Font;
property Glyph: TBitmap read GetGlyph write SetGlyph;
property GrayedInactive: Boolean read FInactiveGrayed write SetInactiveGrayed
default True;
property InitPause: Word read FInitRepeatPause write FInitRepeatPause default 500;
property Layout: TButtonLayout read FLayout write SetLayout default blGlyphTop;
property Margin: Integer read FMargin write SetMargin default -1;
property MarkDropDown: Boolean read FMarkDropDown write SetMarkDropDown default True;
property ModalResult: TModalResult read FModalResult write FModalResult default 0;
property NumGlyphs: TRxNumGlyphs read GetNumGlyphs write SetNumGlyphs default 1;
property ParentFont;
property ParentShowHint default False;
property RepeatInterval: Word read FRepeatPause write FRepeatPause default 100;
property ShowHint default True;
property Spacing: Integer read FSpacing write SetSpacing default 1;
property Style: TButtonStyle read FStyle write SetStyle default bsAutoDetect;
property Transparent: Boolean read FTransparent write SetTransparent default False;
property WordWrap: Boolean read GetWordWrap write SetWordWrap default False;
property Visible;
property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
{$IFDEF WIN32}
property OnStartDrag;
{$ENDIF}
{$IFDEF RX_D4}
property OnEndDock;
property OnStartDock;
{$ENDIF}
end;
{ TButtonImage }
TButtonImage = class(TObject)
private
FGlyph: TObject;
FButtonSize: TPoint;
FCaption: TCaption;
function GetNumGlyphs: TRxNumGlyphs;
procedure SetNumGlyphs(Value: TRxNumGlyphs);
function GetWordWrap: Boolean;
procedure SetWordWrap(Value: Boolean);
function GetAlignment: TAlignment;
procedure SetAlignment(Value: TAlignment);
function GetGlyph: TBitmap;
procedure SetGlyph(Value: TBitmap);
public
constructor Create;
destructor Destroy; override;
procedure Invalidate;
{$IFDEF WIN32}
procedure DrawEx(Canvas: TCanvas; X, Y, Margin, Spacing: Integer;
Layout: TButtonLayout; AFont: TFont; Images: TImageList;
ImageIndex: Integer; Flags: Word);
{$ENDIF}
procedure Draw(Canvas: TCanvas; X, Y, Margin, Spacing: Integer;
Layout: TButtonLayout; AFont: TFont; Flags: Word);
property Alignment: TAlignment read GetAlignment write SetAlignment;
property Caption: TCaption read FCaption write FCaption;
property Glyph: TBitmap read GetGlyph write SetGlyph;
property NumGlyphs: TRxNumGlyphs read GetNumGlyphs write SetNumGlyphs;
property ButtonSize: TPoint read FButtonSize write FButtonSize;
property WordWrap: Boolean read GetWordWrap write SetWordWrap;
end;
{ TRxButtonGlyph }
TRxButtonGlyph = class
private
FOriginal: TBitmap;
FGlyphList: TImageList;
FIndexs: array[TRxButtonState] of Integer;
FTransparentColor: TColor;
FNumGlyphs: TRxNumGlyphs;
FWordWrap: Boolean;
FAlignment: TAlignment;
FOnChange: TNotifyEvent;
procedure GlyphChanged(Sender: TObject);
procedure SetGlyph(Value: TBitmap);
procedure SetNumGlyphs(Value: TRxNumGlyphs);
function MapColor(Color: TColor): TColor;
protected
procedure MinimizeCaption(Canvas: TCanvas; const Caption: string;
Buffer: PChar; MaxLen, Width: Integer);
function CreateButtonGlyph(State: TRxButtonState): Integer;
{$IFDEF WIN32}
function CreateImageGlyph(State: TRxButtonState; Images: TImageList;
Index: Integer): Integer;
{$ENDIF}
procedure CalcButtonLayout(Canvas: TCanvas; const Client: TRect;
var Caption: string; Layout: TButtonLayout; Margin, Spacing: Integer;
PopupMark: Boolean; var GlyphPos: TPoint; var TextBounds: TRect;
Flags: Word {$IFDEF WIN32}; Images: TImageList; ImageIndex: Integer
{$ENDIF});
public
constructor Create;
destructor Destroy; override;
procedure Invalidate;
function DrawButtonGlyph(Canvas: TCanvas; X, Y: Integer;
State: TRxButtonState): TPoint;
{$IFDEF WIN32}
function DrawButtonImage(Canvas: TCanvas; X, Y: Integer; Images: TImageList;
ImageIndex: Integer; State: TRxButtonState): TPoint;
function DrawEx(Canvas: TCanvas; const Client: TRect; const Caption: string;
Layout: TButtonLayout; Margin, Spacing: Integer; PopupMark: Boolean;
Images: TImageList; ImageIndex: Integer; State: TRxButtonState;
Flags: Word): TRect;
{$ENDIF}
procedure DrawButtonText(Canvas: TCanvas; const Caption: string;
TextBounds: TRect; State: TRxButtonState; Flags: Word);
procedure DrawPopupMark(Canvas: TCanvas; X, Y: Integer;
State: TRxButtonState);
function Draw(Canvas: TCanvas; const Client: TRect; const Caption: string;
Layout: TButtonLayout; Margin, Spacing: Integer; PopupMark: Boolean;
State: TRxButtonState; Flags: Word): TRect;
property Alignment: TAlignment read FAlignment write FAlignment;
property Glyph: TBitmap read FOriginal write SetGlyph;
property NumGlyphs: TRxNumGlyphs read FNumGlyphs write SetNumGlyphs;
property WordWrap: Boolean read FWordWrap write FWordWrap;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
function DrawShadowText(DC: HDC; Str: PChar; Count: Integer; var Rect: TRect;
Format: Word; ShadowSize: Byte; ShadowColor: TColorRef;
ShadowPos: TShadowPosition): Integer;
function CheckBitmap: TBitmap;
implementation
{$IFDEF WIN32}
{$R *.R32}
{$ELSE}
{$R *.R16}
{$ENDIF}
uses SysUtils, Dialogs, {$IFDEF WIN32} CommCtrl, {$ELSE} Str16, {$ENDIF}
VCLUtils, MaxMin, Consts, AppUtils {$IFDEF RX_D4}, ImgList,
ActnList {$ENDIF};
const
Alignments: array [TAlignment] of Word = (DT_LEFT, DT_RIGHT, DT_CENTER);
WordWraps: array[Boolean] of Word = (0, DT_WORDBREAK);
{ TTextListBox }
procedure TTextListBox.SetHorizontalExtent;
begin
SendMessage(Handle, LB_SETHORIZONTALEXTENT, FMaxWidth, 0);
end;
function TTextListBox.GetItemWidth(Index: Integer): Integer;
var
ATabWidth: Longint;
S: string;
begin
S := Items[Index] + 'x';
if TabWidth > 0 then begin
ATabWidth := Round((TabWidth * Canvas.TextWidth('0')) * 0.25);
Result := LoWord(GetTabbedTextExtent(Canvas.Handle, @S[1], Length(S),
1, ATabWidth));
end
else Result := Canvas.TextWidth(S);
end;
procedure TTextListBox.ResetHorizontalExtent;
var
I: Integer;
begin
FMaxWidth := 0;
for I := 0 to Items.Count - 1 do
FMaxWidth := Max(FMaxWidth, GetItemWidth(I));
SetHorizontalExtent;
end;
{$IFNDEF WIN32}
procedure TTextListBox.SetTabWidth(Value: Integer);
begin
if Value < 0 then Value := 0;
if FTabWidth <> Value then begin
FTabWidth := Value;
RecreateWnd;
end;
end;
procedure TTextListBox.CreateParams(var Params: TCreateParams);
const
TabStops: array[Boolean] of Longword = (0, LBS_USETABSTOPS);
begin
inherited CreateParams(Params);
Params.Style := Params.Style or TabStops[FTabWidth <> 0];
end;
procedure TTextListBox.CreateWnd;
begin
inherited CreateWnd;
if FTabWidth <> 0 then
SendMessage(Handle, LB_SETTABSTOPS, 1, Longint(@FTabWidth));
end;
{$ENDIF}
procedure TTextListBox.WndProc(var Message: TMessage);
begin
case Message.Msg of
LB_ADDSTRING, LB_INSERTSTRING:
begin
inherited WndProc(Message);
FMaxWidth := Max(FMaxWidth, GetItemWidth(Message.Result));
SetHorizontalExtent;
end;
LB_DELETESTRING:
begin
if GetItemWidth(Message.wParam) >= FMaxWidth then begin
Perform(WM_HSCROLL, SB_TOP, 0);
inherited WndProc(Message);
ResetHorizontalExtent;
end
else inherited WndProc(Message);
end;
LB_RESETCONTENT:
begin
FMaxWidth := 0;
SetHorizontalExtent;
Perform(WM_HSCROLL, SB_TOP, 0);
inherited WndProc(Message);
end;
WM_SETFONT:
begin
inherited WndProc(Message);
Canvas.Font.Assign(Self.Font);
ResetHorizontalExtent;
Exit;
end;
else inherited WndProc(Message);
end;
end;
{ TRxCustomListBox implementation copied from STDCTRLS.PAS and modified }
{ TRxListBoxStrings }
type
TRxListBoxStrings = class(TStrings)
private
ListBox: TRxCustomListBox;
protected
{$IFNDEF RX_D3}
procedure Error(Msg: Word; Data: Integer);
{$ENDIF}
function Get(Index: Integer): string; override;
function GetCount: Integer; override;
function GetObject(Index: Integer): TObject; override;
procedure PutObject(Index: Integer; AObject: TObject); override;
procedure SetUpdateState(Updating: Boolean); override;
public
function Add(const S: string): Integer; override;
procedure Clear; override;
procedure Delete(Index: Integer); override;
procedure Insert(Index: Integer; const S: string); override;
end;
{$IFNDEF RX_D3}
procedure TRxListBoxStrings.Error(Msg: Word; Data: Integer);
{$IFDEF WIN32}
function ReturnAddr: Pointer;
asm
MOV EAX,[EBP+4]
end;
{$ELSE}
function ReturnAddr: Pointer; assembler;
asm
MOV AX,[BP].Word[2]
MOV DX,[BP].Word[4]
end;
{$ENDIF}
begin
raise EStringListError.CreateFmt('%s: %d', [LoadStr(Msg),
Data]) at ReturnAddr;
end;
{$ENDIF}
function TRxListBoxStrings.GetCount: Integer;
begin
Result := SendMessage(ListBox.Handle, LB_GETCOUNT, 0, 0);
end;
function TRxListBoxStrings.Get(Index: Integer): string;
var
Len: Integer;
{$IFDEF WIN32}
Text: array[0..4095] of Char;
{$ENDIF}
begin
Len := SendMessage(ListBox.Handle, LB_GETTEXT, Index,
{$IFDEF WIN32} LongInt(@Text) {$ELSE} LongInt(@Result) {$ENDIF});
if Len < 0 then Error(SListIndexError, Index);
{$IFDEF WIN32}
SetString(Result, Text, Len);
{$ELSE}
System.Move(Result[0], Result[1], Len);
Result[0] := Char(Len);
{$ENDIF}
end;
function TRxListBoxStrings.GetObject(Index: Integer): TObject;
begin
Result := TObject(ListBox.GetItemData(Index));
if Longint(Result) = LB_ERR then Error(SListIndexError, Index);
end;
procedure TRxListBoxStrings.PutObject(Index: Integer; AObject: TObject);
begin
ListBox.SetItemData(Index, LongInt(AObject));
end;
function TRxListBoxStrings.Add(const S: string): Integer;
{$IFNDEF WIN32}
var
Text: array[0..255] of Char;
{$ENDIF}
begin
{$IFDEF WIN32}
Result := SendMessage(ListBox.Handle, LB_ADDSTRING, 0, LongInt(PChar(S)));
{$ELSE}
Result := SendMessage(ListBox.Handle, LB_ADDSTRING, 0, LongInt(StrPCopy(Text, S)));
{$ENDIF}
if Result < 0 then raise EOutOfResources.Create(ResStr(SInsertLineError));
end;
procedure TRxListBoxStrings.Insert(Index: Integer; const S: string);
{$IFNDEF WIN32}
var
Text: array[0..255] of Char;
{$ENDIF}
begin
if SendMessage(ListBox.Handle, LB_INSERTSTRING, Index,
{$IFDEF WIN32}
Longint(PChar(S))) < 0 then
{$ELSE}
Longint(StrPCopy(Text, S))) < 0 then
{$ENDIF}
raise EOutOfResources.Create(ResStr(SInsertLineError));
end;
procedure TRxListBoxStrings.Delete(Index: Integer);
begin
ListBox.DeleteString(Index);
end;
procedure TRxListBoxStrings.Clear;
begin
ListBox.ResetContent;
end;
procedure TRxListBoxStrings.SetUpdateState(Updating: Boolean);
begin
SendMessage(ListBox.Handle, WM_SETREDRAW, Ord(not Updating), 0);
if not Updating then ListBox.Refresh;
end;
{ TRxCustomListBox }
procedure ListIndexError(Index: Integer);
{$IFDEF WIN32}
function ReturnAddr: Pointer;
asm
MOV EAX,[EBP+4]
end;
{$ELSE}
function ReturnAddr: Pointer; assembler;
asm
MOV AX,[BP].Word[2]
MOV DX,[BP].Word[4]
end;
{$ENDIF}
begin
{$IFDEF RX_D3}
raise EStringListError.CreateFmt(SListIndexError, [Index]) at ReturnAddr;
{$ELSE}
raise EStringListError.CreateFmt('%s: %d', [LoadStr(SListIndexError),
Index]) at ReturnAddr;
{$ENDIF}
end;
constructor TRxCustomListBox.Create(AOwner: TComponent);
const
ListBoxStyle = [csSetCaption, csDoubleClicks];
begin
inherited Create(AOwner);
{$IFDEF WIN32}
if NewStyleControls then ControlStyle := ListBoxStyle
else ControlStyle := ListBoxStyle + [csFramed];
{$ELSE}
ControlStyle := ListBoxStyle + [csFramed];
{$ENDIF}
Width := 121;
Height := 97;
TabStop := True;
ParentColor := False;
FItems := CreateItemList;
TRxListBoxStrings(FItems).ListBox := Self;
FCanvas := TControlCanvas.Create;
TControlCanvas(FCanvas).Control := Self;
FItemHeight := 16;
FBorderStyle := bsSingle;
FExtendedSelect := True;
end;
destructor TRxCustomListBox.Destroy;
begin
inherited Destroy;
FCanvas.Free;
FItems.Free;
FSaveItems.Free;
end;
function TRxCustomListBox.CreateItemList: TStrings;
begin
Result := TRxListBoxStrings.Create;
end;
function TRxCustomListBox.GetItemData(Index: Integer): LongInt;
begin
Result := SendMessage(Handle, LB_GETITEMDATA, Index, 0);
end;
procedure TRxCustomListBox.SetItemData(Index: Integer; AData: LongInt);
begin
SendMessage(Handle, LB_SETITEMDATA, Index, AData);
end;
procedure TRxCustomListBox.DeleteString(Index: Integer);
begin
SendMessage(Handle, LB_DELETESTRING, Index, 0);
end;
procedure TRxCustomListBox.SetHorizontalExtent;
begin
SendMessage(Handle, LB_SETHORIZONTALEXTENT, FMaxItemWidth, 0);
end;
function TRxCustomListBox.GetItemWidth(Index: Integer): Integer;
var
ATabWidth: Longint;
S: string;
begin
if (Style <> lbStandard) and Assigned(FOnGetItemWidth) and
Assigned(FOnDrawItem) then
begin
Result := 0;
FOnGetItemWidth(Self, Index, Result);
end
else begin
S := Items[Index] + 'x';
if TabWidth > 0 then begin
{if (FTabChar > #0) then
for I := 1 to Length(S) do
if S[I] = FTabChar then S[I] := #9;}
ATabWidth := Round((TabWidth * Canvas.TextWidth('0')) * 0.25);
Result := LoWord(GetTabbedTextExtent(Canvas.Handle, @S[1], Length(S),
1, ATabWidth));
end
else Result := Canvas.TextWidth(S);
end;
end;
procedure TRxCustomListBox.ResetHorizontalExtent;
var
I: Integer;
begin
FMaxItemWidth := 0;
for I := 0 to Items.Count - 1 do
FMaxItemWidth := Max(FMaxItemWidth, GetItemWidth(I));
SetHorizontalExtent;
end;
procedure TRxCustomListBox.ResetContent;
begin
SendMessage(Handle, LB_RESETCONTENT, 0, 0);
end;
procedure TRxCustomListBox.Clear;
begin
FItems.Clear;
end;
procedure TRxCustomListBox.SetColumnWidth;
begin
if FColumns > 0 then
SendMessage(Handle, LB_SETCOLUMNWIDTH, (Width + FColumns - 3) div
FColumns, 0);
end;
procedure TRxCustomListBox.SetColumns(Value: Integer);
begin
if FColumns <> Value then
if (FColumns = 0) or (Value = 0) then begin
FColumns := Value;
RecreateWnd;
end
else begin
FColumns := Value;
if HandleAllocated then SetColumnWidth;
end;
end;
function TRxCustomListBox.GetItemIndex: Integer;
begin
Result := SendMessage(Handle, LB_GETCURSEL, 0, 0);
end;
function TRxCustomListBox.GetSelCount: Integer;
begin
Result := SendMessage(Handle, LB_GETSELCOUNT, 0, 0);
end;
procedure TRxCustomListBox.SetItemIndex(Value: Integer);
begin
if GetItemIndex <> Value then
SendMessage(Handle, LB_SETCURSEL, Value, 0);
end;
procedure TRxCustomListBox.SetExtendedSelect(Value: Boolean);
begin
if Value <> FExtendedSelect then begin
FExtendedSelect := Value;
RecreateWnd;
end;
end;
procedure TRxCustomListBox.SetIntegralHeight(Value: Boolean);
begin
if Value <> FIntegralHeight then begin
FIntegralHeight := Value;
RecreateWnd;
end;
end;
function TRxCustomListBox.GetAutoScroll: Boolean;
begin
Result := FAutoScroll and (Columns = 0);
end;
procedure TRxCustomListBox.SetOnDrawItem(Value: TDrawItemEvent);
begin
if Assigned(FOnDrawItem) <> Assigned(Value) then begin
FOnDrawItem := Value;
Perform(WM_HSCROLL, SB_TOP, 0);
if HandleAllocated then
if AutoScroll then ResetHorizontalExtent
else SendMessage(Handle, LB_SETHORIZONTALEXTENT, 0, 0);
end
else FOnDrawItem := Value;
end;
procedure TRxCustomListBox.SetOnGetItemWidth(Value: TGetItemWidthEvent);
begin
if Assigned(FOnGetItemWidth) <> Assigned(Value) then begin
FOnGetItemWidth := Value;
Perform(WM_HSCROLL, SB_TOP, 0);
if HandleAllocated then
if AutoScroll then ResetHorizontalExtent
else SendMessage(Handle, LB_SETHORIZONTALEXTENT, 0, 0);
end
else FOnGetItemWidth := Value;
end;
procedure TRxCustomListBox.SetAutoScroll(Value: Boolean);
begin
if AutoScroll <> Value then begin
FAutoScroll := Value;
Perform(WM_HSCROLL, SB_TOP, 0);
if HandleAllocated then begin
if AutoScroll then ResetHorizontalExtent
else SendMessage(Handle, LB_SETHORIZONTALEXTENT, 0, 0);
end;
end;
end;
function TRxCustomListBox.GetItemHeight: Integer;
var
R: TRect;
begin
Result := FItemHeight;
if HandleAllocated and (FStyle = lbStandard) then begin
Perform(LB_GETITEMRECT, 0, Longint(@R));
Result := R.Bottom - R.Top;
end;
end;
procedure TRxCustomListBox.SetItemHeight(Value: Integer);
begin
if (FItemHeight <> Value) and (Value > 0) then begin
FItemHeight := Value;
RecreateWnd;
end;
end;
procedure TRxCustomListBox.SetTabWidth(Value: Integer);
begin
if Value < 0 then Value := 0;
if FTabWidth <> Value then begin
FTabWidth := Value;
RecreateWnd;
end;
end;
procedure TRxCustomListBox.SetMultiSelect(Value: Boolean);
begin
if FMultiSelect <> Value then begin
FMultiSelect := Value;
RecreateWnd;
end;
end;
function TRxCustomListBox.GetSelected(Index: Integer): Boolean;
var
R: Longint;
begin
R := SendMessage(Handle, LB_GETSEL, Index, 0);
if R = LB_ERR then ListIndexError(Index);
Result := LongBool(R);
end;
procedure TRxCustomListBox.SetSelected(Index: Integer; Value: Boolean);
begin
if MultiSelect then begin
if SendMessage(Handle, LB_SETSEL, Ord(Value), Index) = LB_ERR then
ListIndexError(Index);
end
else begin
if Value then SetItemIndex(Index)
else if (ItemIndex = Index) then SetItemIndex(-1);
end;
end;
procedure TRxCustomListBox.SetSorted(Value: Boolean);
begin
if FSorted <> Value then begin
FSorted := Value;
RecreateWnd;
end;
end;
procedure TRxCustomListBox.SetStyle(Value: TListBoxStyle);
begin
if FStyle <> Value then begin
FStyle := Value;
RecreateWnd;
end;
end;
function TRxCustomListBox.GetTopIndex: Integer;
begin
Result := SendMessage(Handle, LB_GETTOPINDEX, 0, 0);
end;
procedure TRxCustomListBox.SetBorderStyle(Value: TBorderStyle);
begin
if FBorderStyle <> Value then begin
FBorderStyle := Value;
RecreateWnd;
end;
end;
procedure TRxCustomListBox.SetTopIndex(Value: Integer);
begin
if GetTopIndex <> Value then SendMessage(Handle, LB_SETTOPINDEX, Value, 0);
end;
procedure TRxCustomListBox.SetGraySelection(Value: Boolean);
begin
if FGraySelection <> Value then begin
FGraySelection := Value;
if not Focused then Invalidate;
end;
end;
procedure TRxCustomListBox.SetItems(Value: TStrings);
begin
Items.Assign(Value);
end;
function TRxCustomListBox.ItemAtPos(Pos: TPoint; Existing: Boolean): Integer;
var
Count: Integer;
ItemRect: TRect;
begin
if PtInRect(ClientRect, Pos) then begin
Result := TopIndex;
Count := Items.Count;
while Result < Count do begin
Perform(LB_GETITEMRECT, Result, Longint(@ItemRect));
if PtInRect(ItemRect, Pos) then Exit;
Inc(Result);
end;
if not Existing then Exit;
end;
Result := -1;
end;
function TRxCustomListBox.ItemRect(Index: Integer): TRect;
var
Count: Integer;
begin
Count := Items.Count;
if (Index = 0) or (Index < Count) then
Perform(LB_GETITEMRECT, Index, Longint(@Result))
else if Index = Count then begin
Perform(LB_GETITEMRECT, Index - 1, Longint(@Result));
OffsetRect(Result, 0, Result.Bottom - Result.Top);
end
else FillChar(Result, SizeOf(Result), 0);
end;
procedure TRxCustomListBox.CreateParams(var Params: TCreateParams);
type
PSelects = ^TSelects;
TSelects = array[Boolean] of Longword;
const
BorderStyles: array[TBorderStyle] of Longword = (0, WS_BORDER);
Styles: array[TListBoxStyle] of Longword =
(0, LBS_OWNERDRAWFIXED, LBS_OWNERDRAWVARIABLE, LBS_OWNERDRAWFIXED, LBS_OWNERDRAWVARIABLE);
Sorteds: array[Boolean] of Longword = (0, LBS_SORT);
MultiSelects: array[Boolean] of Longword = (0, LBS_MULTIPLESEL);
ExtendSelects: array[Boolean] of Longword = (0, LBS_EXTENDEDSEL);
IntegralHeights: array[Boolean] of Longword = (LBS_NOINTEGRALHEIGHT, 0);
MultiColumns: array[Boolean] of Longword = (0, LBS_MULTICOLUMN);
TabStops: array[Boolean] of Longword = (0, LBS_USETABSTOPS);
var
Selects: PSelects;
begin
inherited CreateParams(Params);
CreateSubClass(Params, 'LISTBOX');
with Params do begin
{$IFNDEF WIN32}
Inc(X); Inc(Y);
Dec(Width, 2); Dec(Height, 2);
{$ENDIF}
Selects := @MultiSelects;
if FExtendedSelect then Selects := @ExtendSelects;
Style := Style or (WS_HSCROLL or WS_VSCROLL or LBS_HASSTRINGS or
LBS_NOTIFY) or Styles[FStyle] or Sorteds[FSorted] or
Selects^[FMultiSelect] or IntegralHeights[FIntegralHeight] or
MultiColumns[FColumns <> 0] or BorderStyles[FBorderStyle] or
TabStops[FTabWidth <> 0];
{$IFDEF WIN32}
if NewStyleControls and Ctl3D and (FBorderStyle = bsSingle) then begin
Style := Style and not WS_BORDER;
ExStyle := ExStyle or WS_EX_CLIENTEDGE;
end;
{$ENDIF}
WindowClass.Style := WindowClass.Style and not (CS_HREDRAW or CS_VREDRAW);
end;
end;
procedure TRxCustomListBox.CreateWnd;
var
W, H: Integer;
begin
W := Width;
H := Height;
inherited CreateWnd;
SetWindowPos(Handle, 0, Left, Top, W, H, SWP_NOZORDER or SWP_NOACTIVATE);
if FTabWidth <> 0 then
SendMessage(Handle, LB_SETTABSTOPS, 1, Longint(@FTabWidth));
SetColumnWidth;
if FSaveItems <> nil then begin
FItems.Assign(FSaveItems);
SetTopIndex(FSaveTopIndex);
SetItemIndex(FSaveItemIndex);
FSaveItems.Free;
FSaveItems := nil;
end;
end;
procedure TRxCustomListBox.DestroyWnd;
begin
if FItems.Count > 0 then begin
FSaveItems := TStringList.Create;
FSaveItems.Assign(FItems);
FSaveTopIndex := GetTopIndex;
FSaveItemIndex := GetItemIndex;
end;
inherited DestroyWnd;
end;
procedure TRxCustomListBox.WndProc(var Message: TMessage);
begin
if AutoScroll then begin
case Message.Msg of
LB_ADDSTRING, LB_INSERTSTRING:
begin
inherited WndProc(Message);
FMaxItemWidth := Max(FMaxItemWidth, GetItemWidth(Message.Result));
SetHorizontalExtent;
Exit;
end;
LB_DELETESTRING:
begin
if GetItemWidth(Message.wParam) >= FMaxItemWidth then begin
Perform(WM_HSCROLL, SB_TOP, 0);
inherited WndProc(Message);
ResetHorizontalExtent;
end
else inherited WndProc(Message);
Exit;
end;
LB_RESETCONTENT:
begin
FMaxItemWidth := 0;
SetHorizontalExtent;
Perform(WM_HSCROLL, SB_TOP, 0);
inherited WndProc(Message);
Exit;
end;
WM_SETFONT:
begin
inherited WndProc(Message);
Canvas.Font.Assign(Self.Font);
ResetHorizontalExtent;
Exit;
end;
end;
end;
{for auto drag mode, let listbox handle itself, instead of TControl}
if not (csDesigning in ComponentState) and ((Message.Msg = WM_LBUTTONDOWN) or
(Message.Msg = WM_LBUTTONDBLCLK)) and not Dragging then
begin
if DragMode = dmAutomatic then begin
if IsControlMouseMsg(TWMMouse(Message)) then Exit;
ControlState := ControlState + [csLButtonDown];
Dispatch(Message); {overrides TControl's BeginDrag}
Exit;
end;
end;
inherited WndProc(Message);
end;
procedure TRxCustomListBox.WMLButtonDown(var Message: TWMLButtonDown);
var
ItemNo: Integer;
ShiftState: TShiftState;
begin
ShiftState := KeysToShiftState(Message.Keys);
if (DragMode = dmAutomatic) and FMultiSelect then begin
if not (ssShift in ShiftState) or (ssCtrl in ShiftState) then begin
ItemNo := ItemAtPos(SmallPointToPoint(Message.Pos), True);
if (ItemNo >= 0) and (Selected[ItemNo]) then begin
BeginDrag(False);
Exit;
end;
end;
end;
inherited;
if (DragMode = dmAutomatic) and not (FMultiSelect and
((ssCtrl in ShiftState) or (ssShift in ShiftState))) then
BeginDrag(False);
end;
procedure TRxCustomListBox.WMNCHitTest(var Msg: TWMNCHitTest);
begin
if csDesigning in ComponentState then DefaultHandler(Msg)
else inherited;
end;
procedure TRxCustomListBox.CNCommand(var Message: TWMCommand);
begin
case Message.NotifyCode of
LBN_SELCHANGE:
begin
{$IFDEF RX_D3}
inherited Changed;
{$ENDIF}
Click;
end;
LBN_DBLCLK: DblClick;
end;
end;
procedure TRxCustomListBox.WMPaint(var Message: TWMPaint);
procedure PaintListBox;
var
DrawItemMsg: TWMDrawItem;
MeasureItemMsg: TWMMeasureItem;
DrawItemStruct: TDrawItemStruct;
MeasureItemStruct: TMeasureItemStruct;
R: TRect;
Y, I, H, W: Integer;
begin
{ Initialize drawing records }
DrawItemMsg.Msg := CN_DRAWITEM;
DrawItemMsg.DrawItemStruct := @DrawItemStruct;
DrawItemMsg.Ctl := Handle;
DrawItemStruct.CtlType := ODT_LISTBOX;
DrawItemStruct.itemAction := ODA_DRAWENTIRE;
DrawItemStruct.itemState := 0;
DrawItemStruct.hDC := Message.DC;
DrawItemStruct.CtlID := Handle;
DrawItemStruct.hwndItem := Handle;
{ Intialize measure records }
MeasureItemMsg.Msg := CN_MEASUREITEM;
MeasureItemMsg.IDCtl := Handle;
MeasureItemMsg.MeasureItemStruct := @MeasureItemStruct;
MeasureItemStruct.CtlType := ODT_LISTBOX;
MeasureItemStruct.CtlID := Handle;
{ Draw the listbox }
Y := 0;
I := TopIndex;
GetClipBox(Message.DC, R);
H := Height;
W := Width;
while Y < H do begin
MeasureItemStruct.itemID := I;
if I < Items.Count then
MeasureItemStruct.itemData := Longint(Pointer(Items.Objects[I]));
MeasureItemStruct.itemWidth := W;
MeasureItemStruct.itemHeight := FItemHeight;
DrawItemStruct.itemData := MeasureItemStruct.itemData;
DrawItemStruct.itemID := I;
Dispatch(MeasureItemMsg);
DrawItemStruct.rcItem := Rect(0, Y, MeasureItemStruct.itemWidth,
Y + Integer(MeasureItemStruct.itemHeight));
Dispatch(DrawItemMsg);
Inc(Y, MeasureItemStruct.itemHeight);
Inc(I);
if I >= Items.Count then break;
end;
end;
begin
if Message.DC <> 0 then PaintListBox
else inherited;
end;
procedure TRxCustomListBox.WMSize(var Message: TWMSize);
begin
inherited;
SetColumnWidth;
end;
procedure TRxCustomListBox.DragCanceled;
var
M: TWMMouse;
{$IFDEF WIN32}
MousePos: TPoint;
{$ENDIF}
begin
with M do begin
Msg := WM_LBUTTONDOWN;
{$IFDEF WIN32}
GetCursorPos(MousePos);
Pos := PointToSmallPoint(ScreenToClient(MousePos));
{$ELSE}
GetCursorPos(Pos);
Pos := ScreenToClient(Pos);
{$ENDIF}
Keys := 0;
Result := 0;
end;
DefaultHandler(M);
M.Msg := WM_LBUTTONUP;
DefaultHandler(M);
end;
procedure TRxCustomListBox.DefaultDrawText(X, Y: Integer; const S: string);
var
ATabWidth: Longint;
begin
{$IFDEF RX_D4}
TControlCanvas(FCanvas).UpdateTextFlags;
{$ENDIF}
if FTabWidth = 0 then FCanvas.TextOut(X, Y, S)
else begin
ATabWidth := Round((TabWidth * Canvas.TextWidth('0')) * 0.25);
TabbedTextOut(FCanvas.Handle, X, Y, @S[1], Length(S), 1, ATabWidth, X);
end;
end;
procedure TRxCustomListBox.DrawItem(Index: Integer; Rect: TRect;
State: TOwnerDrawState);
begin
if Assigned(FOnDrawItem) then FOnDrawItem(Self, Index, Rect, State)
else begin
FCanvas.FillRect(Rect);
if Index < Items.Count then begin
{$IFDEF RX_D4}
if not UseRightToLeftAlignment then Inc(Rect.Left, 2)
else Dec(Rect.Right, 2);
{$ELSE}
Inc(Rect.Left, 2);
{$ENDIF}
DefaultDrawText(Rect.Left, Max(Rect.Top, (Rect.Bottom +
Rect.Top - Canvas.TextHeight('Wy')) div 2), Items[Index]);
end;
end;
end;
procedure TRxCustomListBox.MeasureItem(Index: Integer; var Height: Integer);
begin
if Assigned(FOnMeasureItem) then FOnMeasureItem(Self, Index, Height)
end;
procedure TRxCustomListBox.CNDrawItem(var Message: TWMDrawItem);
var
State: TOwnerDrawState;
begin
with Message.DrawItemStruct^ do begin
{$IFDEF WIN32}
{$IFDEF RX_D5}
State := TOwnerDrawState(LongRec(itemState).Lo);
{$ELSE}
State := TOwnerDrawState(WordRec(LongRec(itemState).Lo).Lo);
{$ENDIF}
{$ELSE}
State := TOwnerDrawState(WordRec(itemState).Lo);
{$ENDIF}
FCanvas.Handle := hDC;
FCanvas.Font := Font;
FCanvas.Brush := Brush;
if (Integer(itemID) >= 0) and (odSelected in State) then begin
with FCanvas do
if not (csDesigning in ComponentState) and FGraySelection and
not Focused then
begin
Brush.Color := clBtnFace;
if ColorToRGB(Font.Color) = ColorToRGB(clBtnFace) then
Font.Color := clBtnText;
end
else begin
Brush.Color := clHighlight;
Font.Color := clHighlightText
end;
end;
if Integer(itemID) >= 0 then DrawItem(itemID, rcItem, State)
else FCanvas.FillRect(rcItem);
if odFocused in State then DrawFocusRect(hDC, rcItem);
FCanvas.Handle := 0;
end;
end;
procedure TRxCustomListBox.CNMeasureItem(var Message: TWMMeasureItem);
begin
with Message.MeasureItemStruct^ do begin
itemHeight := FItemHeight;
if FStyle = lbOwnerDrawVariable then
MeasureItem(itemID, Integer(itemHeight));
end;
end;
procedure TRxCustomListBox.WMKillFocus(var Msg: TWMKillFocus);
begin
inherited;
if FGraySelection and MultiSelect and (SelCount > 1) then Invalidate;
end;
procedure TRxCustomListBox.WMSetFocus(var Msg: TWMSetFocus);
begin
inherited;
if FGraySelection and MultiSelect and (SelCount > 1) then Invalidate;
end;
{$IFDEF WIN32}
procedure TRxCustomListBox.CMCtl3DChanged(var Message: TMessage);
begin
if NewStyleControls and (FBorderStyle = bsSingle) then RecreateWnd;
inherited;
end;
{$ENDIF}
{ TCheckListBoxItem }
type
TCheckListBoxItem = class
private
FData: LongInt;
FState: TCheckBoxState;
FEnabled: Boolean;
function GetChecked: Boolean;
public
constructor Create;
property Checked: Boolean read GetChecked;
property Enabled: Boolean read FEnabled write FEnabled;
property State: TCheckBoxState read FState write FState;
end;
constructor TCheckListBoxItem.Create;
begin
inherited Create;
FState := clbDefaultState;
FEnabled := clbDefaultEnabled;
end;
function TCheckListBoxItem.GetChecked: Boolean;
begin
Result := FState = cbChecked;
end;
{ TCheckListBoxStrings }
type
TCheckListBoxStrings = class(TRxListBoxStrings)
public
procedure Exchange(Index1, Index2: Integer); override;
procedure Move(CurIndex, NewIndex: Integer); override;
end;
procedure TCheckListBoxStrings.Exchange(Index1, Index2: Integer);
var
TempEnabled1, TempEnabled2: Boolean;
TempState1, TempState2: TCheckBoxState;
begin
with TRxCheckListBox(ListBox) do begin
TempState1 := State[Index1];
TempEnabled1 := EnabledItem[Index1];
TempState2 := State[Index2];
TempEnabled2 := EnabledItem[Index2];
inherited Exchange(Index1, Index2);
State[Index1] := TempState2;
EnabledItem[Index1] := TempEnabled2;
State[Index2] := TempState1;
EnabledItem[Index2] := TempEnabled1;
end;
end;
procedure TCheckListBoxStrings.Move(CurIndex, NewIndex: Integer);
var
TempEnabled: Boolean;
TempState: TCheckBoxState;
begin
with TRxCheckListBox(ListBox) do begin
TempState := State[CurIndex];
TempEnabled := EnabledItem[CurIndex];
inherited Move(CurIndex, NewIndex);
State[NewIndex] := TempState;
EnabledItem[NewIndex] := TempEnabled;
end;
end;
{ TRxCheckListBox }
const
FCheckBitmap: TBitmap = nil;
function CheckBitmap: TBitmap;
begin
if FCheckBitmap = nil then begin
FCheckBitmap := TBitmap.Create;
FCheckBitmap.Handle := LoadBitmap(hInstance, 'CHECK_IMAGES');
end;
Result := FCheckBitmap;
end;
procedure DestroyLocals; far;
begin
if FCheckBitmap <> nil then begin
FCheckBitmap.Free;
FCheckBitmap := nil;
end;
end;
const
InternalVersion = 202; { for backward compatibility only }
constructor TRxCheckListBox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FAutoScroll := True;
with CheckBitmap do begin
FCheckWidth := Width div 6;
FCheckHeight := Height div 3;
end;
FDrawBitmap := TBitmap.Create;
with FDrawBitmap do begin
Width := FCheckWidth;
Height := FCheckHeight;
end;
FIniLink := TIniLink.Create;
FIniLink.OnSave := IniSave;
FIniLink.OnLoad := IniLoad;
end;
destructor TRxCheckListBox.Destroy;
begin
FSaveStates.Free;
FSaveStates := nil;
FDrawBitmap.Free;
FDrawBitmap := nil;
FIniLink.Free;
inherited Destroy;
end;
procedure TRxCheckListBox.Loaded;
begin
inherited Loaded;
UpdateCheckStates;
end;
function TRxCheckListBox.CreateItemList: TStrings;
begin
Result := TCheckListBoxStrings.Create;
end;
const
sCount = 'Count';
sItem = 'Item';
procedure TRxCheckListBox.InternalSaveStates(IniFile: TObject;
const Section: string);
var
I: Integer;
begin
IniEraseSection(IniFile, Section);
IniWriteInteger(IniFile, Section, sCount, Items.Count);
for I := 0 to Items.Count - 1 do
IniWriteInteger(IniFile, Section, sItem + IntToStr(I), Integer(State[I]));
end;
procedure TRxCheckListBox.InternalRestoreStates(IniFile: TObject;
const Section: string);
var
I: Integer;
ACount: Integer;
begin
ACount := Min(IniReadInteger(IniFile, Section, sCount, 0), Items.Count);
for I := 0 to ACount - 1 do begin
State[I] := TCheckBoxState(IniReadInteger(IniFile, Section,
sItem + IntToStr(I), Integer(clbDefaultState)));
if (State[I] = cbChecked) and (FCheckKind = ckRadioButtons) then Exit;
end;
end;
{$IFDEF WIN32}
procedure TRxCheckListBox.SaveStatesReg(IniFile: TRegIniFile);
begin
InternalSaveStates(IniFile, GetDefaultSection(Self));
end;
procedure TRxCheckListBox.RestoreStatesReg(IniFile: TRegIniFile);
begin
InternalRestoreStates(IniFile, GetDefaultSection(Self));
end;
{$ENDIF WIN32}
procedure TRxCheckListBox.SaveStates(IniFile: TIniFile);
begin
InternalSaveStates(IniFile, GetDefaultSection(Self));
end;
procedure TRxCheckListBox.RestoreStates(IniFile: TIniFile);
begin
InternalRestoreStates(IniFile, GetDefaultSection(Self));
end;
function TRxCheckListBox.GetStorage: TFormPlacement;
begin
Result := FIniLink.Storage;
end;
procedure TRxCheckListBox.SetStorage(Value: TFormPlacement);
begin
FIniLink.Storage := Value;
end;
procedure TRxCheckListBox.IniSave(Sender: TObject);
begin
if (Name <> '') and (FIniLink.IniObject <> nil) then
InternalSaveStates(FIniLink.IniObject, FIniLink.RootSection +
GetDefaultSection(Self));
end;
procedure TRxCheckListBox.IniLoad(Sender: TObject);
begin
if (Name <> '') and (FIniLink.IniObject <> nil) then
InternalRestoreStates(FIniLink.IniObject, FIniLink.RootSection +
GetDefaultSection(Self));
end;
procedure TRxCheckListBox.ReadCheckData(Reader: TReader);
var
I: Integer;
begin
Items.BeginUpdate;
try
Reader.ReadListBegin;
Clear;
while not Reader.EndOfList do begin
I := Items.Add(Reader.ReadString);
if FReserved >= InternalVersion then begin
State[I] := TCheckBoxState(Reader.ReadInteger);
EnabledItem[I] := Reader.ReadBoolean;
end
else begin { for backward compatibility only }
Checked[I] := Reader.ReadBoolean;
EnabledItem[I] := Reader.ReadBoolean;
if FReserved > 0 then
State[I] := TCheckBoxState(Reader.ReadInteger);
end;
end;
Reader.ReadListEnd;
UpdateCheckStates;
finally
Items.EndUpdate;
end;
end;
procedure TRxCheckListBox.WriteCheckData(Writer: TWriter);
var
I: Integer;
begin
with Writer do begin
WriteListBegin;
for I := 0 to Items.Count - 1 do begin
WriteString(Items[I]);
WriteInteger(Integer(Self.State[I]));
WriteBoolean(EnabledItem[I]);
end;
WriteListEnd;
end;
end;
procedure TRxCheckListBox.ReadVersion(Reader: TReader);
begin
FReserved := Reader.ReadInteger;
end;
procedure TRxCheckListBox.WriteVersion(Writer: TWriter);
begin
Writer.WriteInteger(InternalVersion);
end;
procedure TRxCheckListBox.DefineProperties(Filer: TFiler);
{$IFDEF WIN32}
function DoWrite: Boolean;
var
I: Integer;
Ancestor: TRxCheckListBox;
begin
Result := False;
Ancestor := TRxCheckListBox(Filer.Ancestor);
if (Ancestor <> nil) and (Ancestor.Items.Count = Items.Count) and
(Ancestor.Items.Count > 0) then
for I := 1 to Items.Count - 1 do begin
Result := (CompareText(Items[I], Ancestor.Items[I]) <> 0) or
(State[I] <> Ancestor.State[I]) or
(EnabledItem[I] <> Ancestor.EnabledItem[I]);
if Result then Break;
end
else Result := Items.Count > 0;
end;
{$ENDIF}
begin
inherited DefineProperties(Filer);
Filer.DefineProperty('InternalVersion', ReadVersion, WriteVersion,
{$IFDEF WIN32} Filer.Ancestor = nil {$ELSE} True {$ENDIF});
Filer.DefineProperty('Strings', ReadCheckData, WriteCheckData,
{$IFDEF WIN32} DoWrite {$ELSE} Items.Count > 0 {$ENDIF});
end;
procedure TRxCheckListBox.CreateWnd;
begin
inherited CreateWnd;
if FSaveStates <> nil then begin
FSaveStates.Free;
FSaveStates := nil;
end;
ResetItemHeight;
end;
procedure TRxCheckListBox.DestroyWnd;
begin
inherited DestroyWnd;
end;
procedure TRxCheckListBox.WMDestroy(var Msg: TWMDestroy);
var
I: Integer;
begin
if Items.Count > 0 then begin
if FSaveStates <> nil then FSaveStates.Clear
else FSaveStates := TList.Create;
for I := 0 to Items.Count - 1 do begin
FSaveStates.Add(TObject(MakeLong(Ord(EnabledItem[I]), Word(State[I]))));
FindCheckObject(I).Free;
end;
end;
inherited;
end;
procedure TRxCheckListBox.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
with Params do
if Style and (LBS_OWNERDRAWFIXED or LBS_OWNERDRAWVARIABLE) = 0 then
Style := Style or LBS_OWNERDRAWFIXED;
end;
procedure TRxCheckListBox.SetItems(Value: TStrings);
var
I: Integer;
begin
Items.BeginUpdate;
try
inherited SetItems(Value);
if (Value <> nil) and (Value is TRxListBoxStrings) and
(TRxListBoxStrings(Value).ListBox <> nil) and
(TRxListBoxStrings(Value).ListBox is TRxCheckListBox) then
begin
for I := 0 to Items.Count - 1 do
if I < Value.Count then begin
Self.State[I] := TRxCheckListBox(TRxListBoxStrings(Value).ListBox).State[I];
EnabledItem[I] := TRxCheckListBox(TRxListBoxStrings(Value).ListBox).EnabledItem[I];
end;
end;
finally
Items.EndUpdate;
end;
end;
function TRxCheckListBox.GetItemWidth(Index: Integer): Integer;
begin
Result := inherited GetItemWidth(Index) + GetCheckWidth;
end;
function TRxCheckListBox.GetCheckWidth: Integer;
begin
Result := FCheckWidth + 2;
end;
function TRxCheckListBox.GetAllowGrayed: Boolean;
begin
Result := FAllowGrayed and (FCheckKind in [ckCheckBoxes, ckCheckMarks]);
end;
procedure TRxCheckListBox.CMFontChanged(var Message: TMessage);
begin
inherited;
ResetItemHeight;
end;
function TRxCheckListBox.GetItemHeight: Integer;
var
R: TRect;
begin
Result := FItemHeight;
if HandleAllocated and ((FStyle = lbStandard) or
((FStyle = lbOwnerDrawFixed) and not Assigned(FOnDrawItem))) then
begin
Perform(LB_GETITEMRECT, 0, Longint(@R));
Result := R.Bottom - R.Top;
end;
end;
procedure TRxCheckListBox.ResetItemHeight;
var
H: Integer;
begin
if (Style = lbStandard) or ((Style = lbOwnerDrawFixed) and
not Assigned(FOnDrawItem)) then
begin
Canvas.Font := Font;
H := Max(Canvas.TextHeight('Wg'), FCheckHeight);
if Style = lbOwnerDrawFixed then H := Max(H, FItemHeight);
Perform(LB_SETITEMHEIGHT, 0, H);
if (H * Items.Count) <= ClientHeight then
SetScrollRange(Handle, SB_VERT, 0, 0, True);
end;
end;
procedure TRxCheckListBox.DrawItem(Index: Integer; Rect: TRect;
State: TOwnerDrawState);
var
R: TRect;
SaveEvent: TDrawItemEvent;
begin
if Index < Items.Count then begin
R := Rect;
{$IFDEF RX_D4}
if not UseRightToLeftAlignment then begin
R.Right := Rect.Left;
R.Left := R.Right - GetCheckWidth;
end
else
begin
R.Left := Rect.Right;
R.Right := R.Left + GetCheckWidth;
end;
{$ELSE}
R.Right := Rect.Left;
R.Left := R.Right - GetCheckWidth;
{$ENDIF}
DrawCheck(R, GetState(Index), EnabledItem[Index]);
if not EnabledItem[Index] then
if odSelected in State then Canvas.Font.Color := clInactiveCaptionText
else Canvas.Font.Color := clGrayText;
end;
if (Style = lbStandard) and Assigned(FOnDrawItem) then begin
SaveEvent := OnDrawItem;
OnDrawItem := nil;
try
inherited DrawItem(Index, Rect, State);
finally
OnDrawItem := SaveEvent;
end;
end
else inherited DrawItem(Index, Rect, State);
end;
procedure TRxCheckListBox.CNDrawItem(var Message: TWMDrawItem);
begin
with Message.DrawItemStruct^ do
{$IFDEF RX_D4}
if not UseRightToLeftAlignment then
rcItem.Left := rcItem.Left + GetCheckWidth
else
rcItem.Right := rcItem.Right - GetCheckWidth;
{$ELSE}
rcItem.Left := rcItem.Left + GetCheckWidth;
{$ENDIF}
inherited;
end;
procedure TRxCheckListBox.DrawCheck(R: TRect; AState: TCheckBoxState;
Enabled: Boolean);
const
CheckImages: array[TCheckBoxState, TCheckKind, Boolean] of Integer =
(((3, 0), (9, 6), (15, 12)), { unchecked }
((4, 1), (10, 7), (16, 13)), { checked }
((5, 2), (11, 8), (17, 14))); { grayed }
var
DrawRect: TRect;
SaveColor: TColor;
begin
DrawRect.Left := R.Left + (R.Right - R.Left - FCheckWidth) div 2;
DrawRect.Top := R.Top + (R.Bottom - R.Top - FCheckHeight) div 2;
DrawRect.Right := DrawRect.Left + FCheckWidth;
DrawRect.Bottom := DrawRect.Top + FCheckHeight;
SaveColor := Canvas.Brush.Color;
AssignBitmapCell(CheckBitmap, FDrawBitmap, 6, 3,
CheckImages[AState, FCheckKind, Enabled]);
Canvas.Brush.Color := Self.Color;
try
Canvas.BrushCopy(DrawRect, FDrawBitmap, Bounds(0, 0, FCheckWidth,
FCheckHeight), CheckBitmap.TransparentColor and not PaletteMask);
finally
Canvas.Brush.Color := SaveColor;
end;
end;
procedure TRxCheckListBox.ApplyState(AState: TCheckBoxState;
EnabledOnly: Boolean);
var
I: Integer;
begin
if FCheckKind in [ckCheckBoxes, ckCheckMarks] then
for I := 0 to Items.Count - 1 do
if not EnabledOnly or EnabledItem[I] then begin
State[I] := AState;
end;
end;
function TRxCheckListBox.GetCheckedIndex: Integer;
var
I: Integer;
begin
Result := -1;
if FCheckKind = ckRadioButtons then
for I := 0 to Items.Count - 1 do
if State[I] = cbChecked then begin
Result := I;
Exit;
end;
end;
procedure TRxCheckListBox.SetCheckedIndex(Value: Integer);
begin
if (FCheckKind = ckRadioButtons) and (Items.Count > 0) then
SetState(Max(Value, 0), cbChecked);
end;
procedure TRxCheckListBox.UpdateCheckStates;
begin
if (FCheckKind = ckRadioButtons) and (Items.Count > 0) then begin
FInUpdateStates := True;
try
SetState(Max(GetCheckedIndex, 0), cbChecked);
finally
FInUpdateStates := False;
end;
end;
end;
procedure TRxCheckListBox.SetCheckKind(Value: TCheckKind);
begin
if FCheckKind <> Value then begin
FCheckKind := Value;
UpdateCheckStates;
Invalidate;
end;
end;
procedure TRxCheckListBox.SetChecked(Index: Integer; AChecked: Boolean);
const
CheckStates: array[Boolean] of TCheckBoxState = (cbUnchecked, cbChecked);
begin
SetState(Index, CheckStates[AChecked]);
end;
procedure TRxCheckListBox.SetState(Index: Integer; AState: TCheckBoxState);
var
I: Integer;
begin
if (AState <> GetState(Index)) or FInUpdateStates then begin
if (FCheckKind = ckRadioButtons) and (AState = cbUnchecked) and
(GetCheckedIndex = Index) then Exit;
TCheckListBoxItem(GetCheckObject(Index)).State := AState;
if (FCheckKind = ckRadioButtons) and (AState = cbChecked) then
for I := Items.Count - 1 downto 0 do begin
if (I <> Index) and (GetState(I) = cbChecked) then begin
TCheckListBoxItem(GetCheckObject(I)).State := cbUnchecked;
InvalidateCheck(I);
end;
end;
InvalidateCheck(Index);
if not (csReading in ComponentState) then ChangeItemState(Index);
end;
end;
procedure TRxCheckListBox.SetItemEnabled(Index: Integer; Value: Boolean);
begin
if Value <> GetItemEnabled(Index) then begin
TCheckListBoxItem(GetCheckObject(Index)).Enabled := Value;
InvalidateItem(Index);
end;
end;
procedure TRxCheckListBox.InvalidateCheck(Index: Integer);
var
R: TRect;
begin
R := ItemRect(Index);
{$IFDEF RX_D4}
if not UseRightToLeftAlignment then R.Right := R.Left + GetCheckWidth
else R.Left := R.Right - GetCheckWidth;
{$ELSE}
R.Right := R.Left + GetCheckWidth;
{$ENDIF}
InvalidateRect(Handle, @R, not (csOpaque in ControlStyle));
UpdateWindow(Handle);
end;
procedure TRxCheckListBox.InvalidateItem(Index: Integer);
var
R: TRect;
begin
R := ItemRect(Index);
InvalidateRect(Handle, @R, not (csOpaque in ControlStyle));
UpdateWindow(Handle);
end;
function TRxCheckListBox.GetChecked(Index: Integer): Boolean;
begin
if IsCheckObject(Index) then
Result := TCheckListBoxItem(GetCheckObject(Index)).GetChecked
else Result := False;
end;
function TRxCheckListBox.GetState(Index: Integer): TCheckBoxState;
begin
if IsCheckObject(Index) then
Result := TCheckListBoxItem(GetCheckObject(Index)).State
else Result := clbDefaultState;
if (FCheckKind = ckRadioButtons) and (Result <> cbChecked) then
Result := cbUnchecked;
end;
function TRxCheckListBox.GetItemEnabled(Index: Integer): Boolean;
begin
if IsCheckObject(Index) then
Result := TCheckListBoxItem(GetCheckObject(Index)).Enabled
else Result := clbDefaultEnabled;
end;
procedure TRxCheckListBox.KeyPress(var Key: Char);
begin
inherited KeyPress(Key);
case Key of
' ':
begin
ToggleClickCheck(ItemIndex);
Key := #0;
end;
'+':
begin
ApplyState(cbChecked, True);
ClickCheck;
end;
'-':
begin
ApplyState(cbUnchecked, True);
ClickCheck;
end;
end;
end;
procedure TRxCheckListBox.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
var
Index: Integer;
begin
inherited MouseDown(Button, Shift, X, Y);
if Button = mbLeft then begin
Index := ItemAtPos(Point(X,Y), True);
if (Index <> -1) then begin
{$IFDEF RX_D4}
if not UseRightToLeftAlignment then begin
if X - ItemRect(Index).Left < GetCheckWidth then
ToggleClickCheck(Index);
end
else begin
Dec(X, ItemRect(Index).Right - GetCheckWidth);
if (X > 0) and (X < GetCheckWidth) then
ToggleClickCheck(Index);
end;
{$ELSE}
if X - ItemRect(Index).Left < GetCheckWidth then
ToggleClickCheck(Index);
{$ENDIF}
end;
end;
end;
procedure TRxCheckListBox.ToggleClickCheck(Index: Integer);
var
State: TCheckBoxState;
begin
if (Index >= 0) and (Index < Items.Count) and EnabledItem[Index] then begin
State := Self.State[Index];
case State of
cbUnchecked:
if AllowGrayed then State := cbGrayed else State := cbChecked;
cbChecked: State := cbUnchecked;
cbGrayed: State := cbChecked;
end;
Self.State[Index] := State;
ClickCheck;
end;
end;
procedure TRxCheckListBox.ChangeItemState(Index: Integer);
begin
if Assigned(FOnStateChange) then FOnStateChange(Self, Index);
end;
procedure TRxCheckListBox.ClickCheck;
begin
if Assigned(FOnClickCheck) then FOnClickCheck(Self);
end;
function TRxCheckListBox.GetItemData(Index: Integer): LongInt;
var
Item: TCheckListBoxItem;
begin
Result := 0;
if IsCheckObject(Index) then begin
Item := TCheckListBoxItem(GetCheckObject(Index));
if Item <> nil then Result := Item.FData;
end;
end;
function TRxCheckListBox.GetCheckObject(Index: Integer): TObject;
begin
Result := FindCheckObject(Index);
if Result = nil then Result := CreateCheckObject(Index);
end;
function TRxCheckListBox.FindCheckObject(Index: Integer): TObject;
var
ItemData: Longint;
begin
Result := nil;
ItemData := inherited GetItemData(Index);
if ItemData = LB_ERR then ListIndexError(Index)
else begin
Result := TCheckListBoxItem(ItemData);
if not (Result is TCheckListBoxItem) then Result := nil;
end;
end;
function TRxCheckListBox.CreateCheckObject(Index: Integer): TObject;
begin
Result := TCheckListBoxItem.Create;
inherited SetItemData(Index, LongInt(Result));
end;
function TRxCheckListBox.IsCheckObject(Index: Integer): Boolean;
begin
Result := FindCheckObject(Index) <> nil;
end;
procedure TRxCheckListBox.SetItemData(Index: Integer; AData: LongInt);
var
Item: TCheckListBoxItem;
L: Longint;
begin
Item := TCheckListBoxItem(GetCheckObject(Index));
Item.FData := AData;
if (FSaveStates <> nil) and (FSaveStates.Count > 0) then begin
L := Longint(Pointer(FSaveStates[0]));
Item.FState := TCheckBoxState(LongRec(L).Hi);
Item.FEnabled := LongRec(L).Lo <> 0;
FSaveStates.Delete(0);
end;
end;
procedure TRxCheckListBox.ResetContent;
var
I: Integer;
begin
for I := Items.Count - 1 downto 0 do begin
if IsCheckObject(I) then GetCheckObject(I).Free;
inherited SetItemData(I, 0);
end;
inherited ResetContent;
end;
procedure TRxCheckListBox.DeleteString(Index: Integer);
begin
if IsCheckObject(Index) then GetCheckObject(Index).Free;
inherited SetItemData(Index, 0);
inherited DeleteString(Index);
end;
{ TRxCustomLabel }
function DrawShadowText(DC: HDC; Str: PChar; Count: Integer; var Rect: TRect;
Format: Word; ShadowSize: Byte; ShadowColor: TColorRef;
ShadowPos: TShadowPosition): Integer;
var
RText, RShadow: TRect;
Color: TColorRef;
begin
RText := Rect;
RShadow := Rect;
Color := SetTextColor(DC, ShadowColor);
case ShadowPos of
spLeftTop: OffsetRect(RShadow, -ShadowSize, -ShadowSize);
spRightBottom: OffsetRect(RShadow, ShadowSize, ShadowSize);
spLeftBottom:
begin
{OffsetRect(RText, ShadowSize, 0);}
OffsetRect(RShadow, -ShadowSize, ShadowSize);
end;
spRightTop:
begin
{OffsetRect(RText, 0, ShadowSize);}
OffsetRect(RShadow, ShadowSize, -ShadowSize);
end;
end; { case }
Result := DrawText(DC, Str, Count, RShadow, Format);
if Result > 0 then Inc(Result, ShadowSize);
SetTextColor(DC, Color);
DrawText(DC, Str, Count, RText, Format);
UnionRect(Rect, RText, RShadow);
end;
constructor TRxCustomLabel.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := ControlStyle + [csOpaque];
{$IFDEF WIN32}
ControlStyle := ControlStyle + [csReplicatable];
{$ENDIF}
Width := 65;
Height := 17;
FAutoSize := True;
FShowAccelChar := True;
FShadowColor := clBtnHighlight;
FShadowSize := 1;
FShadowPos := spLeftTop;
end;
function TRxCustomLabel.GetLabelCaption: string;
begin
Result := Caption;
end;
function TRxCustomLabel.GetDefaultFontColor: TColor;
begin
Result := Font.Color;
end;
procedure TRxCustomLabel.DoDrawText(var Rect: TRect; Flags: Word);
var
{$IFDEF WIN32}
Text: string;
{$ELSE}
Text: array[0..255] of Char;
{$ENDIF}
PosShadow: TShadowPosition;
SizeShadow: Byte;
ColorShadow: TColor;
begin
{$IFDEF WIN32}
Text := GetLabelCaption;
if (Flags and DT_CALCRECT <> 0) and ((Text = '') or FShowAccelChar and
(Text[1] = '&') and (Text[2] = #0)) then Text := Text + ' ';
{$ELSE}
StrPLCopy(Text, GetLabelCaption, 255);
if (Flags and DT_CALCRECT <> 0) and ((Text[0] = #0) or FShowAccelChar and
(Text[0] = '&') and (Text[1] = #0)) then StrCopy(Text, ' ');
{$ENDIF}
if not FShowAccelChar then Flags := Flags or DT_NOPREFIX;
{$IFDEF RX_D4}
Flags := DrawTextBiDiModeFlags(Flags);
{$ENDIF}
Canvas.Font := Font;
Canvas.Font.Color := GetDefaultFontColor;
PosShadow := FShadowPos;
SizeShadow := FShadowSize;
ColorShadow := FShadowColor;
if not Enabled then begin
if (FShadowSize = 0) and NewStyleControls then begin
PosShadow := spRightBottom;
SizeShadow := 1;
end;
Canvas.Font.Color := clGrayText;
ColorShadow := clBtnHighlight;
end;
{$IFDEF WIN32}
DrawShadowText(Canvas.Handle, PChar(Text), Length(Text), Rect, Flags,
SizeShadow, ColorToRGB(ColorShadow), PosShadow);
{$ELSE}
DrawShadowText(Canvas.Handle, Text, StrLen(Text), Rect, Flags,
SizeShadow, ColorToRGB(ColorShadow), PosShadow);
{$ENDIF}
end;
procedure TRxCustomLabel.Paint;
var
Rect: TRect;
DrawStyle: Integer;
begin
if not Enabled and not (csDesigning in ComponentState) then
FDragging := False;
with Canvas do begin
if not Transparent then begin
Brush.Color := Self.Color;
Brush.Style := bsSolid;
FillRect(ClientRect);
end;
Brush.Style := bsClear;
Rect := ClientRect;
Inc(Rect.Left, FLeftMargin);
Dec(Rect.Right, FRightMargin);
InflateRect(Rect, -1, 0);
DrawStyle := DT_EXPANDTABS or WordWraps[FWordWrap] or Alignments[FAlignment];
{ Calculate vertical layout }
if FLayout <> tlTop then begin
DoDrawText(Rect, DrawStyle or DT_CALCRECT);
Rect.Left := ClientRect.Left + FLeftMargin;
Rect.Right := ClientRect.Right - FRightMargin;
if FLayout = tlBottom then OffsetRect(Rect, 0, Height - Rect.Bottom)
else OffsetRect(Rect, 0, (Height - Rect.Bottom) div 2);
end;
DoDrawText(Rect, DrawStyle);
if FShowFocus and Assigned(FFocusControl) and FFocused and
not (csDesigning in ComponentState) then
begin
InflateRect(Rect, 1, 0);
{$IFDEF WIN32}
Brush.Color := Self.Color;
{$ENDIF}
DrawFocusRect(Rect);
end;
end;
end;
procedure TRxCustomLabel.AdjustBounds;
var
DC: HDC;
X: Integer;
Rect: TRect;
AAlignment: TAlignment;
begin
if AutoSize then begin
Rect := ClientRect;
Inc(Rect.Left, FLeftMargin);
Dec(Rect.Right, FRightMargin);
InflateRect(Rect, -1, 0);
DC := GetDC(0);
Canvas.Handle := DC;
DoDrawText(Rect, DT_EXPANDTABS or DT_CALCRECT or WordWraps[FWordWrap]);
Dec(Rect.Left, FLeftMargin);
Inc(Rect.Right, FRightMargin);
Canvas.Handle := 0;
ReleaseDC(0, DC);
InflateRect(Rect, 1, 0);
X := Left;
AAlignment := FAlignment;
{$IFDEF RX_D4}
if UseRightToLeftAlignment then ChangeBiDiModeAlignment(AAlignment);
{$ENDIF}
if AAlignment = taRightJustify then Inc(X, Width - Rect.Right);
SetBounds(X, Top, Rect.Right, Rect.Bottom);
end;
end;
procedure TRxCustomLabel.SetAlignment(Value: TAlignment);
begin
if FAlignment <> Value then begin
FAlignment := Value;
Invalidate;
end;
end;
procedure TRxCustomLabel.SetAutoSize(Value: Boolean);
begin
if AutoSize <> Value then begin
FAutoSize := Value;
AdjustBounds;
end;
end;
procedure TRxCustomLabel.SetLayout(Value: TTextLayout);
begin
if FLayout <> Value then begin
FLayout := Value;
Invalidate;
end;
end;
procedure TRxCustomLabel.SetLeftMargin(Value: Integer);
begin
if FLeftMargin <> Value then begin
FLeftMargin := Max(Value, 0);
AdjustBounds;
Invalidate;
end;
end;
procedure TRxCustomLabel.SetRightMargin(Value: Integer);
begin
if FRightMargin <> Value then begin
FRightMargin := Max(Value, 0);
AdjustBounds;
Invalidate;
end;
end;
procedure TRxCustomLabel.SetShadowColor(Value: TColor);
begin
if Value <> FShadowColor then begin
FShadowColor := Value;
Invalidate;
end;
end;
procedure TRxCustomLabel.SetShadowSize(Value: Byte);
begin
if Value <> FShadowSize then begin
FShadowSize := Value;
AdjustBounds;
Invalidate;
end;
end;
procedure TRxCustomLabel.SetShadowPos(Value: TShadowPosition);
begin
if Value <> FShadowPos then begin
FShadowPos := Value;
Invalidate;
end;
end;
function TRxCustomLabel.GetTransparent: Boolean;
begin
Result := not (csOpaque in ControlStyle);
end;
procedure TRxCustomLabel.SetFocusControl(Value: TWinControl);
begin
FFocusControl := Value;
{$IFDEF WIN32}
if Value <> nil then Value.FreeNotification(Self);
{$ENDIF}
if FShowFocus then Invalidate;
end;
procedure TRxCustomLabel.SetShowAccelChar(Value: Boolean);
begin
if FShowAccelChar <> Value then begin
FShowAccelChar := Value;
Invalidate;
end;
end;
procedure TRxCustomLabel.SetTransparent(Value: Boolean);
begin
if Transparent <> Value then begin
if Value then ControlStyle := ControlStyle - [csOpaque]
else ControlStyle := ControlStyle + [csOpaque];
Invalidate;
end;
end;
procedure TRxCustomLabel.SetShowFocus(Value: Boolean);
begin
if FShowFocus <> Value then begin
FShowFocus := Value;
Invalidate;
end;
end;
procedure TRxCustomLabel.SetWordWrap(Value: Boolean);
begin
if FWordWrap <> Value then begin
FWordWrap := Value;
AdjustBounds;
end;
end;
procedure TRxCustomLabel.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = FFocusControl) then
FocusControl := nil;
end;
procedure TRxCustomLabel.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited MouseDown(Button, Shift, X, Y);
if (Button = mbLeft) and Enabled then begin
FDragging := True;
end;
end;
procedure TRxCustomLabel.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited MouseUp(Button, Shift, X, Y);
if FDragging and (Button = mbLeft) then FDragging := False;
UpdateTracking;
end;
procedure TRxCustomLabel.MouseEnter;
begin
if Assigned(FOnMouseEnter) then FOnMouseEnter(Self);
end;
procedure TRxCustomLabel.MouseLeave;
begin
if Assigned(FOnMouseLeave) then FOnMouseLeave(Self);
end;
procedure TRxCustomLabel.UpdateTracking;
var
P: TPoint;
OldValue: Boolean;
begin
OldValue := FMouseInControl;
GetCursorPos(P);
FMouseInControl := Enabled and (FindDragTarget(P, True) = Self) and
IsForegroundTask;
if (FMouseInControl <> OldValue) then
if FMouseInControl then MouseEnter else MouseLeave;
end;
procedure TRxCustomLabel.CMFocusChanged(var Message: TCMFocusChanged);
var
Active: Boolean;
begin
Active := Assigned(FFocusControl) and (Message.Sender = FFocusControl);
if FFocused <> Active then begin
FFocused := Active;
if FShowFocus then Invalidate;
end;
inherited;
end;
procedure TRxCustomLabel.CMTextChanged(var Message: TMessage);
begin
Invalidate;
AdjustBounds;
end;
procedure TRxCustomLabel.CMFontChanged(var Message: TMessage);
begin
inherited;
AdjustBounds;
end;
procedure TRxCustomLabel.CMDialogChar(var Message: TCMDialogChar);
begin
if (FFocusControl <> nil) and Enabled and ShowAccelChar and
IsAccel(Message.CharCode, GetLabelCaption) then
with FFocusControl do
if CanFocus then begin
SetFocus;
Message.Result := 1;
end;
end;
procedure TRxCustomLabel.WMRButtonDown(var Message: TWMRButtonDown);
begin
inherited;
UpdateTracking;
end;
procedure TRxCustomLabel.WMRButtonUp(var Message: TWMRButtonUp);
begin
inherited;
UpdateTracking;
end;
procedure TRxCustomLabel.CMEnabledChanged(var Message: TMessage);
begin
inherited;
UpdateTracking;
end;
procedure TRxCustomLabel.CMVisibleChanged(var Message: TMessage);
begin
inherited;
if Visible then UpdateTracking;
end;
procedure TRxCustomLabel.CMMouseEnter(var Message: TMessage);
begin
inherited;
if not FMouseInControl and Enabled and IsForegroundTask then begin
FMouseInControl := True;
MouseEnter;
end;
end;
procedure TRxCustomLabel.CMMouseLeave(var Message: TMessage);
begin
inherited;
if FMouseInControl and Enabled and not FDragging then begin
FMouseInControl := False;
MouseLeave;
end;
end;
{ TSecretPanel }
constructor TSecretPanel.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FScrollCnt := 0;
FAlignment := taCenter;
FActive := False;
FTxtDivider := 1;
FGlyphLayout := glGlyphLeft;
ControlStyle := ControlStyle - [csSetCaption];
BevelOuter := bvLowered;
FTextStyle := bvNone;
FLines := TStringList.Create;
TStringList(FLines).OnChange := LinesChanged;
FGlyph := TBitmap.Create;
FGlyph.OnChange := GlyphChanged;
FHiddenList := TList.Create;
FTimer := TRxTimer.Create(Self);
with FTimer do begin
Enabled := False;
OnTimer := TimerExpired;
Interval := 30;
{$IFDEF RX_D3}
SyncEvent := False;
FAsyncDrawing := True;
{$ENDIF}
end;
end;
destructor TSecretPanel.Destroy;
begin
SetActive(False);
FGlyph.OnChange := nil;
FGlyph.Free;
TStringList(FLines).OnChange := nil;
FLines.Free;
FHiddenList.Free;
inherited Destroy;
end;
procedure TSecretPanel.GlyphChanged(Sender: TObject);
begin
if Active then begin
UpdateMemoryImage;
Invalidate;
end;
end;
procedure TSecretPanel.LinesChanged(Sender: TObject);
begin
if Active then begin
FScrollCnt := 0;
UpdateMemoryImage;
Invalidate;
end;
end;
procedure TSecretPanel.CMFontChanged(var Message: TMessage);
begin
inherited;
if Active then UpdateMemoryImage;
end;
procedure TSecretPanel.CMColorChanged(var Message: TMessage);
begin
inherited;
if Active then UpdateMemoryImage;
end;
procedure TSecretPanel.WMSize(var Message: TMessage);
begin
inherited;
if Active then begin
UpdateMemoryImage;
Invalidate;
end;
end;
{$IFDEF RX_D3}
procedure TSecretPanel.SetAsyncDrawing(Value: Boolean);
begin
if FAsyncDrawing <> Value then begin
FTimer.SyncEvent := not Value;
FAsyncDrawing := Value;
end;
end;
{$ENDIF RX_D3}
procedure TSecretPanel.AlignControls(AControl: TControl; var Rect: TRect);
begin
inherited AlignControls(AControl, Rect);
if (AControl = nil) and Active then UpdateMemoryImage;
end;
function TSecretPanel.GetInflateWidth: Integer;
begin
Result := BorderWidth;
if BevelOuter <> bvNone then Inc(Result, BevelWidth);
if BevelInner <> bvNone then Inc(Result, BevelWidth);
end;
procedure TSecretPanel.RecalcDrawRect;
const
MinOffset = 3;
var
InflateWidth: Integer;
LastLine: Integer;
begin
FTxtRect := GetClientRect;
FPaintRect := FTxtRect;
InflateWidth := GetInflateWidth;
InflateRect(FPaintRect, -InflateWidth, -InflateWidth);
Inc(InflateWidth, MinOffset);
InflateRect(FTxtRect, -InflateWidth, -InflateWidth);
with FGlyphOrigin do begin
case FGlyphLayout of
glGlyphLeft:
begin
X := FTxtRect.Left;
Y := (FTxtRect.Bottom + FTxtRect.Top - Glyph.Height) div 2;
if Y < FTxtRect.Top then Y := FTxtRect.Top;
if Glyph.Width > 0 then begin
Inc(X, MinOffset);
FTxtRect.Left := X + Glyph.Width + InflateWidth;
end;
end;
glGlyphRight:
begin
Y := (FTxtRect.Bottom + FTxtRect.Top - Glyph.Height) div 2;
if Y < FTxtRect.Top then Y := FTxtRect.Top;
X := FTxtRect.Right - Glyph.Width;
if Glyph.Width > 0 then begin
Dec(X, MinOffset);
if X < FTxtRect.Left then X := FTxtRect.Left;
FTxtRect.Right := X - InflateWidth;
end;
end;
glGlyphTop:
begin
Y := FTxtRect.Top;
X := (FTxtRect.Right + FTxtRect.Left - Glyph.Width) div 2;
if X < FTxtRect.Left then X := FTxtRect.Left;
if Glyph.Height > 0 then begin
Inc(Y, MinOffset);
FTxtRect.Top := Y + Glyph.Height + (InflateWidth + MinOffset);
end;
end;
glGlyphBottom:
begin
X := (FTxtRect.Right + FTxtRect.Left - Glyph.Width) div 2;
if X < FTxtRect.Left then X := FTxtRect.Left;
Y := FTxtRect.Bottom - Glyph.Height;
if Glyph.Height > 0 then begin
Dec(Y, MinOffset);
if Y < FTxtRect.Top then Y := FTxtRect.Top;
FTxtRect.Bottom := Y - (InflateWidth + MinOffset);
end;
end;
end;
end;
if FDirection = sdHorizontal then begin
LastLine := FLines.Count - 1;
while (LastLine >= 0) and (Trim(FLines[LastLine]) = '') do
Dec(LastLine);
InflateWidth := HeightOf(FTxtRect) -
(LastLine + 1 - FFirstLine) * FTxtDivider;
if InflateWidth > 0 then
InflateRect(FTxtRect, 0, - InflateWidth div 2);
end;
with FTxtRect do
if (Left >= Right) or (Top >= Bottom) then FTxtRect := Rect(0, 0, 0, 0);
end;
procedure TSecretPanel.PaintGlyph;
begin
if not FGlyph.Empty then begin
RecalcDrawRect;
DrawBitmapTransparent(Canvas, FGlyphOrigin.X, FGlyphOrigin.Y,
FGlyph, FGlyph.TransparentColor and not PaletteMask);
end;
end;
procedure TSecretPanel.PaintText;
var
STmp: array[0..255] of Char;
R: TRect;
I: Integer;
Flags: Longint;
begin
if (FLines.Count = 0) or IsRectEmpty(FTxtRect) or not HandleAllocated then
Exit;
{$IFDEF RX_D3}
FMemoryImage.Canvas.Lock;
try
{$ENDIF}
with FMemoryImage.Canvas do begin
I := SaveDC(Handle);
try
with FTxtRect do
MoveWindowOrg(Handle, -Left, -Top);
Brush.Color := Self.Color;
PaintClient(FMemoryImage.Canvas, FPaintRect);
finally
RestoreDC(Handle, I);
SetBkMode(Handle, Transparent);
end;
end;
R := Bounds(0, 0, WidthOf(FTxtRect), HeightOf(FTxtRect));
if FDirection = sdHorizontal then begin
{$IFDEF RX_D4}
if IsRightToLeft then begin
R.Right := R.Left + FScrollCnt;
R.Left := R.Right - (FMaxScroll - WidthOf(FTxtRect));
end
else begin
R.Left := R.Right - FScrollCnt;
R.Right := R.Left + (FMaxScroll - WidthOf(FTxtRect));
end;
{$ELSE}
R.Left := R.Right - FScrollCnt;
R.Right := R.Left + (FMaxScroll - WidthOf(FTxtRect));
{$ENDIF}
end
else begin { sdVertical }
R.Top := R.Bottom - FScrollCnt;
end;
R.Bottom := R.Top + FTxtDivider;
Flags := DT_EXPANDTABS or Alignments[FAlignment] or DT_SINGLELINE or
DT_NOCLIP or DT_NOPREFIX;
{$IFDEF RX_D4}
Flags := DrawTextBiDiModeFlags(Flags);
{$ENDIF}
for I := FFirstLine to FLines.Count do begin
if I = FLines.Count then StrCopy(STmp, ' ')
else StrPLCopy(STmp, FLines[I], SizeOf(STmp) - 1);
if R.Top >= HeightOf(FTxtRect) then Break
else if R.Bottom > 0 then begin
if FTextStyle <> bvNone then begin
FMemoryImage.Canvas.Font.Color := clBtnHighlight;
case FTextStyle of
bvLowered:
begin
OffsetRect(R, 1, 1);
DrawText(FMemoryImage.Canvas.Handle, STmp, -1, R, Flags);
OffsetRect(R, -1, -1);
end;
bvRaised:
begin
OffsetRect(R, -1, -1);
DrawText(FMemoryImage.Canvas.Handle, STmp, -1, R, Flags);
OffsetRect(R, 1, 1);
end;
end;
FMemoryImage.Canvas.Font.Color := Self.Font.Color;
SetBkMode(FMemoryImage.Canvas.Handle, Transparent);
end;
DrawText(FMemoryImage.Canvas.Handle, STmp, -1, R, Flags);
end;
OffsetRect(R, 0, FTxtDivider);
end;
{$IFDEF RX_D3}
Canvas.Lock;
try
{$ENDIF}
BitBlt(Canvas.Handle, FTxtRect.Left, FTxtRect.Top, FMemoryImage.Width,
FMemoryImage.Height, FMemoryImage.Canvas.Handle, 0, 0, SRCCOPY);
ValidateRect(Handle, @FTxtRect);
{$IFDEF RX_D3}
finally
Canvas.Unlock;
end;
{$ENDIF}
{$IFDEF RX_D3}
finally
FMemoryImage.Canvas.Unlock;
end;
{$ENDIF}
end;
procedure TSecretPanel.PaintClient(Canvas: TCanvas; Rect: TRect);
begin
if Assigned(FOnPaintClient) then FOnPaintClient(Self, Canvas, Rect)
else Canvas.FillRect(Rect);
end;
procedure TSecretPanel.Paint;
var
Rect: TRect;
TopColor, BottomColor: TColor;
SaveIndex: Integer;
procedure AdjustColors(Bevel: TPanelBevel);
begin
TopColor := clBtnHighlight;
if Bevel = bvLowered then TopColor := clBtnShadow;
BottomColor := clBtnShadow;
if Bevel = bvLowered then BottomColor := clBtnHighlight;
end;
begin
Rect := GetClientRect;
if BevelOuter <> bvNone then begin
AdjustColors(BevelOuter);
Frame3D(Canvas, Rect, TopColor, BottomColor, BevelWidth);
end;
Frame3D(Canvas, Rect, Color, Color, BorderWidth);
if BevelInner <> bvNone then begin
AdjustColors(BevelInner);
Frame3D(Canvas, Rect, TopColor, BottomColor, BevelWidth);
end;
SaveIndex := SaveDC(Canvas.Handle);
try
with Rect do
IntersectClipRect(Canvas.Handle, Left, Top, Right, Bottom);
Canvas.Brush.Color := Self.Color;
PaintClient(Canvas, Rect);
finally
RestoreDC(Canvas.Handle, SaveIndex);
end;
if Active then begin
PaintGlyph;
{PaintText;}
end;
end;
procedure TSecretPanel.StartPlay;
begin
if Assigned(FOnStartPlay) then FOnStartPlay(Self);
end;
procedure TSecretPanel.StopPlay;
begin
if Assigned(FOnStopPlay) then FOnStopPlay(Self);
end;
procedure TSecretPanel.TimerExpired(Sender: TObject);
begin
if (FScrollCnt < FMaxScroll) then begin
Inc(FScrollCnt);
if Assigned(FMemoryImage) then PaintText;
end
else if Cycled then begin
FScrollCnt := 0;
if Assigned(FMemoryImage) then PaintText;
end
else begin
{$IFDEF RX_D3}
FTimer.Synchronize(Stop);
{$ELSE}
SetActive(False);
{$ENDIF}
end;
end;
procedure TSecretPanel.UpdateMemoryImage;
var
Metrics: TTextMetric;
I: Integer;
begin
if FMemoryImage = nil then FMemoryImage := TBitmap.Create;
{$IFDEF RX_D3}
FMemoryImage.Canvas.Lock;
try
{$ENDIF}
FFirstLine := 0;
while (FFirstLine < FLines.Count) and (Trim(FLines[FFirstLine]) = '') do
Inc(FFirstLine);
Canvas.Font := Self.Font;
GetTextMetrics(Canvas.Handle, Metrics);
FTxtDivider := Metrics.tmHeight + Metrics.tmExternalLeading;
if FTextStyle <> bvNone then Inc(FTxtDivider);
RecalcDrawRect;
if FDirection = sdHorizontal then begin
FMaxScroll := 0;
for I := FFirstLine to FLines.Count - 1 do
FMaxScroll := Max(FMaxScroll, Canvas.TextWidth(FLines[I]));
Inc(FMaxScroll, WidthOf(FTxtRect));
end
else begin { sdVertical }
FMaxScroll := ((FLines.Count - FFirstLine) * FTxtDivider) +
HeightOf(FTxtRect);
end;
FMemoryImage.Width := WidthOf(FTxtRect);
FMemoryImage.Height := HeightOf(FTxtRect);
with FMemoryImage.Canvas do begin
Font := Self.Font;
Brush.Color := Self.Color;
SetBkMode(Handle, Transparent);
end;
{$IFDEF RX_D3}
finally
FMemoryImage.Canvas.UnLock;
end;
{$ENDIF}
end;
function TSecretPanel.GetInterval: Cardinal;
begin
Result := FTimer.Interval;
end;
procedure TSecretPanel.SetInterval(Value: Cardinal);
begin
FTimer.Interval := Value;
end;
procedure TSecretPanel.Play;
begin
SetActive(True);
end;
procedure TSecretPanel.Stop;
begin
SetActive(False);
end;
procedure TSecretPanel.SetActive(Value: Boolean);
var
I: Integer;
begin
if Value <> FActive then begin
FActive := Value;
if FActive then begin
FScrollCnt := 0;
UpdateMemoryImage;
try
FTimer.Enabled := True;
StartPlay;
except
FActive := False;
FTimer.Enabled := False;
raise;
end;
end
else begin
{$IFDEF RX_D3}
FMemoryImage.Canvas.Lock;
{ ensure that canvas is locked before timer is disabled }
{$ENDIF}
FTimer.Enabled := False;
FScrollCnt := 0;
FMemoryImage.Free;
FMemoryImage := nil;
StopPlay;
if (csDesigning in ComponentState) and
not (csDestroying in ComponentState) then
ValidParentForm(Self).Designer.Modified;
end;
if not (csDestroying in ComponentState) then
for I := 0 to Pred(ControlCount) do begin
if FActive then begin
if Controls[I].Visible then FHiddenList.Add(Controls[I]);
if not (csDesigning in ComponentState) then
Controls[I].Visible := False
end
else if FHiddenList.IndexOf(Controls[I]) >= 0 then begin
Controls[I].Visible := True;
Controls[I].Invalidate;
if (csDesigning in ComponentState) then Controls[I].Update;
end;
end;
if not FActive then FHiddenList.Clear;
Invalidate;
end;
end;
procedure TSecretPanel.SetAlignment(Value: TAlignment);
begin
if FAlignment <> Value then begin
FAlignment := Value;
if Active then Invalidate;
end;
end;
procedure TSecretPanel.SetGlyph(Value: TBitmap);
begin
FGlyph.Assign(Value);
end;
procedure TSecretPanel.SetDirection(Value: TScrollDirection);
begin
if FDirection <> Value then begin
FDirection := Value;
if FActive then begin
FScrollCnt := 0;
UpdateMemoryImage;
Invalidate;
end;
end;
end;
procedure TSecretPanel.SetTextStyle(Value: TPanelBevel);
begin
if FTextStyle <> Value then begin
FTextStyle := Value;
if FActive then begin
UpdateMemoryImage;
Invalidate;
end;
end;
end;
procedure TSecretPanel.SetGlyphLayout(Value: TGlyphLayout);
begin
if FGlyphLayout <> Value then begin
FGlyphLayout := Value;
if FActive then begin
UpdateMemoryImage;
Invalidate;
end;
end;
end;
procedure TSecretPanel.SetLines(Value: TStrings);
begin
FLines.Assign(Value);
end;
{ TGlyphList }
type
TGlyphList = class(TImageList)
private
FUsed: TBits;
FCount: Integer;
function AllocateIndex: Integer;
public
constructor CreateSize(AWidth, AHeight: Integer);
destructor Destroy; override;
function Add(Image, Mask: TBitmap): Integer;
function AddMasked(Image: TBitmap; MaskColor: TColor): Integer;
{$IFDEF WIN32}
{$IFNDEF RX_D3} { Delphi 2.0 bug fix }
procedure ReplaceMasked(Index: Integer; NewImage: TBitmap; MaskColor: TColor);
{$ENDIF}
{$ENDIF}
procedure Delete(Index: Integer);
property Count: Integer read FCount;
end;
{ TGlyphCache }
TGlyphCache = class
private
FGlyphLists: TList;
public
constructor Create;
destructor Destroy; override;
function GetList(AWidth, AHeight: Integer): TGlyphList;
procedure ReturnList(List: TGlyphList);
function Empty: Boolean;
end;
{ TGlyphList }
constructor TGlyphList.CreateSize(AWidth, AHeight: Integer);
begin
{$IFDEF WIN32}
inherited CreateSize(AWidth, AHeight);
{$ELSE}
inherited Create(AWidth, AHeight);
{$ENDIF}
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;
{$IFDEF WIN32}
{$IFNDEF RX_D3} { Delphi 2.0 bug fix }
procedure TGlyphList.ReplaceMasked(Index: Integer; NewImage: TBitmap; MaskColor: TColor);
var
TempIndex: Integer;
Image, Mask: TBitmap;
begin
if HandleAllocated then begin
TempIndex := inherited AddMasked(NewImage, MaskColor);
if TempIndex <> -1 then
try
Image := TBitmap.Create;
Mask := TBitmap.Create;
try
with Image do begin
Height := Self.Height;
Width := Self.Width;
end;
with Mask do begin
Monochrome := True; { fix }
Height := Self.Height;
Width := Self.Width;
end;
ImageList_Draw(Handle, TempIndex, Image.Canvas.Handle, 0, 0, ILD_NORMAL);
ImageList_Draw(Handle, TempIndex, Mask.Canvas.Handle, 0, 0, ILD_MASK);
if not ImageList_Replace(Handle, Index, Image.Handle, Mask.Handle) then
raise EInvalidOperation.Create(LoadStr(SReplaceImage));
finally
Image.Free;
Mask.Free;
end;
finally
inherited Delete(TempIndex);
end
else raise EInvalidOperation.Create(LoadStr(SReplaceImage));
end;
Change;
end;
{$ENDIF}
{$ENDIF}
function TGlyphList.Add(Image, Mask: TBitmap): Integer;
begin
Result := AllocateIndex;
Replace(Result, Image, Mask);
Inc(FCount);
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 := FGlyphLists[I];
with Result do
if (AWidth = Width) and (AHeight = Height) then Exit;
end;
Result := TGlyphList.CreateSize(AWidth, AHeight);
FGlyphLists.Add(Result);
end;
procedure TGlyphCache.ReturnList(List: TGlyphList);
begin
if List = nil then Exit;
if List.Count = 0 then begin
FGlyphLists.Remove(List);
List.Free;
end;
end;
function TGlyphCache.Empty: Boolean;
begin
Result := FGlyphLists.Count = 0;
end;
const
GlyphCache: TGlyphCache = nil;
{ TRxButtonGlyph }
constructor TRxButtonGlyph.Create;
var
I: TRxButtonState;
begin
inherited Create;
FOriginal := TBitmap.Create;
FOriginal.OnChange := GlyphChanged;
FTransparentColor := clFuchsia;
FAlignment := taCenter;
FNumGlyphs := 1;
for I := Low(I) to High(I) do FIndexs[I] := -1;
if GlyphCache = nil then GlyphCache := TGlyphCache.Create;
end;
destructor TRxButtonGlyph.Destroy;
begin
FOriginal.Free;
Invalidate;
if Assigned(GlyphCache) and GlyphCache.Empty then begin
GlyphCache.Free;
GlyphCache := nil;
end;
inherited Destroy;
end;
procedure TRxButtonGlyph.Invalidate;
var
I: TRxButtonState;
begin
for I := Low(I) to High(I) do begin
if Assigned(FGlyphList) then
if (FIndexs[I] <> -1) then TGlyphList(FGlyphList).Delete(FIndexs[I]);
FIndexs[I] := -1;
end;
GlyphCache.ReturnList(TGlyphList(FGlyphList));
FGlyphList := nil;
end;
procedure TRxButtonGlyph.GlyphChanged(Sender: TObject);
var
Glyphs: Integer;
begin
if Sender = FOriginal then begin
Invalidate;
if (FOriginal <> nil) and (FOriginal.Height > 0) then begin
FTransparentColor := FOriginal.TransparentColor and not PaletteMask;
if FOriginal.Width mod FOriginal.Height = 0 then begin
Glyphs := FOriginal.Width div FOriginal.Height;
if Glyphs > (Ord(High(TRxButtonState)) + 1) then Glyphs := 1;
SetNumGlyphs(Glyphs);
end;
end;
if Assigned(FOnChange) then FOnChange(Self);
end;
end;
procedure TRxButtonGlyph.SetGlyph(Value: TBitmap);
begin
Invalidate;
FOriginal.Assign(Value);
end;
procedure TRxButtonGlyph.SetNumGlyphs(Value: TRxNumGlyphs);
begin
if (Value <> FNumGlyphs) and (Value > 0) then begin
Invalidate;
FNumGlyphs := Value;
end;
end;
function TRxButtonGlyph.MapColor(Color: TColor): TColor;
var
Index: Byte;
begin
if (Color = FTransparentColor) or (ColorToRGB(Color) =
ColorToRGB(clBtnFace)) then Result := Color
else begin
Color := ColorToRGB(Color);
Index := Byte(Longint(Word(GetRValue(Color)) * 77 +
Word(GetGValue(Color)) * 150 + Word(GetBValue(Color)) * 29) shr 8);
Result := RGB(Index, Index, Index);
end;
end;
{$IFDEF WIN32}
function TRxButtonGlyph.CreateImageGlyph(State: TRxButtonState;
Images: TImageList; Index: Integer): Integer;
var
TmpImage, Mask: TBitmap;
IWidth, IHeight, X, Y: Integer;
begin
if (State = rbsDown) then State := rbsUp;
Result := FIndexs[State];
if (Result <> -1) or (Images.Width = 0) or (Images.Height = 0) or
(Images.Count = 0) then Exit;
IWidth := Images.Width;
IHeight := Images.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;
case State of
rbsUp, rbsDown, rbsExclusive:
begin
with TmpImage.Canvas do begin
FillRect(Rect(0, 0, IWidth, IHeight));
ImageList_Draw(Images.Handle, Index, Handle, 0, 0, ILD_NORMAL);
end;
Mask := TBitmap.Create;
try
with Mask do begin
Monochrome := True;
Height := IHeight;
Width := IWidth;
end;
with Mask.Canvas do begin
FillRect(Rect(0, 0, IWidth, IHeight));
ImageList_Draw(Images.Handle, Index, Handle, 0, 0, ILD_MASK);
end;
FIndexs[State] := TGlyphList(FGlyphList).Add(TmpImage, Mask);
finally
Mask.Free;
end;
end;
rbsDisabled:
begin
TmpImage.Canvas.Brush.Color := clBtnFace;
TmpImage.Canvas.FillRect(Rect(0, 0, IWidth, IHeight));
ImageListDrawDisabled(Images, TmpImage.Canvas, 0, 0, Index,
clBtnHighlight, clBtnShadow, True);
FIndexs[State] := TGlyphList(FGlyphList).AddMasked(TmpImage,
ColorToRGB(clBtnFace));
end;
rbsInactive:
begin
TmpImage.Canvas.Brush.Color := clBtnFace;
TmpImage.Canvas.FillRect(Rect(0, 0, IWidth, IHeight));
ImageList_Draw(Images.Handle, Index, TmpImage.Canvas.Handle, 0, 0,
ILD_NORMAL);
with TmpImage do begin
for X := 0 to Width - 1 do
for Y := 0 to Height - 1 do
Canvas.Pixels[X, Y] := MapColor(Canvas.Pixels[X, Y]);
end;
FIndexs[State] := TGlyphList(FGlyphList).AddMasked(TmpImage,
ColorToRGB(clBtnFace));
end;
end;
finally
TmpImage.Free;
end;
Result := FIndexs[State];
end;
{$ENDIF}
function TRxButtonGlyph.CreateButtonGlyph(State: TRxButtonState): Integer;
var
TmpImage, MonoBmp: TBitmap;
IWidth, IHeight, X, Y: Integer;
IRect, ORect: TRect;
I: TRxButtonState;
begin
if (State = rbsDown) and (NumGlyphs < 3) then State := rbsUp;
Result := FIndexs[State];
if (Result <> -1) or (FOriginal.Width = 0) or (FOriginal.Height = 0) or
FOriginal.Empty 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;
I := State;
if Ord(I) >= NumGlyphs then I := rbsUp;
ORect := Rect(Ord(I) * IWidth, 0, (Ord(I) + 1) * IWidth, IHeight);
case State of
rbsUp, rbsDown, rbsExclusive:
begin
TmpImage.Canvas.CopyRect(IRect, FOriginal.Canvas, ORect);
FIndexs[State] := TGlyphList(FGlyphList).AddMasked(TmpImage, FTransparentColor);
end;
rbsDisabled:
if NumGlyphs > 1 then begin
TmpImage.Canvas.CopyRect(IRect, FOriginal.Canvas, ORect);
FIndexs[State] := TGlyphList(FGlyphList).AddMasked(TmpImage, FTransparentColor);
end
else begin
MonoBmp := CreateDisabledBitmap(FOriginal, clBlack);
try
FIndexs[State] := TGlyphList(FGlyphList).AddMasked(MonoBmp,
ColorToRGB(clBtnFace));
finally
MonoBmp.Free;
end;
end;
rbsInactive:
if NumGlyphs > 4 then begin
TmpImage.Canvas.CopyRect(IRect, FOriginal.Canvas, ORect);
FIndexs[State] := TGlyphList(FGlyphList).AddMasked(TmpImage, FTransparentColor);
end
else begin
with TmpImage do begin
for X := 0 to Width - 1 do
for Y := 0 to Height - 1 do
Canvas.Pixels[X, Y] := MapColor(FOriginal.Canvas.Pixels[X, Y]);
end;
FIndexs[State] := TGlyphList(FGlyphList).AddMasked(TmpImage, FTransparentColor);
end;
end;
finally
TmpImage.Free;
end;
Result := FIndexs[State];
FOriginal.Dormant;
end;
procedure TRxButtonGlyph.DrawPopupMark(Canvas: TCanvas; X, Y: Integer;
State: TRxButtonState);
var
AColor: TColor;
procedure DrawMark;
var
I: Integer;
begin
with Canvas do begin
for I := 0 to 6 do begin
Pixels[X + I, Y - 1] := AColor;
if (I > 0) and (I < 6) then begin
Pixels[X + I, Y] := AColor;
if (I > 1) and (I < 5) then Pixels[X + I, Y + 1] := AColor;
end;
end;
Pixels[X + 3, Y + 2] := AColor;
end;
end;
begin
if State = rbsDisabled then begin
AColor := clBtnHighlight;
Inc(X, 1); Inc(Y, 1);
DrawMark;
Dec(X, 1); Dec(Y, 1);
AColor := clBtnShadow;
end
else AColor := clBtnText;
DrawMark;
end;
function TRxButtonGlyph.DrawButtonGlyph(Canvas: TCanvas; X, Y: Integer;
State: TRxButtonState): TPoint;
var
Index: Integer;
begin
Result := Point(0, 0);
if (FOriginal = nil) or (FOriginal.Width = 0) or (FOriginal.Height = 0) or
FOriginal.Empty then Exit;
Index := CreateButtonGlyph(State);
if Index >= 0 then begin
{$IFDEF WIN32}
ImageList_Draw(FGlyphList.Handle, Index, Canvas.Handle, X, Y, ILD_NORMAL);
{$ELSE}
FGlyphList.Draw(Canvas, X, Y, Index);
{$ENDIF}
Result := Point(FGlyphList.Width, FGlyphList.Height);
end;
end;
{$IFDEF WIN32}
function TRxButtonGlyph.DrawButtonImage(Canvas: TCanvas; X, Y: Integer;
Images: TImageList; ImageIndex: Integer; State: TRxButtonState): TPoint;
var
Index: Integer;
begin
Result := Point(0, 0);
if (Images = nil) or (ImageIndex < 0) or (ImageIndex >= Images.Count) then
Exit;
if State = rbsDisabled then begin
ImageListDrawDisabled(Images, Canvas, X, Y, ImageIndex, clBtnHighlight,
clBtnShadow, True);
end
else if State = rbsInactive then begin
Index := CreateImageGlyph(State, Images, ImageIndex);
if Index >= 0 then
ImageList_Draw(FGlyphList.Handle, Index, Canvas.Handle, X, Y, ILD_NORMAL);
end
else
ImageList_Draw(Images.Handle, ImageIndex, Canvas.Handle, X, Y, ILD_NORMAL);
Result := Point(Images.Width, Images.Height);
end;
{$ENDIF}
procedure TRxButtonGlyph.MinimizeCaption(Canvas: TCanvas; const Caption: string;
Buffer: PChar; MaxLen, Width: Integer);
var
I: Integer;
{$IFNDEF WIN32}
P: PChar;
{$ENDIF}
Lines: TStrings;
begin
StrPLCopy(Buffer, Caption, MaxLen);
if FWordWrap then Exit;
Lines := TStringList.Create;
try
{$IFDEF WIN32}
Lines.Text := Caption;
for I := 0 to Lines.Count - 1 do
Lines[I] := MinimizeText(Lines[I], Canvas, Width);
StrPLCopy(Buffer, TrimRight(Lines.Text), MaxLen);
{$ELSE}
Lines.SetText(Buffer);
for I := 0 to Lines.Count - 1 do
Lines[I] := MinimizeText(Lines[I], Canvas, Width);
P := Lines.GetText;
try
StrPLCopy(Buffer, TrimRight(StrPas(P)), MaxLen);
finally
StrDispose(P);
end;
{$ENDIF}
finally
Lines.Free;
end;
end;
procedure TRxButtonGlyph.DrawButtonText(Canvas: TCanvas; const Caption: string;
TextBounds: TRect; State: TRxButtonState; Flags: Word);
var
CString: array[0..255] of Char;
begin
Canvas.Brush.Style := bsClear;
StrPLCopy(CString, Caption, SizeOf(CString) - 1);
Flags := DT_VCENTER or WordWraps[FWordWrap] or Flags;
if State = rbsDisabled then begin
with Canvas do begin
OffsetRect(TextBounds, 1, 1);
Font.Color := clBtnHighlight;
DrawText(Handle, CString, Length(Caption), TextBounds, Flags);
OffsetRect(TextBounds, -1, -1);
Font.Color := clBtnShadow;
DrawText(Handle, CString, Length(Caption), TextBounds, Flags);
end;
end
else DrawText(Canvas.Handle, CString, -1, TextBounds, Flags);
end;
procedure TRxButtonGlyph.CalcButtonLayout(Canvas: TCanvas; const Client: TRect;
var Caption: string; Layout: TButtonLayout; Margin, Spacing: Integer;
PopupMark: Boolean; var GlyphPos: TPoint; var TextBounds: TRect; Flags: Word
{$IFDEF WIN32}; Images: TImageList; ImageIndex: Integer {$ENDIF});
var
TextPos: TPoint;
MaxSize, ClientSize, GlyphSize, TextSize: TPoint;
TotalSize: TPoint;
CString: array[0..255] of Char;
begin
{ calculate the item sizes }
ClientSize := Point(Client.Right - Client.Left, Client.Bottom - Client.Top);
{$IFDEF WIN32}
if Assigned(Images) and (Images.Width > 0) and (ImageIndex >= 0) and
(ImageIndex < Images.Count) then
GlyphSize := Point(Images.Width, Images.Height)
else
{$ENDIF}
if FOriginal <> nil then
GlyphSize := Point(FOriginal.Width div FNumGlyphs, FOriginal.Height)
else GlyphSize := Point(0, 0);
if Layout in [blGlyphLeft, blGlyphRight] then begin
MaxSize.X := ClientSize.X - GlyphSize.X;
if Margin <> -1 then Dec(MaxSize.X, Margin);
if Spacing <> -1 then Dec(MaxSize.X, Spacing);
if PopupMark then Dec(MaxSize.X, 9);
MaxSize.Y := ClientSize.Y;
end
else { blGlyphTop, blGlyphBottom } begin
MaxSize.X := ClientSize.X;
MaxSize.Y := ClientSize.Y - GlyphSize.Y;
if Margin <> -1 then Dec(MaxSize.Y, Margin);
if Spacing <> -1 then Dec(MaxSize.Y, Spacing);
end;
MaxSize.X := Max(0, MaxSize.X);
MaxSize.Y := Max(0, MaxSize.Y);
MinimizeCaption(Canvas, Caption, CString, SizeOf(CString) - 1, MaxSize.X);
Caption := StrPas(CString);
if Length(Caption) > 0 then begin
TextBounds := Rect(0, 0, MaxSize.X, 0);
DrawText(Canvas.Handle, CString, -1, TextBounds, DT_CALCRECT or DT_CENTER
or DT_VCENTER or WordWraps[FWordWrap] or Flags);
end
else TextBounds := Rect(0, 0, 0, 0);
TextBounds.Bottom := Max(TextBounds.Top, TextBounds.Top +
Min(MaxSize.Y, HeightOf(TextBounds)));
TextBounds.Right := Max(TextBounds.Left, TextBounds.Left +
Min(MaxSize.X, WidthOf(TextBounds)));
TextSize := Point(TextBounds.Right - TextBounds.Left, TextBounds.Bottom -
TextBounds.Top);
if PopupMark then
if ((GlyphSize.X = 0) or (GlyphSize.Y = 0)) or (Layout = blGlyphLeft) then
Inc(TextSize.X, 9)
else if (GlyphSize.X > 0) then
Inc(GlyphSize.X, 6);
{ 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 div 2) - (GlyphSize.Y div 2);
TextPos.Y := (ClientSize.Y div 2) - (TextSize.Y div 2);
end
else begin
GlyphPos.X := (ClientSize.X div 2) - (GlyphSize.X div 2);
TextPos.X := (ClientSize.X div 2) - (TextSize.X 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 div 2) - (TotalSize.X div 2)
else Margin := (ClientSize.Y div 2) - (TotalSize.Y 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 div 2) - (TextSize.X div 2)
else Spacing := (TotalSize.Y div 2) - (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 }
Inc(GlyphPos.X, Client.Left);
Inc(GlyphPos.Y, Client.Top);
OffsetRect(TextBounds, TextPos.X + Client.Left, TextPos.Y + Client.Top);
end;
{$IFDEF WIN32}
function TRxButtonGlyph.Draw(Canvas: TCanvas; const Client: TRect;
const Caption: string; Layout: TButtonLayout; Margin, Spacing: Integer;
PopupMark: Boolean; State: TRxButtonState; Flags: Word): TRect;
begin
Result := DrawEx(Canvas, Client, Caption, Layout, Margin, Spacing,
PopupMark, nil, -1, State, Flags);
end;
{$ENDIF}
{$IFDEF WIN32}
function TRxButtonGlyph.DrawEx(Canvas: TCanvas; const Client: TRect;
const Caption: string; Layout: TButtonLayout; Margin, Spacing: Integer;
PopupMark: Boolean; Images: TImageList; ImageIndex: Integer;
State: TRxButtonState; Flags: Word): TRect;
{$ELSE}
function TRxButtonGlyph.Draw(Canvas: TCanvas; const Client: TRect;
const Caption: string; Layout: TButtonLayout; Margin, Spacing: Integer;
PopupMark: Boolean; State: TRxButtonState; Flags: Word): TRect;
{$ENDIF}
var
{$IFDEF WIN32}
UseImages: Boolean;
{$ENDIF}
GlyphPos, PopupPos: TPoint;
TextBounds: TRect;
CaptionText: string;
begin
CaptionText := Caption;
CalcButtonLayout(Canvas, Client, CaptionText, Layout, Margin, Spacing,
PopupMark, GlyphPos, TextBounds, Flags {$IFDEF WIN32}, Images,
ImageIndex {$ENDIF});
{$IFDEF WIN32}
UseImages := False;
if Assigned(Images) and (ImageIndex >= 0) and (ImageIndex < Images.Count) and
(Images.Width > 0) then
begin
UseImages := True;
PopupPos := DrawButtonImage(Canvas, GlyphPos.X, GlyphPos.Y, Images,
ImageIndex, State);
end else
{$ENDIF}
PopupPos := DrawButtonGlyph(Canvas, GlyphPos.X, GlyphPos.Y, State);
DrawButtonText(Canvas, CaptionText, TextBounds, State, Flags);
if PopupMark then
if (Layout <> blGlyphLeft) and (((FOriginal <> nil) and
(FOriginal.Width > 0)) {$IFDEF WIN32} or UseImages {$ENDIF}) then
begin
PopupPos.X := GlyphPos.X + PopupPos.X + 1;
PopupPos.Y := GlyphPos.Y + PopupPos.Y div 2;
DrawPopupMark(Canvas, PopupPos.X, PopupPos.Y, State);
end
else begin
if CaptionText <> '' then
PopupPos.X := TextBounds.Right + 3
else
PopupPos.X := (Client.Left + Client.Right - 7) div 2;
PopupPos.Y := TextBounds.Top + HeightOf(TextBounds) div 2;
DrawPopupMark(Canvas, PopupPos.X, PopupPos.Y, State);
end;
Result := TextBounds;
end;
const
{$IFNDEF RX_D4}
Pattern: TBitmap = nil;
{$ENDIF}
ButtonCount: Integer = 0;
{ DrawButtonFrame - returns the remaining usable area inside the Client rect }
function DrawButtonFrame(Canvas: TCanvas; const Client: TRect;
IsDown, IsFlat: Boolean; Style: TButtonStyle): TRect;
var
NewStyle: Boolean;
begin
Result := Client;
NewStyle := (Style = bsNew) or (NewStyleControls and (Style = bsAutoDetect));
if IsDown then begin
if NewStyle then begin
Frame3D(Canvas, Result, clWindowFrame, clBtnHighlight, 1);
if not IsFlat then
Frame3D(Canvas, Result, clBtnShadow, clBtnFace, 1);
end
else begin
if IsFlat then
Frame3D(Canvas, Result, clWindowFrame, clBtnHighlight, 1)
else begin
Frame3D(Canvas, Result, clWindowFrame, clWindowFrame, 1);
Canvas.Pen.Color := clBtnShadow;
Canvas.PolyLine([Point(Result.Left, Result.Bottom - 1),
Point(Result.Left, Result.Top), Point(Result.Right, Result.Top)]);
end;
end;
end
else begin
if NewStyle then begin
if IsFlat then
Frame3D(Canvas, Result, clBtnHighlight, clBtnShadow, 1)
else begin
Frame3D(Canvas, Result, clBtnHighlight, clWindowFrame, 1);
Frame3D(Canvas, Result, clBtnFace, clBtnShadow, 1);
end;
end
else begin
if IsFlat then
Frame3D(Canvas, Result, clBtnHighlight, clWindowFrame, 1)
else begin
Frame3D(Canvas, Result, clWindowFrame, clWindowFrame, 1);
Frame3D(Canvas, Result, clBtnHighlight, clBtnShadow, 1);
end;
end;
end;
InflateRect(Result, -1, -1);
end;
{ TButtonImage }
constructor TButtonImage.Create;
begin
FGlyph := TRxButtonGlyph.Create;
NumGlyphs := 1;
FButtonSize := Point(24, 23);
end;
destructor TButtonImage.Destroy;
begin
FGlyph.Free;
inherited Destroy;
end;
procedure TButtonImage.Invalidate;
begin
TRxButtonGlyph(FGlyph).Invalidate;
end;
function TButtonImage.GetNumGlyphs: TRxNumGlyphs;
begin
Result := TRxButtonGlyph(FGlyph).NumGlyphs;
end;
procedure TButtonImage.SetNumGlyphs(Value: TRxNumGlyphs);
begin
TRxButtonGlyph(FGlyph).NumGlyphs := Value;
end;
function TButtonImage.GetWordWrap: Boolean;
begin
Result := TRxButtonGlyph(FGlyph).WordWrap;
end;
procedure TButtonImage.SetWordWrap(Value: Boolean);
begin
TRxButtonGlyph(FGlyph).WordWrap := Value;
end;
function TButtonImage.GetGlyph: TBitmap;
begin
Result := TRxButtonGlyph(FGlyph).Glyph;
end;
procedure TButtonImage.SetGlyph(Value: TBitmap);
begin
TRxButtonGlyph(FGlyph).Glyph := Value;
end;
function TButtonImage.GetAlignment: TAlignment;
begin
Result := TRxButtonGlyph(FGlyph).Alignment;
end;
procedure TButtonImage.SetAlignment(Value: TAlignment);
begin
TRxButtonGlyph(FGlyph).Alignment := Value;
end;
{$IFDEF WIN32}
procedure TButtonImage.Draw(Canvas: TCanvas; X, Y, Margin, Spacing: Integer;
Layout: TButtonLayout; AFont: TFont; Flags: Word);
begin
DrawEx(Canvas, X, Y, Margin, Spacing, Layout, AFont, nil, -1, Flags);
end;
{$ENDIF}
{$IFDEF WIN32}
procedure TButtonImage.DrawEx(Canvas: TCanvas; X, Y, Margin, Spacing: Integer;
Layout: TButtonLayout; AFont: TFont; Images: TImageList; ImageIndex: Integer;
Flags: Word);
{$ELSE}
procedure TButtonImage.Draw(Canvas: TCanvas; X, Y, Margin, Spacing: Integer;
Layout: TButtonLayout; AFont: TFont; Flags: Word);
{$ENDIF}
var
Target: TRect;
SaveColor: Integer;
SaveFont: TFont;
begin
SaveColor := Canvas.Brush.Color;
SaveFont := TFont.Create;
SaveFont.Assign(Canvas.Font);
try
Target := Bounds(X, Y, FButtonSize.X, FButtonSize.Y);
Canvas.Brush.Color := clBtnFace;
Canvas.FillRect(Target);
Frame3D(Canvas, Target, clBtnShadow, clWindowFrame, 1);
Frame3D(Canvas, Target, clBtnHighlight, clBtnShadow, 1);
if AFont <> nil then Canvas.Font := AFont;
{$IFDEF WIN32}
TRxButtonGlyph(FGlyph).DrawEx(Canvas, Target, Caption, Layout, Margin,
Spacing, False, Images, ImageIndex, rbsUp, Flags);
{$ELSE}
TRxButtonGlyph(FGlyph).Draw(Canvas, Target, Caption, Layout, Margin,
Spacing, False, rbsUp, Flags);
{$ENDIF}
finally
Canvas.Font.Assign(SaveFont);
SaveFont.Free;
Canvas.Brush.Color := SaveColor;
end;
end;
{ TRxSpeedButton }
constructor TRxSpeedButton.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
SetBounds(0, 0, 25, 25);
ControlStyle := [csCaptureMouse, csOpaque, csDoubleClicks];
{$IFDEF WIN32}
ControlStyle := ControlStyle + [csReplicatable];
{$ENDIF}
FInactiveGrayed := True;
FDrawImage := TBitmap.Create;
FGlyph := TRxButtonGlyph.Create;
TRxButtonGlyph(FGlyph).OnChange := GlyphChanged;
ParentFont := True;
ParentShowHint := False;
ShowHint := True;
FSpacing := 1;
FMargin := -1;
FInitRepeatPause := 500;
FRepeatPause := 100;
FStyle := bsAutoDetect;
FLayout := blGlyphTop;
FMarkDropDown := True;
Inc(ButtonCount);
end;
destructor TRxSpeedButton.Destroy;
begin
TRxButtonGlyph(FGlyph).Free;
Dec(ButtonCount);
{$IFNDEF RX_D4}
if ButtonCount = 0 then begin
Pattern.Free;
Pattern := nil;
end;
{$ENDIF}
FDrawImage.Free;
FDrawImage := nil;
if FRepeatTimer <> nil then FRepeatTimer.Free;
inherited Destroy;
end;
procedure TRxSpeedButton.Loaded;
var
State: TRxButtonState;
begin
inherited Loaded;
if Enabled then begin
if Flat then State := rbsInactive
else State := rbsUp;
end
else State := rbsDisabled;
TRxButtonGlyph(FGlyph).CreateButtonGlyph(State);
end;
procedure TRxSpeedButton.PaintGlyph(Canvas: TCanvas; ARect: TRect;
AState: TRxButtonState; DrawMark: Boolean);
begin
TRxButtonGlyph(FGlyph).Draw(Canvas, ARect, Caption, FLayout,
FMargin, FSpacing, DrawMark, AState,
{$IFDEF RX_D4} DrawTextBiDiModeFlags(Alignments[Alignment]) {$ELSE}
Alignments[Alignment] {$ENDIF});
end;
procedure TRxSpeedButton.Paint;
var
PaintRect: TRect;
AState: TRxButtonState;
begin
if not Enabled {and not (csDesigning in ComponentState)} then begin
FState := rbsDisabled;
FDragging := False;
end
else if FState = rbsDisabled then
if FDown and (GroupIndex <> 0) then FState := rbsExclusive
else FState := rbsUp;
AState := FState;
if FFlat and not FMouseInControl and not (csDesigning in ComponentState) then
AState := rbsInactive;
PaintRect := Rect(0, 0, Width, Height);
FDrawImage.Width := Self.Width;
FDrawImage.Height := Self.Height;
with FDrawImage.Canvas do begin
Font := Self.Font;
Brush.Color := clBtnFace;
Brush.Style := bsSolid;
FillRect(PaintRect);
if FTransparent then CopyParentImage(Self, FDrawImage.Canvas);
if (AState <> rbsInactive) or (FState = rbsExclusive) then
PaintRect := DrawButtonFrame(FDrawImage.Canvas, PaintRect,
FState in [rbsDown, rbsExclusive], FFlat, FStyle)
else if FFlat then
InflateRect(PaintRect, -2, -2);
end;
if (FState = rbsExclusive) and not Transparent and
(not FFlat or (AState = rbsInactive)) then
begin
{$IFDEF RX_D4}
FDrawImage.Canvas.Brush.Bitmap := AllocPatternBitmap(clBtnFace, clBtnHighlight);
{$ELSE}
if Pattern = nil then
Pattern := CreateTwoColorsBrushPattern(clBtnFace, clBtnHighlight);
FDrawImage.Canvas.Brush.Bitmap := Pattern;
{$ENDIF}
InflateRect(PaintRect, 1, 1);
FDrawImage.Canvas.FillRect(PaintRect);
InflateRect(PaintRect, -1, -1);
end;
if FState in [rbsDown, rbsExclusive] then OffsetRect(PaintRect, 1, 1);
if (FState = rbsDisabled) or not FInactiveGrayed then AState := FState;
PaintGlyph(FDrawImage.Canvas, PaintRect, AState, FMarkDropDown and
Assigned(FDropDownMenu));
Canvas.Draw(0, 0, FDrawImage);
end;
procedure TRxSpeedButton.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (AComponent = DropDownMenu) and (Operation = opRemove) then
DropDownMenu := nil;
end;
function TRxSpeedButton.GetDropDownMenuPos: TPoint;
begin
if Assigned(FDropDownMenu) then begin
if MenuPosition = dmpBottom then begin
case FDropDownMenu.Alignment of
paLeft: Result := Point(-1, Height);
paRight: Result := Point(Width + 1, Height);
else {paCenter} Result := Point(Width div 2, Height);
end;
end
else { dmpRight } begin
case FDropDownMenu.Alignment of
paLeft: Result := Point(Width, -1);
paRight: Result := Point(-1, -1);
else {paCenter} Result := Point(Width div 2, Height);
end;
end;
end else Result := Point(0, 0);
end;
function TRxSpeedButton.CheckBtnMenuDropDown: Boolean;
begin
Result := CheckMenuDropDown(
{$IFDEF WIN32}PointToSmallPoint(GetDropDownMenuPos){$ELSE}
GetDropDownMenuPos{$ENDIF}, True);
end;
function TRxSpeedButton.CheckMenuDropDown(const Pos: TSmallPoint;
Manual: Boolean): Boolean;
var
Form: TCustomForm;
begin
Result := False;
if csDesigning in ComponentState then Exit;
if Assigned(FDropDownMenu) and (DropDownMenu.AutoPopup or Manual) then
begin
Form := GetParentForm(Self);
if Form <> nil then Form.SendCancelMode(nil);
DropDownMenu.PopupComponent := Self;
with ClientToScreen(SmallPointToPoint(Pos)) do DropDownMenu.Popup(X, Y);
Result := True;
end;
end;
procedure TRxSpeedButton.MouseEnter;
begin
if Assigned(FOnMouseEnter) then FOnMouseEnter(Self);
end;
procedure TRxSpeedButton.MouseLeave;
begin
if Assigned(FOnMouseLeave) then FOnMouseLeave(Self);
end;
procedure TRxSpeedButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
var
P: TPoint;
Msg: TMsg;
begin
if FMenuTracking then Exit;
inherited MouseDown(Button, Shift, X, Y);
if (not FMouseInControl) and Enabled then begin
FMouseInControl := True;
Repaint;
end;
if (Button = mbLeft) and Enabled {and not (ssDouble in Shift)} then begin
if not FDown then begin
FState := rbsDown;
Repaint;
end;
FDragging := True;
FMenuTracking := True;
try
P := GetDropDownMenuPos;
if CheckMenuDropDown(PointToSmallPoint(P), False) then
DoMouseUp(Button, Shift, X, Y);
if PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then begin
if (Msg.Message = WM_LBUTTONDOWN) or (Msg.Message = WM_LBUTTONDBLCLK) then
begin
P := ScreenToClient(Msg.Pt);
if (P.X >= 0) and (P.X < ClientWidth) and (P.Y >= 0)
and (P.Y <= ClientHeight) then KillMessage(0, Msg.Message);
{PeekMessage(Msg, 0, 0, 0, PM_REMOVE);}
end;
end;
finally
FMenuTracking := False;
end;
if FAllowTimer then begin
if FRepeatTimer = nil then FRepeatTimer := TTimer.Create(Self);
FRepeatTimer.Interval := InitPause;
FRepeatTimer.OnTimer := TimerExpired;
FRepeatTimer.Enabled := True;
end;
end;
end;
procedure TRxSpeedButton.MouseMove(Shift: TShiftState; X, Y: Integer);
var
NewState: TRxButtonState;
begin
inherited MouseMove(Shift, X, Y);
if FDragging then begin
if not FDown then NewState := rbsUp
else NewState := rbsExclusive;
if (X >= 0) and (X < ClientWidth) and (Y >= 0) and (Y <= ClientHeight) then
if FDown then NewState := rbsExclusive else NewState := rbsDown;
if NewState <> FState then begin
FState := NewState;
Repaint;
end;
end;
end;
procedure TRxSpeedButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited MouseUp(Button, Shift, X, Y);
DoMouseUp(Button, Shift, X, Y);
if FRepeatTimer <> nil then FRepeatTimer.Enabled := False;
end;
procedure TRxSpeedButton.DoMouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
var
DoClick: Boolean;
begin
if FDragging and (Button = mbLeft) then begin
FDragging := False;
DoClick := (X >= 0) and (X < ClientWidth) and (Y >= 0) and (Y <= ClientHeight);
if FGroupIndex = 0 then begin
FState := rbsUp;
FMouseInControl := False;
if DoClick and not (FState in [rbsExclusive, rbsDown]) then
Repaint
else Invalidate;
end
else if DoClick then begin
SetDown(not FDown);
if FDown then Repaint;
end
else begin
if FDown then FState := rbsExclusive;
Repaint;
end;
if DoClick and not FMenuTracking then Click;
end;
UpdateTracking;
end;
procedure TRxSpeedButton.ButtonClick;
var
FirstTickCount, Now: Longint;
begin
if FMenuTracking or (not Enabled) or (Assigned(FDropDownMenu) and
DropDownMenu.AutoPopup) then Exit;
if not FDown then begin
FState := rbsDown;
Repaint;
end;
try
FirstTickCount := GetTickCount;
repeat
Now := GetTickCount;
until (Now - FirstTickCount >= 20) or (Now < FirstTickCount);
if FGroupIndex = 0 then Click;
finally
FState := rbsUp;
if FGroupIndex = 0 then Repaint
else begin
SetDown(not FDown);
Click;
end;
end;
end;
procedure TRxSpeedButton.Click;
var
Form: TCustomForm;
begin
Form := GetParentForm(Self);
if Form <> nil then Form.ModalResult := ModalResult;
inherited Click;
end;
function TRxSpeedButton.GetPalette: HPALETTE;
begin
Result := Glyph.Palette;
end;
function TRxSpeedButton.GetWordWrap: Boolean;
begin
Result := TRxButtonGlyph(FGlyph).WordWrap;
end;
procedure TRxSpeedButton.SetWordWrap(Value: Boolean);
begin
if Value <> WordWrap then begin
TRxButtonGlyph(FGlyph).WordWrap := Value;
Invalidate;
end;
end;
function TRxSpeedButton.GetAlignment: TAlignment;
begin
Result := TRxButtonGlyph(FGlyph).Alignment;
end;
procedure TRxSpeedButton.SetAlignment(Value: TAlignment);
begin
if Alignment <> Value then begin
TRxButtonGlyph(FGlyph).Alignment := Value;
Invalidate;
end;
end;
function TRxSpeedButton.GetGlyph: TBitmap;
begin
Result := TRxButtonGlyph(FGlyph).Glyph;
end;
procedure TRxSpeedButton.SetGlyph(Value: TBitmap);
begin
TRxButtonGlyph(FGlyph).Glyph := Value;
Invalidate;
end;
function TRxSpeedButton.GetNumGlyphs: TRxNumGlyphs;
begin
Result := TRxButtonGlyph(FGlyph).NumGlyphs;
end;
procedure TRxSpeedButton.SetNumGlyphs(Value: TRxNumGlyphs);
begin
if Value < 0 then Value := 1
else if Value > Ord(High(TRxButtonState)) + 1 then
Value := Ord(High(TRxButtonState)) + 1;
if Value <> TRxButtonGlyph(FGlyph).NumGlyphs then begin
TRxButtonGlyph(FGlyph).NumGlyphs := Value;
Invalidate;
end;
end;
procedure TRxSpeedButton.GlyphChanged(Sender: TObject);
begin
Invalidate;
end;
procedure TRxSpeedButton.UpdateExclusive;
var
Msg: TMessage;
begin
if (FGroupIndex <> 0) and (Parent <> nil) then begin
Msg.Msg := CM_RXBUTTONPRESSED;
Msg.WParam := FGroupIndex;
Msg.LParam := Longint(Self);
Msg.Result := 0;
Parent.Broadcast(Msg);
end;
end;
procedure TRxSpeedButton.SetDown(Value: Boolean);
begin
if FGroupIndex = 0 then Value := False;
if Value <> FDown then begin
if FDown and (not FAllowAllUp) then Exit;
FDown := Value;
if Value then begin
if FState = rbsUp then Invalidate;
FState := rbsExclusive;
end
else begin
FState := rbsUp;
end;
Repaint;
if Value then UpdateExclusive;
Invalidate;
end;
end;
procedure TRxSpeedButton.SetGroupIndex(Value: Integer);
begin
if FGroupIndex <> Value then begin
FGroupIndex := Value;
UpdateExclusive;
end;
end;
procedure TRxSpeedButton.SetLayout(Value: TButtonLayout);
begin
if FLayout <> Value then begin
FLayout := Value;
Invalidate;
end;
end;
procedure TRxSpeedButton.SetMargin(Value: Integer);
begin
if (Value <> FMargin) and (Value >= -1) then begin
FMargin := Value;
Invalidate;
end;
end;
procedure TRxSpeedButton.SetSpacing(Value: Integer);
begin
if Value <> FSpacing then begin
FSpacing := Value;
Invalidate;
end;
end;
procedure TRxSpeedButton.SetAllowAllUp(Value: Boolean);
begin
if FAllowAllUp <> Value then begin
FAllowAllUp := Value;
UpdateExclusive;
end;
end;
procedure TRxSpeedButton.SetAllowTimer(Value: Boolean);
begin
FAllowTimer := Value;
if not FAllowTimer and (FRepeatTimer <> nil) then begin
FRepeatTimer.Enabled := False;
FRepeatTimer.Free;
FRepeatTimer := nil;
end;
end;
procedure TRxSpeedButton.SetDropDownMenu(Value: TPopupMenu);
begin
FDropDownMenu := Value;
{$IFDEF WIN32}
if Value <> nil then Value.FreeNotification(Self);
{$ENDIF}
if FMarkDropDown then Invalidate;
end;
procedure TRxSpeedButton.SetInactiveGrayed(Value: Boolean);
begin
if Value <> FInactiveGrayed then begin
FInactiveGrayed := Value;
Invalidate;
end;
end;
procedure TRxSpeedButton.SetFlat(Value: Boolean);
begin
if Value <> FFlat then begin
FFlat := Value;
Invalidate;
end;
end;
procedure TRxSpeedButton.SetStyle(Value: TButtonStyle);
begin
if Style <> Value then begin
FStyle := Value;
Invalidate;
end;
end;
procedure TRxSpeedButton.SetMarkDropDown(Value: Boolean);
begin
if Value <> FMarkDropDown then begin
FMarkDropDown := Value;
Invalidate;
end;
end;
procedure TRxSpeedButton.SetTransparent(Value: Boolean);
begin
if Value <> FTransparent then begin
FTransparent := Value;
Invalidate;
end;
end;
procedure TRxSpeedButton.WMRButtonDown(var Message: TWMRButtonDown);
begin
inherited;
UpdateTracking;
end;
procedure TRxSpeedButton.WMRButtonUp(var Message: TWMRButtonUp);
begin
inherited;
UpdateTracking;
end;
procedure TRxSpeedButton.WMLButtonDblClk(var Message: TWMLButtonDown);
begin
if not FMenuTracking then begin
inherited;
if FDown then DblClick;
end;
end;
procedure TRxSpeedButton.CMEnabledChanged(var Message: TMessage);
var
State: TRxButtonState;
begin
inherited;
if Enabled then begin
if Flat then State := rbsInactive
else State := rbsUp;
end else State := rbsDisabled;
TRxButtonGlyph(FGlyph).CreateButtonGlyph(State);
UpdateTracking;
Repaint;
end;
procedure TRxSpeedButton.CMVisibleChanged(var Message: TMessage);
begin
inherited;
if Visible then UpdateTracking;
end;
procedure TRxSpeedButton.CMMouseEnter(var Message: TMessage);
begin
inherited;
if (not FMouseInControl) and Enabled and IsForegroundTask then begin
FMouseInControl := True;
if FFlat then Repaint;
MouseEnter;
end;
end;
procedure TRxSpeedButton.CMMouseLeave(var Message: TMessage);
begin
inherited;
if FMouseInControl and Enabled and not FDragging then begin
FMouseInControl := False;
if FFlat then Invalidate;
MouseLeave;
end;
end;
procedure TRxSpeedButton.WMMouseMove(var Message: TMessage);
begin
inherited;
end;
procedure TRxSpeedButton.CMButtonPressed(var Message: TMessage);
var
Sender: TControl;
begin
if (Message.WParam = FGroupIndex) and Parent.HandleAllocated then begin
Sender := TControl(Message.LParam);
if (Sender <> nil) and (Sender is TRxSpeedButton) then
if Sender <> Self then begin
if TRxSpeedButton(Sender).Down and FDown then begin
FDown := False;
FState := rbsUp;
Repaint;
end;
FAllowAllUp := TRxSpeedButton(Sender).AllowAllUp;
end;
end;
end;
procedure TRxSpeedButton.CMDialogChar(var Message: TCMDialogChar);
begin
with Message do
if IsAccel(CharCode, Caption) and Enabled then begin
Click;
Result := 1;
end
else inherited;
end;
procedure TRxSpeedButton.CMFontChanged(var Message: TMessage);
begin
Invalidate;
end;
procedure TRxSpeedButton.CMTextChanged(var Message: TMessage);
begin
Invalidate;
end;
procedure TRxSpeedButton.CMSysColorChange(var Message: TMessage);
begin
TRxButtonGlyph(FGlyph).Invalidate;
Invalidate;
end;
procedure TRxSpeedButton.UpdateTracking;
var
P: TPoint;
OldValue: Boolean;
begin
OldValue := FMouseInControl;
GetCursorPos(P);
FMouseInControl := Enabled and (FindDragTarget(P, True) = Self) and
IsForegroundTask;
if (FMouseInControl <> OldValue) then
if FMouseInControl then begin
if Flat then Repaint;
MouseEnter;
end
else begin
if Flat then Invalidate;
MouseLeave;
end;
end;
procedure TRxSpeedButton.TimerExpired(Sender: TObject);
begin
FRepeatTimer.Interval := RepeatInterval;
if (FState = rbsDown) and MouseCapture then
try
Click;
except
FRepeatTimer.Enabled := False;
raise;
end;
end;
{$IFDEF RX_D4}
procedure TRxSpeedButton.ActionChange(Sender: TObject; CheckDefaults: Boolean);
procedure CopyImage(ImageList: TCustomImageList; Index: Integer);
begin
with Glyph do begin
Width := ImageList.Width;
Height := ImageList.Height;
Canvas.Brush.Color := clFuchsia;
Canvas.FillRect(Rect(0, 0, Width, Height));
ImageList.Draw(Canvas, 0, 0, Index);
TransparentColor := clFuchsia;
end;
end;
begin
inherited ActionChange(Sender, CheckDefaults);
if Sender is TCustomAction then
with TCustomAction(Sender) do begin
if (not CheckDefaults or (Self.Down = False)) and (FGroupIndex <> 0) then
Self.Down := Checked;
if (Glyph.Empty) and (ActionList <> nil) and (ActionList.Images <> nil) and
(ImageIndex >= 0) and (ImageIndex < ActionList.Images.Count) then
CopyImage(ActionList.Images, ImageIndex);
end;
end;
{$ENDIF RX_D4}
{$IFDEF WIN32}
initialization
FCheckBitmap := nil;
finalization
DestroyLocals;
{$ELSE}
initialization
FCheckBitmap := nil;
AddExitProc(DestroyLocals);
{$ENDIF}
end.