{ Fifth 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

  Example of a second window, having its own menu and own
  message processing.
  This is unusual, and needs some work.

  This example is only a minimal work to have the second window,
  but not very interresting.

  tEx006.pp  is a more elaborated example, modifying more things
  in the secondary window.
  It will also modify the  TApplicParam2  object to save more information
  in the  .prm  parameter file.

  Facilities from the library are used to process the messages.

  Both the main window and the second window will be able to
  edit a small text, only to have something special to do.
  Both windows quite the application when closed.

  This example is based on the  Edit.pp  example, created by
  Copyright (c) 1999 by Michael van Canneyt and Goran Andersson
  ----------------------------------------------------------------}
program tEx005;

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

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

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

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

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

  // Put  strWinClass = ''  to use the class defined in the application object
  // This is what is usually done.
  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)

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

// Initialise the object oStatusL and oEditB
oStatusL.Init(@Self);
oEditB.Init(@Self);
end;  // TMyWindow.Init

destructor TMyWindow.Done;
//========================
begin
oStatusL.Done;
oEditB.Done;

inherited Done;
end;  // TMyWindow.Init

procedure TMyWindow.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,'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');

// usually hWin = 0 here, and the menu is set into the window
// at the creation of the window
if (hWin <> 0) then SetMenu(hWin, hMenuWin);
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);

oStatusL.statuscreate;

// Add a status bar to the edit box
oEditB.poStatusLine:=@oStatusL;

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

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

// Then create the editbox.
oEditB.CtrlCreate;

SetFocus(oEditB.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
wNrMenu   := LoWord(wPar);
case wNrMenu of
   101 : oEditB.NewText;
   102 : oEditB.LoadText;
   103 : oEditB.SaveText;
   104 : PostMessage(hWin, WM_Close,0,0);
   201 : SendMessage(oEditB.hWin, WM_Undo,0,0);
   202 : SendMessage(oEditB.hWin, WM_Cut,0,0);
   203 : SendMessage(oEditB.hWin, WM_Copy,0,0);
   204 : SendMessage(oEditB.hWin, WM_Paste,0,0);
   301 : oEditB.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
      oEditB.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 : SetFocus(oEditB.hWin);
   WM_Size : begin
      // the controls must be replaced at their right place.
      // In the next version, these calls will not be necessary.
      oStatusL.NotifyParentResize(FALSE);
      oEditB.NotifyParentResize(FALSE);
      end;

   WM_Command : WindowProc:=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

var
  oApp        : TApplication;
  poMySecWin,
  poMyMainWin : PMyWindow;
  
  // Window Class to register the second window
  SecWindowClass : WndClassEx;

// THIS NEW EVENT HANDLER IS IMPORTANT FOR THE SECOND WINDOW
Function SecWindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; stdcall; export;
//=================================================================================================
Begin
// Call the event handler of the second application window.
SecWindowProc := poMySecWin^.WindowProc(hWindow, wMsg, wPar, lPar);
End;  // SecWindowProc

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

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

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

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

// Registering the class of the main window
// ''''''''''''''''''''''''''''''''''''''''
// Copying the WindowClass record defined in oApp.Init
SecWindowClass:=oApp.WindowClass;

// Usually it is not necessary to register a second window class

// Name under which the second window is registered. Spaces are not allowed
SecWindowClass.lpszClassName:='Example005_SecWin';
// Changes the event handler of the second window
SecWindowClass.lpfnWndProc:=WndProc(@SecWindowProc);

if (RegisterClassEx(SecWindowClass) = 0) then begin
   MessageBox (0, 'Second Window Register failed', NIL, mb_Ok);
   end
else begin
   // Creating the second window
   poMySecWin^.WinCreate('Example005_SecWin');
   if longint(poMySecWin^.hWin)=0 then begin
      MessageBox (0, 'Second WinCreate failed', NIL, MB_OK);
      end;
   end;

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

dispose(poMySecWin, Done);  // destroys the second window object.
End. // tEx005.pp

