constructor TSplitter.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FAutoSnap := True;
Align := alLeft;
Width := 3;
Cursor := crHSplit;
FMinSize := 30;
FResizeStyle := rsPattern;
FOldSize := -1;
end;destructor TSplitter.Destroy;
begin
FBrush.Free;
inherited Destroy;
end;procedure TSplitter.AllocateLineDC;
begin
FLineDC := GetDCEx(Parent.Handle, 0, DCX_CACHE or DCX_CLIPSIBLINGS
or DCX_LOCKWINDOWUPDATE);
if ResizeStyle = rsPattern then
begin
if FBrush = nil then
begin
FBrush := TBrush.Create;
FBrush.Bitmap := AllocPatternBitmap(clBlack, clWhite);
end;
FPrevBrush := SelectObject(FLineDC, FBrush.Handle);
end;
end;procedure TSplitter.DrawLine;
var
P: TPoint;
begin
FLineVisible := not FLineVisible;
P := Point(Left, Top);
if Align in [alLeft, alRight] then
P.X := Left + FSplit else
P.Y := Top + FSplit;
with P do PatBlt(FLineDC, X, Y, Width, Height, PATINVERT);
end;procedure TSplitter.ReleaseLineDC;
begin
if FPrevBrush <> 0 then
SelectObject(FLineDC, FPrevBrush);
ReleaseDC(Parent.Handle, FLineDC);
if FBrush <> nil then
begin
FBrush.Free;
FBrush := nil;
end;
end;function TSplitter.FindControl: TControl;
var
P: TPoint;
I: Integer;
R: TRect;
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 Result.Visible and Result.Enabled then
begin
R := Result.BoundsRect;
if (R.Right - R.Left) = 0 then
if Align in [alTop, alLeft] then
Dec(R.Left)
else
Inc(R.Right);
if (R.Bottom - R.Top) = 0 then
if Align in [alTop, alLeft] then
Dec(R.Top)
else
Inc(R.Bottom);
if PtInRect(R, P) then Exit;
end;
end;
Result := nil;
end;procedure TSplitter.RequestAlign;
begin
inherited RequestAlign;
if (Cursor <> crVSplit) and (Cursor <> crHSplit) then Exit;
if Align in [alBottom, alTop] then
Cursor := crVSplit
else
Cursor := crHSplit;
end;procedure TSplitter.Paint;
const
XorColor = $00FFD8CE;
var
FrameBrush: HBRUSH;
R: TRect;
begin
R := ClientRect;
Canvas.Brush.Color := Color;
Canvas.FillRect(ClientRect);
if Beveled then
begin
if Align in [alLeft, alRight] then
InflateRect(R, -1, 2) else
InflateRect(R, 2, -1);
OffsetRect(R, 1, 1);
FrameBrush := CreateSolidBrush(ColorToRGB(clBtnHighlight));
FrameRect(Canvas.Handle, R, FrameBrush);
DeleteObject(FrameBrush);
OffsetRect(R, -2, -2);
FrameBrush := CreateSolidBrush(ColorToRGB(clBtnShadow));
FrameRect(Canvas.Handle, R, FrameBrush);
DeleteObject(FrameBrush);
end;
if csDesigning in ComponentState then
{ Draw outline }
with Canvas do
begin
Pen.Style := psDot;
Pen.Mode := pmXor;
Pen.Color := XorColor;
Brush.Style := bsClear;
Rectangle(0, 0, ClientWidth, ClientHeight);
end;
if Assigned(FOnPaint) then FOnPaint(Self);
end;function TSplitter.DoCanResize(var NewSize: Integer): Boolean;
begin
Result := CanResize(NewSize);
if Result and (NewSize <= MinSize) and FAutoSnap then
NewSize := 0;
end;function TSplitter.CanResize(var NewSize: Integer): Boolean;
begin
Result := True;
if Assigned(FOnCanResize) then FOnCanResize(Self, NewSize, Result);
end;
begin
inherited Create(AOwner);
FAutoSnap := True;
Align := alLeft;
Width := 3;
Cursor := crHSplit;
FMinSize := 30;
FResizeStyle := rsPattern;
FOldSize := -1;
end;destructor TSplitter.Destroy;
begin
FBrush.Free;
inherited Destroy;
end;procedure TSplitter.AllocateLineDC;
begin
FLineDC := GetDCEx(Parent.Handle, 0, DCX_CACHE or DCX_CLIPSIBLINGS
or DCX_LOCKWINDOWUPDATE);
if ResizeStyle = rsPattern then
begin
if FBrush = nil then
begin
FBrush := TBrush.Create;
FBrush.Bitmap := AllocPatternBitmap(clBlack, clWhite);
end;
FPrevBrush := SelectObject(FLineDC, FBrush.Handle);
end;
end;procedure TSplitter.DrawLine;
var
P: TPoint;
begin
FLineVisible := not FLineVisible;
P := Point(Left, Top);
if Align in [alLeft, alRight] then
P.X := Left + FSplit else
P.Y := Top + FSplit;
with P do PatBlt(FLineDC, X, Y, Width, Height, PATINVERT);
end;procedure TSplitter.ReleaseLineDC;
begin
if FPrevBrush <> 0 then
SelectObject(FLineDC, FPrevBrush);
ReleaseDC(Parent.Handle, FLineDC);
if FBrush <> nil then
begin
FBrush.Free;
FBrush := nil;
end;
end;function TSplitter.FindControl: TControl;
var
P: TPoint;
I: Integer;
R: TRect;
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 Result.Visible and Result.Enabled then
begin
R := Result.BoundsRect;
if (R.Right - R.Left) = 0 then
if Align in [alTop, alLeft] then
Dec(R.Left)
else
Inc(R.Right);
if (R.Bottom - R.Top) = 0 then
if Align in [alTop, alLeft] then
Dec(R.Top)
else
Inc(R.Bottom);
if PtInRect(R, P) then Exit;
end;
end;
Result := nil;
end;procedure TSplitter.RequestAlign;
begin
inherited RequestAlign;
if (Cursor <> crVSplit) and (Cursor <> crHSplit) then Exit;
if Align in [alBottom, alTop] then
Cursor := crVSplit
else
Cursor := crHSplit;
end;procedure TSplitter.Paint;
const
XorColor = $00FFD8CE;
var
FrameBrush: HBRUSH;
R: TRect;
begin
R := ClientRect;
Canvas.Brush.Color := Color;
Canvas.FillRect(ClientRect);
if Beveled then
begin
if Align in [alLeft, alRight] then
InflateRect(R, -1, 2) else
InflateRect(R, 2, -1);
OffsetRect(R, 1, 1);
FrameBrush := CreateSolidBrush(ColorToRGB(clBtnHighlight));
FrameRect(Canvas.Handle, R, FrameBrush);
DeleteObject(FrameBrush);
OffsetRect(R, -2, -2);
FrameBrush := CreateSolidBrush(ColorToRGB(clBtnShadow));
FrameRect(Canvas.Handle, R, FrameBrush);
DeleteObject(FrameBrush);
end;
if csDesigning in ComponentState then
{ Draw outline }
with Canvas do
begin
Pen.Style := psDot;
Pen.Mode := pmXor;
Pen.Color := XorColor;
Brush.Style := bsClear;
Rectangle(0, 0, ClientWidth, ClientHeight);
end;
if Assigned(FOnPaint) then FOnPaint(Self);
end;function TSplitter.DoCanResize(var NewSize: Integer): Boolean;
begin
Result := CanResize(NewSize);
if Result and (NewSize <= MinSize) and FAutoSnap then
NewSize := 0;
end;function TSplitter.CanResize(var NewSize: Integer): Boolean;
begin
Result := True;
if Assigned(FOnCanResize) then FOnCanResize(Self, NewSize, Result);
end;
X, Y: Integer);
var
I: Integer;
begin
inherited MouseDown(Button, Shift, X, Y);
if Button = mbLeft then
begin
FControl := FindControl;
FDownPos := Point(X, Y);
if Assigned(FControl) then
begin
if Align in [alLeft, alRight] then
begin
FMaxSize := Parent.ClientWidth - FMinSize;
for I := 0 to Parent.ControlCount - 1 do
with Parent.Controls[I] do
if Visible and (Align in [alLeft, alRight]) then Dec(FMaxSize, Width);
Inc(FMaxSize, FControl.Width);
end
else
begin
FMaxSize := Parent.ClientHeight - FMinSize;
for I := 0 to Parent.ControlCount - 1 do
with Parent.Controls[I] do
if Align in [alTop, alBottom] then Dec(FMaxSize, Height);
Inc(FMaxSize, FControl.Height);
end;
UpdateSize(X, Y);
AllocateLineDC;
with ValidParentForm(Self) do
if ActiveControl <> nil then
begin
FActiveControl := ActiveControl;
FOldKeyDown := TWinControlAccess(FActiveControl).OnKeyDown;
TWinControlAccess(FActiveControl).OnKeyDown := FocusKeyDown;
end;
if ResizeStyle in [rsLine, rsPattern] then DrawLine;
end;
end;
end;procedure TSplitter.UpdateControlSize;
begin
if FNewSize <> FOldSize then
begin
case Align of
alLeft: FControl.Width := FNewSize;
alTop: FControl.Height := FNewSize;
alRight:
begin
Parent.DisableAlign;
try
FControl.Left := FControl.Left + (FControl.Width - FNewSize);
FControl.Width := FNewSize;
finally
Parent.EnableAlign;
end;
end;
alBottom:
begin
Parent.DisableAlign;
try
FControl.Top := FControl.Top + (FControl.Height - FNewSize);
FControl.Height := FNewSize;
finally
Parent.EnableAlign;
end;
end;
end;
Update;
if Assigned(FOnMoved) then FOnMoved(Self);
FOldSize := FNewSize;
end;
end;procedure TSplitter.CalcSplitSize(X, Y: Integer; var NewSize, Split: Integer);
var
S: Integer;
begin
if Align in [alLeft, alRight] then
Split := X - FDownPos.X
else
Split := Y - FDownPos.Y;
S := 0;
case Align of
alLeft: S := FControl.Width + Split;
alRight: S := FControl.Width - Split;
alTop: S := FControl.Height + Split;
alBottom: S := FControl.Height - Split;
end;
NewSize := S;
if S < FMinSize then
NewSize := FMinSize
else if S > FMaxSize then
NewSize := FMaxSize;
if S <> NewSize then
begin
if Align in [alRight, alBottom] then
S := S - NewSize else
S := NewSize - S;
Inc(Split, S);
end;
end;procedure TSplitter.UpdateSize(X, Y: Integer);
begin
CalcSplitSize(X, Y, FNewSize, FSplit);
end;procedure TSplitter.MouseMove(Shift: TShiftState; X, Y: Integer);
var
NewSize, Split: Integer;
begin
inherited;
if (ssLeft in Shift) and Assigned(FControl) then
begin
CalcSplitSize(X, Y, NewSize, Split);
if DoCanResize(NewSize) then
begin
if ResizeStyle in [rsLine, rsPattern] then DrawLine;
FNewSize := NewSize;
FSplit := Split;
if ResizeStyle = rsUpdate then UpdateControlSize;
if ResizeStyle in [rsLine, rsPattern] then DrawLine;
end;
end;
end;procedure TSplitter.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited;
if Assigned(FControl) then
begin
if ResizeStyle in [rsLine, rsPattern] then DrawLine;
UpdateControlSize;
StopSizing;
end;
end;procedure TSplitter.FocusKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if Key = VK_ESCAPE then
StopSizing
else if Assigned(FOldKeyDown) then
FOldKeyDown(Sender, Key, Shift);
end;procedure TSplitter.SetBeveled(Value: Boolean);
begin
FBeveled := Value;
Repaint;
end;procedure TSplitter.StopSizing;
begin
if Assigned(FControl) then
begin
if FLineVisible then DrawLine;
FControl := nil;
ReleaseLineDC;
if Assigned(FActiveControl) then
begin
TWinControlAccess(FActiveControl).OnKeyDown := FOldKeyDown;
FActiveControl := nil;
end;
end;
if Assigned(FOnMoved) then
FOnMoved(Self);
end;