On transcribing an old Delphi-Program to a Lazarus-program i was in need do have working MDI-functions.
I tried to implement them in customform.inc and they work fine with my program and in my environment.
There are still some problematic spots in the code and i would appreciate comments/solutions for them.
 
regards
H. Niemeyer
{------------------------------------------------------------------------------
  Method:  TCustomForm.ActiveMDIChild
  Params:  None
  Returns: Nothing

  Returns currently active MDI child form of self.
  Valid result is returned only when Self FormStyle = fsMDIForm or fsMDIChild,
  otherwise Result is nil.
 ------------------------------------------------------------------------------}
function TCustomForm.ActiveMDIChild: TCustomForm;
var actMdiChild : TCustomForm;
    k           : integer;
begin
  Result := nil;
(*  if not (FormStyle in [fsMDIForm, fsMDIChild]) then
    exit;
  if HandleAllocated and not (csDesigning in ComponentState) then
    Result := TWSCustomFormClass(WidgetSetClass).ActiveMDIChild(Self);   *)

  if (csDesigning in ComponentState) or not(FormStyle in [fsMDIForm, fsMDIChild]) then
    exit;
  if HandleAllocated then
    Result := TWSCustomFormClass(WidgetSetClass).ActiveMDIChild(Self);

  if Result=nil then
    begin
      k := 0;
      while (k<Screen.CustomFormZOrderCount) and (result=nil) do
        begin
          actMdiChild:=Screen.CustomFormsZOrdered[k];
          if (actMdiChild.Owner=self) and  actMdiChild.Visible
             and (actMdiChild.FormStyle in [fsMDIForm, fsMDIChild])
            then result:=actMdiChild
            else k:=k+1
        end;
    end;
end;

{------------------------------------------------------------------------------
  Method:  TCustomForm.MDIChildCount
  Params:  None
  Returns: Nothing

  Returns count of MDIChild forms.
  Result is returned only when Self FormStyle = fsMDIForm or fsMDIChild (can
  be 0 ... number of mdichild forms).
  If Result is -1 then caller isn't mdi or handle is not allocated.
 ------------------------------------------------------------------------------}
function TCustomForm.MDIChildCount: Integer;
var k : integer;
begin
  Result := -1;
(*  if not (FormStyle in [fsMDIForm, fsMDIChild]) then
    exit;
  if HandleAllocated and not (csDesigning in ComponentState) then
    Result := TWSCustomFormClass(WidgetSetClass).MDIChildCount(Self); *)

  if (csDesigning in ComponentState) or not(FormStyle in [fsMDIForm, fsMDIChild]) then
    exit;
  if HandleAllocated then
    Result := TWSCustomFormClass(WidgetSetClass).MDIChildCount(Self)
    else Result:=0;
  if Result = 0 then
    begin
      for k := 0 to ComponentCount-1 do
        if (Components[k] is TCustomForm) and (TCustomForm(Components[k]).FormStyle in [fsMDIForm, fsMDIChild])
           then result:=result+1;
    end;
end;


{------------------------------------------------------------------------------
  Method:  TCustomForm.GetMDIChildren
  Params:  AIndex: Integer;
  Returns: TCustomForm with FormStyle = fsMDIChild

  Returns MDI child (fsMDIChild) of parent mdi form (fsMDIForm) at index
  AIndex in list of mdi children.
  Result can be nil if caller isn't an mdi type or handle isn't allocated.
 ------------------------------------------------------------------------------}
function TCustomForm.GetMDIChildren(AIndex: Integer): TCustomForm;
var k, index : integer;
begin
  Result := nil;
