{ Tenth example of program.
  This example show how to create a Multiple Document Interface (MDI)
  which is a window containing other windows.
  using the library
  wApplication0  as usuall
  wMDIWindow0  to treat MDI main window
  wMDIChildWindow0  to treat MDI child window

  uses the library to simplify greatly the treatment of MDI windows.

  This is a small example, of creating an MDI, with a menu,
  and default simple behaviour
  --------------------------------------------}
program tEx010;

// To tell FreePascal that the application is a Graphical User Interface
// i.e. is running in windows, not in text mode.
{$APPTYPE GUI}

Uses
  Windows
 ,wApplication0
 ,wMDIWindow0
 ,wMDIChildWindow0
 ,wDebug0;

type
  PMyMDIWindow = ^TMyMDIWindow;
  TMyMDIWindow = object(TMDIWindow)
  //"""""""""""""""""""""""""""""""
  constructor Init(strWinTitlePrm:ShortString);
  destructor Done; virtual;

  // Add a menu to the window
  procedure MenuCreate; virtual;

  procedure CreateMDIChild; virtual;

  // Handles the menu messages
  function WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;

  function WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  end; // TMyMDIWindow = object(TMDIWindow0)

type
  PMyMDIChildWindow = ^TMyMDIChildWindow;
  TMyMDIChildWindow = object(TMDIChildWindow)
  //"""""""""""""""""""""""""""""""""""""""""
  constructor Init(strWinTitlePrm:ShortString);
//  destructor Done; virtual;

  // Text specific to each child window
  strText : string[100];

  // Memorise the value of the glnCpt for each MDI child window
  nCpt : integer;

  function WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  end; // TMyMDIChildWindow = object(TMDIChildWindow0)

const
  // Child window count
  glnCpt : integer = 0;
  // menu id in the WM_Command when a MDI child window is selected in the menu
  cteFiveHund = 500;

var
  oApp        : TApplication0;
  poMyMainWin : PMyMDIWindow;

// var nNotUsed : integer; // only to avoid an error message while compliling in DevPascal 1.9

//***************************************************
// TMyMDIWindow = object(TMDIWindow)
//***************************************************

constructor TMyMDIWindow.Init(strWinTitlePrm:ShortString);
//========================================================
begin
inherited init(strWinTitlePrm);

// in which sub menu will the child window menu appair
// 0 => appair in the first menu (File menu usually)
// 1 => appair in the second menu (Edit menu)
// usually set a number to have it in the 'Window' menu
// this is usually set by the user
// In the case of this demo, the Window menu is the second, thus :=1;
nChildSubMenuPos :=1;

// When a child window is created, it will appair in the subMenu.
// designated by 'nChildSubMenuPo'
// When it is selected, it will send a WM_Command
// with wPar = nChildSubMenuID     for the first child,
// with wPar = nChildSubMenuID + 1 for the second child
// with wPar = nChildSubMenuID + 2 for the Third child
// etc.
// with wPar = nChildSubMenuID + 8 for the ninth child
// with wPar = nChildSubMenuID + 9 when a dialog with a list box is opened.
// this is usually set by the user
// set a number not used in the menu.
nChildSubMenuID :=cteFiveHund;

end;  // TMyMDIWindow.Init

destructor TMyMDIWindow.Done;
//===========================
begin
inherited done;
end;  // TMyMDIWindow.Done

procedure TMyMDIWindow.MenuCreate;
//================================
var
  hSubMenu    : HMenu;

begin
hMenuWin := CreateMenu;
hSubMenu := CreateMenu;
AppendMenu(hSubmenu,MF_STRING,100,'&New child window');
AppendMenu(hSubmenu,MF_SEPARATOR,0,Nil);
AppendMenu(hSubmenu,MF_STRING,101,'&Close child window');
AppendMenu(hSubmenu,MF_SEPARATOR,0,Nil);
AppendMenu(hSubMenu,MF_String,199,'E&xit');
AppendMenu(hMenuWin, MF_POPUP, hSubMenu, '&File');

hSubMenu := CreateMenu;
AppendMenu(hSubmenu,MF_STRING,200,'&Tile');
AppendMenu(hSubmenu,MF_STRING,201,'&Cascade');
AppendMenu(hSubmenu,MF_STRING,202,'&Arange icons');
AppendMenu(hMenuWin, MF_POPUP, hSubMenu, '&Window');
end;  // TMyMDIWindow.MenuCreate

procedure TMyMDIWindow.CreateMDIChild;
//====================================
// From the menu, a new child window can be opened
var
  poMDIChild  : PMyMDIChildWindow;
  strTitle    : string[30];

begin
inc(glnCpt);
strTitle :='Hello ' + IntToStr(glnCpt,3);

new(poMDIChild, init(strTitle));

poMDIChild^.strText :=strTitle;

// Creates an MDI child window, and gives it a pointer on its grand parent.
poMDIChild^.WinMDICreate(@Self);
end;  // TMyMDIWindow.CreateMDIChild

