Unit wApplication0;

{ Feel free to use this unit as you want.
  First developped by Bernard Gisin
  This unit uses object programming to simplify the developpment
  of programs.
----------------------------------}

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

INTERFACE
//"""""""

uses wGlobals2, windows;

type
  // Usually it is not necessary to define a descendent of TApplication0
  PApplication0 = ^TApplication0;
  TApplication0 = object
  //""""""""""""""""""""
// gglstrClassWinName : string[30] is defined in wGlobals0.pp
// classname of the main window or later of a new window class name, if needed

  WindowClass : WndClassEx;
  // Window Class to register a new window

  WindowClassMDIChild : WndClass;
  // Window Class to register a new MDI child window
  // if not used, doesn't harm.

  hAccelTable : Handle;
  // handle on an accelerator table

  constructor Init(strWinCName:ShortString);
  // It can be overloaded, if the main window registration parameters change.
  // call inherited Init; at the beggining of a new Init constructor.

  destructor  Done; virtual;
  // Call Done; at the end of a new destructor.

  procedure Run; virtual;
  // Enter the main loop to treat the window messages

  function IsKeyPressed(wOption:word32):word32; virtual;
  // Wait a key to be pressed.
  // return the ASCII code of the pressed key, or zero if non pressed.
  // If wOptions = 1, then
  // continues to let window messages arrive to the main application.
  // this can make confusion, or errors in the program...
  // but with it, it is very simple to loop until a key is pressed.

  end; // TApplication0 = object
  TApplication =  TApplication0;
  PApplication = ^TApplication;

const
  gglpoApplication : PApplication0 = NIL;
  // Pointer on the TApplication0.
  // wWindow.gglpoMainWindow is more usefull
  // wWindowBase.gglpoMainWindowCopy points to the same object
  // and has the advantage of being define in a lower unit.

  gglhDialogWin : HWND = 0;
  // Handle of a modeless dialog box, or of a window containing
  // controls.
  // It should be = 0 if not used. It's its default value
  // It should be a valid modeless dialog box or window handle
  // if it should be used.
  // It will be rarely used.

IMPLEMENTATION
//""""""""""""

uses wObjectCreator2, wMDIChildWindow0, wWindow0, wWindowBase0,
     wParamApplic2, wUtiles0, wMessages2, wErrors0, wDebug0,
     wObjectCreatorLOW2; // for gglpoObjCreate

var glnNotUsed : integer; // To avoid an error in the DevPascal 1.9 environment

constructor TApplication0.Init(strWinCName:ShortString);
//======================================================
var
  poObjCr     : PObjectCreator2;
begin
gglpoApplication:=@Self;

// If the object creator has not been redefined and created,
// then the default one is used.
if (gglpoObjCreate = NIL) then begin
   // create the Object creator, Hi Level in the library
   // (i.e. which creates the deepest descendents)
   // if not created by the final application, which will create even
   // deepest descendents.
   new(poObjCr, Init);

   // Assign the pointer on the object creator,
   // which will be used in the library to create ojects.
   // This will allow the library to create objects defined by the
   // final application.
   gglpoObjCreate:=poObjCr;
   end;

// define a standard default window class
gglstrClassWinName:=strWinCName + #0; // is defined in wGlobals0.pp
with WindowClass do begin
   cbSize        :=SizeOf(WNDCLASSEX);
   Style         := cs_hRedraw Or cs_vRedraw;
   lpfnWndProc   := WndProc(@MainWindowProc);
   cbClsExtra    := 0;
   cbWndExtra    := GGLCTE_NB_WND_EXTRA;
       // reserve extra memory in the window to remember :
       // 8 bytes for a signature,
       // 4 bytes to describe the object
       // Main window = GGLCTE_MAIN_WINDOW = 1
       // MDI client window = GGLCTE_CLIENT_WINDO = 2
       // MDI Child window = GGLCTE_CHILD_WINDOW = 3
       // 4 bytes for a pointer on the associated object
       // see wGlobals2.pp
   hInstance     := system.MainInstance;
   hIcon         := LoadIcon (0,idi_Application);
   hCursor       := LoadCursor (0,idc_Arrow);
   hbrBackground := GetStockObject(WHITE_BRUSH);
//  hbrBackground :=COLOR_BACKGROUND+1; // to have the desktop color
   lpszMenuName  := NIL; // no menu is defined in the resources
   lpszClassName := @gglstrClassWinName[1]; // is defined in wGlobals0.pp
   hIconSm       := 0; // LoadIcon (0,idi_Application); // ??? or set to zero ?
   end; // with WindowClass do begin


