Componentes.Terceros.jvcl/official/3.39/run/JvScrollPanel.pas
2010-01-18 16:55:50 +00:00

769 lines
20 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: JvScrollPanel.PAS, released on 2002-05-26.
The Initial Developer of the Original Code is Peter Thörnqvist [peter3 at sourceforge dot net]
Portions created by Peter Thörnqvist are Copyright (C) 2002 Peter Thörnqvist.
All Rights Reserved.
Contributor(s):
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.delphi-jedi.org
Description:
A scrolling TToolWindow like the ones in IE 4.0 with popup scrollbuttons
either on top/bottom or left/right edge.
Known Issues:
-----------------------------------------------------------------------------}
// $Id: JvScrollPanel.pas 12461 2009-08-14 17:21:33Z obones $
unit JvScrollPanel;
{$I jvcl.inc}
interface
uses
{$IFDEF UNITVERSIONING}
JclUnitVersioning,
{$ENDIF UNITVERSIONING}
SysUtils, Classes,
Windows, Messages, Graphics, Controls, ToolWin, ExtCtrls,
JvComponent, JvExForms;
type
TJvCustomScrollPanel = class;
TJvDivideKind = (dkDivider, dkSeparator);
TJvScrollKind = (sbUp, sbDown, sbLeft, sbRight);
/// (DFCS_SCROLLUP, DFCS_SCROLLDOWN, DFCS_SCROLLLEFT, DFCS_SCROLLRIGHT);
TJvScrollDirection = (sdHorizontal, sdVertical);
TJvScrollingEvent = procedure(Sender: TObject; var AllowChange: Boolean; Kind: TJvScrollKind) of object;
TJvScrolledEvent = procedure(Sender: TObject; Kind: TJvScrollKind) of object;
TJvDivider = class(TJvGraphicControl)
private
FKind: TJvDivideKind;
FVertical: Boolean;
procedure SetKind(Value: TJvDivideKind);
procedure SetVertical(Value: Boolean);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
published
property Align;
property Vertical: Boolean read FVertical write SetVertical default True;
property Kind: TJvDivideKind read FKind write SetKind default dkDivider;
end;
TJvScrollButton = class(TJvCustomControl)
private
FDown: Boolean;
FRepeat: Boolean;
FFlat: Boolean;
FAutoRepeat: Boolean;
FIncrement: Word;
FTimer: TTimer;
FKind: TJvScrollKind;
procedure SetKind(Value: TJvScrollKind);
procedure SetFlat(Value: Boolean);
procedure OnTime(Sender: TObject);
protected
procedure SetPosition; virtual;
procedure Paint; override;
procedure Click; override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure MouseEnter(Control: TControl); override;
procedure MouseLeave(Control: TControl); override;
procedure EnabledChanged; override;
public
constructor Create(AOwner: TComponent); override;
published
property AutoRepeat: Boolean read FAutoRepeat write FAutoRepeat default False;
property Flat: Boolean read FFlat write SetFlat default False;
property Kind: TJvScrollKind read FKind write SetKind default sbUp;
property Increment: Word read FIncrement write FIncrement default 16;
property Width default 16;
property Height default 16;
end;
TJvCustomScrollPanel = class(TJvExToolWindow)
private
FScrollDirection: TJvScrollDirection;
FScrollAmount: Word;
FAutoHide: Boolean;
FAutoRepeat: Boolean;
FAutoArrange: Boolean;
FUpLeft: TJvScrollButton;
FDownRight: TJvScrollButton;
FOnScrolling: TJvScrollingEvent;
FOnScrolled: TJvScrolledEvent;
FFlat: Boolean;
procedure SetAutoArrange(Value: Boolean);
procedure SetAutoHide(Value: Boolean);
procedure SetScrollDirection(Value: TJvScrollDirection);
procedure SetFlat(Value: Boolean);
procedure AlignArrows;
procedure UpdateVisible;
procedure ArrangeChildren;
procedure SetupArrows;
procedure SetScrollAmount(const Value: Word);
protected
procedure VisibleChanged; override;
procedure EnabledChanged; override;
procedure SetParent( AParent: TWinControl); override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
property AutoHide: Boolean read FAutoHide write SetAutoHide;
property AutoRepeat: Boolean read FAutoRepeat write FAutoRepeat;
property AutoArrange: Boolean read FAutoArrange write SetAutoArrange default False;
property Flat: Boolean read FFlat write SetFlat;
property ScrollDirection: TJvScrollDirection read FScrollDirection write SetScrollDirection;
property ScrollAmount: Word read FScrollAmount write SetScrollAmount default 16;
property OnScrolling: TJvScrollingEvent read FOnScrolling write FOnScrolling;
property OnScrolled: TJvScrolledEvent read FOnScrolled write FOnScrolled;
public
constructor Create(AOwner: TComponent); override;
procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
published
property Align default alTop;
property Height default 35;
end;
TJvScrollingWindow = class(TJvCustomScrollPanel)
public
constructor Create(AComponent: TComponent); override;
published
property AutoArrange;
property AutoHide default True;
property AutoRepeat default False;
property Flat;
property ScrollDirection default sdHorizontal;
property ScrollAmount;
{ inherited ones: }
property Align;
property BorderWidth;
property EdgeInner;
property EdgeOuter;
property EdgeBorders;
/// property BevelInner;
/// property BevelOuter;
/// property BevelKind;
/// property BevelWidth;
property Enabled;
property ShowHint;
property Hint;
property ParentShowHint;
property PopupMenu;
property ImeMode;
property ImeName;
property Color;
property ParentColor;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnScrolling;
property OnScrolled;
property TabOrder;
property TabStop;
property HelpContext;
end;
{$IFDEF UNITVERSIONING}
const
UnitVersioning: TUnitVersionInfo = (
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_39/run/JvScrollPanel.pas $';
Revision: '$Revision: 12461 $';
Date: '$Date: 2009-08-14 19:21:33 +0200 (ven., 14 août 2009) $';
LogPath: 'JVCL\run'
);
{$ENDIF UNITVERSIONING}
implementation
uses
Math,
JvThemes, JvExControls;
const
cInitTime = 360;
cTimeDelay = 100;
{
procedure TileBitmap(Dest: TControl; Source: TBitmap);
var
X, Y, W, H: Longint;
DR,SR: TRect;
Tmp: TBitmap;
Canvas: TControlCanvas;
begin
if not Source.Empty then
begin
with Source do
begin
W := Width;
H := Height;
end;
Tmp := TBitmap.Create;
Canvas := TControlCanvas.Create;
Canvas.Control := Dest;
Tmp.Width := Dest.Width;
Tmp.Height := Dest.Height;
Y := 0;
SR := Rect(0,0,W,H);
while y < Dest.Height do
begin
X := 0;
while X < Dest.Width do
begin
DR := Rect(X,Y,X+W,Y+H);
Tmp.Canvas.CopyRect(DR,Source.Canvas,SR);
Inc(X, W);
end;
Inc(Y, H);
end;
BitBlt(Canvas.Handle,0,0,Dest.Width,Dest.Height,Tmp.Handle,0,0,SRCCOPY);
// Canvas.Draw(0,0,Tmp);
Tmp.Free;
Canvas.Free;
end;
end;
}
//=== { TJvDivider } =========================================================
constructor TJvDivider.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
SetBounds(0, 0, 16, 16);
FVertical := True;
FKind := dkDivider;
end;
procedure TJvDivider.SetVertical(Value: Boolean);
begin
if FVertical <> Value then
begin
FVertical := Value;
Invalidate;
end;
end;
procedure TJvDivider.SetKind(Value: TJvDivideKind);
begin
if FKind <> Value then
begin
FKind := Value;
Invalidate;
end;
end;
procedure TJvDivider.Paint;
var
R: TRect;
begin
if not Visible then
Exit;
if FKind = dkDivider then
with Canvas do
begin
if FVertical then
begin
R := Rect(Width div 2 - 1, 1, Width, Height - 1);
DrawEdge(Handle, R, EDGE_ETCHED, BF_LEFT);
end
else
begin
R := Rect(1, Height div 2 - 1, Width, Height - 1);
DrawEdge(Handle, R, EDGE_ETCHED, BF_TOP);
end;
end;
if csDesigning in ComponentState then
with Canvas do
begin
Pen.Style := psDot;
Pen.Color := clBtnShadow;
Brush.Style := bsClear;
Rectangle(0, 0, ClientWidth, ClientHeight);
end;
end;
//=== { TJvScrollButton } ====================================================
constructor TJvScrollButton.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := ControlStyle - [csDoubleClicks, csSetCaption];
FDown := False;
FIncrement := 16;
FAutoRepeat := False;
FFlat := False;
FKind := sbUp;
Width := 16;
Height := 16;
end;
procedure TJvScrollButton.SetKind(Value: TJvScrollKind);
begin
if FKind <> Value then
begin
FKind := Value;
Invalidate;
end;
end;
procedure TJvScrollButton.SetFlat(Value: Boolean);
begin
if FFlat <> Value then
begin
FFlat := Value;
Invalidate;
end;
end;
procedure TJvScrollButton.MouseEnter(Control: TControl);
begin
if csDesigning in ComponentState then
Exit;
if not MouseOver then
begin
inherited MouseEnter(Control);
if FFlat then
Invalidate;
end;
end;
procedure TJvScrollButton.MouseLeave(Control: TControl);
begin
if MouseOver then
begin
FDown := False;
inherited MouseLeave(Control);
if FFlat then
Invalidate;
end;
end;
procedure TJvScrollButton.Paint;
const
Kinds: array [TJvScrollKind] of Integer =
(DFCS_SCROLLUP, DFCS_SCROLLDOWN, DFCS_SCROLLLEFT, DFCS_SCROLLRIGHT);
var
Flags: Integer;
R: TRect;
begin
if not Visible then
Exit;
R := GetClientRect;
Flags := Kinds[FKind];
if not Enabled then
begin
FDown := False;
MouseOver := False;
Flags := Flags or DFCS_INACTIVE or DFCS_FLAT;
end;
if FDown then
Flags := Flags or DFCS_PUSHED;
if FFlat and not MouseOver then
Flags := Flags or DFCS_FLAT;
if MouseOver then
begin
if FKind in [sbUp, sbDown] then
OffsetRect(R, 0, 1)
else
OffsetRect(R, 1, 0);
end;
DrawFrameControl(Canvas.Handle, R, DFC_SCROLL, Flags);
Frame3D(Canvas, R, clBtnFace, clBtnFace, 1);
if FDown then
Frame3D(Canvas, R, clBtnShadow, clBtnHighLight, 1);
end;
procedure TJvScrollButton.Click;
begin
if Enabled then
begin
inherited Click;
ReleaseCapture;
end;
end;
procedure TJvScrollButton.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
FDown := True;
inherited MouseDown(Button, Shift, X, Y);
{ AutoRepeat }
if Parent is TJvCustomScrollPanel then
FAutoRepeat := (Parent as TJvCustomScrollPanel).AutoRepeat;
if FAutoRepeat then
begin
if not Assigned(FTimer) then
FTimer := TTimer.Create(Self);
with FTimer do
begin
OnTimer := OnTime;
Interval := cInitTime;
Enabled := True;
end;
end;
Repaint;
end;
procedure TJvScrollButton.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if not FRepeat then
SetPosition;
FRepeat := False;
inherited MouseUp(Button, Shift, X, Y);
FreeAndNil(FTimer);
FDown := False;
Repaint;
end;
procedure TJvScrollButton.SetPosition;
var
AllowScroll: Boolean;
Sp: TJvCustomScrollPanel;
begin
if (Parent = nil) or not (Parent is TJvCustomScrollPanel) or not Parent.Visible then
Exit;
Sp := TJvCustomScrollPanel(Parent);
AllowScroll := True;
if Assigned(Sp.OnScrolling) then
Sp.OnScrolling(Self, AllowScroll, FKind);
if not AllowScroll then
Exit;
case FKind of
sbUp:
Sp.ScrollBy(0, FIncrement);
sbDown:
Sp.ScrollBy(0, -FIncrement);
sbLeft:
Sp.ScrollBy(FIncrement, 0);
sbRight:
Sp.ScrollBy(-FIncrement, 0);
end;
if Assigned(Sp.OnScrolled) then
Sp.OnScrolled(Self, FKind);
Sp.UpdateVisible;
end;
procedure TJvScrollButton.OnTime(Sender: TObject);
begin
FTimer.Interval := cTimeDelay;
if FDown and MouseCapture then
begin
SetPosition;
FRepeat := True;
if Parent <> nil then
Parent.Invalidate;
end;
end;
procedure TJvScrollButton.EnabledChanged;
begin
inherited EnabledChanged;
if Assigned(Parent) then
Enabled := Parent.Enabled;
Invalidate;
end;
//=== { TJvCustomScrollPanel } ===============================================
constructor TJvCustomScrollPanel.Create(AOwner: TComponent);
begin
// We must set the csCreating flag ourselves into ControlState so that
// other functions can use it. In particular, the Notification method called
// by one of the inherited Create constructors must see it so as to not call
// Invalidate. If it calls it during creation, it triggers a big AV.
// Note that it doesn't seem that the VCL uses that flag itself.
ControlState := ControlState + [csCreating];
try
inherited Create(AOwner);
// this is very strange: without it I get a "Control '' has no parent window" error
// when dropping it in design-time. Never seen the need before
// (rom) probably assigning Align causes it. That needs a parent.
if AOwner is TWinControl then
Parent := TWinControl(AOwner);
ControlStyle := ControlStyle + [csAcceptsControls];
IncludeThemeStyle(Self, [csParentBackground]);
BevelInner := bvRaised;
BevelOuter := bvNone;
BevelKind := bkTile;
FScrollDirection := sdHorizontal;
FScrollAmount := 16;
Align := alTop;
Height := 35;
SetupArrows;
finally
ControlState := ControlState - [csCreating];
end;
end;
procedure TJvCustomScrollPanel.AlignArrows;
begin
if FUpLeft = nil then
Exit;
case FScrollDirection of
sdVertical:
begin
FUpLeft.Kind := sbUp;
FUpLeft.SetBounds(0, 0, ClientWidth, 16);
// FUpLeft.Anchors := [akTop, akLeft, akRight];
FUpLeft.Align := alTop;
FDownRight.Kind := sbDown;
FDownRight.SetBounds(0, ClientHeight - 16, ClientWidth, 16);
// FDownRight.Anchors := [akLeft, akRight, akBottom];
FDownRight.Align := alBottom;
end;
sdHorizontal:
begin
FUpLeft.Kind := sbLeft;
FUpLeft.SetBounds(0, 0, 16, ClientHeight);
// FUpLeft.Anchors := [akTop, akLeft, akBottom];
FUpLeft.Align := alLeft;
FDownRight.Kind := sbRight;
FDownRight.SetBounds(ClientWidth - 16, 0, 16, ClientHeight);
// FDownRight.Anchors := [akTop, akRight, akBottom];
FDownRight.Align := alRight;
end;
end;
UpdateVisible;
end;
procedure TJvCustomScrollPanel.SetAutoArrange(Value: Boolean);
begin
if FAutoArrange <> Value then
FAutoArrange := Value;
end;
procedure TJvCustomScrollPanel.SetAutoHide(Value: Boolean);
begin
if FAutoHide <> Value then
begin
FAutoHide := Value;
UpdateVisible;
Invalidate;
end;
end;
procedure TJvCustomScrollPanel.SetScrollAmount(const Value: Word);
begin
if FScrollAmount <> Value then
begin
FScrollAmount := Value;
if Assigned(FUpLeft) then
FUpLeft.Increment := Value;
if Assigned(FDownRight) then
FDownRight.Increment := Value;
end;
end;
procedure TJvCustomScrollPanel.SetScrollDirection(Value: TJvScrollDirection);
begin
if FScrollDirection <> Value then
begin
FScrollDirection := Value;
if FAutoArrange then
ArrangeChildren;
Invalidate;
AlignArrows;
UpdateVisible;
AlignArrows;
end;
end;
procedure TJvCustomScrollPanel.ArrangeChildren;
var
I: Integer;
begin
if FUpLeft = nil then
Exit;
DisableAlign;
try
for I := 0 to ControlCount - 1 do
if (Controls[I] <> FUpLeft) and (Controls[I] <> FDownRight) then
Controls[I].SetBounds(Controls[I].Top, Controls[I].Left, Controls[I].Height, Controls[I].Width);
if not (csLoading in ComponentState) and (Align = alNone) then
SetBounds(0, 0, Height, Width);
finally
EnableAlign;
end;
end;
procedure TJvCustomScrollPanel.UpdateVisible;
var
Less, More, I: Integer;
begin
if FUpLeft = nil then
Exit;
DisableAlign;
try
if FAutoHide then
begin
if FScrollDirection = sdVertical then
begin
Less := ClientWidth;
More := 0;
for I := 0 to ControlCount - 1 do
if (Controls[I] <> FUpLeft) and (Controls[I] <> FDownRight) and Controls[I].Visible then
begin
Less := Min(Controls[I].Top, Less);
More := Max(Controls[I].Top + Controls[I].Height, More);
end;
FUpLeft.Visible := Less < 0;
FDownRight.Visible := More > ClientHeight;
end
else
if FScrollDirection = sdHorizontal then
begin
Less := ClientHeight;
More := 0;
for I := 0 to ControlCount - 1 do
if (Controls[I] <> FUpLeft) and (Controls[I] <> FDownRight) and Controls[I].Visible then
begin
Less := Min(Controls[I].Left, Less);
More := Max(Controls[I].Left + Controls[I].Width, More);
end;
FUpLeft.Visible := Less < 0;
FDownRight.Visible := More > ClientWidth;
end
end
else { always show }
begin
FUpLeft.Visible := True;
FDownRight.Visible := True;
end;
finally
EnableAlign;
end;
end;
procedure TJvCustomScrollPanel.SetFlat(Value: Boolean);
begin
if FFlat <> Value then
begin
FFlat := Value;
if FUpLeft <> nil then
begin
FUpLeft.Flat := FFlat;
FDownRight.Flat := FFlat;
end;
Invalidate;
end;
end;
procedure TJvCustomScrollPanel.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
inherited SetBounds(ALeft, ATop, AWidth, AHeight);
AlignArrows;
UpdateVisible;
end;
procedure TJvCustomScrollPanel.SetupArrows;
begin
if FUpLeft <> nil then
Exit;
FUpLeft := TJvScrollButton.Create(Self);
FUpLeft.FreeNotification(Self);
FUpLeft.Kind := sbLeft;
FDownRight := TJvScrollButton.Create(Self);
FDownRight.FreeNotification(Self);
FDownRight.Kind := sbRight;
end;
procedure TJvCustomScrollPanel.SetParent( AParent: TWinControl);
begin
inherited SetParent(AParent);
if FUpLeft = nil then
Exit;
FUpLeft.Parent := Self;
FUpLeft.Visible := True;
FDownRight.Parent := Self;
FDownRight.Visible := True;
end;
procedure TJvCustomScrollPanel.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if Operation = opRemove then
begin
if AComponent = FUpLeft then
FUpLeft := nil;
if AComponent = FDownRight then
FDownRight := nil;
end;
// If we invalidate while creating, it triggers a series of exceptions
// leading to an access violation at 0000000
// Note that csCreating is specifically added to ControlState in the
// constructor for Notification to be able to use
if not (csCreating in ControlState) then
Invalidate;
end;
procedure TJvCustomScrollPanel.EnabledChanged;
begin
inherited EnabledChanged;
if FUpLeft = nil then
Exit;
FUpLeft.Enabled := Enabled;
FDownRight.Enabled := Enabled;
if AutoHide then
UpdateVisible
else
Invalidate;
end;
procedure TJvCustomScrollPanel.VisibleChanged;
begin
inherited VisibleChanged;
if FUpLeft = nil then
Exit;
FUpLeft.Visible := Visible;
FDownRight.Visible := Visible;
end;
//=== { TJvScrollingWindow } =================================================
constructor TJvScrollingWindow.Create(AComponent: TComponent);
begin
inherited Create(AComponent);
AutoHide := True;
AutoRepeat := False;
ScrollDirection := sdHorizontal;
end;
{$IFDEF UNITVERSIONING}
initialization
RegisterUnitVersion(HInstance, UnitVersioning);
finalization
UnregisterUnitVersion(HInstance);
{$ENDIF UNITVERSIONING}
end.