{ Example of creating dialog boxes.
  This example show how to create dialog boxes, WITHOUT using resources.

  It is even more complicate than tEx022.pp.
  But it will be usefull for using it with the GAP library.

  Since the library unit  wDialog0.pp changed such that no more
  resources are necessary, the example  tEx023.pp
  Works withouts having to include ($R GAPLIB.res)
  No more resources are necessary.

  In the example, tEx023.pp, we will see how to create dialog boxes
  without resources and with the library.

  Later I will use this method to create dynamicaly a dialog box from
  a simple text file descriptor. I hope to have a first version of it
  at the beginning of february 2002.

  --------------------------------------------}
program tEx024;

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

type
  PMyWindow = ^TMyWindow;
  TMyWindow = object(TWindow0)
  //""""""""""""""""""""""""

  constructor Init(strWinTitlePrm:ShortString);

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

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

  procedure WMCreateDlgModal; virtual;
  // Creates a Modal dialog box.
  // Modal means that the rest of the application will not be accessible
  // while the dialog box is opened.

  procedure WMCreateDlgModeless; virtual;
  // Creates a Modeless dialog box.
  // Modeless means that the rest of the application will be accessible
  // while the dialog box is opened.

  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; // TMyWindow = object(TWindow)

var
  glhModelessDlg : HWND;
  // handle on the modeless dialog box.
  // It is 0 if closed, <> 0 if open.

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

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

procedure TMyWindow.MenuCreate;
//=============================
var
  hSubMenu    : HMenu;
begin
hMenuWin := CreateMenu;

hSubMenu := CreateMenu;
AppendMenu(hSubmenu,MF_STRING,100,'&Open debug window');
AppendMenu(hSubmenu,MF_STRING,101,'&1 A dialog box...');
AppendMenu(hSubmenu,MF_STRING,102,'&2nd dialog box...');
AppendMenu(hSubmenu,MF_SEPARATOR,0,Nil);
AppendMenu(hSubMenu,MF_String, 200, 'E&xit');
AppendMenu(hMenuWin, MF_POPUP, hSubMenu, '&File');

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

function DialogProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):BOOL;  stdcall; export;
//============================================================================================
// This is the function which receives all messages from window.
// some standard button :
// IDOK=1, IDCANCEL=2, IDABORT=3, IDRETRY=4, IDIGNORE=5, IDYES=6, IDNO=7,

begin
hWindow:=hWindow; wPar:=wPar; lPar:=lPar;  // to remove Hints.

DialogProc:=True; // default return value

{if (wMsg <> WM_MouseMove)   and (wMsg <> WM_NCMouseMove) and
   (wMsg <> WM_MENUSELECT )   and (wMsg <> WM_ENTERIDLE ) and
   (wMsg <> WM_SetCursor)   and (wMsg <> WM_NCHittest) and
//   (wMsg <> WM_SetFocus) and (wMsg <> WM_KillFocus) and
//   (wMsg <> WM_KEYDOWN) and (wMsg <> WM_KEYUP) and
   (wMsg <> WM_Move)        and (wMsg <> WM_NCActivate) then
   DBW0(32, DBMsgToStr(wMsg) + ITS(wPar) + ITS(lPar)); }

case wMsg of
   WM_InitDialog : begin
//      hBtn:=GetDlgItem(hWindow, IDCANCEL);
//      SetFocus(hBtn); // gives the focus to button

      // Return TRUE to set the focus automatically
      // Return FALSE if you set it yourself
      DialogProc:=TRUE;
      exit;
      end;

   WM_Close : begin
      // the dialog box has been closed, it has the same effect as a cancel
      // It tells to end the dialog Box
      // return  IDCANCEL (=2)  to tell that the CANCEL button
      // has been pressed or that the dialog has been closed.

      if (hWindow = glhModelessDlg) then DestroyWindow(hWindow)
      else                               EndDialog(hWindow, IDCANCEL);
      Exit;
      end; // WM_Close : begin

   WM_Command : begin
      if (wPar = IDCANCEL) then begin
         // IDCANCEL = 2 is the standard value for the ok button.
         // but this ID must have been given to the CANCEL button
         // in the dialog box description defined in tEx022.rc

         // It tells to end the dialog Box
         // return  0  to tell that the CANCEL button has been pressed.
         if (hWindow = glhModelessDlg) then DestroyWindow(hWindow)
         else                               EndDialog(hWindow, IDCANCEL);
         Exit;
         end;
      end; // WM_Command : begin

   WM_Destroy : begin
          if (hWindow = glhModelessDlg) then begin
             glhModelessDlg:=0; // the dialog is closed.

             // Must be set to 0 because no more Modeless dialogs
             // are opened.
             // glhModelessDlg is defined in wApplication0.pp
             gglhDialogWin:=0;
             end;
          end;

   else DialogProc:=False;
   end; // case wMsg of