// Registering the class window for MDI child windows
// If any are used. If not, it is useless, but doesn't harm.
gglstrClassWinMDIChildName:='MDIChildClassName' + #0; // is defined in wGlobals0.pp
with WindowClassMDIChild do begin
   style         := CS_HREDRAW or CS_VREDRAW;
   lpfnWndProc   := WndProc(@ChildWindowProc);
   cbClsExtra    :=0;
   cbWndExtra    :=GGLCTE_NB_WND_EXTRA; // = 16
          // 8 bytes for a signature,
          // 4 bytes to describe the object
          // 4 bytes for a pointer on the associated object
          // c.f. wWindowBase.pp
   hInstance     := System.MainInstance;
   hIcon         := LoadIcon (0, IDI_APPLICATION) ;
   hCursor       := LoadCursor (0, IDC_ARROW) ;
   hbrBackground := GetStockObject (WHITE_BRUSH) ;
   lpszMenuName  := NIL; // no menu is defined in the resources
   lpszClassName := @gglstrClassWinMDIChildName[1]; // is defined in wGlobals0.pp
   end; // with WindowClassMDIChild do begin

hAccelTable:=0; // no accelerator table by default.
end;  // TApplication0.Init

destructor TApplication0.Done;
//============================
begin
// The created accelerator table must be destroyed before ending.
if (hAccelTable <> 0) then DestroyAcceleratorTable(hAccelTable);
hAccelTable:=0;

// destroys the application parameters object if not already done.
if (gglpoPrm <> NIL) and (gglpoMainWindow <> NIL) then begin
   // Copy the main window position, size and state, to save it
   // in the parameters file.
   gglpoPrm^.nMainWinLeft         :=gglpoMainWindow^.nLeft;
   gglpoPrm^.nMainWinTop          :=gglpoMainWindow^.nTop;
   gglpoPrm^.nMainWinWidth        :=gglpoMainWindow^.nWidth;
   gglpoPrm^.nMainWinHeight       :=gglpoMainWindow^.nHeight;
   gglpoPrm^.wMainWinSizeStateLoc :=gglpoMainWindow^.wSizeState;
   end;

// Dispose the main window.
if (gglpoMainWindow <> NIL) then begin
   gglpoMainWindow^.hWin:=0; // Do not try to destroy the window
   dispose(gglpoMainWindow, Done);
   gglpoMainWindow:=NIL;
   end;

// destroys the object creator if not already done.
// gglpoObjCreate is defined in  wObjectCreatorLOW2.pp
if (gglpoObjCreate <> NIL) then dispose(gglpoObjCreate, Done);
gglpoObjCreate:=NIL;

// destroys the application parameters object if not already done.
if (gglpoPrm <> NIL) then begin
   gglpoPrm^.SavePrm; // saves the position and size of the main window
   dispose(gglpoPrm, Done);
   gglpoPrm:=NIL;
   end;

// Closes all message files.
CloseAllMsg;
end;  // TApplication0.Done

procedure TApplication0.Run;
//==========================
var
  rMessage    : Msg;
  wError      : Word32;
  hDCWin      : HDC;         // HDC of the main window, to get the
                             // character height and width.
  tm          : TEXTMETRIC;  // for the text width and height

begin
if (gglpoMainWindow = NIL) then begin
   // the main window object should have been created
   MessageBox (0, 'The main window object must have been created', NIL, mb_Ok);
   exit;
   end;

// just a copy, which is located in wWindowBase0.pp
gglpoMainWindowCopy:=gglpoMainWindow;

// Creates the application parameter object.
// it could be an object defined in the user application,
// which overrides some methodes.
if (gglpoPrm = NIL) then gglpoPrm:=gglpoObjCreate^.CreateParamApplic;

// Loads Application parameters.
if (gglpoPrm <> NIL) then begin
   gglpoPrm^.GetDirectories; // loads the default directories to use.
   gglpoPrm^.LoadPrm;
   end;

// Defines the position, size and state of the main window
gglpoMainWindow^.nLeft      :=gglpoPrm^.nMainWinLeft;
gglpoMainWindow^.nTop       :=gglpoPrm^.nMainWinTop;
gglpoMainWindow^.nWidth     :=gglpoPrm^.nMainWinWidth;
gglpoMainWindow^.nHeight    :=gglpoPrm^.nMainWinHeight;
gglpoMainWindow^.wSizeState :=gglpoPrm^.wMainWinSizeStateLoc;

// If there is a message file, filename, opens it.
if (gglstrMsgPathName <> '') then begin
   // Opens the message file
   OpenAllMessagesFiles(gglstrMsgPathName, wError);

   // 4 possible errors : (other kind of errors have already been reported.
   if (wError = 10) then begin
      ErrorWrite(ERR_TApplication0_Run_2, 'in TApplication0.Run');
      ErrorComment(ERR_TApplication0_Run_1,
         'Error in the message file : ' +  gglstrMsgPathName);
      ErrorComment(ERR_TApplication0_Run_1,
         'Line number are not in increasing orger at : ' +
      IntToStr(gglwMessages2ErrorPosition, 12));
      end;

    // these errors are fatal, and the application stops.
   if (wError = 1) or (wError = 2) or (wError = 3) then begin
      ErrorWrite(ERR_TApplication0_Run_2, 'in TApplication0.Run');
      ErrorComment(ERR_TApplication0_Run_2,
         'Error trying to open the message file : ' +  gglstrMsgPathName);
      ErrorComment(ERR_TApplication0_Run_2,
         'The file probably doesn''t exist. Most texts will be missing.');

      MessageBox (0, 'The message file doesn''t exit, thus stop. See filename.dir to define where the message file is',
                  'Fatal error. The application cannot run', mb_Ok);
      exit;
      end;
   end;

