{ Example of a program using the  wMenus0.pp  unit.
  This is the third example which uses really the Message file, and
  and a description of its menu in the message file.
  It uses the facilities of the library.
  The menu is generated automatically, because the corresponding
  message file exist (tEx031.msg) and line index 10000 is :
  10000 AutoCreate
  # here the menu description comes, c.f. tEx032.msg

  Also the handling of window messages is done automatically,
  the disposal of the menu object also.

  This example is the same as example tEx032.pp but adds the
  functionality of a little MDI editor, similar to the one
  of example tEx012.pp
  See how many code lines have been removed, because they are automatically
  treated in the library.

  It's only to show how simple it became to have the beginning
  of an editor if the GAP library is used.
  --------------------------------------------}
program tEx033;

// 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
 ,wRichText0
 ,wDebug0;

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

  procedure WinCreate(strWinClass:ShortString); virtual;
  // When creating the window, controls will be added.

  procedure CreateMDIChild; virtual;

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

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

type
  PMyMDIChildWindow = ^TMyMDIChildWindow;
  TMyMDIChildWindow = object(TMDIChildWindow)
  //"""""""""""""""""""""""""""""""""""""""""
  // Usually it is better to have a pointer on objects than objects,
  // since pointer can also designate descendent of the objects.
  // More, pointer can be nil, indicating that is has not been initialised.
  oRichEdit   : TRichText;   // RichEdit control contained in the window

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

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

  constructor Init(strWinTitlePrm:ShortString);

  // creation of an MDI child window
  // Can be overriden
  // poGrParentPrm is a pointer on the grand parent, which is normally
  // the main application MDI window
  procedure WinMDICreate(poGrParentPrm:PMDIWindow0); virtual;

  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 :=3;

// 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;

// This line is all what is needed to have a status line.
new(poStatusLine, Init(@Self));
end;  // TMyMDIWindow.Init

procedure TMyMDIWindow.WinCreate(strWinClass:ShortString);
//========================================================
// Creates a new window.
Begin
inherited WinCreate(strWinClass);

// At the begining, there are no window to edit.
poMenu^.EnableMenuItemByMsgNum(10001, MF_GRAYED);
poMenu^.EnableMenuItemByMsgNum(10002, MF_GRAYED);
poMenu^.EnableMenuItemByMsgNum(10003, MF_GRAYED);
poMenu^.EnableMenuItemID(101, MF_GRAYED);
poMenu^.EnableMenuItemID(102, MF_GRAYED);
poMenu^.EnableMenuItemID(103, MF_GRAYED);
poMenu^.EnableMenuItemID(104, MF_GRAYED);
poMenu^.EnableMenuItemID(65400, MF_GRAYED);
DrawMenuBar(hWin); // must redraw the menu bar

End;  // TMyMDIWindow.WinCreate

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);

// If a child window has been created, then we can edit it
// Thus enable the menus concerning child windows.
poMenu^.EnableMenuItemByMsgNum(10001, MF_ENABLED);
poMenu^.EnableMenuItemByMsgNum(10002, MF_ENABLED);
poMenu^.EnableMenuItemByMsgNum(10003, MF_ENABLED);
poMenu^.EnableMenuItemID(101, MF_ENABLED);
poMenu^.EnableMenuItemID(102, MF_ENABLED);
poMenu^.EnableMenuItemID(103, MF_ENABLED);
poMenu^.EnableMenuItemID(104, MF_ENABLED);
poMenu^.EnableMenuItemID(65400, MF_ENABLED);
DrawMenuBar(poMyMainWin^.hWin); // must redraw the menu bar
end;  // TMyMDIWindow.CreateMDIChild

function TMyMDIWindow.WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT;
//================================================================
// Handles the menu messages
Var
  wNrMenu     : word;

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);
if (gglpoMDIActiveWindow <> NIL) then
   with PMyMDIChildWindow(gglpoMDIActiveWindow)^ do begin
   Case wNrMenu Of
      // these treatments will become standard in the library in a next version.
      // menu number over 30000 are reserved for the library.
      101 : oRichEdit.NewText;
      102 : oRichEdit.LoadRICH;
      103 : oRichEdit.SaveRICH;
      104 : oRichEdit.SaveRICHas;

      201 : oRichEdit.UndoText;
      202 : oRichEdit.CutText;
      203 : oRichEdit.CopyText;
      204 : oRichEdit.PasteText;
      205 : oRichEdit.SelectAllText;
      301 : oRichEdit.SelectFont;
      end; // case
   end;

