lazarus/lcl/include/customsplitter.inc

912 lines
27 KiB
PHP

{%MainUnit ../extctrls.pp}
{******************************************************************************
TCustomSplitter
******************************************************************************
*****************************************************************************
* *
* This file is part of the Lazarus Component Library (LCL) *
* *
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
* for details about the copyright. *
* *
* 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. *
* *
*****************************************************************************
}
function FindOppositeControl(Control: TControl): TControl;
var
i,count: Integer;
CurControl: TControl;
fRect: TRect;
fPoint: TPoint;
alignList: TAlignSet;
begin
Result := nil;
count := Control.Parent.ControlCount;
if count > 0 then begin
fRect := Control.BoundsRect;
case Control.Align of
alTop: begin
fPoint := fRect.BottomRight;
fPoint.y := fPoint.y+1;
Dec(fPoint.x);
alignList := [alTop,alRight,alClient];
end;
alBottom: begin
fPoint := fRect.TopLeft;
Dec(fPoint.y);
alignList := [alLeft,alBottom,alClient];
end;
alLeft: begin
fPoint := fRect.BottomRight;
Inc(fPoint.x);
Dec(fPoint.y);
alignList := [alLeft,alClient];
end;
alRight: begin
fPoint := fRect.TopLeft;
Dec(fPoint.x);
alignList := [alRight,alClient];
end;
end; // case
Dec(count);
for i := 0 to count do begin
CurControl := Control.Parent.Controls[i];
if (CurControl <> Control)
and CurControl.Visible
and (CurControl.Align in alignList)
and (PtInRect(CurControl.BoundsRect, fPoint))
then Result := CurControl;
if Assigned(Result) then Break;
end; // for i
end;
end;
function FindVirtualOppositeControl(Control: TControl): TControl;
function CompPos(CurControl, Control: TControl): Boolean;
begin
Result := False;
case Control.Align of
alTop:
if (CurControl.Align = Control.Align)
and (CurControl.Top >= Control.BoundsRect.Bottom)
then Result := True;
alBottom:
if (CurControl.Align = Control.Align)
and (CurControl.BoundsRect.Bottom <= Control.Top)
then Result := True;
alLeft:
if (CurControl.Align = Control.Align)
and (CurControl.Left >= Control.BoundsRect.Right)
then Result := True;
alRight:
if (CurControl.Align = Control.Align)
and (CurControl.BoundsRect.Right <= Control.Left)
then Result := True;
end;
end;
function OppositeControl(CurControl,Control: TControl): Boolean;
begin
Result := False;
case Control.Align of
alLeft: if (CurControl.Align = alRight) then Result := True;
alRight: if (CurControl.Align = alLeft) then Result := True;
alTop: if (CurControl.Align = alBottom) then Result := True;
alBottom: if (CurControl.Align = alTop) then Result := True;
end;
end;
var
i,count: Integer;
CurControl: TControl;
begin
Result := nil;
count := Control.Parent.ControlCount;
if count > 0 then begin
Dec(count);
for i := 0 to count do begin
CurControl := Control.Parent.Controls[i];
if (CurControl <> Control) then begin
if ((Result = nil) and OppositeControl(CurControl, Control))
or (Assigned(Result) and CompPos(CurControl, Result))
then Result := CurControl;
end;
end; // for i
end;
end;
{ TCustomSplitter }
procedure TCustomSplitter.SetResizeStyle(const AValue: TResizeStyle);
begin
if FResizeStyle=AValue then exit;
FResizeStyle:=AValue;
end;
class procedure TCustomSplitter.WSRegisterClass;
begin
inherited WSRegisterClass;
RegisterCustomSplitter;
end;
procedure TCustomSplitter.SetAutoSnap(const AValue: boolean);
begin
if FAutoSnap=AValue then exit;
FAutoSnap:=AValue;
end;
function TCustomSplitter.GetResizeControl: TControl;
begin
if Align in [alLeft,alRight,alTop,alBottom] then
Result:=FindAlignControl
else
Result:=AnchorSide[ResizeAnchor].Control;
end;
function TCustomSplitter.GetOtherResizeControl: TControl;
begin
if Align in [alLeft,alRight,alTop,alBottom] then
Result:=FindAlignOtherControl
else
Result:=AnchorSide[OppositeAnchor[ResizeAnchor]].Control;
end;
procedure TCustomSplitter.MoveSplitter(Offset: integer);
var
CurResizeControl,
LastControl, VirtualOppositeControl, CurOtherResizeControl: TControl;
function GetParentClientSize: Integer;
begin
case ResizeAnchor of
akLeft, akRight: Result := Parent.ClientWidth;
akTop, akBottom: Result := Parent.ClientHeight;
end;
end;
function GetControlMinPos(Control: TControl): Integer;
begin
if Assigned(Control)
then
case ResizeAnchor of
akLeft,akRight: Result := Control.Left;
akTop,akBottom: Result := Control.Top;
end
else
case ResizeAnchor of
akLeft,akTop: Result := 0;
akRight,akBottom: Result := GetParentClientSize;
end;
end;
function GetControlSize(Control: TControl): Integer;
begin
Result := 0;
if Assigned(Control)
then case ResizeAnchor of
akLeft, akRight: Result := Control.Width;
akTop, akBottom: Result := Control.Height;
end;
end;
function GetControlConstraintsMinSize(Control: TControl): Integer;
begin
case ResizeAnchor of
akLeft, akRight: Result := Control.Constraints.EffectiveMinWidth;
akTop, akBottom: Result := Control.Constraints.EffectiveMinHeight;
end;
end;
function GetControlConstraintsMaxSize(Control: TControl): Integer;
begin
case ResizeAnchor of
akLeft, akRight: Result := Control.Constraints.EffectiveMaxWidth;
akTop, akBottom: Result := Control.Constraints.EffectiveMaxHeight;
end;
end;
procedure SetAlignControlSize(NewSize: Integer);
var
NewBounds: TRect;
begin
NewBounds:=CurResizeControl.BoundsRect;
//DebugLn('SetAlignControlSize ',DbgSName(Self),' CurResizeControl=',DbgSName(CurResizeControl),' OldBounds=',dbgs(NewBounds),' NewSize=',dbgs(NewSize));
case ResizeAnchor of
akLeft:
NewBounds.Right := NewBounds.Left+NewSize;
akRight:
NewBounds.Left := NewBounds.Right-NewSize;
akTop:
NewBounds.Bottom := NewBounds.Top+NewSize;
akBottom:
NewBounds.Top := NewBounds.Bottom-NewSize;
end;
//DebugLn('SetAlignControlSize ',DbgSName(Self),' CurResizeControl=',DbgSName(CurResizeControl),' NewBounds=',dbgs(NewBounds));
CurResizeControl.BoundsRect:=NewBounds;
//DebugLn('SetAlignControlSize ',DbgSName(Self),' CurResizeControl=',DbgSName(CurResizeControl),' NowBounds=',dbgs(CurResizeControl.BoundsRect));
end;
function CalcNewSize(StartSize, EndSize, Offset: Integer): Integer;
var
NewSize: Integer;
begin
NewSize := GetControlSize(CurResizeControl);
case ResizeAnchor of
akLeft, akTop: Inc(NewSize, Offset);
akRight, akBottom: Dec(NewSize, Offset);
end;
if NewSize > EndSize then NewSize := EndSize;
if NewSize < StartSize then NewSize := StartSize;
if fAutoSnap and (NewSize < fMinSize)
then NewSize := StartSize;
Result := NewSize;
end;
function GetVirtualControlMinPos(Control: TControl): Integer;
begin
case ResizeAnchor of
akLeft: Result := Control.Left;
akRight: Result := Control.BoundsRect.Right;
akTop: Result := Control.Top;
akBottom: Result := Control.BoundsRect.Bottom;
end;
end;
function FindClientControl: TControl;
var
CurControl: TControl;
count: Integer;
begin
Result := nil;
for count := Parent.ControlCount-1 downto 0 do begin
CurControl := Parent.Controls[count];
if (CurControl <> Self)
and ((CurControl.Align = alClient)
or ((Self.Align in [alTop,alBottom])
and (CurControl.Align in [alLeft,alRight]))) then begin
Result := CurControl;
Break;
end;
end; // for count
end; // function FindClientControl
function FindLastControl(Control: TControl): TControl;
var
CurControl: TControl;
begin
CurControl := Control;
while Assigned(CurControl) do begin
Control := CurControl;
CurControl := FindOppositeControl(Control);
end;
Result := Control;
end;
function GetParentsClientLimit: integer;
// returns the maximum size of the CurResizeControl due to parent's client
// area
begin
if ResizeAnchor in [akLeft,akRight] then begin
if ResizeAnchor=akRight then
Result:=CurResizeControl.Left+CurResizeControl.Width-Width
else
Result:=Parent.ClientWidth-CurResizeControl.Left-Width;
end else begin
if ResizeAnchor=akBottom then
Result:=CurResizeControl.Top+CurResizeControl.Height-Height
else
Result:=Parent.ClientHeight-CurResizeControl.Top-Height;
end;
end;
function GetParentsClientSize: integer;
begin
if ResizeAnchor in [akLeft,akRight] then
Result:=Parent.ClientWidth
else
Result:=Parent.ClientHeight;
end;
var
StartSize: Integer;
EndSize: Integer;
NewSize: Integer;
i: Integer;
OffsetMaxLower: integer;
OffsetMaxUpper: integer;
CurMaxShrink: integer;
CurMaxEnlarge: integer;
begin
//DebugLn('TCustomSplitter.MoveSplitter ',DbgSName(Self),' Offset=',dbgs(Offset));
if Offset = 0 then Exit;
if Align in [alLeft,alTop,alRight,alBottom] then begin
// aligned Splitter
// -> consider aligned siblings for minimum and maximum movement
// get the control to resize
CurResizeControl := GetResizeControl;
if not Assigned(CurResizeControl) then Exit;
CurOtherResizeControl := GetOtherResizeControl;
// calculate minimum size
StartSize := 1;
if not fAutoSnap
then Inc(StartSize,
Max(fMinSize, GetControlConstraintsMinSize(CurResizeControl)));
if StartSize > 1 then Dec(StartSize);
// calculate maximum size
if Assigned(CurOtherResizeControl)
then EndSize := GetControlSize(CurResizeControl)
+ GetControlSize(CurOtherResizeControl)
- Max(fMinSize, GetControlConstraintsMinSize(CurOtherResizeControl))
else begin
VirtualOppositeControl := FindVirtualOppositeControl(Self);
LastControl := FindLastControl(Self);
case ResizeAnchor of
akLeft, akTop: begin
if Assigned(VirtualOppositeControl) then
begin
EndSize := GetControlSize(CurResizeControl)
+ (GetControlMinPos(VirtualOppositeControl)
- (GetControlMinPos(LastControl)
+ GetControlSize(LastControl)));
end
else EndSize := GetControlSize(CurResizeControl)
+ (GetParentClientSize
- GetControlMinPos(LastControl)
- GetControlSize(LastControl))
end;
akRight, akBottom: begin
if Assigned(VirtualOppositeControl) then
EndSize := GetControlSize(CurResizeControl)
+ (GetControlMinPos(LastControl)
- (GetControlMinPos(VirtualOppositeControl)
+ GetControlSize(VirtualOppositeControl)))
else EndSize := GetControlSize(CurResizeControl)
+ GetControlMinPos(LastControl);
end;
end;
end;
//DebugLn('TCustomSplitter.MoveSplitter ',DbgSName(Self),' StartSize=',dbgs(StartSize),' EndSize=',dbgs(EndSize),' Offset=',dbgs(Offset));
NewSize := CalcNewSize(StartSize, EndSize, Offset);
// OnCanResize event
if CheckNewSize(NewSize)
then SetAlignControlSize(NewSize);
end else begin
// anchored Splitter
// -> consider anchored siblings for minimum and maximum movement
// OffsetMaxLower = maximum the Splitter can be moved top/left
OffsetMaxLower := Max(0,GetControlMinPos(Self)-fMinSize);
// OffsetMaxUpper = maximum the Splitter can be moved bottom/right
OffsetMaxUpper := Max(0,GetParentsClientSize
-GetControlSize(Self)-GetControlMinPos(Self));
//DebugLn(['TCustomSplitter.MoveSplitter OffsetMaxLower=',OffsetMaxLower,' OffsetMaxUpper=',OffsetMaxUpper]);
for i:=0 to AnchoredControlCount-1 do begin
CurResizeControl:=AnchoredControls[i];
//debugln('TCustomSplitter.MoveSplitter ',DbgSName(Self),' CurResizeControl=',DbgSName(CurResizeControl));
if (CurResizeControl.AnchorSide[ResizeAnchor].Control=Self)
or (CurResizeControl.AnchorSide[OppositeAnchor[ResizeAnchor]].Control=Self)
then begin
// this control uses this Splitter as anchor
// => moving the Splitter will resize CurResizeControl
// => consider the constraints of CurResizeControl
// for minimum and maximum movement
// calculate how much the CurResizeControl can be shrinked
CurMaxShrink:=Max(0,GetControlSize(CurResizeControl)-
GetControlConstraintsMinSize(CurResizeControl));
// calculate how much the CurResizeControl can be enlarged
CurMaxEnlarge:=Max(0,GetControlConstraintsMaxSize(CurResizeControl)
-GetControlSize(CurResizeControl));
if CurMaxEnlarge=0 then begin
CurMaxEnlarge:=GetParentsClientSize;
if GetControlMinPos(CurResizeControl)<0 then
dec(CurMaxEnlarge,GetControlMinPos(CurResizeControl));
end;
//debugln('TCustomSplitter.MoveSplitter ',DbgSName(Self),' CurResizeControl=',DbgSName(CurResizeControl),' CurMaxShrink=',dbgs(CurMaxShrink),' CurMaxEnlarge=',dbgs(CurMaxEnlarge),' ConstraintsMax=',dbgs(GetControlConstraintsMaxSize(CurResizeControl)));
// apply to the offset boundaries
if (CurResizeControl.AnchorSide[akLeft].Control=Self)
or (CurResizeControl.AnchorSide[akTop].Control=Self) then begin
if CurMaxShrink>0 then
OffsetMaxLower:=Min(OffsetMaxLower,CurMaxShrink);
if CurMaxEnlarge>0 then
OffsetMaxUpper:=Min(OffsetMaxUpper,CurMaxEnlarge);
end else begin
if CurMaxEnlarge>0 then
OffsetMaxLower:=Min(OffsetMaxLower,CurMaxEnlarge);
if CurMaxShrink>0 then
OffsetMaxUpper:=Min(OffsetMaxUpper,CurMaxShrink);
end;
end;
end;
// apply the offset boundaries to the offset
Offset:=Max(Min(Offset,OffsetMaxUpper),-OffsetMaxLower);
//DebugLn(['TCustomSplitter.MoveSplitter Offset=',Offset,' OffsetMaxLower=',OffsetMaxLower,' OffsetMaxUpper=',OffsetMaxUpper]);
// move splitter
if ResizeAnchor in [akLeft, akRight] then
Left := Left + Offset
else
Top := Top + Offset;
end;
end;
procedure TCustomSplitter.SetSplitterPosition(NewPosition: integer);
begin
//DebugLn('TCustomSplitter.SetSplitterPosition ',DbgSName(Self),' NewPosition=',dbgs(NewPosition),' ',dbgs(GetSplitterPosition));
MoveSplitter(NewPosition-GetSplitterPosition);
end;
function TCustomSplitter.GetSplitterPosition: integer;
begin
if ResizeAnchor in [akLeft,akRight] then
Result:=Left
else
Result:=Top;
end;
procedure TCustomSplitter.SetBeveled(const AValue: boolean);
begin
if FBeveled=AValue then exit;
FBeveled:=AValue;
Invalidate;
end;
procedure TCustomSplitter.SetMinSize(const AValue: integer);
begin
if (FMinSize=AValue) or (AValue<1) then exit;
FMinSize:=AValue;
end;
procedure TCustomSplitter.SetResizeAnchor(const AValue: TAnchorKind);
begin
if FResizeAnchor=AValue then exit;
FResizeAnchor:=AValue;
if ResizeAnchor in [akLeft,akRight] then
Cursor := crHSplit
else
Cursor := crVSplit;
if not (csLoading in ComponentState) then begin
Align:=alNone;
end;
end;
procedure TCustomSplitter.SetResizeControl(const AValue: TControl);
begin
if Align in [alLeft,alRight,alTop,alBottom] then begin
if AValue<>nil then begin
case Align of
alLeft: Left:=AValue.Left+1;
alTop: Top:=AValue.Top+1;
alRight: Left:=AValue.Left-1;
alBottom: Top:=AValue.Top-1;
end;
end;
end else begin
AnchorSide[ResizeAnchor].Control:=AValue;
end;
end;
procedure TCustomSplitter.StartSplitterMove(const MouseXY: TPoint);
begin
if FSplitDragging then exit;
FSplitDragging := True;
FSplitterStartMouseXY := MouseXY;
FSplitterStartLeftTop := Point(Left,Top);
if ResizeStyle in [rsLine, rsPattern] then
Invalidate;
end;
procedure TCustomSplitter.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
var
MousePos: TPoint;
begin
inherited MouseDown(Button, Shift, X, Y);
// While resizing X, Y are not valid. Use absolute mouse position.
GetCursorPos(MousePos);
StartSplitterMove(MousePos);
end;
procedure TCustomSplitter.MouseMove(Shift: TShiftState; X, Y: Integer);
var
Offset: Integer;
MousePos: TPoint;
begin
inherited MouseMove(Shift, X, Y);
if (ssLeft in Shift) and (Parent <> nil) and (FSplitDragging) then
begin
// While resizing X, Y are not valid. Use the absolute mouse position.
GetCursorPos(MousePos);
case ResizeAnchor of
akLeft, akRight:
Offset := (MousePos.X - FSplitterStartMouseXY.X)
- (Self.Left - FSplitterStartLeftTop.X);
akTop, akBottom:
Offset := (MousePos.Y - FSplitterStartMouseXY.Y)
- (Self.Top - FSplitterStartLeftTop.Y);
end;
if Offset = 0 then Exit;
MoveSplitter(Offset);
end;
end;
procedure TCustomSplitter.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
begin
inherited MouseUp(Button, Shift, X, Y);
if FSplitDragging then
begin
if Assigned(OnMoved) then OnMoved(Self);
FSplitDragging := False;
if ResizeStyle in [rsLine, rsPattern] then
Invalidate;
end;
end;
function TCustomSplitter.FindAlignControl: TControl;
var
i: Integer;
CurControl: TControl;
BestValue: integer;
procedure FindNearerControl(CurValue, Limit: integer);
begin
if (CurValue<=Limit)
and ((Result=nil) or (BestValue<CurValue)) then begin
BestValue:=CurValue;
Result:=CurControl;
end;
end;
begin
Result := nil;
BestValue:=0;
if (Parent = nil) then Exit;
if not (Align in [alLeft,alTop,alRight,alBottom]) then exit;
for i := Parent.ControlCount-1 downto 0 do begin
CurControl := Parent.Controls[i];
if (CurControl <> Self)
and (CurControl.Visible)
and ((CurControl.Align = Self.Align) or (CurControl.Align=alClient))
then begin
case Self.Align of
alLeft: FindNearerControl(CurControl.Left+CurControl.Width,Left);
alTop: FindNearerControl(CurControl.Top+CurControl.Height,Top);
alRight: FindNearerControl(-CurControl.Left,-Left-Width);
alBottom: FindNearerControl(-CurControl.Top,-Top-Height);
end;
end;
end;
end;
function TCustomSplitter.FindAlignOtherControl: TControl;
// if this splitter is aligned, then it returns the control that will be
// resized as well. Normally an alClient aligned control.
// Or: if alTop,alBottom the alLeft/alRight controls.
// And distance to oposite control should be minimal
function CalcDistance(TestControl: TControl): Integer;
var
TestPosition,
MyPosition: Integer;
begin
case Align of
alLeft:
begin
MyPosition := BoundsRect.Right;
TestPosition := TestControl.Left;
Result := TestPosition - MyPosition;
end;
alRight:
begin
MyPosition := Left;
TestPosition := TestControl.BoundsRect.Right;
Result := MyPosition - TestPosition;
end;
alTop:
begin
MyPosition := BoundsRect.Bottom;
TestPosition := TestControl.Top;
Result := TestPosition - MyPosition;
end;
alBottom:
begin
MyPosition := Top;
TestPosition := TestControl.BoundsRect.Bottom;
Result := MyPosition - TestPosition;
end;
else
Result := -1;
end;
end;
var
CurControl: TControl;
i, CurDistance, MinDistance: Integer;
begin
Result := nil;
MinDistance := MaxInt;
for i := Parent.ControlCount-1 downto 0 do
begin
CurControl := Parent.Controls[i];
if (CurControl <> Self) and (CurControl.Visible) and
(
(CurControl.Align = alClient) or
(
(Self.Align in [alTop, alBottom]) and
(CurControl.Align in [alLeft, alRight])
)
) then
begin
CurDistance := CalcDistance(CurControl);
if (CurDistance >= 0) and (CurDistance < MinDistance) then
begin
Result := CurControl;
MinDistance := CurDistance;
if CurDistance = 0 then
Exit;
end;
end;
end;
end;
procedure TCustomSplitter.SetAlign(Value: TAlign);
var
OldWidth: Integer;
OldHeight: Integer;
OldResizeAnchor: TAnchorKind;
begin
OldResizeAnchor:=ResizeAnchor;
case Value of
alLeft: FResizeAnchor:=akLeft;
alTop: FResizeAnchor:=akTop;
alRight: FResizeAnchor:=akRight;
alBottom: FResizeAnchor:=akBottom;
end;
if ((Align = Value) and (OldResizeAnchor=FResizeAnchor))
or (Value=alClient) then
Exit;
OldWidth := Width;
OldHeight := Height;
DisableAlign;
try
inherited SetAlign(Value);
if ResizeAnchor in [akLeft,akRight] then
Cursor := crHSplit
else
Cursor := crVSplit;
CheckAlignment;
// lfm contains correct size already
if not (csLoading in ComponentState) then begin
if (OldResizeAnchor in [akLeft,akRight])=(ResizeAnchor in [akLeft,akRight])
then begin
// keep width and height
SetBounds(Left,Top,OldWidth,OldHeight);
end else begin
// resize
if Align in [alLeft,alRight] then
Width:=OldHeight
else if Align in [alTop,alBottom] then
Height:=OldWidth;
end;
end;
finally
EnableAlign;
end;
end;
procedure TCustomSplitter.SetAnchors(const AValue: TAnchors);
begin
if AValue = Anchors then exit;
inherited SetAnchors(AValue);
CheckAlignment;
end;
procedure TCustomSplitter.CheckAlignment;
begin
case Align of
alLeft: Anchors:=Anchors-[akRight]+[akLeft];
alTop: Anchors:=Anchors-[akBottom]+[akTop];
alRight: Anchors:=Anchors+[akRight]-[akLeft];
alBottom: Anchors:=Anchors+[akBottom]-[akTop];
end;
end;
function TCustomSplitter.CheckNewSize(var NewSize: Integer): Boolean;
begin
Result := True;
if Assigned(OnCanResize) then
OnCanResize(Self,NewSize,Result);
end;
procedure TCustomSplitter.Paint;
procedure DrawThemedPattern(ARect: TRect);
const
GripperDetailsPart: array[Boolean] of TThemedRebar =
(
trGripperVert,
trGripper
);
var
GripperRect: TRect;
BgPart: TThemedRebar;
BgDetails, GripperDetails: TThemedElementDetails;
GripperSize: TSize;
begin
GripperDetails := ThemeServices.GetElementDetails(GripperDetailsPart[ResizeAnchor in [akLeft,akRight]]);
if not Enabled then
BgPart := trBandDisabled
else
if FMouseInControl then
BgPart := trBandHot
else
BgPart := trBandNormal;
BgDetails := ThemeServices.GetElementDetails(BgPart);
ThemeServices.DrawElement(Canvas.Handle, BgDetails, ARect, nil);
if Beveled then
ThemeServices.DrawEdge(Canvas.Handle, BgDetails, ARect, BDR_RAISEDOUTER,
BF_ADJUST or BF_RECT, @ARect);
GripperRect := ARect;
GripperSize := ThemeServices.GetDetailSize(GripperDetails);
if (GripperSize.cx <> -1) or (GripperSize.cy <> -1) then
begin
if ResizeAnchor in [akLeft,akRight] then
begin
if (GripperRect.Bottom - GripperRect.Top) > GripperSize.cy then
begin
GripperRect.Top := (GripperRect.Top + GripperRect.Bottom - GripperSize.cy) div 2;
GripperRect.Bottom := GripperRect.Top + GripperSize.cy;
end;
end
else
begin
if (GripperRect.Right - GripperRect.Left) > GripperSize.cx then
begin
GripperRect.Left := (GripperRect.Left + GripperRect.Right - GripperSize.cx) div 2;
GripperRect.Right := GripperRect.Left + GripperSize.cx;
end;
end;
end;
ThemeServices.DrawElement(Canvas.Handle, GripperDetails, GripperRect);
end;
procedure DrawResizePattern(ARect: TRect);
begin
if ResizeStyle = rsPattern then
FillRect(Canvas.Handle, ARect, ThemeServices.DottedBrush)
else
FillRect(Canvas.Handle, ARect, GetStockObject(BLACK_BRUSH));
end;
begin
inherited Paint;
if (ResizeStyle in [rsNone, rsUpdate]) or not FSplitDragging then
DrawThemedPattern(ClientRect)
else
DrawResizePattern(ClientRect);
end;
procedure TCustomSplitter.MouseEnter;
begin
inherited MouseEnter;
if csDesigning in ComponentState then exit;
if not FMouseInControl and Enabled and (GetCapture = 0) then
begin
FMouseInControl := True;
invalidate;
end;
end;
procedure TCustomSplitter.MouseLeave;
begin
inherited MouseLeave;
if csDesigning in ComponentState then exit;
if FMouseInControl then
begin
FMouseInControl := False;
invalidate;
end;
end;
constructor TCustomSplitter.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
FResizeStyle := rsUpdate;
FAutoSnap := True;
FBeveled := False;
FMinSize := 30;
FMouseInControl := False;
FResizeAnchor := akLeft;
Align := alLeft;
Width := 5;
end;
procedure TCustomSplitter.AnchorSplitter(Kind: TAnchorKind; AControl: TControl
);
procedure AnchorSplitterSides(
ResizeSide,// the side of the Splitter, where AControl is touched and moved
OppositeResizeSide, // opposite of ResizeSide
FixedSide1,// the first non moving side
FixedSide2:// the second non moving side
TAnchorKind);
begin
Anchors:=Anchors-[OppositeResizeSide]+[ResizeSide,FixedSide1,FixedSide2];
AnchorSide[OppositeResizeSide].Control:=nil;
AnchorToNeighbour(ResizeSide,0,AControl);
AnchorParallel(FixedSide1,0,AControl);
AnchorParallel(FixedSide2,0,AControl);
end;
var
OldResizeAnchor: TAnchorKind;
OldWidth: LongInt;
OldHeight: LongInt;
begin
OldWidth := Self.Width;
OldHeight := Self.Height;
OldResizeAnchor := FResizeAnchor;
Align := alNone;
FResizeAnchor := Kind;
if ResizeAnchor in [akLeft,akRight] then
Cursor := crHSplit
else
Cursor := crVSplit;
case FResizeAnchor of
akLeft: AnchorSplitterSides(akLeft,akRight,akTop,akBottom);
akRight: AnchorSplitterSides(akRight,akLeft,akTop,akBottom);
akTop: AnchorSplitterSides(akTop,akBottom,akLeft,akRight);
akBottom: AnchorSplitterSides(akBottom,akTop,akLeft,akRight);
end;
if (OldResizeAnchor in [akLeft,akRight])=(ResizeAnchor in [akLeft,akRight])
then begin
// keep width and height
SetBounds(Left,Top,OldWidth,OldHeight);
end else begin
// resize
if FResizeAnchor in [akLeft,akRight] then
Width:=OldHeight
else
Height:=OldWidth;
end;
end;
// included by extctrls.pp