end;  // DialogProc

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

procedure TMyWindow.WMCreateDlgModal;
//===================================
// Creates a Modal dialog box from a template, without using any resources.
// It is quite complicate, but enough to use it in the GAP library.
var
  rTemplate   : record
                rDlg   : DLGTEMPLATE;
                wMenu  : word; // = 0 => no menu       2 bytes variable
                wClass : word; // = 0 => default class 2 bytes variable
                awTitle : array[1..6] of word;
                // Title, one word per character.
                // a  zero ('0')  indicate the end.
                rItem : DLGITEMTEMPLATE;
                awItemClass  : array[1..7] of word; // = 'BUTTON'
                awItemTitle  : array[1..7] of word; // =  'OK'
                wItemData   : word; // = 0 => no Data
                // the array length must be odd.
                // At least here ?
                end;
  nRet : integer;

begin
with rTemplate.rDlg do begin
   dwExtendedStyle :=0;
   style  := DS_MODALFRAME or WS_POPUP or WS_CAPTION or WS_SYSMENU
             or WS_TABSTOP;
   cdit   :=1;  // number of controls in the dialog. (could be zero)
   x      :=98; // dialog box coordinate in dialog box unit.
   y      :=58; //  What does it mean ?
   cx     :=142;
   cy     :=92;;
   end; // with rTemplate.rDlg do begin

with rTemplate do begin
   wMenu  :=0; // no menu
   wClass :=0; // default dialog box class
   // The title is defined in an array of word, last one endig with a zero
   awTitle[1]:=word('T');
   awTitle[2]:=word('I');
   awTitle[3]:=word('T');
   awTitle[4]:=word('L');
   awTitle[5]:=word('E');
   awTitle[6]:=0;
   end;

// Just to test, Add one button.
with rTemplate.rItem do begin
   dwExtendedStyle :=0;
   style := WS_VISIBLE or WS_CHILD or WS_TABSTOP or BS_PUSHBUTTON;
   x     :=90;
   y     :=73;
   cx    :=50;
   cy    :=15;
   id    :=IDCANCEL;
   end;

with rTemplate do begin
   // Defining the class of the control in the dialog box.
   awItemClass[1] :=word('B');
   awItemClass[2] :=word('U');
   awItemClass[3] :=word('T');
   awItemClass[4] :=word('T');
   awItemClass[5] :=word('O');
   awItemClass[6] :=word('N');
   awItemClass[7] :=0;

   // defining the label on the button.
   awItemTitle[1] :=word('&');
   awItemTitle[2] :=word('O');
   awItemTitle[3] :=word('K');
   awItemTitle[4] :=0;
   awItemTitle[5] :=0;
   wItemData  :=0;  // no data.
   end;

// Create the dialog box, without resources, just from the description
// above.
nRet:=DialogBoxIndirect( System.MainInstance, @rTemplate, hWin,
                         DLGPROC(@DialogProc));

DBW0(1, 'Return value from Dialog =' + ITS(nRet));
end;  // TMyWindow.WMCreateDlgModal

procedure TMyWindow.WMCreateDlgModeless;
//======================================
// Creates a Modeless dialog box from a template, without using any resources.
// It is quite complicate, but enough to use it in the GAP library.
var
  rTemplate   : record
                rDlg   : DLGTEMPLATE;
                wMenu  : word; // = 0 => no menu       2 bytes variable
                wClass : word; // = 0 => default class 2 bytes variable
                awTitle : array[1..6] of word;
                // Title, one word per character.
                // a  zero ('0')  indicate the end.
                rItem : DLGITEMTEMPLATE;
                awItemClass  : array[1..7] of word; // = 'BUTTON'
                awItemTitle  : array[1..25] of word; // =  'Quit the modeless dialog'
                wItemData   : word; // = 0 => no Data
                // the array length must be odd.
                // At least here ?
                end;
  nn          : integer;
  strS        : string[30];

