{----------------------------------------------------------------------------- The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: JvSwitch.PAS, released on 2002-07-04. The Initial Developers of the Original Code are: Fedor Koshevnikov, Igor Pavluk and Serge Korolev Copyright (c) 1997, 1998 Fedor Koshevnikov, Igor Pavluk and Serge Korolev Copyright (c) 2001,2002 SGB Software All Rights Reserved. You may retrieve the latest version of this file at the Project JEDI's JVCL home page, located at http://jvcl.sourceforge.net Known Issues: -----------------------------------------------------------------------------} // $Id: JvSwitch.pas 10612 2006-05-19 19:04:09Z jfudickar $ unit JvSwitch; {$I jvcl.inc} interface uses {$IFDEF UNITVERSIONING} JclUnitVersioning, {$ENDIF UNITVERSIONING} SysUtils, Classes, Windows, Messages, Graphics, Controls, Forms, Menus, {$IFDEF VisualCLX} Qt, {$ENDIF VisualCLX} JvJCLUtils, JvComponent; type TTextPos = (tpNone, tpLeft, tpRight, tpAbove, tpBelow); TSwitchBitmaps = set of Boolean; TJvSwitch = class(TJvCustomControl) private FActive: Boolean; FBitmaps: array [Boolean] of TBitmap; FDisableBitmaps: array [Boolean] of TBitmap; FOnOn: TNotifyEvent; FOnOff: TNotifyEvent; FStateOn: Boolean; FTextPosition: TTextPos; FBorderStyle: TBorderStyle; FToggleKey: TShortCut; FShowFocus: Boolean; FUserBitmaps: TSwitchBitmaps; procedure GlyphChanged(Sender: TObject); procedure SetStateOn(Value: Boolean); procedure SetTextPosition(Value: TTextPos); procedure SetBorderStyle(Value: TBorderStyle); function GetSwitchGlyph(Index: Integer): TBitmap; procedure SetSwitchGlyph(Index: Integer; Value: TBitmap); function StoreBitmap(Index: Integer): Boolean; procedure SetShowFocus(Value: Boolean); procedure CreateDisabled(Index: Boolean); procedure ReadBinaryData(Stream: TStream); procedure WriteBinaryData(Stream: TStream); protected procedure FocusChanged(Control: TWinControl); override; function DoEraseBackground(Canvas: TCanvas; Param: Integer): Boolean; override; function WantKey(Key: Integer; Shift: TShiftState; const KeyText: WideString): Boolean; override; procedure TextChanged; override; procedure EnabledChanged; override; procedure DefineProperties(Filer: TFiler); override; {$IFDEF VCL} procedure CreateParams(var Params: TCreateParams); override; function GetPalette: HPALETTE; override; {$ENDIF VCL} 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 {$IFDEF JVCLThemesEnabled} property ParentBackground default True; {$ENDIF JVCLThemesEnabled} property Align; property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsNone; property Caption; property Color; property Cursor; {$IFDEF VCL} property DragCursor; property DragKind; property OnEndDock; property OnStartDock; {$ENDIF VCL} property DragMode; property Enabled; property Font; property GlyphOff: TBitmap index 0 read GetSwitchGlyph write SetSwitchGlyph stored StoreBitmap; property GlyphOn: TBitmap index 1 read GetSwitchGlyph write SetSwitchGlyph stored StoreBitmap; 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 Ord(' '); property ShowHint; property StateOn: Boolean read FStateOn write SetStateOn default False; property TabOrder; property TabStop default True; property TextPosition: TTextPos read FTextPosition write SetTextPosition default tpNone; property Anchors; property Constraints; property Visible; property OnClick; property OnDblClick; property OnEnter; property OnExit; property OnMouseMove; property OnMouseDown; property OnMouseUp; property OnKeyDown; property OnKeyUp; property OnKeyPress; property OnDragOver; property OnDragDrop; property OnEndDrag; property OnStartDrag; property OnContextPopup; property OnOn: TNotifyEvent read FOnOn write FOnOn; property OnOff: TNotifyEvent read FOnOff write FOnOff; end; {$IFDEF UNITVERSIONING} const UnitVersioning: TUnitVersionInfo = ( RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_32/run/JvSwitch.pas $'; Revision: '$Revision: 10612 $'; Date: '$Date: 2006-05-19 21:04:09 +0200 (ven., 19 mai 2006) $'; LogPath: 'JVCL\run' ); {$ENDIF UNITVERSIONING} implementation uses JvJVCLUtils, JvThemes; {$R JvSwitch.Res} constructor TJvSwitch.Create(AOwner: TComponent); var I: Boolean; begin inherited Create(AOwner); ControlStyle := [csClickEvents, csSetCaption, csCaptureMouse, csOpaque, csDoubleClicks]; IncludeThemeStyle(Self, [csParentBackground]); Width := 50; Height := 60; for I := False to True do begin FBitmaps[I] := TBitmap.Create; SetSwitchGlyph(Ord(I), nil); FBitmaps[I].OnChange := GlyphChanged; end; FUserBitmaps := []; FShowFocus := True; FStateOn := False; FTextPosition := tpNone; FBorderStyle := bsNone; FToggleKey := Ord(' '); TabStop := True; end; destructor TJvSwitch.Destroy; var I: Boolean; begin for I := False to True do begin FBitmaps[I].OnChange := nil; FDisableBitmaps[I].Free; FBitmaps[I].Free; end; inherited Destroy; end; {$IFDEF VCL} procedure TJvSwitch.CreateParams(var Params: TCreateParams); const BorderStyles: array [TBorderStyle] of Longint = (0, WS_BORDER); 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; {$ENDIF VCL} procedure TJvSwitch.DefineProperties(Filer: TFiler); function DoWrite: Boolean; begin if Assigned(Filer.Ancestor) then Result := FUserBitmaps <> TJvSwitch(Filer.Ancestor).FUserBitmaps else Result := FUserBitmaps <> []; end; begin inherited DefineProperties(Filer); Filer.DefineBinaryProperty('Data', ReadBinaryData, WriteBinaryData,DoWrite); end; {$IFDEF VCL} function TJvSwitch.GetPalette: HPALETTE; begin if Enabled then Result := FBitmaps[FStateOn].Palette else Result := 0; end; {$ENDIF VCL} procedure TJvSwitch.ReadBinaryData(Stream: TStream); begin Stream.ReadBuffer(FUserBitmaps, SizeOf(FUserBitmaps)); end; procedure TJvSwitch.WriteBinaryData(Stream: TStream); begin Stream.WriteBuffer(FUserBitmaps, SizeOf(FUserBitmaps)); end; function TJvSwitch.StoreBitmap(Index: Integer): Boolean; begin Result := (Index <> 0) in FUserBitmaps; end; function TJvSwitch.GetSwitchGlyph(Index: Integer): TBitmap; begin if csLoading in ComponentState then Include(FUserBitmaps, Index <> 0); Result := FBitmaps[Index <> 0]; end; procedure TJvSwitch.CreateDisabled(Index: Boolean); begin FreeAndNil(FDisableBitmaps[Index]); FDisableBitmaps[Index] := CreateDisabledBitmap(FBitmaps[Index], clBlack); end; procedure TJvSwitch.GlyphChanged(Sender: TObject); var I: Boolean; begin for I := False to True do if Sender = FBitmaps[I] then CreateDisabled(I); Invalidate; end; procedure TJvSwitch.SetSwitchGlyph(Index: Integer; Value: TBitmap); const ResName: array [Boolean] of PChar = ('JvSwitchOFF', 'JvSwitchON'); begin if Value <> nil then begin FBitmaps[Index <> 0].Assign(Value); Include(FUserBitmaps, Index <> 0); end else begin FBitmaps[Index <> 0].Assign(nil); // fixes GDI resource leak FBitmaps[Index <> 0].LoadFromResourceName(HInstance, ResName[Index <> 0]); Exclude(FUserBitmaps, Index <> 0); end; end; procedure TJvSwitch.FocusChanged(Control: TWinControl); var Active: Boolean; begin Active := (Control = Self); if Active <> FActive then begin FActive := Active; if FShowFocus then Invalidate; end; inherited FocusChanged(Control); end; procedure TJvSwitch.EnabledChanged; begin inherited EnabledChanged; Invalidate; end; procedure TJvSwitch.TextChanged; begin inherited TextChanged; Invalidate; end; function TJvSwitch.WantKey(Key: Integer; Shift: TShiftState; const KeyText: WideString): Boolean; begin Result := IsAccel(Key, Caption) and CanFocus and (ssAlt in Shift); if Result then SetFocus; end; function TJvSwitch.DoEraseBackground(Canvas: TCanvas; Param: Integer): Boolean; begin Result := True; // the component paints the background in Paint end; procedure TJvSwitch.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 TJvSwitch.KeyDown(var Key: Word; Shift: TShiftState); begin inherited KeyDown(Key, Shift); if FToggleKey = ShortCut(Key, Shift) then begin ToggleSwitch; Key := 0; end; end; procedure TJvSwitch.Paint; var ARect: TRect; Text: string; FontHeight: Integer; procedure DrawBitmap(Bmp: TBitmap); var IWidth, IHeight, X, Y: Integer; IRect: TRect; begin IWidth := Bmp.Width; IHeight := Bmp.Height; IRect := Rect(0, 0, IWidth, IHeight); 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; Bmp.Transparent := True; 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)); end; begin ARect := GetClientRect; {$IFDEF VisualCLX} Canvas.Start; try {$ENDIF VisualCLX} with Canvas do begin Font := Self.Font; Brush.Color := Self.Color; DrawThemedBackground(Self, Canvas, 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; Text := Caption; DrawText(Canvas, Text, Length(Caption), ARect, DT_EXPANDTABS or DT_VCENTER or DT_CENTER); end; end; {$IFDEF VisualCLX} if BorderStyle = bsSingle then begin Canvas.Pen.Color := clBlack; Canvas.Pen.Mode := pmCopy; Canvas.Brush.Style := bsClear; Canvas.Rectangle(ClientRect); end; finally Canvas.Stop; end; {$ENDIF VisualCLX} end; procedure TJvSwitch.DoOn; begin if Assigned(FOnOn) then FOnOn(Self); end; procedure TJvSwitch.DoOff; begin if Assigned(FOnOff) then FOnOff(Self); end; procedure TJvSwitch.ToggleSwitch; begin StateOn := not StateOn; end; procedure TJvSwitch.SetBorderStyle(Value: TBorderStyle); begin if FBorderStyle <> Value then begin FBorderStyle := Value; RecreateWnd; end; end; procedure TJvSwitch.SetStateOn(Value: Boolean); begin if FStateOn <> Value then begin FStateOn := Value; Invalidate; if Value then DoOn else DoOff; end; end; procedure TJvSwitch.SetTextPosition(Value: TTextPos); begin if FTextPosition <> Value then begin FTextPosition := Value; Invalidate; end; end; procedure TJvSwitch.SetShowFocus(Value: Boolean); begin if FShowFocus <> Value then begin FShowFocus := Value; if not (csDesigning in ComponentState) then Invalidate; end; end; {$IFDEF UNITVERSIONING} initialization RegisterUnitVersion(HInstance, UnitVersioning); finalization UnregisterUnitVersion(HInstance); {$ENDIF UNITVERSIONING} end.