// Registering the class of the main window
if (RegisterClassEx(WindowClass) = 0) then begin
   MessageBox (0, 'Register the Main Window class failed',
                  'The application cannot run', mb_Ok);
   exit;
   end;

// If it is an MDI application, register the class of the MDI child windows
if (gglpoMainWindow^.wWindowType = GGLCTE_MAIN_MDI_WINDOW) then begin
   if (RegisterClass(WindowClassMDIChild) = 0) then begin
      MessageBox (0, 'Register the MDI child window class failed',
                  'The application continues, but is probably useless', mb_Ok);
      end;
   end;

// Creating the main window
gglpoMainWindow^.WinCreate('');
if longint(gglpoMainWindow^.hWin)=0 then begin
   MessageBox (0, 'Main Window Creation failed', NIL, MB_OK);
   exit;
   end;

// Put in the ParamApplic, the size of characters.
if (gglpoPrm <> NIL) then begin
   // gets the text height and witdth
   hDCWin:=GetDC(gglpoMainWindow^.hWin);
   GetTextMetrics(hDCWin, @tm);

   // convertion from Ch to pix
   gglpoPrm^.wWidthPix_Ch := tm.tmAveCharWidth; // mean character width
   gglpoPrm^.wHeightPix_Ch := tm.tmHeight;      // max height of a line

   ReleaseDC(gglpoMainWindow^.hWin, hDCWin);

   gglpoPrm^.wScreenWidthPix :=GetSystemMetrics(SM_CXSCREEN);   // width  of the screen in pixels
   gglpoPrm^.wScreenHeightPix:=GetSystemMetrics(SM_CYSCREEN);   // height of the screen in pixels
   end; // if (gglpoPrm <> NIL) then begin

// Auto load the accelerator table if asked so in the .msg file
if (UpCase(GetMsg(10100)) = 'AUTOCREATE') then
   hAccelTable:=AccelTableMSGCreate(10100);

// Loop to treat the WM_ messages
while GetMessage(@rMessage,0,0,0) Do Begin
   if ((gglhDialogWin = 0) or
       (not IsDialogMessage(gglhDialogWin, rMessage))) and
      ((gglpoMainWindow^.hWinClient = 0) or
       (not TranslateMDISysAccel(gglpoMainWindow^.hWinClient, rMessage))) and
      ((hAccelTable = 0) or
       (TranslateAccelerator( gglpoMainWindow^.hWin,
                             hAccelTable, rMessage) = 0)) then begin
      TranslateMessage(rMessage);
      DispatchMessage(rMessage);
      end;
   end; // while
end;  // TApplication0.Run

function TApplication0.IsKeyPressed(wOption:word32):word32;
//=========================================================
// Wait a key to be pressed.
// return the ASCII code of the pressed key, or zero if non pressed.
// If wOptions = 1, then
// continues to let window messages arrive to the main application.
// this can make confusion, or errors in the program...
// but with it, it is very simple to loop until a key is pressed.
var
  rMessage    : Msg;

begin
IsKeyPressed:=0;

if (wOption <> 1) then begin
   // Is there a message in the queue ?
   if PeekMessage(rMessage, 0, 0, 0, pm_Remove) then begin
      // Remove all other messages
      repeat
         if (rMessage.message = WM_KEYDOWN) then IsKeyPressed:=rMessage.wParam;
         until not PeekMessage(rMessage, 0, 0, 0, pm_Remove);
      end;

   exit;
   end;

// If any message arrived, then treat it.
if PeekMessage(rMessage, 0, 0, 0, pm_Remove) then begin
   if ((gglhDialogWin = 0) or
       (not IsDialogMessage(gglhDialogWin, rMessage))) and
      ((gglpoMainWindow^.hWinClient = 0) or
       (not TranslateMDISysAccel(gglpoMainWindow^.hWinClient, rMessage))) and
      ((hAccelTable = 0) or
       (TranslateAccelerator( gglpoMainWindow^.hWin,
                             hAccelTable, rMessage) = 0)) then begin
      TranslateMessage(rMessage);
      DispatchMessage(rMessage);

      // Quit violent to quit the application,
      // but without it, the main window can be closed,
      // and the application, still running
      if (rMessage.message = WM_QUIT) then Halt(1);
      end;

   // if the message was a character pressed on the keyboard, then
   // return this character.
   if (rMessage.message = WM_CHAR) then IsKeyPressed:=rMessage.wParam;
   end; // while
end;  // TApplication0.IsKeyPressed

end. // wApplication0