begin
if (glhModelessDlg <> 0) then begin
   MessageBeep(0);
   exit; // don't want to open it twice
   end;

with rTemplate.rDlg do begin
   dwExtendedStyle :=0;
   style  := DS_MODALFRAME or WS_POPUP or WS_CAPTION or WS_SYSMENU
             or WS_TABSTOP;
   cdit   :=1;  // number of controls in the dialog
   x      :=18; // dialog box coordinate in dialog box unit.
   y      :=48; //  What does it mean ?
   cx     :=142;
   cy     :=92;;
   end; // with rTemplate.rDlg do begin

with rTemplate do begin
   wMenu  :=0;
   wClass :=0;
   // The title is defined in an array of word, last one endig with a zero
   awTitle[1]:=word('W');
   awTitle[2]:=word('O');
   awTitle[3]:=word('R');
   awTitle[4]:=word('K');
   awTitle[5]:=word('S');
   awTitle[6]:=0;
   end;

// Just to test, Add one button.
with rTemplate.rItem do begin
   dwExtendedStyle :=0;
   style := WS_VISIBLE or WS_CHILD or WS_TABSTOP or BS_PUSHBUTTON;
   x     :=10;
   y     :=73;
   cx    :=120;
   cy    :=15;
   id    :=IDCANCEL;
   end;

with rTemplate do begin
   // Defining the class of the control in the dialog box.
   awItemClass[1] :=word('B');
   awItemClass[2] :=word('U');
   awItemClass[3] :=word('T');
   awItemClass[4] :=word('T');
   awItemClass[5] :=word('O');
   awItemClass[6] :=word('N');
   awItemClass[7] :=0;

   // defining the label on the button. Must end with a zero ( #0 )
   strS:='Quit the modeless dialog'+#0;
   for nn:=1 to length(strS) do  awItemTitle[nn] :=Word(strS[nn]);

   wItemData  :=0;  // no data.
   end;

// Create the dialog box, without resources, just from the description
// above.
glhModelessDlg:=CreateDialogIndirect( System.MainInstance, @rTemplate, hWin,
                              DLGPROC(@DialogProc));

// To treat the keys input correctly of the modeless dialog box.
// The Tabs will work correctly.
// glhModelessDlg is defined in wApplication0.pp
gglhDialogWin:=glhModelessDlg;

// Show the window dialog box
ShowWindow(glhModelessDlg, SW_SHOWNORMAL);
end;  // TMyWindow.WMCreateDlgModeless

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
   // call the parent WMCommand method.
   WMCommand:=inherited WMCommand(wPar, lPar);
   exit;
   end;

// for the menus,  lPar = 0
//=========================
wNrMenu   := LoWord(wPar);
Case wNrMenu Of
   // these calls to DBW0 can be done from anywhere
   100 : DBW0(0, '');  // just open the debugging window
   101 : WMCreateDlgModal;
   102 : WMCreateDlgModeless;

   200 : PostMessage( hWin,WM_Close,0,0);
   401 : MessageBox( hWin,'No Help, try simply the dialog boxes.',
                          'No Help',
                     MB_OK Or MB_IconInformation);
   else WMCommand:=inherited WMCommand(wPar, lPar);
   end;  // Case NrMenu Of
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

{if (wMsg <> WM_MouseMove)   and (wMsg <> WM_NCMouseMove) and
   (wMsg <> WM_MENUSELECT )   and (wMsg <> WM_ENTERIDLE ) and
   (wMsg <> WM_SetCursor)   and (wMsg <> WM_NCHittest) and
//   (wMsg <> WM_SetFocus) and (wMsg <> WM_KillFocus) and
//   (wMsg <> WM_KEYDOWN) and (wMsg <> WM_KEYUP) and
   (wMsg <> WM_Move)        and (wMsg <> WM_NCActivate) then
   DBW0(32, DBMsgToStr(wMsg) + ITS(wPar) + ITS(lPar)); }

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

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

// the dialog box is not open.
glhModelessDlg:=0;

// Change the color of the background of the main window.
// to have the desktop color
oApp.WindowClass.hbrBackground :=COLOR_BACKGROUND+1;

// Creation of the main window
new(poMyMainWin, Init('tEx024. Creating dialog boxes without resources.'));

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

