{  Example of program using the units
   wError0.pp,
   A unit to write in an independent window, errors messages.
   There are always parts of program, where
   normally, a condition must be satified, but we are never sure.
   For example, when memory becomes unavailable, many errors can occurs,
   which were not planned.

   It starts from tEx004.pp, and generate some error message
   to see how it works.
  ----------------------------------------------------------------}
program tEx013;

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

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

type
  PMyWindow = ^TMyWindow;
  TMyWindow = object(TWindow0)
  //"""""""""""""""""""""""""
  // 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      : TEditBox0;    // Edit Box contained in the window
  oStatusL    : TStatusLine0; // Status line of the main window

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

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

  // Set  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)

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

// 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,310,'&Opens the error window');
AppendMenu(hSubMenu,MF_String,311,'Error &1');
AppendMenu(hSubMenu,MF_String,312,'Error &2');
AppendMenu(hSubMenu,MF_String,313,'Error &3');
AppendMenu(hSubmenu,MF_SEPARATOR,0,Nil);
AppendMenu(hSubMenu,MF_String,301,'&Font...');
AppendMenu(hMenuWin, MF_POPUP, hSubMenu, '&Options');

hSubMenu := CreateMenu;
AppendMenu(hSubMenu,MF_String, 401, 'mini &Info...');
AppendMenu(hMenuWin, MF_POPUP, hSubMenu, '&Help');
end;  // TMyWindow.MenuCreate

procedure TMyWindow.WinCreate(strWinClass:ShortString);
//=====================================================
// Create the window, and insert an edit box and a status line in it.
begin
// here strWinClass=''.
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

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;
   310 : ErrorWrite(0, ''); // Opens the error window
   311 : begin
         // The error number can be any. Normally, they will be
         // defined in constant in the  wError0.pp  unit.
         // errors above 100'000 can be used by the final application.
         ErrorWrite(128, 'in TMyWindow.WMCommand');
         ErrorComment(128,
           'This is a demonstration how to write error notifications.');
         ErrorComment(128,
           'It has been generated from the menu ''Error 1''');
         end;
   312 : begin
         // for the example here, the mask number are power of two.
         // to be masked easily.
         // later any number will be used, since the masking will be
         // more general, I hope.
         ErrorWrite(4096, 'in TMyWindow.WMCommand');
         ErrorComment(4096,
           'This is a second demonstration how to write error notifications.');
         ErrorComment(4096,
           'It has been generated from the menu ''Error 2''');
         end;
   313 : begin
         ErrorWrite(16, 'in TMyWindow.WMCommand');
         ErrorComment(16,
           'This is a third demonstration how to write error notifications.');
         ErrorComment(16,
           'You can mask these error from the mask menu');
         ErrorComment(16,
           'of the error window.');
         ErrorComment(16,
           'Later the masking possibilities will be improved, I hope.');
         end;
   401 : MessageBox( hWin,
      'This program shows you how errors can be notified in an independent window',
      'Demonstration of errors notification', 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.
Var
  rRec        : rect;
  wStatH      : Word;
  alEdges     : array[1..2] of LongInt;

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_EraseBkgnd : Exit;
   WM_Notify : begin
         ErrorWrite(1024, 'in TMyWindow.WindowProc, WM_Notify');
         ErrorComment(1024,
           'Generated error, to see how it looks.');

         // must be called to treat the notifications messages.
      WindowProc:=WMNotify(wPar, lPar);
      end;
   WM_Command : begin
      ErrorWrite(2048, 'in TMyWindow.WindowProc, WM_Command');
      ErrorComment(2048,
         'Generated error, to see how it looks.');

      // must be called to treat the notifications messages.

      WindowProc:=WMCommand(wPar, lPar);
      end;
   WM_Size : begin
      GetClientRect(oStatusL.hWin, @rRec);
      wStatH := word(rRec.Bottom - rRec.Top);
      GetClientRect(hWindow, @rRec);
      MoveWindow (oEditB.hWin,0,0, rRec.Right, rRec.Bottom - wStatH, False);
      MoveWindow (oStatusL.hWin,0, rRec.Bottom - wStatH, rRec.Right, rRec.Bottom, False);

      // Define the position of the separation in the Status line
      alEdges[1] := rRec.Right  - rRec.Left - 80;
      alEdges[2] := rRec.Right  - rRec.Left;
      SendMessage(oStatusL.hWin, SB_SETPARTS, 2, LongInt(@alEdges));
      end; // WM_Size
{   WM_CtlColorEdit : begin
      SetTextColor(wPar, oEditB.TheColor);
      Exit(GetSysColorBrush(COLOR_WINDOW));
      end; ?????? DELETE}

   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        : TApplication0;
  poMyMainWin : PMyWindow;

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

// Creation of the main window
new(poMyMainWin, Init('Title of the Example013 (Ex013.pp) Window'));

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