(*  if not (FormStyle in [fsMDIForm, fsMDIChild]) then
    exit;
  if HandleAllocated and not (csDesigning in ComponentState) then
    Result := TWSCustomFormClass(WidgetSetClass).GetMDIChildren(Self, AIndex); *)

  if (csDesigning in ComponentState) or not(FormStyle in [fsMDIForm, fsMDIChild]) then
    exit;
  if HandleAllocated then
    Result := TWSCustomFormClass(WidgetSetClass).GetMDIChildren(Self, AIndex);
  if Result = nil then
    begin
      k := -1;  index := -1;
      While (k<ComponentCount-1) and (index<>AIndex) do
       begin
         k := k+1;
         if (Components[k] is TCustomForm) and (TCustomForm(Components[k]).FormStyle in [fsMDIForm, fsMDIChild]) then index:=index+1;
       end;
      if (k<ComponentCount) and (index = AIndex) then result := TCustomForm(Components[k]);
    end;
end;


// Boundsrect gives values for inner size. Setting Boundsrect produces a form with bigger size because of frame size.
// Is there a function returning those sizes?
// Following values are experimental. Don't know if they are correct for other monitors or OSs

const defaultFormBorderSize = 8;
      defaultFormCaptionSize = 22;


{------------------------------------------------------------------------------
  Method: TForm.Cascade
  Params:  None
  Returns: Nothing

  Arranges MDI child forms so they overlap.
  Use Cascade to arrange MDI child forms so they overlap.
  Cascade works only if the form is an MDI parent form (FormStyle=fsMDIForm).
 ------------------------------------------------------------------------------}
procedure TForm.Cascade;
const offsetY = defaultFormCaptionSize+defaultFormBorderSize; //don't overlap form.caption
      offsetX = offsetY;                                      //no spezial reason for this
var CascadeOk : boolean;
    r         : TRect;
    w, h, k   : integer;
    comp      : TComponent;
    temp      : TCustomForm;
    visMDIList: TList;
begin
(*  if (FormStyle <> fsMDIForm) then
    exit;
  if HandleAllocated and not (csDesigning in ComponentState) then
    TWSCustomFormClass(WidgetSetClass).Cascade(Self);      *)
  if (FormStyle <> fsMDIForm) or (csDesigning in ComponentState) then
    exit;
  if HandleAllocated
    then CascadeOk:=TWSCustomFormClass(WidgetSetClass).Cascade(Self)
    else CascadeOk:=false;

  if CascadeOk then exit;
  visMDIList := TList.Create;
  for k := screen.CustomFormZOrderCount-1 downto 0 do               // keep old order; activeMDIChild (index=0) in front;
   begin
     temp := Screen.CustomFormsZOrdered[k];
     if (temp.FormStyle in [fsMDIForm, fsMDIChild]) and (temp.Owner=self)
         and temp.Visible and (temp.WindowState<>wsMinimized)       // don't cascade non-visible or minimized MDIChilds ?
       then visMdiList.Add(temp);
   end;
  if visMdiList.Count>0 then
    begin
      temp:=TCustomForm(visMdiList.Items[0]);
      comp:=temp.Parent;
      if (comp<>nil) and (comp is TCustomForm)
       then r := TCustomForm(comp).ClientRect
       else r := Screen.WorkAreaRect;            // screen.DesktopRect;
       w:=(r.right - r.left)*3 div 4;            // no spezial reason for this value
       h:=(r.bottom - r.top)*3 div 4;
       if (w>0) and (h>0) then
         for k:=0 to visMdiList.Count-1 do
           begin
             temp:=TCustomForm(visMdiList.Items[k]);
             temp.SetBounds(r.left + k*offsetX, r.top + k*offsetY, w, h);
           end;
    end;
  visMDIList.Free;
end;

{------------------------------------------------------------------------------
  Method: TForm.Next
  Params:  None
  Returns: Nothing

  Activates the next child MDI form (fsMDIChild) in the form sequence.
  Use Next to change the active child form of an MDI parent.
  If calling of Next comes to the end of count it restarts and activates
  first dsMDIChild in sequence.
  The Next method applies only to forms with FormStyle = fsMDIForm.
 ------------------------------------------------------------------------------}
procedure TForm.Next;
var k       : integer;
    success : boolean;
    Comp    : TComponent;
    nextMDIChild, actMDIChild : TCustomForm;
