unit Resizer;interfaceuses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, ExtCtrls, StdCtrls, TabNotBk;type
  pControlInfo = ^tControlInfo;
  tControlInfo = record
     { This record holds information about a component on the form}
     { or about a component inside a container object}
     Obj:TControl;
     ClassName:String;
     lRatio,tRatio,wRatio,hRatio:Real;
     Contains:pControlInfo;
     Next:pControlInfo;
  End;
  TResizer = class(TComponent)
  private
    { These variables and functions should not be needed by the user, }
    { only by the RESIZER component.}
     ResizerInitialized:Boolean;
     Function  GetClientControlCount(Sender:TObject):LongInt;
     procedure GetNewWidthHeight(Sender:TObject;Var NewW,NewH:LongInt);
     Procedure PerformResize(CurCont:pControlInfo;CWidth,CHeight:LongInt);
     Function  GetClientControlObject(Sender:TObject;Index:LongInt):TControl;
     Function  Initialize(Sender:TObject;CWidth,CHeight:LongInt):pControlInfo;
     Procedure DeleteControlList(CurCont:pControlInfo);
  public
    constructor Create(AOwner: TComponent); override;
    destructor  Destroy; override;
    { These are useful to the programmer. I currently dont use NewShapshot, but}
    { somebody out there might.... especially if you are using DYNAMICALLY}
    { created components on your form.}
    procedure   ReSize(ParentForm:TObject);
    procedure   NewSnapshot(ParentForm:TObject);
  end;procedure Register;implementationVar ControlList:pControlInfo;constructor TResizer.Create(AOwner: TComponent);
Var Count:LongInt;
Begin
   inherited Create(AOwner);
   { Do my init stuff}
   ResizerInitialized:=False;
   ControlList:=nil;
End;destructor TResizer.Destroy;
Begin
   { Destroy the existing ControlList }
   DeleteControlList(ControlList);
   ResizerInitialized:=False;
   ControlList:=nil;
   inherited Destroy;
End;{ Recursively setup throw the control list and all containers}
{ and delete all the dynamically allocated objects}
Procedure TResizer.DeleteControlList(CurCont:pControlInfo);
Var NextCont:pControlInfo;
Begin
   While(CurCont<>nil) Do
   Begin
      If((CurCont^.Contains)<>nil) Then
         DeleteControlList(CurCont^.Contains);
      NextCont:=CurCont^.Next;
      FreeMem(CurCont,SizeOf(tControlInfo));
      CurCont:=NextCont;
   End;
