532 lines
14 KiB
ObjectPascal
532 lines
14 KiB
ObjectPascal
{ rxswitch unit
|
|
|
|
Copyright (C) 2005-2017 Lagunov Aleksey alexs75@yandex.ru and Lazarus team
|
|
original conception from rx library for Delphi (c)
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version with the following modification:
|
|
|
|
As a special exception, the copyright holders of this library give you
|
|
permission to link this library with independent modules to produce an
|
|
executable, regardless of the license terms of these independent modules,and
|
|
to copy and distribute the resulting executable under terms of your choice,
|
|
provided that you also meet, for each linked independent module, the terms
|
|
and conditions of the license of that module. An independent module is a
|
|
module which is not derived from or based on this library. If you modify
|
|
this library, you may extend this exception to your version of the library,
|
|
but you are not obligated to do so. If you do not wish to do so, delete this
|
|
exception statement from your version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; if not, write to the Free Software Foundation,
|
|
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
}
|
|
|
|
unit rxswitch;
|
|
|
|
{$I rx.inc}
|
|
|
|
interface
|
|
|
|
uses SysUtils, LCLType, LCLProc, LCLIntf, LMessages, Classes, Graphics,
|
|
Controls, Forms, ExtCtrls, Menus;
|
|
|
|
type
|
|
|
|
{ TRxSwitch }
|
|
|
|
TTextPos = (tpNone, tpLeft, tpRight, tpAbove, tpBelow);
|
|
TSwithState = (sw_off, sw_on);
|
|
TSwitchBitmaps = set of TSwithState;
|
|
|
|
TRxSwitch = class(TCustomControl)
|
|
private
|
|
FActive: Boolean;
|
|
FBitmaps: array [TSwithState] of TBitmap;
|
|
FDisableBitmaps: array [TSwithState] of TBitmap;
|
|
FOnOn: TNotifyEvent;
|
|
FOnOff: TNotifyEvent;
|
|
FStateOn: TSwithState;
|
|
FTextPosition: TTextPos;
|
|
FBorderStyle: TBorderStyle;
|
|
FToggleKey: TShortCut;
|
|
FShowFocus: Boolean;
|
|
FUserBitmaps: TSwitchBitmaps;
|
|
function GetSwitchGlyphOff: TBitmap;
|
|
function GetSwitchGlyphOn: TBitmap;
|
|
procedure GlyphChanged(Sender: TObject);
|
|
procedure SetStateOn(Value: TSwithState);
|
|
procedure SetSwitchGlyphOff(const AValue: TBitmap);
|
|
procedure SetSwitchGlyphOn(const AValue: TBitmap);
|
|
procedure SetTextPosition(Value: TTextPos);
|
|
procedure SetBorderStyle(Value: TBorderStyle);
|
|
function GetSwitchGlyph(Index: TSwithState): TBitmap;
|
|
procedure SetSwitchGlyph(Index: TSwithState; Value: TBitmap);
|
|
function StoreBitmap(Index: TSwithState): Boolean;
|
|
procedure SetShowFocus(Value: Boolean);
|
|
procedure CreateDisabled(Index: TSwithState);
|
|
procedure ReadBinaryData(Stream: TStream);
|
|
function StoreBitmapOff: boolean;
|
|
function StoreBitmapOn: boolean;
|
|
procedure WriteBinaryData(Stream: TStream);
|
|
procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
|
|
procedure CMFocusChanged(var Message: TLMessage); message CM_FOCUSCHANGED;
|
|
procedure CMTextChanged(var Message: TLMessage); message CM_TEXTCHANGED;
|
|
procedure CMEnabledChanged(var Message: TLMessage); message CM_ENABLEDCHANGED;
|
|
protected
|
|
procedure CreateParams(var Params: TCreateParams); override;
|
|
procedure DefineProperties(Filer: TFiler); override;
|
|
function GetPalette: HPALETTE; override;
|
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer); override;
|
|
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
|
|
procedure Paint; override;
|
|
procedure DoOn; dynamic;
|
|
procedure DoOff; dynamic;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure ToggleSwitch;
|
|
published
|
|
property Align;
|
|
property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle
|
|
default bsNone;
|
|
property Caption;
|
|
property Color;
|
|
property Cursor;
|
|
property DragMode;
|
|
property DragCursor;
|
|
property Enabled;
|
|
property Font;
|
|
property GlyphOff: TBitmap read GetSwitchGlyphOff write SetSwitchGlyphOff
|
|
stored StoreBitmapOff;
|
|
property GlyphOn: TBitmap read GetSwitchGlyphOn write SetSwitchGlyphOn
|
|
stored StoreBitmapOn;
|
|
property ParentColor;
|
|
property ParentFont;
|
|
property ParentShowHint;
|
|
property PopupMenu;
|
|
property ShowFocus: Boolean read FShowFocus write SetShowFocus default True;
|
|
property ToggleKey: TShortCut read FToggleKey write FToggleKey
|
|
default VK_SPACE;
|
|
property ShowHint;
|
|
property StateOn: TSwithState read FStateOn write SetStateOn default sw_off;
|
|
property TabOrder;
|
|
property TabStop default True;
|
|
property TextPosition: TTextPos read FTextPosition write SetTextPosition
|
|
default tpNone;
|
|
property Anchors;
|
|
property Constraints;
|
|
property DragKind;
|
|
property Visible;
|
|
property OnClick;
|
|
property OnDblClick;
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnMouseMove;
|
|
property OnMouseDown;
|
|
property OnMouseUp;
|
|
property OnMouseWheel;
|
|
property OnMouseWheelDown;
|
|
property OnMouseWheelUp;
|
|
property OnKeyDown;
|
|
property OnKeyUp;
|
|
property OnKeyPress;
|
|
property OnDragOver;
|
|
property OnDragDrop;
|
|
property OnEndDrag;
|
|
property OnStartDrag;
|
|
property OnContextPopup;
|
|
property OnEndDock;
|
|
property OnStartDock;
|
|
property OnOn: TNotifyEvent read FOnOn write FOnOn;
|
|
property OnOff: TNotifyEvent read FOnOff write FOnOff;
|
|
end;
|
|
|
|
{$R rxswitch.res}
|
|
|
|
implementation
|
|
|
|
uses rxlclutils;
|
|
|
|
const
|
|
BorderStyles: array[TBorderStyle] of Longint = (0, WS_BORDER);
|
|
|
|
{ TRxSwitch component }
|
|
|
|
constructor TRxSwitch.Create(AOwner: TComponent);
|
|
var
|
|
I : TSwithState;
|
|
begin
|
|
inherited Create(AOwner);
|
|
ControlStyle := [csClickEvents, csSetCaption, csCaptureMouse,
|
|
csOpaque, csDoubleClicks];
|
|
Width := 50;
|
|
Height := 60;
|
|
for I := sw_off to sw_on do
|
|
begin
|
|
FBitmaps[I] := TBitmap.Create;
|
|
SetSwitchGlyph(I, nil);
|
|
FBitmaps[I].OnChange := @GlyphChanged;
|
|
end;
|
|
FUserBitmaps := [];
|
|
FShowFocus := True;
|
|
FStateOn := sw_off;
|
|
FTextPosition := tpNone;
|
|
FBorderStyle := bsNone;
|
|
FToggleKey := VK_SPACE;
|
|
TabStop := True;
|
|
end;
|
|
|
|
destructor TRxSwitch.Destroy;
|
|
var
|
|
I: Byte;
|
|
begin
|
|
for I := 0 to 1 do
|
|
begin
|
|
FBitmaps[TSwithState(I)].OnChange := nil;
|
|
FDisableBitmaps[TSwithState(I)].Free;
|
|
FBitmaps[TSwithState(I)].Free;
|
|
end;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TRxSwitch.CreateParams(var Params: TCreateParams);
|
|
begin
|
|
inherited CreateParams(Params);
|
|
with Params do begin
|
|
WindowClass.Style := WindowClass.Style or CS_HREDRAW or CS_VREDRAW;
|
|
Style := Style or Longword(BorderStyles[FBorderStyle]);
|
|
end;
|
|
end;
|
|
|
|
procedure TRxSwitch.DefineProperties(Filer: TFiler);
|
|
|
|
function DoWrite: Boolean;
|
|
begin
|
|
if Assigned(Filer.Ancestor) then
|
|
Result := FUserBitmaps <> TRxSwitch(Filer.Ancestor).FUserBitmaps
|
|
else Result := FUserBitmaps <> [];
|
|
end;
|
|
|
|
begin
|
|
inherited DefineProperties(Filer);
|
|
Filer.DefineBinaryProperty('Data', @ReadBinaryData, @WriteBinaryData,
|
|
DoWrite);
|
|
end;
|
|
|
|
function TRxSwitch.GetPalette: HPALETTE;
|
|
begin
|
|
if Enabled then Result := FBitmaps[FStateOn].Palette else Result := 0;
|
|
end;
|
|
|
|
procedure TRxSwitch.ReadBinaryData(Stream: TStream);
|
|
begin
|
|
Stream.ReadBuffer(FUserBitmaps, SizeOf(FUserBitmaps));
|
|
end;
|
|
|
|
function TRxSwitch.StoreBitmapOff: boolean;
|
|
begin
|
|
Result:=StoreBitmap(sw_off);
|
|
end;
|
|
|
|
function TRxSwitch.StoreBitmapOn: boolean;
|
|
begin
|
|
Result:=StoreBitmap(sw_on);
|
|
end;
|
|
|
|
procedure TRxSwitch.WriteBinaryData(Stream: TStream);
|
|
begin
|
|
Stream.WriteBuffer(FUserBitmaps, SizeOf(FUserBitmaps));
|
|
end;
|
|
|
|
function TRxSwitch.StoreBitmap(Index: TSwithState): Boolean;
|
|
begin
|
|
Result := Index in FUserBitmaps;
|
|
end;
|
|
|
|
function TRxSwitch.GetSwitchGlyph(Index: TSwithState): TBitmap;
|
|
begin
|
|
if csLoading in ComponentState then Include(FUserBitmaps, Index);
|
|
Result := FBitmaps[Index]
|
|
end;
|
|
|
|
procedure TRxSwitch.CreateDisabled(Index: TSwithState);
|
|
begin
|
|
if FDisableBitmaps[Index] <> nil then
|
|
FDisableBitmaps[Index].Free;
|
|
try
|
|
FDisableBitmaps[Index] :=nil;
|
|
// CreateDisabledBitmap(FBitmaps[Index], clBlack);
|
|
except
|
|
FDisableBitmaps[Index] := nil;
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
procedure TRxSwitch.GlyphChanged(Sender: TObject);
|
|
var
|
|
I: TSwithState;
|
|
begin
|
|
for I := sw_off to sw_on do
|
|
if Sender = FBitmaps[I] then
|
|
begin
|
|
CreateDisabled(I);
|
|
end;
|
|
Invalidate;
|
|
end;
|
|
|
|
function TRxSwitch.GetSwitchGlyphOff: TBitmap;
|
|
begin
|
|
Result:=GetSwitchGlyph(sw_off);
|
|
end;
|
|
|
|
function TRxSwitch.GetSwitchGlyphOn: TBitmap;
|
|
begin
|
|
Result:=GetSwitchGlyph(sw_on);
|
|
end;
|
|
|
|
procedure TRxSwitch.SetSwitchGlyph(Index: TSwithState; Value: TBitmap);
|
|
var
|
|
S: String;
|
|
B: TBitmap;
|
|
begin
|
|
FBitmaps[Index].Clear;
|
|
if Value <> nil then
|
|
begin
|
|
FBitmaps[Index].Assign(Value);
|
|
Include(FUserBitmaps, Index);
|
|
end
|
|
else
|
|
begin
|
|
case Index of
|
|
{ sw_off: FBitmaps[Index].Handle:=CreatePixmapIndirect(@RXSWITCH_OFF[0], GetSysColor(COLOR_BTNFACE));
|
|
sw_on: FBitmaps[Index].Handle:=CreatePixmapIndirect(@RXSWITCH_ON[0],
|
|
GetSysColor(COLOR_BTNFACE));}
|
|
sw_off:S:='rxswitch_off';
|
|
sw_on:S:='rxswitch_on';
|
|
else
|
|
Exit;
|
|
end;
|
|
B:=CreateResBitmap(S);
|
|
FBitmaps[Index].Assign(B);
|
|
B.Free;
|
|
Exclude(FUserBitmaps, Index);
|
|
end;
|
|
end;
|
|
|
|
procedure TRxSwitch.CMFocusChanged(var Message: TLMessage);
|
|
var
|
|
Active: Boolean;
|
|
begin
|
|
{ with Message do Active := (Sender = Self);
|
|
if Active <> FActive then
|
|
begin
|
|
FActive := Active;
|
|
if FShowFocus then Invalidate;
|
|
end;}
|
|
inherited;
|
|
end;
|
|
|
|
procedure TRxSwitch.CMEnabledChanged(var Message: TLMessage);
|
|
begin
|
|
inherited;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TRxSwitch.CMTextChanged(var Message: TLMessage);
|
|
begin
|
|
inherited;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TRxSwitch.CMDialogChar(var Message: TCMDialogChar);
|
|
begin
|
|
if IsAccel(Message.CharCode, Caption) and CanFocus then begin
|
|
SetFocus;
|
|
Message.Result := 1;
|
|
end;
|
|
end;
|
|
|
|
procedure TRxSwitch.MouseDown(Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
if Button = mbLeft then
|
|
begin
|
|
if TabStop and CanFocus then SetFocus;
|
|
ToggleSwitch;
|
|
end;
|
|
inherited MouseDown(Button, Shift, X, Y);
|
|
end;
|
|
|
|
procedure TRxSwitch.KeyDown(var Key: Word; Shift: TShiftState);
|
|
begin
|
|
inherited KeyDown(Key, Shift);
|
|
if FToggleKey = ShortCut(Key, Shift) then begin
|
|
ToggleSwitch;
|
|
Key := 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TRxSwitch.Paint;
|
|
var
|
|
ARect: TRect;
|
|
Text1: array[0..255] of Char;
|
|
FontHeight: Integer;
|
|
|
|
procedure DrawBitmap(Bmp: TBitmap);
|
|
var
|
|
TmpImage: TBitmap;
|
|
IWidth, IHeight, X, Y: Integer;
|
|
IRect: TRect;
|
|
begin
|
|
IWidth := Bmp.Width;
|
|
IHeight := Bmp.Height;
|
|
IRect := Rect(0, 0, IWidth, IHeight);
|
|
TmpImage := TBitmap.Create;
|
|
try
|
|
TmpImage.Width := IWidth;
|
|
TmpImage.Height := IHeight;
|
|
TmpImage.Canvas.Brush.Color := Self.Brush.Color;
|
|
// TmpImage.Canvas.BrushCopy(IRect, Bmp, IRect, Bmp.TransparentColor);
|
|
X := 0; Y := 0;
|
|
case FTextPosition of
|
|
tpNone:
|
|
begin
|
|
X := ((Width - IWidth) div 2);
|
|
Y := ((Height - IHeight) div 2);
|
|
end;
|
|
tpLeft:
|
|
begin
|
|
X := Width - IWidth;
|
|
Y := ((Height - IHeight) div 2);
|
|
Dec(ARect.Right, IWidth);
|
|
end;
|
|
tpRight:
|
|
begin
|
|
X := 0;
|
|
Y := ((Height - IHeight) div 2);
|
|
Inc(ARect.Left, IWidth);
|
|
end;
|
|
tpAbove:
|
|
begin
|
|
X := ((Width - IWidth) div 2);
|
|
Y := Height - IHeight;
|
|
Dec(ARect.Bottom, IHeight);
|
|
end;
|
|
tpBelow:
|
|
begin
|
|
X := ((Width - IWidth) div 2);
|
|
Y := 0;
|
|
Inc(ARect.Top, IHeight);
|
|
end;
|
|
end;
|
|
// Canvas.Draw(X, Y, TmpImage);
|
|
Canvas.Draw(X, Y, Bmp);
|
|
// if Focused and FShowFocus and TabStop and not (csDesigning in ComponentState) then
|
|
// Canvas.DrawFocusRect(Rect(X, Y, X + IWidth, Y + IHeight));
|
|
// Canvas.FrameRect(Rect(X, Y, X + IWidth, Y + IHeight));
|
|
finally
|
|
TmpImage.Free;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
ARect := GetClientRect;
|
|
with Canvas do
|
|
begin
|
|
Font := Self.Font;
|
|
Brush.Color := Self.Color;
|
|
FillRect(ARect);
|
|
if not Enabled and (FDisableBitmaps[FStateOn] <> nil) then
|
|
DrawBitmap(FDisableBitmaps[FStateOn])
|
|
else
|
|
DrawBitmap(FBitmaps[FStateOn]);
|
|
if FTextPosition <> tpNone then
|
|
begin
|
|
FontHeight := TextHeight('W');
|
|
with ARect do
|
|
begin
|
|
Top := ((Bottom + Top) - FontHeight) shr 1;
|
|
Bottom := Top + FontHeight;
|
|
end;
|
|
StrPCopy(Text1, Caption);
|
|
DrawText(Handle, Text1, StrLen(Text1), ARect, {DT_EXPANDTABS or }DT_VCENTER or DT_CENTER);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TRxSwitch.DoOn;
|
|
begin
|
|
if Assigned(FOnOn) then FOnOn(Self);
|
|
end;
|
|
|
|
procedure TRxSwitch.DoOff;
|
|
begin
|
|
if Assigned(FOnOff) then FOnOff(Self);
|
|
end;
|
|
|
|
procedure TRxSwitch.ToggleSwitch;
|
|
begin
|
|
StateOn := TSwithState(not boolean(StateOn));
|
|
end;
|
|
|
|
procedure TRxSwitch.SetBorderStyle(Value: TBorderStyle);
|
|
begin
|
|
if FBorderStyle <> Value then
|
|
begin
|
|
FBorderStyle := Value;
|
|
RecreateWnd(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TRxSwitch.SetStateOn(Value: TSwithState);
|
|
begin
|
|
if FStateOn <> Value then
|
|
begin
|
|
FStateOn := Value;
|
|
Invalidate;
|
|
if Value = sw_on then
|
|
DoOn
|
|
else
|
|
DoOff;
|
|
end;
|
|
end;
|
|
|
|
procedure TRxSwitch.SetSwitchGlyphOff(const AValue: TBitmap);
|
|
begin
|
|
SetSwitchGlyph(sw_off, AValue);
|
|
end;
|
|
|
|
procedure TRxSwitch.SetSwitchGlyphOn(const AValue: TBitmap);
|
|
begin
|
|
SetSwitchGlyph(sw_on, AValue);
|
|
end;
|
|
|
|
procedure TRxSwitch.SetTextPosition(Value: TTextPos);
|
|
begin
|
|
if FTextPosition <> Value then
|
|
begin
|
|
FTextPosition := Value;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TRxSwitch.SetShowFocus(Value: Boolean);
|
|
begin
|
|
if FShowFocus <> Value then
|
|
begin
|
|
FShowFocus := Value;
|
|
if not (csDesigning in ComponentState) then Invalidate;
|
|
end;
|
|
end;
|
|
|
|
end.
|