{ Sixth example of program using the units
  wApplication0.pp  and  wWindow0.pp
  wEditBox0.pp  to facilitate to have an editBox in a window
  wStatusLine0.pp to have a status line at the bottom of a window
  wApplicParam2.pp to add some information in the  .prm  parameter file
                   which saves information about the application,
                   such as windows sizes and positions.

  Example of a second window, having its own menu and own
  message processing.
  This is unusual, and needs some work.
  In  tEx005.pp  example was given, with minimal changes.

  This example is more elaborated, modifying more things
  in the secondary window.

  It will also show how the  TObjectCreator2  can be used, to
  modify the  TApplicParam2  object to save more information
  in the  .prm  parameter file.
  In fact, no! I did it another way, without the need to define
  a descendent of  TObjectCreator2.
  The two lines just after the begin of the main Window
  make that the library will use the application parameters.
  new(poMyAppPrm, Init);
  gglpoAppPrm:=poMyAppPrm; // it will be destroyed in the TApplication automatically

  Both the main window and the second window will be able to
  edit a small text, only to have something special to do.
  ----------------------------------------------------------------}
program tEx006;

// 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
 ,wWindow0
 ,wStatusLine0
 ,wEditBox0
 ,wParamApplic2
 ,wDebug0;

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

type
  PMyWindow = ^TMyWindow;
  TMyWindow = object(TWindow)
  //"""""""""""""""""""""""""
  // 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.
  poEditB      : PEditBox;    // Edit Box contained in the window
  poStatusL    : PStatusLine; // Status line of the main window

  constructor Init(strWinTitlePrm:ShortString);
  destructor Done; virtual;

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

  // strWinClass='' to use the class defined in the Application object
  procedure WinCreate(strWinClass:ShortString); 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; // TMyWindow = object(TWindow)

type
  PMySecWindow = ^TMySecWindow;
  TMySecWindow = object(TMyWindow)
  //""""""""""""""""""""""""""""""
  fClosed : boolean; // indicate if the window is closed or opened.

  constructor Init(strWinTitlePrm:ShortString);
  destructor Done; virtual;

  // Add a menu to the window
  // The menu of the second window is different from the one of the main window
  procedure MenuCreate; virtual;

  // strWinClass='' to use the class defined in the Application object
  procedure WinCreate(strWinClass:ShortString); 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; // TMySecWindow = object(TMyWindow)

// To add functionalities to the application parameters,
// which are saved in a file.
type
  PMyParamApplic = ^TMyParamApplic;
  TMyParamApplic = object(TParamApplic)
  //"""""""""""""""""""""""""""""""""""
  constructor Init;
//  destructor  Done; virtual;  use default

  // To save some parameters informations in the text file fOut
  // This is often overriden
  procedure SavePrmWrite(var fOut:text); virtual;

  // To load some parameters informations from the text file fIn
  // This is often overriden
  procedure LoadPrmRead(var fIn:text);  virtual;
  end; // TMyParamApplic = object(TParamApplic2)

var
  oApp        : TApplication;
  poMyMainWin : PMyWindow;
  poMySecWin  : PMySecWindow;
  poMyAppPrm  : PMyParamApplic;

//*****************************************************************
// TMyWindow
//*****************************************************************

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

{ You could change the default position and size of the window here,
  but it is not a good idea, since position and size will be the
  same as they were when the windo was closed
// To change the default position and size of the window when created.
nLeft   :=5;
nTop    :=50;
nWidth  :=400;
nHeight :=200;
---------------}

// Create and initialise the object poStatusL^ and poEditB^
new(poStatusL, Init(@Self));
new(poEditB, Init(@Self));
end;  // TMyWindow.Init

destructor TMyWindow.Done;
//========================
// This destructor is useless, and could let the parent do all the job.
// thus it simplifies the code to write. (Less code)
begin
// the next two lines does not harm (i.e. they make no problem,
// But they are useless, since the disposes are done in the
// parent ("inherited Done") methods.
// if (poStatusL <> NIL) then dispose(poStatusL, Done);
// if (poEditB   <> NIL) then dispose(poEditB, Done);
poStatusL :=NIL; // useless
poEditB   :=NIL; // useless

