{%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 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