End;procedure TResizer.GetNewWidthHeight(Sender:TObject;Var NewW,NewH:LongInt);
Begin
   { Determine the type of container component we have then get its}
   { width and height and tag number}
   If(Sender is TForm) Then
   With TForm(Sender) Do
   Begin
      { Since this is a TForm, we want ClientWidth and ClientHeight}
      NewW:=ClientWidth;
      NewH:=ClientHeight;
   End
   Else
   If(Sender is TPanel) Then
   With TPanel(Sender) Do
   Begin
      NewW:=Width;
      NewH:=Height;
   End
   Else
   If(Sender is TGroupBox) Then
   With TGroupBox(Sender) Do
   Begin
      NewW:=Width;
      NewH:=Height;
   End
   Else
   {The TTabbedNotebook stuff doesn't work right... Components inside}
   {the tabbed notebook won't resize as of yet}
   If(Sender is TTabbedNotebook) Then
   With TTabbedNotebook(Sender) Do
   Begin
      NewW:=Width;
      NewH:=Height;
   End
   Else
   Begin
      { We don't recognize the container, so supply 0 values}
      NewW:=0;
      NewH:=0;
   End;
End;Function TResizer.GetClientControlCount(Sender:TObject):LongInt;
Begin
   { Determine the type of container component we have then}
   { return the number of controls on that container}
   If(Sender is TForm) Then
      Result:=TForm(Sender).ControlCount
   Else
   If(Sender is TPanel) Then
      Result:=TPanel(Sender).ControlCount
   Else
   If(Sender is TGroupBox) Then
      Result:=TGroupBox(Sender).ControlCount
   Else
   {The TTabbedNotebook stuff doesn't work right... Components inside}
   {the tabbed notebook won't resize as of yet}
   If(Sender is TTabbedNotebook) Then
      Result:=TTabbedNotebook(Sender).ControlCount
   Else
      { We don't recognize the container, so supply a 0 value}
      Result:=0;
End;
Function TResizer.GetClientControlObject(Sender:TObject;Index:LongInt):TControl;
Begin
   If(Sender is TForm) Then
      Result:=TForm(Sender).Controls[Index]
   Else
   If(Sender is TPanel) Then
      Result:=TPanel(Sender).Controls[Index]
   Else
   If(Sender is TGroupBox) Then
      Result:=TGroupBox(Sender).Controls[Index]
   Else
   {The TTabbedNotebook stuff doesn't work right... Components inside}
   {the tabbed notebook won't resize as of yet}
   If(Sender is TTabbedNotebook) Then
      Result:=TTabbedNotebook(Sender).Controls[Index]
   Else
      Result:=nil;
End;Function TResizer.Initialize(Sender:TObject;CWidth,CHeight:LongInt):pControlInfo;
Var Temp:pControlInfo;
    Count:Integer;
Begin
   Result:=nil;
   For Count:=0 to (GetClientControlCount(Sender)-1) Do
   Begin
      GetMem(Temp,SizeOf(tControlInfo));
      Temp^.Obj:=GetClientControlObject(Sender,Count);
      With(Temp^) Do
      Begin
         lRatio:=(Obj.Left) / CWidth;
         tRatio:=(Obj.Top) / CHeight;
         wRatio:=(Obj.Width) / CWidth;
         hRatio:=(Obj.Height) / CHeight;
         Contains:=nil;
         Next:=Result;
      End;
      Result:=Temp;
      {The TTabbedNotebook stuff doesn't work right... Components inside}
      {the tabbed notebook won't resize as of yet}
      If((Temp^.Obj is TForm) or
         (Temp^.Obj is TPanel) or
         (Temp^.Obj is TGroupBox) or
         (Temp^.Obj is TTabbedNotebook)) Then
      With(Temp^) Do
         Contains:=Initialize(Obj,Obj.Width,Obj.Height);
   End;
End;Procedure TResizer.PerformResize(CurCont:pControlInfo;CWidth,CHeight:LongInt);
Begin
   While(CurCont<>nil) Do
   Begin
      With(CurCont^) Do
      Begin
         With(Obj) Do
            SetBounds(Round(lRatio*CWidth),Round(tRatio*CHeight),
               Round(wRatio*CWidth),Round(hRatio*CHeight));
         If(Contains<>nil) Then
            PerformResize(Contains,Obj.Width,Obj.Height);
      End;
      CurCont:=CurCont^.Next;
   End;
End;procedure TResizer.NewSnapshot(ParentForm:TObject);
Var NewClientWidth,NewClientHeight:LongInt;
Begin
   GetNewWidthHeight(ParentForm,NewClientWidth,NewClientHeight);
   { Delete the existing ControlList for this form}
   DeleteControlList(ControlList);
   ControlList:=nil;
   ResizerInitialized:=False;
   { Initialize the ControlList for this form}
   ControlList:=Initialize(ParentForm,NewClientWidth,NewClientHeight);
   If(ControlList<>nil) Then
      { The control list HAS been initialized!}
      ResizerInitialized:=True;
End;{ This should be called everytime the form is resized (ie in the OnSized}
{ event). Pass OnSized "Sender" parameter to this procedure}
procedure TResizer.ReSize(ParentForm:TObject);
Var NewClientWidth,NewClientHeight:LongInt;
    Count:Integer;
    Left,Top,Width,Height:LongInt;
Begin
   GetNewWidthHeight(ParentForm,NewClientWidth,NewClientHeight);
   If(ResizerInitialized) Then
      { The ControlList already exists, resize the form and its controls}
      PerformResize(ControlList,NewClientWidth,NewClientHeight)
   Else
      { No ControlList exists. Let's create one}
      NewSnapshot(ParentForm);
End;{ This should be called only if you want to take a NEW shapshot of the}
{ relative positions and sizes of the controls on the form. The paramter}
{ should be the form on which the object resides}
procedure Register;
begin
   { Register the RESIZER component}
   RegisterComponents('Custom', [TResizer]);
end;