fixed TSplitter resizing for alBottom, alRight from Pawel Piwowar

git-svn-id: trunk@6853 -
This commit is contained in:
mattias 2005-02-26 21:56:55 +00:00
parent 5baf8a8fef
commit e2f04f299f

View File

@ -20,7 +20,6 @@
ToDo:
- Fix changing Mouse cursor
- Fix gtk look
- AutoSnap
- ResizeStyle
}
@ -56,9 +55,9 @@ procedure TCustomSplitter.StartSplitterMove(Restart: boolean;
const MouseXY: TPoint);
begin
if (not Restart) and FSplitDragging then exit;
FSplitDragging:=true;
FSplitDragging := True;
fSplitterStartMouseXY:=MouseXY;
fSplitterStartLeftTop:=Point(Left,Top);
fSplitterStartLeftTop:= Point(Left,Top);
end;
procedure TCustomSplitter.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
@ -69,76 +68,303 @@ begin
inherited MouseDown(Button, Shift, X, Y);
// While resizing X, Y are not valid. Use absolute mouse position.
GetCursorPos(MousePos);
StartSplitterMove(true,MousePos);
StartSplitterMove(True,MousePos);
end;
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;
procedure TCustomSplitter.MouseMove(Shift: TShiftState; X, Y: Integer);
var
AlignControl, LastControl, VirtualOppositeControl, ClientControl: TControl;
function GetParentClientSize: Integer;
begin
case Self.Align of
alLeft, alRight: Result := Parent.ClientWidth;
alTop, alBottom: Result := Parent.ClientHeight;
end;
end;
function GetControlMinPos(Control: TControl): Integer;
begin
if Assigned(Control)
then case Self.Align of
alLeft,alRight: Result := Control.Left;
alTop,alBottom: Result := Control.Top;
end
else case Self.Align of
alLeft,alTop: Result := 0;
alRight,alBottom: Result := GetParentClientSize;
end;
end;
function GetControlSize(Control: TControl): Integer;
begin
Result := 0;
if Assigned(Control)
then case Self.Align of
alLeft, alRight: Result := Control.Width;
alTop, alBottom: Result := Control.Height;
end;
end;
function GetControlConstraintsMinSize(Control: TControl): Integer;
begin
case Self.Align of
alLeft, alRight: Result := Control.Constraints.MinWidth;
alTop, alBottom: Result := Control.Constraints.MinHeight;
end;
end;
procedure SetAlignControlSize(NewSize: Integer);
begin
case Self.Align of
alLeft:
AlignControl.Width := NewSize;
alRight:
begin
Parent.DisableAlign;
AlignControl.Left := AlignControl.Left + (AlignControl.Width - NewSize);
AlignControl.Width := NewSize;
Parent.EnableAlign;
end;
alTop:
AlignControl.Height := NewSize;
alBottom:
begin
Parent.DisableAlign;
AlignControl.Top := AlignControl.Top + (AlignControl.Height - NewSize);
AlignControl.Height := NewSize;
Parent.EnableAlign;
end;
end;
end;
function CalcNewSize(StartSize, EndSize, Offset: Integer): Integer;
var
NewSize: Integer;
begin
NewSize := GetControlSize(AlignControl);
case Self.Align of
alLeft, alTop: Inc(NewSize, Offset);
alRight, alBottom: 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 Self.Align of
alLeft: Result := Control.Left;
alRight: Result := Control.BoundsRect.Right;
alTop: Result := Control.Top;
alBottom: Result := Control.BoundsRect.Bottom;
end;
end;
function CalcOffset(X,Y: Integer): Integer;
begin
case Self.Align of
alLeft, alRight:
Result := (X-fSplitterStartMouseXY.X)
- (Self.Left-fSplitterStartLeftTop.X);
alTop, alBottom:
Result := (Y-fSplitterStartMouseXY.Y)
- (Self.Top-fSplitterStartLeftTop.Y);
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 FindLastControl
var
Offset: Integer;
MinLeft: Integer;
MaxLeft: Integer;
NewLeft: Integer;
AlignControl: TControl;
MinTop: Integer;
MaxTop: Integer;
NewTop: Integer;
StartSize: Integer;
EndSize: Integer;
NewSize: Integer;
MousePos: TPoint;
begin
inherited MouseMove(Shift, X, Y);
if (ssLeft in Shift) and (Parent<>nil) then begin
if not (Self.Align in [alLeft, alRight, alTop, alBottom]) then Exit;
if (ssLeft in Shift) and (Parent <> nil) then begin
AlignControl := FindAlignControl;
if not Assigned(AlignControl) then Exit;
// While resizing X, Y are not valid. Use absolute mouse position.
GetCursorPos(MousePos);
StartSplitterMove(false,MousePos);
if Align in [alLeft,alRight] then begin
Offset:=(MousePos.X-fSplitterStartMouseXY.X)
-(Left-fSplitterStartLeftTop.X);
if Offset=0 then exit;
MinLeft:=0;
MaxLeft:=Parent.ClientWidth-Width;
AlignControl:=FindAlignControl;
if AlignControl<>nil then
if Align=alLeft then
MinLeft:=AlignControl.Left+MinSize
else
MaxLeft:=Parent.ClientWidth-Width-MinSize;
NewLeft:=Left+Offset;
if NewLeft>MaxLeft then NewLeft:=MaxLeft;
if NewLeft<MinLeft then NewLeft:=MinLeft;
AlignControl:=FindAlignControl;
if not CheckNewSize(NewLeft) then exit;
if AlignControl<>nil then begin
if Align=alLeft then
AlignControl.Width:=NewLeft-AlignControl.Left
else
AlignControl.Left:=NewLeft+Width;
end else
Left:=NewLeft;
end
else if Align in [alTop, alBottom] then begin
Offset:=(MousePos.Y-fSplitterStartMouseXY.Y)
-(Top-fSplitterStartLeftTop.Y);
if Offset=0 then exit;
MinTop:=0;
MaxTop:=Parent.ClientHeight-Height;
AlignControl:=FindAlignControl;
if AlignControl<>nil then
if Align=alTop then
MinTop:=AlignControl.Top+MinSize
else
MaxTop:=Parent.ClientHeight-Height-MinSize;
NewTop:=Top+Offset;
if NewTop>MaxTop then NewTop:=MaxTop;
if NewTop<MinTop then NewTop:=MinTop;
AlignControl:=FindAlignControl;
if not CheckNewSize(NewLeft) then exit;
if AlignControl<>nil then begin
if Align=alTop then
AlignControl.Height:=NewTop-AlignControl.Top
else
AlignControl.Top:=NewTop+Height;
end else
Top:=NewTop;
StartSplitterMove(False,MousePos);
Offset := CalcOffset(MousePos.X, MousePos.Y);
if Offset = 0 then Exit;
ClientControl := FindClientControl;
StartSize := 1;
if not fAutoSnap
then Inc(StartSize, Max(fMinSize, GetControlConstraintsMinSize(AlignControl)));
if StartSize > 1 then Dec(StartSize);
if Assigned(ClientControl)
then EndSize := GetControlSize(AlignControl)
+ GetControlSize(ClientControl)
- fMinSize
else begin
VirtualOppositeControl := FindVirtualOppositeControl(Self);
LastControl := FindLastControl(Self);
case Self.Align of
alLeft, alTop: begin
if Assigned(VirtualOppositeControl) then
begin
EndSize := GetControlSize(AlignControl)
+ (GetControlMinPos(VirtualOppositeControl)
- (GetControlMinPos(LastControl)
+ GetControlSize(LastControl)));
end
else EndSize := GetControlSize(AlignControl)
+ (GetParentClientSize
- GetControlMinPos(LastControl)
- GetControlSize(LastControl))
end;
alRight, alBottom: begin
if Assigned(VirtualOppositeControl) then
EndSize := GetControlSize(AlignControl)
+ (GetControlMinPos(LastControl)
- (GetControlMinPos(VirtualOppositeControl)
+ GetControlSize(VirtualOppositeControl)))
else EndSize := GetControlSize(AlignControl)
+ GetControlMinPos(LastControl);
end;
end; // case Self.Align
end;
NewSize := CalcNewSize(StartSize, EndSize, Offset);
// OnCanResize event
if CheckNewSize(NewSize)
then SetAlignControlSize(NewSize);
end;
end;
@ -146,9 +372,10 @@ procedure TCustomSplitter.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
begin
inherited MouseUp(Button, Shift, X, Y);
if not (Self.Align in [alLeft,alTop,alRight,alBottom]) then Exit;
if FSplitDragging then begin
if Assigned(OnMoved) then OnMoved(Self);
FSplitDragging:=false;
FSplitDragging := False;
end;
end;
@ -157,26 +384,33 @@ var
i: Integer;
CurControl: TControl;
begin
Result:=nil;
if (Parent=nil) then exit;
for i:=Parent.ControlCount-1 downto 0 do begin
CurControl:=Parent.Controls[i];
if (CurControl.Align in ([alClient,Align]))
and (CurControl.Visible)
and (((Align=alLeft) and (CurControl.Left<Left))
or ((Align=alTop) and (CurControl.Top<Top))
or ((Align=alRight) and (CurControl.Left>Left))
or ((Align=alBottom) and (CurControl.Top>Top)))
Result := nil;
if (Parent = nil) 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)
then begin
// candidate found
if (Result=nil)
or (((Align=alLeft) and (CurControl.Left>Result.Left))
or ((Align=alTop) and (CurControl.Top>Result.Top))
or ((Align=alRight) and (CurControl.Left<Result.Left))
or ((Align=alBottom) and (CurControl.Top<Result.Top)))
then
// better candidate found
Result:=CurControl;
case Self.Align of
alLeft:
if (CurControl.Height = Self.Height)
and (CurControl.Left+CurControl.Width = Self.Left)
then Result := CurControl;
alTop:
if (CurControl.Width = Self.Width)
and (CurControl.Top+CurControl.Height = Self.Top)
then Result := CurControl;
alRight:
if (CurControl.Height = Self.Height)
and (CurControl.Left-Self.Width = Self.Left)
then Result := CurControl;
alBottom:
if (CurControl.Width = Self.Width)
and (CurControl.Top-Self.Height = Self.Top)
then Result := CurControl;
end; // case Self.Align
if Assigned(Result) then Break;
end;
end;
end;
@ -187,18 +421,18 @@ var
OldWidth: Integer;
OldHeight: Integer;
begin
if (Align=Value) or (not (Value in [alLeft,alTop,alRight,alBottom])) then
exit;
OldWidth:=Width;
OldHeight:=Height;
OldAlign:=Align;
if (Self.Align = Value)
or (not (Value in [alLeft,alTop,alRight,alBottom]))
then Exit;
OldWidth := Self.Width;
OldHeight := Self.Height;
OldAlign := Self.Align;
inherited SetAlign(Value);
if Self.Align in [alLeft,alRight]
then Self.Cursor := crHSplit
else Self.Cursor := crVSplit;
CheckAlignment;
if Align in [alLeft,alRight] then begin
Cursor:=crHSplit;
end else begin
Cursor:=crVSplit;
end;
if (OldAlign in [alLeft,alRight])=(Align in [alLeft,alRight]) then begin
// keep width and height
SetBounds(Left,Top,OldWidth,OldHeight);
@ -210,7 +444,7 @@ end;
procedure TCustomSplitter.SetAnchors(const AValue: TAnchors);
begin
if AValue=Anchors then exit;
if AValue = Anchors then exit;
inherited SetAnchors(AValue);
CheckAlignment;
end;
@ -218,16 +452,16 @@ 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];
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;
function TCustomSplitter.CheckNewSize(var NewSize: Integer): Boolean;
begin
Result:=true;
Result := True;
if Assigned(OnCanResize) then
OnCanResize(Self,NewSize,Result);
end;