inherited Done;
end;  // TMyWindow.Done

procedure TMyWindow.MenuCreate;
//=============================
var
  hSubMenu    : HMenu;
begin
hMenuWin := CreateMenu;
hSubMenu := CreateMenu;
AppendMenu(hSubmenu,MF_STRING,100,'New Second Win');
AppendMenu(hSubmenu,MF_STRING,101,'&New...');
AppendMenu(hSubmenu,MF_STRING,102,'&Open...');
AppendMenu(hSubmenu,MF_STRING,103,'&Save...');
AppendMenu(hSubmenu,MF_SEPARATOR,0,Nil);
AppendMenu(hSubMenu,MF_String,104,'E&xit');
AppendMenu(hMenuWin, MF_POPUP, hSubMenu, '&File');

hSubMenu := CreateMenu;
AppendMenu(hSubMenu,MF_String,201,'&Undo'#8'Ctrl+Z');
AppendMenu(hSubmenu,MF_SEPARATOR,0,Nil);
AppendMenu(hSubMenu,MF_String,202,'&Cut'#8'Ctrl+X');
AppendMenu(hSubMenu,MF_String,203,'&Copy'#8'Ctrl+C');
AppendMenu(hSubMenu,MF_STRING,204,'&Paste'#8'Ctrl+V');
AppendMenu(hMenuWin, MF_POPUP, hSubMenu, '&Edit');

hSubMenu := CreateMenu;
AppendMenu(hSubMenu,MF_String,301,'&Font...');
AppendMenu(hMenuWin, MF_POPUP, hSubMenu,'&Options');

// this is not a good example, normally a top menu should have a sub-menu
AppendMenu(hMenuWin, MF_STRING, 401, '&Help');
end;  // TMyWindow.MenuCreate

procedure TMyWindow.WinCreate(strWinClass:ShortString);
//=====================================================
// Create the window, and insert an edit box and a status line in it.
begin
inherited WinCreate(strWinClass);

if (poStatusL <> NIL) then poStatusL^.statuscreate;
if (poEditB   <> NIL) then begin
   // Add a status bar to the edit box it poStatusL <> NIL
   poEditB^.poStatusLine:=poStatusL; // can be NIL too

   // Change the style to be multiline and have scrollbars.
   poEditB^.dwStyle:= WS_Child or WS_HScroll or WS_VScroll or ES_MultiLine or
                      ES_Left;

   // Size = the whole client areat
   poEditB^.vXSizeRel:=1;
   poEditB^.vYSizeRel:=1;

   poEditB^.CtrlCreate;
   SetFocus(poEditB^.hWin);
   end;

// Creation of the second window
if (poMySecWin^.hWin = 0) then begin
   // if you remove the next comment, the second window will remain over the main window
   // poMySecWin^.hParent:=hWin;
   poMySecWin^.WinCreate('');

   // IF you let the two following code lines away, there is no
   // problems, but the parent will not dispose automatically
   // this second object window.
   // say who is the parent object window.
   poMySecWin^.poParent:=gglpoMainWindow;

   // Add it to the parent's child list.
   poMySecWin^.poParent^.AddChildObjectWindow(poMySecWin);
   end;

SetFocus(hWin);
end;  // TMyWindow.WinCreate

function TMyWindow.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
// Here I assume that  poEditB  is well defined.
wNrMenu   := LoWord(wPar);
case wNrMenu of
   100 : begin
         if (poMySecWin^.fClosed) then poMySecWin^.WinCreate('')
         else MessageBox( hWin, 'Second window is already opended',
                          'Information',
                          MB_OK Or MB_IconInformation);
         end;
   101 : poEditB^.NewText;
   102 : poEditB^.LoadText;
   103 : poEditB^.SaveText;
   104 : PostMessage(hWin, WM_Close,0,0);
   201 : SendMessage(poEditB^.hWin, WM_Undo,0,0);
   202 : SendMessage(poEditB^.hWin, WM_Cut,0,0);
   203 : SendMessage(poEditB^.hWin, WM_Copy,0,0);
   204 : SendMessage(poEditB^.hWin, WM_Paste,0,0);
   301 : poEditB^.SelectFont;
   401 : MessageBox( hWin, 'Help', 'Not implemented',
                     MB_OK Or MB_IconInformation);
   else WMCommand:=inherited WMCommand(wPar, lPar);
   end;  // case
end;  // TMyWindow.WMCommand

function TMyWindow.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
   WM_Close : begin
      if (poEditB <> NIL) then poEditB^.AskSave;
      WindowProc:=inherited WindowProc(hWindow, wMsg, wPar, lPar);
      end;
//   WM_Destroy : PostQuitMessage (0); // This is the default behaviour.
//              This should not be treated here, or at least the
//              inherited WindowProc should be called.
//              This allows to save the window position and size in a file
   WM_SetFocus : if (poEditB <> NIL) then SetFocus(poEditB^.hWin);
   WM_EraseBkgnd : Exit;
   WM_Size : begin
      // the controls must be replaced at their right place.
      // In the next version, these calls will not be necessary.
      if (poStatusL <> NIL) then poStatusL^.NotifyParentResize(FALSE);
      if (poEditB <> NIL) then poEditB^.NotifyParentResize(FALSE);
      end;

   WM_Command : WMCommand(wPar, lPar);

   else begin // Case wMsg Of
      // Default processing of the messages.
      WindowProc:=inherited WindowProc(hWindow, wMsg, wPar, lPar);
      end; // Case wMsg Of
   End; // Case wMsg Of

End;  // TMyWindow.WindowProc

//*****************************************************************
// TMySecWindow
//*****************************************************************

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

fClosed:=TRUE;

// Just to have a difference, the second window doesn't have a status line.
poStatusL:=NIL;

// in reallity a status line object has been created, but it will not be used
// in this second window
end;  // TMySecWindow.Init

destructor TMySecWindow.Done;
//===========================
begin
inherited Done;
end;  // TMySecWindow.Done

procedure TMySecWindow.MenuCreate;
//================================
var
  hSubMenu     : HMenu;
begin
hMenuWin := CreateMenu;
hSubMenu := CreateMenu;
AppendMenu(hSubmenu,MF_STRING,101,'&New...');
AppendMenu(hSubmenu,MF_STRING,102,'&Open...');
AppendMenu(hSubmenu,MF_STRING,103,'&Save...');
AppendMenu(hSubmenu,MF_SEPARATOR,0,Nil);
AppendMenu(hSubMenu,MF_String,104,'&Close');
AppendMenu(hMenuWin, MF_POPUP, hSubMenu, '&File');

hSubMenu := CreateMenu;
AppendMenu(hSubMenu,MF_String,201,'&Undo'#8'Ctrl+Z');
AppendMenu(hSubmenu,MF_SEPARATOR,0,Nil);
AppendMenu(hSubMenu,MF_String,202,'&Cut'#8'Ctrl+X');
AppendMenu(hSubMenu,MF_String,203,'&Copy'#8'Ctrl+C');
AppendMenu(hSubMenu,MF_STRING,204,'&Paste'#8'Ctrl+V');
AppendMenu(hMenuWin, MF_POPUP, hSubMenu, '&Edit');

hSubMenu := CreateMenu;
AppendMenu(hSubMenu,MF_String,301,'Hint &1...');
AppendMenu(hSubMenu,MF_String,302,'Hint &2...');
AppendMenu(hSubmenu,MF_SEPARATOR,0,Nil);
AppendMenu(hSubMenu,MF_String,303,'&About...');
AppendMenu(hMenuWin, MF_POPUP, hSubMenu, '&Help');
end;  // TMySecWindow.MenuCreate

procedure TMySecWindow.WinCreate(strWinClass:ShortString);
//========================================================
// Create the window, and insert an edit box and a status line in it.
begin
// To load the position and size of the window when it was closed.
gglpoPrm^.LoadPrm;

inherited WinCreate(strWinClass);

fClosed := (longint(hWin) = 0);
if fClosed then begin
   MessageBox (0, 'Second WinCreate failed', NIL, MB_OK);
   end;
end;  // TMySecWindow.WinCreate

function TMySecWindow.WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT;
//=================================================================
// Handles the menu messages
Var
  wNrMenu     : word;
begin
if (lPar <> 0) then begin
   WMCommand:=inherited WMCommand(wPar, lPar);
   exit;
   end;

// for the menu, lPar = 0
wNrMenu   := LoWord(wPar);
case wNrMenu of
   301 : MessageBox( hWin, 'Status line has gone in this window', 'Hint 1',
                     MB_OK Or MB_IconInformation);
   302 : MessageBox( hWin, 'Options have been removed', 'Hint 2',
                     MB_OK Or MB_IconInformation);
   303 : MessageBox( hWin, 'Example 006 of two windows', 'About',
                     MB_OK Or MB_IconInformation);
   else WMCommand:=inherited WMCommand(wPar, lPar);
   end;  // case
end;  // TMySecWindow.WMCommand

function TMySecWindow.WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT;
//====================================================================================
// All messages to the second window are send here.
Begin
WindowProc := 0; // Default return value when processing a message

Case wMsg Of
   WM_Destroy : begin
      // save the position of the windows in a .prm file
      // to be restaured when they are reopened
      gglpoPrm^.SavePrm;

      // indicate that the second window is closed
      fClosed:=TRUE;
      end; // doesn't quit the main window

   else begin // Case wMsg Of
      // Default processing of the messages.
      WindowProc:=inherited WindowProc(hWindow, wMsg, wPar, lPar);
      end; // Case wMsg Of
   End; // Case wMsg Of

End;  // TMySecWindow.WindowProc

//*****************************************************************
// TMyParamApplic = object(TParamApplic2)
//*****************************************************************

constructor TMyParamApplic.Init;
//==============================
begin
inherited Init;
end;  // TMyParamApplic.Init

procedure TMyParamApplic.SavePrmWrite(var fOut:text);
//===================================================
begin
// First let the parent write its parameters, then its your turn.
inherited SavePrmWrite(fOut);

{$i-}
writeln(fOut, '...Signature : Param of Main Application');
writeln(fOut, 100, '   = Version');

// Saves the position and size of the second window
writeln(fOut, poMySecWin^.nLeft:6,  ' ', poMySecWin^.nTop:6, ' ',
              poMySecWin^.nWidth:6, ' ', poMySecWin^.nHeight:6);
end;  // TMyParamApplic.SavePrmWrite

procedure TMyParamApplic.LoadPrmRead(var fIn:text);
//=================================================
var
  strS        : ShortString;
  nErr,
  nVersion,
  nLeft, nTop,
  nWidth, nHeight : integer;

begin
// First let the parent read its parameters, then its your turn.
inherited LoadPrmRead(fIn);

{$i-}
readln(fIn, strS);
// strS should equal '...Signature : Param of Main Application'

readln(fIn, nVersion);
readln(fIn, nLeft, nTop, nWidth, nHeight);

nErr:=IOResult;
if (nErr <> 0) then exit; // error, not normal !?!
if (nHeight <= 0) or (nWidth <= 0) then exit; // not normal

poMySecWin^.nLeft   :=nLeft;
poMySecWin^.nTop    :=nTop;
poMySecWin^.nWidth  :=nWidth;
poMySecWin^.nHeight :=nHeight;
end;  // TMyParamApplic.LoadPrmRead

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

Begin // MAIN ******
// to use the application parameters defined here.
new(poMyAppPrm, Init);
gglpoPrm:=poMyAppPrm; // it will be destroyed in the TApplication automatically

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

// creates the main window object
new(poMyMainWin, Init('Title of the Example006 (Ex006.pp) Window'));

// Second window
new(poMySecWin, Init('Title of the Second Window, without status line'));

// it is not necessary to register the second window class.
// the event handler will be directed to the right window object.

// Since registration is done in the oApp.run,
// creation of a new window can only be done later,
// for example in the creation of the main window.
oApp.Run; // the main window is created here.
oApp.Done;  // The main window object is disposed here.

// Do not dispose the second window object.
// It has been done by the parent already.
// if (poMySecWin <> NIL) then dispose(poMySecWin, Done);

DBWaitSec(10);
End. // tEx006.pp