function TMyMDIWindow.WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT;
//================================================================
// Handles the menu messages
Var
  wNrMenu     : word;
  hWinChild   : HWND; // handle of the active MDI child window
begin
WMCommand := 0; // Default return value when processing a message

if (lPar <> 0) then begin
   WMCommand:=inherited WMCommand(wPar, lPar);
   exit;
   end;

// for the menu, lPar = 0
wNrMenu   := LoWord(wPar);
Case wNrMenu Of
   // from the file menu
   100 : CreateMDIChild;
   199 : PostMessage( hWin,WM_Close,0,0);

   // from the window menu
   101 : begin
      hWinChild:=LOWORD (SendMessage (hWinClient, WM_MDIGETACTIVE, 0, 0)) ;

      if (SendMessage ( hWinChild, WM_QUERYENDSESSION, 0, 0) <> 0) then
         SendMessage (hWinClient, WM_MDIDESTROY, hWinChild, 0);
      end;
{   102 : begin // Attempt to close all children
         lpfnEnum := MakeProcInstance (CloseEnumProc, system.MainInstance) ;
         EnumChildWindows (hwndClient, lpfnEnum, 0) ;
         FreeProcInstance (lpfnEnum) ;
         end;}

   // Messages for arranging windows
   200 : SendMessage (hWinClient, WM_MDITILE, 0, 0);
   201 : SendMessage (hWinClient, WM_MDICASCADE, 0, 0);
   202 : SendMessage (hWinClient, WM_MDIICONARRANGE, 0, 0);

   cteFiveHund..cteFiveHund+9 : begin
      // it is difficult to know to which MDI child window
      // this menu message is destinated.
      // But using the default window handling, does what one expect.
      // DBW0(16, 'menu :' + ITS(wPar) + ITS(lPar));

      // Menu messages corresponding to the selection of a child window
      // should call the inherited method to have the default handling
      WMCommand:=inherited WMCommand(wPar, lPar);
      end;

   else WMCommand:=inherited WMCommand(wPar, lPar);
   end;  // Case NrMenu Of
end;  // TMyMDIWindow.WMCommand

function TMyMDIWindow.WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT;
//==========================================================================================
// All window messages are send here.
Begin
WindowProc := 0; // Default return value when processing a message
// DBW0(1024, DBMsgToStr(wMsg));

Case wMsg Of
   WM_Destroy : PostQuitMessage (0); // quit the application
   WM_Command : WindowProc:=WMCommand(wPar, lPar);
   else begin // Case wMsg Of
      // Default processing of the messages, for MDI windows
      WindowProc:=inherited WindowProc(hWindow, wMsg, wPar, lPar);
      end; // else Case wMsg Of
   End; // Case wMsg Of
End;  // TMyWindow.WindowProc

//***************************************************
// TMyMDIChildWindow = object(TMDIChildWindow0)
//***************************************************

constructor TMyMDIChildWindow.Init(strWinTitlePrm:ShortString);
//============================================================
begin
inherited Init(strWinTitlePrm);

strText:='';

nCpt:=glnCpt;
end;  // TMyMDIChildWindow.Init

function TMyMDIChildWindow.WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT;
//===============================================================================================
// All window messages are send here.
var
  hDevC       : HDC; // handle on a device context, to paint.
  rPaint      : TPAINTSTRUCT; // = PAINTSTRUCT in C c.f. Win 32 Reference help (Win32.hlp)
  rRec        : RECT;

Begin
WindowProc := 0; // Default return value when processing a message

case wMsg of
   // processing of messages
   WM_PAINT : begin // Paint the MDI Child window
      hDevC := BeginPaint (hWindow, @rPaint) ;
      SetTextColor (hDevC, RGB( 255 - ((60*nCpt) mod 250),
                                      (130*nCpt) mod 250, 0)) ;
      GetClientRect (hWindow, @rRec);
      rRec.Top:=rRec.Top - 25;
      DrawText ( hDevC, 'New Hello, World!', -1, @rRec,
                 DT_SINGLELINE or DT_CENTER or DT_VCENTER);
      rRec.Top:=rRec.Top + 50;
      DrawText ( hDevC, @strText[1], length(strText), @rRec,
                 DT_SINGLELINE or DT_CENTER or DT_VCENTER);

      EndPaint (hWindow, @rPaint) ;
      end;
   else WindowProc := inherited WindowProc(hWindow, wMsg, wPar, lPar);
        // Default message handling for MDI child windows
   end; // case
End;  // TMyMDIChildWindow.WindowProc

//*********************************************************
// Main programm
//*********************************************************

Begin // MAIN ******
// Name under which the main window is registered. Spaces are not allowed
oApp.Init('Example010');

// Creation of the main window
new(poMyMainWin, Init('Title of the MDI Example010 (Ex010.pp) Window'));

// The App.WindowClass can be modified here, if wanted. (Not usual)
oApp.Run;
oApp.Done;  // The main window object is disposed here.
End. // program tEx010;

