home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 September
/
Chip_2001-09_cd1.bin
/
zkuste
/
delphi
/
kolekce
/
d6
/
RX275D6.ZIP
/
Units
/
RXSPLIT.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1999-10-12
|
17KB
|
565 lines
{*******************************************************}
{ }
{ Delphi VCL Extensions (RX) }
{ }
{ Copyright (c) 1995, 1996 AO ROSNO }
{ Copyright (c) 1997 Master-Bank }
{ }
{*******************************************************}
unit RXSplit;
interface
{$I RX.INC}
uses Classes, {$IFDEF WIN32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF}
Controls, ExtCtrls, Forms, Graphics, VCLUtils;
type
{ TRxSplitter }
TSplitterStyle = (spUnknown, spHorizontalFirst, spHorizontalSecond,
spVerticalFirst, spVerticalSecond);
TInverseMode = (imNew, imClear, imMove);
TSplitterMoveEvent = procedure (Sender: TObject; X, Y: Integer;
var AllowChange: Boolean) of object;
TRxSplitter = class(TCustomPanel)
private
FControlFirst: TControl;
FControlSecond: TControl;
FSizing: Boolean;
FStyle: TSplitterStyle;
FPrevOrg: TPoint;
FOffset: TPoint;
FNoDropCursor: Boolean;
FLimitRect: TRect;
FTopLeftLimit: Integer;
FBottomRightLimit: Integer;
FForm: TCustomForm;
FActiveControl: TWinControl;
FAppShowHint: Boolean;
FOldKeyDown: TKeyEvent;
FOnPosChanged: TNotifyEvent;
FOnPosChanging: TSplitterMoveEvent;
function FindControl: TControl;
procedure ControlKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure StartInverseRect;
procedure EndInverseRect(X, Y: Integer; AllowChange, Apply: Boolean);
function GetAlign: TAlign;
procedure MoveInverseRect(X, Y: Integer; AllowChange: Boolean);
procedure ShowInverseRect(X, Y: Integer; Mode: TInverseMode);
procedure DrawSizingLine(Split: TPoint);
function GetStyle: TSplitterStyle;
function GetCursor: TCursor;
procedure SetControlFirst(Value: TControl);
procedure SetControlSecond(Value: TControl);
procedure SetAlign(Value: TAlign);
procedure StopSizing(X, Y: Integer; Apply: Boolean);
procedure CheckPosition(var X, Y: Integer);
procedure ReadOffset(Reader: TReader);
procedure WriteOffset(Writer: TWriter);
protected
procedure DefineProperties(Filer: TFiler); override;
procedure Loaded; override;
procedure Notification(AComponent: TComponent; AOperation: TOperation); override;
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 Changed; dynamic;
procedure Changing(X, Y: Integer; var AllowChange: Boolean); dynamic;
public
constructor Create(AOwner: TComponent); override;
procedure UpdateState;
published
property ControlFirst: TControl read FControlFirst write SetControlFirst;
property ControlSecond: TControl read FControlSecond write SetControlSecond;
property Align: TAlign read GetAlign write SetAlign default alNone;
{$IFDEF RX_D4}
property Constraints;
{$ENDIF}
property BevelInner;
property BevelOuter;
property BevelWidth;
property BorderStyle;
property Enabled;
property Color;
property Ctl3D {$IFDEF WIN32} default False {$ENDIF};
property Cursor read GetCursor stored False;
property TopLeftLimit: Integer read FTopLeftLimit write FTopLeftLimit default 20;
property BottomRightLimit: Integer read FBottomRightLimit write FBottomRightLimit default 20;
property ParentColor;
property ParentCtl3D default False;
property ParentShowHint;
property ShowHint;
property Visible;
property OnPosChanged: TNotifyEvent read FOnPosChanged write FOnPosChanged;
property OnPosChanging: TSplitterMoveEvent read FOnPosChanging write FOnPosChanging;
property OnClick;
property OnDblClick;
property OnEnter;
property OnExit;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnResize;
end;
implementation
uses SysUtils;
const
InverseThickness = 2;
DefWidth = 3;
function CToC(C1, C2: TControl; P: TPoint): TPoint;
begin
Result := C1.ScreenToClient(C2.ClientToScreen(P));
end;
type
THack = class(TWinControl);
{ TRxSplitter }
constructor TRxSplitter.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := [csAcceptsControls, csCaptureMouse, csClickEvents,
csOpaque, csDoubleClicks];
Width := 185;
Height := DefWidth;
FSizing := False;
FTopLeftLimit := 20;
FBottomRightLimit := 20;
FControlFirst := nil;
FControlSecond := nil;
ParentCtl3D := False;
{$IFDEF WIN32}
Ctl3D := False;
{$ENDIF}
end;
procedure TRxSplitter.Loaded;
begin
inherited Loaded;
UpdateState;
end;
procedure TRxSplitter.DefineProperties(Filer: TFiler); { for backward compatibility }
begin
inherited DefineProperties(Filer);
Filer.DefineProperty('LimitOffset', ReadOffset, WriteOffset, False);
end;
procedure TRxSplitter.ReadOffset(Reader: TReader);
var
I: Integer;
begin
I := Reader.ReadInteger;
FTopLeftLimit := I;
FBottomRightLimit := I;
end;
procedure TRxSplitter.WriteOffset(Writer: TWriter);
begin
Writer.WriteInteger(FTopLeftLimit);
end;
procedure TRxSplitter.UpdateState;
begin
inherited Cursor := Cursor;
end;
function TRxSplitter.FindControl: TControl;
var
P: TPoint;
I: Integer;
begin
Result := nil;
P := Point(Left, Top);
case Align of
alLeft: Dec(P.X);
alRight: Inc(P.X, Width);
alTop: Dec(P.Y);
alBottom: Inc(P.Y, Height);
else Exit;
end;
for I := 0 to Parent.ControlCount - 1 do begin
Result := Parent.Controls[I];
if PtInRect(Result.BoundsRect, P) then Exit;
end;
Result := nil;
end;
procedure TRxSplitter.CheckPosition(var X, Y: Integer);
begin
if X - FOffset.X < FLimitRect.Left then
X := FLimitRect.Left + FOffset.X
else if X - FOffset.X + Width > FLimitRect.Right then
X := FLimitRect.Right - Width + FOffset.X;
if Y - FOffset.Y < FLimitRect.Top then
Y := FLimitRect.Top + FOffset.Y
else if Y - FOffset.Y + Height > FLimitRect.Bottom then
Y := FLimitRect.Bottom + FOffset.Y - Height;
end;
procedure TRxSplitter.StartInverseRect;
var
R: TRect;
W: Integer;
begin
if Parent = nil then Exit;
R := Parent.ClientRect;
FLimitRect.TopLeft := CToC(Self, Parent, Point(R.Left + FTopLeftLimit,
R.Top + FTopLeftLimit));
FLimitRect.BottomRight := CToC(Self, Parent, Point(R.Right - R.Left -
FBottomRightLimit, R.Bottom - R.Top - FBottomRightLimit));
FNoDropCursor := False;
FForm := ValidParentForm(Self);
FForm.Canvas.Handle := GetDCEx(FForm.Handle, 0, DCX_CACHE or DCX_CLIPSIBLINGS
or DCX_LOCKWINDOWUPDATE);
with FForm.Canvas do begin
Pen.Color := clWhite;
if FStyle in [spHorizontalFirst, spHorizontalSecond] then W := Height
else W := Width;
if W > InverseThickness + 1 then W := W - InverseThickness
else W := InverseThickness;
Pen.Width := W;
Pen.Mode := pmXOR;
end;
ShowInverseRect(Width div 2, Height div 2, imNew);
end;
procedure TRxSplitter.EndInverseRect(X, Y: Integer; AllowChange,
Apply: Boolean);
const
DecSize = 3;
var
NewSize: Integer;
Rect: TRect;
W, H: Integer;
DC: HDC;
P: TPoint;
begin
if FForm <> nil then begin
ShowInverseRect(0, 0, imClear);
with FForm do begin
DC := Canvas.Handle;
Canvas.Handle := 0;
ReleaseDC(Handle, DC);
end;
FForm := nil;
end;
FNoDropCursor := False;
if Parent = nil then Exit;
Rect := Parent.ClientRect;
H := Rect.Bottom - Rect.Top - Height;
W := Rect.Right - Rect.Left - Width;
if not AllowChange then begin
P := ScreenToClient(FPrevOrg);
X := P.X + FOffset.X - Width div 2;
Y := P.Y + FOffset.Y - Height div 2
end;
if not Apply then Exit;
CheckPosition(X, Y);
if (ControlFirst.Align = alRight) or
((ControlSecond <> nil) and (ControlSecond.Align = alRight)) then
begin
X := -X;
FOffset.X := -FOffset.X;
end;
if (ControlFirst.Align = alBottom) or
((ControlSecond <> nil) and (ControlSecond.Align = alBottom)) then
begin
Y := -Y;
FOffset.Y := -FOffset.Y;
end;
Parent.DisableAlign;
try
if FStyle = spHorizontalFirst then begin
NewSize := ControlFirst.Height + Y - FOffset.Y;
if NewSize <= 0 then NewSize := 1;
if NewSize >= H then NewSize := H - DecSize;
ControlFirst.Height := NewSize;
end
else if FStyle = spHorizontalSecond then begin
NewSize := ControlSecond.Height + Y - FOffset.Y;
if NewSize <= 0 then NewSize := 1;
if NewSize >= H then NewSize := H - DecSize;
ControlSecond.Height := NewSize;
end
else if FStyle = spVerticalFirst then begin
NewSize := ControlFirst.Width + X - FOffset.X;
if NewSize <= 0 then NewSize := 1;
if NewSize >= W then NewSize := W - DecSize;
ControlFirst.Width := NewSize;
end
else if FStyle = spVerticalSecond then begin
NewSize := ControlSecond.Width + X - FOffset.X;
if NewSize <= 0 then NewSize := 1;
if NewSize >= W then NewSize := W - DecSize;
ControlSecond.Width := NewSize;
end;
finally
Parent.EnableAlign;
end;
end;
procedure TRxSplitter.MoveInverseRect(X, Y: Integer; AllowChange: Boolean);
var
P: TPoint;
NoDrop: Boolean;
begin
if not AllowChange then begin
SetCursor(Screen.Cursors[crNoDrop]);
Exit;
end;
P := Point(X, Y);
CheckPosition(X, Y);
NoDrop := not AllowChange or (((X <> P.X) and (FStyle in [spVerticalFirst,
spVerticalSecond])) or ((Y <> P.Y) and (FStyle in [spHorizontalFirst,
spHorizontalSecond])));
if NoDrop <> FNoDropCursor then begin
FNoDropCursor := NoDrop;
if NoDrop then SetCursor(Screen.Cursors[crNoDrop])
else SetCursor(Screen.Cursors[Cursor]);
end;
ShowInverseRect(X - FOffset.X + Width div 2, Y - FOffset.Y + Height div 2,
imMove);
end;
procedure TRxSplitter.ShowInverseRect(X, Y: Integer; Mode: TInverseMode);
var
P: TPoint;
MaxRect: TRect;
Horiz: Boolean;
begin
P := Point(0, 0);
if FStyle in [spHorizontalFirst, spHorizontalSecond] then begin
P.Y := Y;
Horiz := True;
end
else begin
P.X := X;
Horiz := False;
end;
MaxRect := Parent.ClientRect;
P := ClientToScreen(P);
with P, MaxRect do begin
TopLeft := Parent.ClientToScreen(TopLeft);
BottomRight := Parent.ClientToScreen(BottomRight);
if X < Left then X := Left;
if X > Right then X := Right;
if Y < Top then Y := Top;
if Y > Bottom then Y := Bottom;
end;
if (Mode = imMove) then
if ((P.X = FPrevOrg.X) and not Horiz) or
((P.Y = FPrevOrg.Y) and Horiz) then Exit;
if Mode in [imClear, imMove] then
DrawSizingLine(FPrevOrg);
if Mode in [imNew, imMove] then begin
DrawSizingLine(P);
FPrevOrg := P;
end;
end;
procedure TRxSplitter.DrawSizingLine(Split: TPoint);
var
P: TPoint;
begin
if FForm <> nil then begin
P := FForm.ScreenToClient(Split);
with FForm.Canvas do begin
MoveTo(P.X, P.Y);
if FStyle in [spHorizontalFirst, spHorizontalSecond] then
LineTo(CToC(FForm, Self, Point(Width, 0)).X, P.Y)
else LineTo(P.X, CToC(FForm, Self, Point(0, Height)).Y);
end;
end;
end;
function TRxSplitter.GetStyle: TSplitterStyle;
begin
Result := spUnknown;
if ControlFirst <> nil then begin
if ((ControlFirst.Align = alTop) and ((ControlSecond = nil) or
(ControlSecond.Align = alClient))) or
((ControlFirst.Align = alBottom) and ((ControlSecond = nil) or
(ControlSecond.Align = alClient))) then
Result := spHorizontalFirst
else if ((ControlFirst.Align = alClient) and (ControlSecond <> nil) and
(ControlSecond.Align = alBottom)) or
((ControlFirst.Align = alClient) and (ControlSecond <> nil) and
(ControlSecond.Align = alTop)) then
Result := spHorizontalSecond
else if ((ControlFirst.Align = alLeft) and ((ControlSecond = nil) or
(ControlSecond.Align = alClient))) or
((ControlFirst.Align = alRight) and ((ControlSecond = nil) or
(ControlSecond.Align = alClient))) then
Result := spVerticalFirst
else if ((ControlFirst.Align = alClient) and (ControlSecond <> nil) and
(ControlSecond.Align = alRight)) or
((ControlFirst.Align = alClient) and (ControlSecond <> nil) and
(ControlSecond.Align = alLeft)) then
Result := spVerticalSecond;
case Result of
spHorizontalFirst, spVerticalFirst:
if Align <> FControlFirst.Align then Result := spUnknown;
spHorizontalSecond, spVerticalSecond:
if Align <> FControlSecond.Align then Result := spUnknown;
end;
end;
end;
procedure TRxSplitter.SetAlign(Value: TAlign);
begin
if not (Align in [alTop, alBottom, alLeft, alRight]) then begin
inherited Align := Value;
if not (csReading in ComponentState) then begin
if Value in [alTop, alBottom] then Height := DefWidth
else if Value in [alLeft, alRight] then Width := DefWidth;
end;
end
else inherited Align := Value;
if (ControlFirst = nil) and (ControlSecond = nil) then
ControlFirst := FindControl;
end;
function TRxSplitter.GetAlign: TAlign;
begin
Result := inherited Align;
end;
function TRxSplitter.GetCursor: TCursor;
begin
Result := crDefault;
case GetStyle of
spHorizontalFirst, spHorizontalSecond: Result := crVSplit;
spVerticalFirst, spVerticalSecond: Result := crHSplit;
end;
end;
procedure TRxSplitter.SetControlFirst(Value: TControl);
begin
if Value <> FControlFirst then begin
if (Value = Self) or (Value is TForm) then FControlFirst := nil
else begin
FControlFirst := Value;
{$IFDEF WIN32}
if Value <> nil then Value.FreeNotification(Self);
{$ENDIF}
end;
UpdateState;
end;
end;
procedure TRxSplitter.SetControlSecond(Value: TControl);
begin
if Value <> FControlSecond then begin
if (Value = Self) or (Value is TForm) then FControlSecond := nil
else begin
FControlSecond := Value;
{$IFDEF WIN32}
if Value <> nil then Value.FreeNotification(Self);
{$ENDIF}
end;
UpdateState;
end;
end;
procedure TRxSplitter.Notification(AComponent: TComponent; AOperation: TOperation);
begin
inherited Notification(AComponent, AOperation);
if AOperation = opRemove then begin
if AComponent = ControlFirst then ControlFirst := nil
else if AComponent = ControlSecond then ControlSecond := nil;
end;
end;
procedure TRxSplitter.Changed;
begin
if Assigned(FOnPosChanged) then FOnPosChanged(Self);
end;
procedure TRxSplitter.Changing(X, Y: Integer; var AllowChange: Boolean);
begin
if Assigned(FOnPosChanging) then FOnPosChanging(Self, X, Y, AllowChange);
end;
procedure TRxSplitter.StopSizing(X, Y: Integer; Apply: Boolean);
var
AllowChange: Boolean;
begin
if FSizing then begin
ReleaseCapture;
AllowChange := Apply;
if Apply then Changing(X, Y, AllowChange);
EndInverseRect(X, Y, AllowChange, Apply);
FSizing := False;
Application.ShowHint := FAppShowHint;
if Assigned(FActiveControl) then begin
THack(FActiveControl).OnKeyDown := FOldKeyDown;
FActiveControl := nil;
end;
if Apply then Changed;
end;
end;
procedure TRxSplitter.ControlKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if Key = VK_ESCAPE then StopSizing(0, 0, False)
else if Assigned(FOldKeyDown) then FOldKeyDown(Sender, Key, Shift);
end;
procedure TRxSplitter.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited MouseDown(Button, Shift, X, Y);
if not (csDesigning in ComponentState) and (Button = mbLeft) then begin
FStyle := GetStyle;
if FStyle <> spUnknown then begin
FSizing := True;
FAppShowHint := Application.ShowHint;
SetCapture(Handle);
with ValidParentForm(Self) do begin
if ActiveControl <> nil then FActiveControl := ActiveControl
else FActiveControl := GetParentForm(Self);
FOldKeyDown := THack(FActiveControl).OnKeyDown;
THack(FActiveControl).OnKeyDown := ControlKeyDown;
end;
Application.ShowHint := False;
FOffset := Point(X, Y);
StartInverseRect;
end;
end;
end;
procedure TRxSplitter.MouseMove(Shift: TShiftState; X, Y: Integer);
var
AllowChange: Boolean;
begin
inherited MouseMove(Shift, X, Y);
if (GetCapture = Handle) and FSizing then begin
AllowChange := True;
Changing(X, Y, AllowChange);
MoveInverseRect(X, Y, AllowChange);
end;
end;
procedure TRxSplitter.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
StopSizing(X, Y, True);
inherited MouseUp(Button, Shift, X, Y);
end;
end.