begin
 (* if (FormStyle <> fsMDIForm) then
    exit;
  if HandleAllocated and not (csDesigning in ComponentState) then
    TWSCustomFormClass(WidgetSetClass).Next(Self);  *)
  if (FormStyle <> fsMDIForm) or (csDesigning in ComponentState) then
    exit;
  if HandleAllocated
    then success:=TWSCustomFormClass(WidgetSetClass).Next(Self)
    else success:=false;

  if success then exit;            // successful handling by WidgetSetClass
  actMDIChild := ActiveMDIChild;
  if actMDIChild=nil then exit;    //no active MDIChild

  k := -1; nextMDIChild := nil;
  //Don't use Screen.CustomForms as positions in that list are changed, when activating a form
  While (k<ComponentCount-1) and not success do
    begin
      k := k+1;
      Comp := Components[k];
      if (Comp is TCustomForm) and (TCustomForm(Comp).FormStyle in [fsMDIForm, fsMDIChild]) // and TCustomForm(Comp).Visible
       then
        begin
          if nextMDIChild=nil then nextMDIChild := TCustomForm(Comp);  // nextMDIChild := GetMDIChildren(0);
          if TCustomForm(Comp)=actMDIChild then success:=true;
         end;
    end;
  success:=false;
  While (k<ComponentCount-1) and (not success) do                     //search for MDIChild after activeMDIChild
    begin
      k := k+1;
      Comp := Components[k];
      if (Comp is TCustomForm) and (TCustomForm(Comp).FormStyle in [fsMDIForm, fsMDIChild])
        then success:=true;
    end;
  if success then nextMDIChild := TCustomForm(Comp);                  //found  MDIChild after activeMDIChild
                                                                      //otherwise take GetMDIChildren(0);
  nextMDIChild.visible:=true;
  if nextMDIChild.WindowState=wsMinimized then nextMDIChild.WindowState:=wsNormal;
  nextMDIChild.BringToFront;
  nextMDIChild.SetFocus;
end;


{------------------------------------------------------------------------------
  Method: TForm.Previous
  Params:  None
  Returns: Nothing
  Activates the previous MDI child form in the form sequence.
  Behaviour is vice-versa of TForm.Next.
  The Previous method can be called only for forms with FormStyle = fsMDIForm
 ------------------------------------------------------------------------------}
procedure TForm.Previous;
var k         : integer;
    success   : boolean;
    Comp      : TComponent;
    PrevMDIChild, lastMDIChild, actMDIChild : TCustomForm;
begin
(*  if (FormStyle <> fsMDIForm) then
    exit;
  if HandleAllocated and not (csDesigning in ComponentState) then
    TWSCustomFormClass(WidgetSetClass).Previous(Self);    *)
  if (FormStyle <> fsMDIForm) or (csDesigning in ComponentState) then
    exit;
  if HandleAllocated then
    success:=TWSCustomFormClass(WidgetSetClass).Previous(Self)
    else success:=false;

  if success then exit;            // successful handling by WidgetSetClass
  actMDIChild := ActiveMDIChild;
  if actMDIChild=nil then exit;    // no active MDIChild
  k := -1;
  PrevMDIChild := nil; Comp := nil; lastMDIChild := nil;
  //Don't use Screen.CustomForms as positions in that list are changed, when activating a form
  While (k<ComponentCount-1) and not success do
    begin
      k := k+1;
      Comp := Components[k];
      if (Comp is TCustomForm) and (TCustomForm(Comp).FormStyle in [fsMDIForm, fsMDIChild]) //and TCustomForm(Comp).Visible
        then begin
               PrevMDIChild := lastMDIChild;
               lastMDIChild := TCustomForm(Comp);
               if TCustomForm(Comp) = actMDIChild then success:=true;
             end;
    end;
  // if PrevMDIChild=nil then PrevMDIChild := GetMDIChildren(MDIChildCount-1);
  if PrevMDIChild=nil then                    // no MDIchild before activeMDIChild
    begin                                     // get GetMDIChildren(MDIChildCount-1) directly, as we are nearly there
      PrevMDIChild := lastMDIChild;
      While (k<ComponentCount-1) do
        begin
          k := k+1;
          Comp := Components[k];
          if (Comp is TCustomForm) and (TCustomForm(Comp).FormStyle in [fsMDIForm, fsMDIChild]) then
             PrevMDIChild := TCustomForm(Comp);
        end;
     end;
   PrevMDIChild.visible:=true;
   if PrevMDIChild.WindowState=wsMinimized then PrevMDIChild.WindowState:=wsNormal;
   PrevMDIChild.BringToFront;
   PrevMDIChild.SetFocus;
