Componentes.Terceros.jvcl/official/3.32/run/JvImage.pas

413 lines
11 KiB
ObjectPascal

{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is: JvImage.PAS, released on 2001-02-28.
The Initial Developer of the Original Code is Sébastien Buysse [sbuysse att buypin dott com]
Portions created by Sébastien Buysse are Copyright (C) 2001 Sébastien Buysse.
All Rights Reserved.
Contributor(s): Michael Beck [mbeck att bigfoot dott com].
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: JvImage.pas 11057 2006-11-29 14:32:05Z marquardt $
unit JvImage;
{$I jvcl.inc}
interface
uses
{$IFDEF UNITVERSIONING}
JclUnitVersioning,
{$ENDIF UNITVERSIONING}
Windows, SysUtils, Classes, Graphics, ExtCtrls, Controls, Forms,
JvExExtCtrls;
type
TPicState = (stDefault, stEntered, stClicked1, stClicked2, stDown);
TJvPictures = class(TPersistent)
private
FOnChanged: TNotifyEvent;
FPicClicked1: TPicture;
FPicClicked2: TPicture;
FPicDown: TPicture;
FPicEnter: TPicture;
procedure SetPicClicked(const Value: TPicture);
procedure SetPicClicked2(const Value: TPicture);
procedure SetPicDown(const Value: TPicture);
procedure SetPicEnter(const Value: TPicture);
protected
property OnChanged: TNotifyEvent read FOnChanged write FOnChanged;
procedure Changed;
public
constructor Create;
destructor Destroy; override;
published
property PicEnter: TPicture read FPicEnter write SetPicEnter;
property PicClicked1: TPicture read FPicClicked1 write SetPicClicked;
property PicClicked2: TPicture read FPicClicked2 write SetPicClicked2;
property PicDown: TPicture read FPicDown write SetPicDown;
end;
TJvImage = class(TJvExImage)
private
FOnStateChanged: TNotifyEvent;
FPictures: TJvPictures;
FState: TPicState;
FPicture: TPicture;
FClickCount: Integer;
FPictureChange: TNotifyEvent;
FDrawing: Boolean;
procedure SetState(Value: TPicState);
procedure PicturesChanged(Sender: TObject);
procedure DoPictureChange(Sender: TObject);
procedure DoOwnPictureChange(Sender: TObject);
procedure SetPicture(const Value: TPicture);
procedure ApplyClick;
function UsesPictures: Boolean;
protected
procedure Click; override;
procedure Paint; override;
procedure MouseEnter(Control: TControl); override;
procedure MouseLeave(Control: TControl); override;
function HitTest(X, Y: Integer): Boolean; override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property HintColor;
property Pictures: TJvPictures read FPictures write FPictures;
property Picture: TPicture read FPicture write SetPicture;
property State: TPicState read FState write SetState default stDefault;
property OnMouseEnter;
property OnMouseLeave;
property OnStateChanged: TNotifyEvent read FOnStateChanged write FOnStateChanged;
end;
{$IFDEF UNITVERSIONING}
const
UnitVersioning: TUnitVersionInfo = (
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_32/run/JvImage.pas $';
Revision: '$Revision: 11057 $';
Date: '$Date: 2006-11-29 15:32:05 +0100 (mer., 29 nov. 2006) $';
LogPath: 'JVCL\run'
);
{$ENDIF UNITVERSIONING}
implementation
//=== { TJvImage } ===========================================================
constructor TJvImage.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FState := stDefault;
FPictures := TJvPictures.Create;
FPictures.OnChanged := PicturesChanged;
FPicture := TPicture.Create;
FPicture.OnChange := DoOwnPictureChange;
FPictureChange := inherited Picture.OnChange;
inherited Picture.OnChange := DoPictureChange;
end;
destructor TJvImage.Destroy;
begin
inherited Picture.OnChange := FPictureChange;
FPictureChange := nil;
FPictures.Free;
FPicture.Free;
inherited Destroy;
end;
procedure TJvImage.ApplyClick;
begin
case FClickCount of
1:
begin
State := stClicked1;
if State <> stClicked1 then
begin
FClickCount := 0;
State := stDefault;
end;
end;
2:
begin
State := stClicked2;
if State <> stClicked2 then
begin
FClickCount := 0;
State := stDefault;
end;
end;
0, 3:
begin
State := stDefault;
FClickCount := 0;
end;
end;
end;
procedure TJvImage.Click;
begin
inherited Click;
if UsesPictures then
begin
Inc(FClickCount);
ApplyClick;
end;
end;
procedure TJvImage.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited MouseDown(Button, Shift, X, Y);
if UsesPictures then
State := stDown;
end;
procedure TJvImage.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
begin
inherited MouseUp(Button, Shift, X, Y);
if not UsesPictures or (State = stClicked1) or (State = stClicked2) then
Exit;
if (X > 0) and (X < Width) and (Y > 0) and (Y < Height) then
begin
SetState(stEntered);
if State <> stEntered then
ApplyClick;
end
else
ApplyClick;
end;
procedure TJvImage.MouseEnter(Control: TControl);
begin
if csDesigning in ComponentState then
Exit;
if not MouseOver then
begin
if UsesPictures then
State := stEntered;
inherited MouseEnter(Control);
end;
end;
procedure TJvImage.MouseLeave(Control: TControl);
begin
if MouseOver then
begin
if UsesPictures then
ApplyClick;
inherited MouseLeave(Control);
end;
end;
// (rom) improvement. now only non-transparent pixels are considered
// (rom) part of the clickable area
// (p3) NB!!! This only works if TGraphic is a TBitmap! For PNG and JPG images, the result is that
// the FPicture is cleared when "Assigned(Picture.Bitmap)" is called!
// A (somewhat) better solution would be to replace the test with
// "if Assigned(Picture) and (Picture.Graphic is TBitmap) and Transparent and"...
// but then the PicEnter image will be assigned as soon as the mouse enters the component as no
// transparency detection is possible (TGraphic doesn't have the necessary TransparentColor and Canvas.Pixels)
// (rom) improved
function TJvImage.HitTest(X, Y: Integer): Boolean;
begin
Result := inherited HitTest(X, Y);
if (not UsesPictures) and Assigned(Picture) and (Picture.Graphic is TBitmap) and
Transparent and (X < Picture.Bitmap.Width) and (Y < Picture.Bitmap.Height) and
(Picture.Bitmap.Canvas.Pixels[X, Y] = ColorToRGB(Picture.Bitmap.TransparentColor)) then
Result := False;
end;
procedure TJvImage.DoOwnPictureChange(Sender: TObject);
var
G: TGraphic;
D : TRect;
begin
// All this code is required for Transparent, Center and other inherited
// properties to work fine.
if AutoSize and (Picture.Width > 0) and (Picture.Height > 0) then
SetBounds(Left, Top, Picture.Width, Picture.Height);
G := Picture.Graphic;
if G <> nil then
begin
if not ((G is TMetaFile) or (G is TIcon)) then
G.Transparent := inherited Transparent;
D := DestRect;
if (not G.Transparent) and (D.Left <= 0) and (D.Top <= 0) and
(D.Right >= Width) and (D.Bottom >= Height) then
ControlStyle := ControlStyle + [csOpaque]
else // picture might not cover entire clientrect
ControlStyle := ControlStyle - [csOpaque];
if DoPaletteChange and FDrawing then
Update;
end
else ControlStyle := ControlStyle - [csOpaque];
if not FDrawing then
Invalidate;
inherited Picture.Assign(FPicture);
end;
procedure TJvImage.Paint;
begin
FDrawing := True;
try
inherited Paint;
finally
FDrawing := False;
end;
end;
procedure TJvImage.PicturesChanged(Sender: TObject);
begin
if UsesPictures then
SetState(State);
end;
procedure TJvImage.SetPicture(const Value: TPicture);
begin
FPicture.Assign(Value);
end;
procedure TJvImage.SetState(Value: TPicState);
function NotEmpty(Value: TPicture): Boolean;
begin
Result := (Value <> nil) and (Value.Width > 0) and (Value.Height > 0);
end;
begin
case Value of
stDefault:
if NotEmpty(FPicture) then
begin
inherited Picture.Assign(FPicture);
FState := Value;
end;
stEntered:
if NotEmpty(Pictures.PicEnter) then
begin
inherited Picture.Assign(Pictures.PicEnter);
FState := Value;
end;
stClicked1:
if NotEmpty(Pictures.PicClicked1) then
begin
inherited Picture.Assign(Pictures.PicClicked1);
FState := Value;
end;
stClicked2:
if NotEmpty(Pictures.PicClicked2) then
begin
inherited Picture.Assign(Pictures.PicClicked2);
FState := Value;
end;
stDown:
if NotEmpty(Pictures.PicDown) then
begin
inherited Picture.Assign(Pictures.PicDown);
FState := Value;
end;
end;
if Assigned(FOnStateChanged) then
FOnStateChanged(Self);
end;
procedure TJvImage.DoPictureChange(Sender: TObject);
begin
Invalidate;
end;
function TJvImage.UsesPictures: Boolean;
begin
Result := Assigned(Pictures.PicEnter.Graphic) or
Assigned(Pictures.PicClicked1.Graphic) or
Assigned(Pictures.PicClicked2.Graphic) or
Assigned(Pictures.PicDown.Graphic);
end;
//=== { TJvPictures } ========================================================
constructor TJvPictures.Create;
begin
inherited Create;
FPicClicked1 := TPicture.Create;
FPicClicked2 := TPicture.Create;
FPicDown := TPicture.Create;
FPicEnter := TPicture.Create;
end;
destructor TJvPictures.Destroy;
begin
FPicClicked1.Free;
FPicClicked2.Free;
FPicDown.Free;
FPicEnter.Free;
inherited Destroy;
end;
procedure TJvPictures.Changed;
begin
if Assigned(FOnChanged) then
FOnChanged(Self);
end;
procedure TJvPictures.SetPicClicked(const Value: TPicture);
begin
FPicClicked1.Assign(Value);
Changed;
end;
procedure TJvPictures.SetPicClicked2(const Value: TPicture);
begin
FPicClicked2.Assign(Value);
Changed;
end;
procedure TJvPictures.SetPicDown(const Value: TPicture);
begin
FPicDown.Assign(Value);
Changed;
end;
procedure TJvPictures.SetPicEnter(const Value: TPicture);
begin
FPicEnter.Assign(Value);
Changed;
end;
{$IFDEF UNITVERSIONING}
initialization
RegisterUnitVersion(HInstance, UnitVersioning);
finalization
UnregisterUnitVersion(HInstance);
{$ENDIF UNITVERSIONING}
end.