Case wNrMenu Of
   // from the file menu
   100 : CreateMDIChild;
   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.
// For the state of the development of the program,
Begin
{  Useless, but kept for tests.
WindowProc := 0; // Default return value when processing a message

Case wMsg Of
   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
}
WindowProc:=inherited WindowProc(hWindow, wMsg, wPar, lPar);
End;  // TMyWindow.WindowProc

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

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

strText:='';

nCpt:=glnCpt;

// change the default size
nWidth  :=350;
nHeight :=200;

// Initialise the object oEditB
oRichEdit.Init(@Self);

oRichEdit.vXSizeRel:=1;
oRichEdit.vYSizeRel:=1;
end;  // TMyMDIChildWindow.Init

procedure TMyMDIChildWindow.WinMDICreate(poGrParentPrm:PMDIWindow0);
//==================================================================
// creation of an MDI child window
begin
inherited WinMDICreate(poGrParentPrm);

// Tell the edit box that the main window has a status bar.
oRichEdit.poStatusLine:=poMyMainWin^.poStatusLine;

// Size = the whole client areat
oRichEdit.vXSizeRel:=1;  // if you don't specify, it is set automatically
oRichEdit.vYSizeRel:=1;  // but for clarity, it is better to specify.

// The status line is in the main window.
oRichEdit.CtrlCreate;
SetFocus(oRichEdit.hWin);

// Set the status line state.
with PMyMDIWindow(poGrParent)^ do begin
   oRichEdit.SetModifyState(oRichEdit.fModified);
   end;
end;  // TMyMDIChildWindow.WinMDICreate

function TMyMDIChildWindow.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

case wMsg of
   // processing of messages
   WM_DESTROY : begin
      // A complicate way to know if it was the last MDI child window
      // But it works, desactivate corresponding menus.
      if (Cardinal(EnableMenuItem( poMyMainWin^.poMenu^.hMenuObj, cteFiveHund,
                          MF_BYCOMMAND or MF_ENABLED)) = -1) then begin
         // it was the last child window, desactivate the menu Edit.
         poMyMainWin^.poMenu^.EnableMenuItemByMsgNum(10001, MF_GRAYED);
         poMyMainWin^.poMenu^.EnableMenuItemByMsgNum(10002, MF_GRAYED);
         poMyMainWin^.poMenu^.EnableMenuItemByMsgNum(10003, MF_GRAYED);
         poMyMainWin^.poMenu^.EnableMenuItemID(101, MF_GRAYED);
         poMyMainWin^.poMenu^.EnableMenuItemID(102, MF_GRAYED);
         poMyMainWin^.poMenu^.EnableMenuItemID(103, MF_GRAYED);
         poMyMainWin^.poMenu^.EnableMenuItemID(104, MF_GRAYED);
         poMyMainWin^.poMenu^.EnableMenuItemID(65400, MF_GRAYED);
         DrawMenuBar(poMyMainWin^.hWin); // must redraw the menu bar
         end;
      end;

   WM_Close : begin
      // Ask only if it is closed explicitely, not if the main window is closed
      oRichEdit.AskSave;
      WindowProc:=inherited WindowProc(hWindow, wMsg, wPar, lPar);
      end;
   WM_SETFOCUS : begin
      // The status line must change
      with  PMyMDIWindow(poGrParent)^ do begin
         oRichEdit.SetModifyState(oRichEdit.fModified);
         end;

      // give the focus to the rich text.
      SetFocus(oRichEdit.hWin);
      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('Example033');

// Creation of the main window
new(poMyMainWin, Init('tEx033. A little MDI text editor. Very simple to create.'));

oApp.Run;
oApp.Done;  // The main window object is disposed here.
End. // program tEx012;