end;


{------------------------------------------------------------------------------
  Method: TForm.Tile
  Params:  None
  Returns: Nothing

  Arranges MDI child forms so that they are all the same size.
  Use Tile to arrange MDI child forms so that they are all the same size.
  Tiled forms completely fill up the client area of the parent form.
  How the forms arrange themselves depends upon the values of
  their TileMode properties, and it depends on widgetset.
  Tile works only if the form FormStyle = fsMDIForm.
 ------------------------------------------------------------------------------}
procedure TForm.Tile;
// see comment before procedure TForm.Cascade
const xframeoffset = 2*defaultFormBorderSize;
      yframeoffset = 2*defaultFormBorderSize+defaultFormCaptionSize;
var TileOk : boolean;
    r      : TRect;
    w,h,k,c,z,x,y : integer;
    comp   : TComponent;
    temp   : TCustomForm;
    visMDIList : TList;
begin
(*  if (FormStyle <> fsMDIForm) then
    exit;
  if HandleAllocated and not (csDesigning in ComponentState) then
    TWSCustomFormClass(WidgetSetClass).Tile(Self);  *)
   if (FormStyle <> fsMDIForm) or (csDesigning in ComponentState) then
    exit;
  if HandleAllocated
    then TileOk:=TWSCustomFormClass(WidgetSetClass).Tile(Self)
    else TileOk:=false;

  if TileOk then exit;      // Tile was done by WidgetSetClass

  visMDIList := TList.Create;
  for k := 0 to screen.CustomFormZOrderCount-1 do                   // activeMDIChild first - position TopLeft; keep old order
   begin
     temp := Screen.CustomFormsZOrdered[k];
     if (temp.FormStyle in [fsMDIForm, fsMDIChild]) and (temp.Owner=self)
         and temp.Visible and (temp.WindowState<>wsMinimized)       // don't tile non-visible or minimized MDIChilds ?
       then visMdiList.Add(temp);
   end;
  if visMdiList.Count>0 then
    begin
      temp:=TCustomForm(visMdiList.Items[0]);
      comp:=temp.Parent;

      if (comp<>nil) and (comp is TCustomForm)
        then r := TCustomForm(comp).ClientRect
        else r := screen.WorkAreaRect;
 (*  { tileMode: vertical }
      z := visMdiList.Count;
      c := 1;  *)

 (*  { tileMode: horizontal }
      z := 1;
      c := visMdiList.Count; *)

     { tileMode: grid-like }
      z:=Round(Sqrt(visMdiList.Count));
      c:=1;
      while z*c<visMdiList.Count do c:=c+1;

      w:=(r.right - r.left) div c;
      h:=(r.bottom - r.top) div z;
      y:=-1;
      if (w>0) and (h>defaultFormCaptionSize) then
        for k:=0 to visMdiList.Count-1 do
          begin
            temp:=TCustomForm(visMdiList.Items[k]);

       (*  { tileMode: vertical }
          //  x := 0;
          //  y := k;
            temp.SetBounds(r.left ,r.top + k*h, w-xframeoffset, h-yframeoffset);
         *)

       (*  { tileMode: horizontal }
          //  x := k;
          //  y := 0;
            temp.SetBounds(r.left + k*w, r.top, w-xframeoffset, h-yframeoffset);
        *)

          { tileMode: grid-like }
            x := k mod c;
            if (x=0) then y:=y+1;
            temp.SetBounds(r.left + x*w, r.top + y*h, w-xframeoffset, h-yframeoffset);
          end;
      end;
  visMDIList.Free;
end;
--
_______________________________________________
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply via email to