{ Test of the unit wDialogCreatorLOW2.pp
  Some test have been made in  tEx035.pp
  Here, we are near from a final use of the dialog boxes.

  Use the  wDialogCreatorLOW2  instead of the  wDialogCreator2.
  It will hide many constant, types etc. which are not usefull
  to know for creating Dialog boxes.

  Remark : wDialog0.gglpoActiveDialog  points to the active dialog,
  Modal or modeless.

  See how simple it is to create a dialog box.
  --------------------------------------------}
program tEx038;

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

Uses
  wApplication0
 ,wWindow0
 ,wDialog0
 ,wButtonPush0
 ,wControl0
 ,wPopupWindow0
 ,wDialogCreatorLOW2
 ,wVariableNumLink2
 ,wWindowBase0
 ,wErrors0
 ,wGlobals2
 ,wDebug0
 ,Windows;

type
  PMyWindow = ^TMyWindow;
  TMyWindow = object(TWindow)
  //"""""""""""""""""""""""""
  wMemberValue1,
  wMemberValue2,
  wMemberValue3 : Word32;
  // Values changed in an edit box or combo box.

  strMember1,
  strMember2,
  strMember3 : string[50];
  // Values changed in an edit box or combo box.

  fShowValue : boolean;
  // For the test 6, show the value of the variable,
  // not for other tests.

  // Used in 6th test, to do range checking
  wNum1       : Word32;
  fLimitIt    : boolean;
  strName     : string[60];
  afConvert   : array[1..3] of boolean;

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

  procedure Test1; virtual;

  procedure Test2; virtual;

  procedure Test3; virtual;

  procedure CtrlVarUpdate(poCtrl:PWindowBase0; pVar:pointer); virtual;
  // When a control changed its value and it is linked to a variable and
  // it belongs to a dialog belonging to a window, then
  // the control calls this method with a pointer on itself and
  // a pointer on the associated variable.
  // Either you know the type, or you can get it with
  // pControl(poCtrl)^.rVarLinkInfo.wVarType

  procedure CtrlLooseFocus(poCtrl:PWindowBase0; var wAcceptQuit:word32); virtual;
  // If a control is about to loose its focus, then the grand parent window
  // which is usually the main window, will receive this message with
  // poCtrl = a pointer on the control loosing the focus.
  // If the value of  wAcceptQuit  is set to  0
  // then it is refused that the control loosed its focus
  // and it will keep it.
  // For example,  wAcceptQuit:=0;
  // will reject the possibility that the control looses the focus.
  // Is destinated to be overriden, does nothing by default.

  procedure AskAcceptDlgQuit(poDlg:PWindowBase0; wCtrlIDP:word32; var wRep:word32); virtual;
  // If a dialog box is about to quit with return, i.e.
  // accepting its changes, then this dialog parent's method is called
  // poDlg is a pointer on the dialog box.
  // If the value of wRep is set to  0
  // then it is refused to quit the dialog box.
  // For example, modifying  wRep:=0;
  // will reject the possibility to quit the dialog box.
  // Is destinated to be overriden, does nothing by default.

  procedure DialogAllRestored(poDlg:PWindowBase0); virtual;
  // When a dialog box is ended with a Cancel, all variables associated
  // to controls are set back to their original values.
  // Thus the dialog box calls this method with a pointer on itself.

  procedure ButtonClicked(poCtrl:PWindowBase0; wCtrlID:Word32); virtual;
  // When a button is clicked, and it is in a dialog which belongs to a Window,
  // then the button calls this method, with a pointer on itself
  // and the ID it has been given.

  function WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
  // Handles the menu messages

//  function WindowProc(hWindow:HWND; wMsg:UINT; wPar:WPARAM; lPar:LPARAM):LRESULT; virtual;
    // Not Used
  end; // TMyWindow = object(TWindow)

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

// default values
wMemberValue1 :=250;
wMemberValue2 :=5678;
wMemberValue3 :=333;
strMember1    :='In the Edit';
strMember2    :='In The Combo Drop Down';
strMember3    :='Combo Drop Down List';

fShowValue:=FALSE;

wNum1       := 0;
fLimitIt    :=FALSE;
strName     := '';
afConvert[1]:=TRUE;
afConvert[2]:=FALSE;
afConvert[3]:=FALSE;

// For the whole program, if these numbers are not used by other
// variables in the program, (the end developper must not make this mistake)
// then these links will remain.
// It will not be necessary to 'ClearField(..', since the linke number are not used again
Word32Field(101, wMemberValue1);
Word32Field(102, wMemberValue2);
Word32Field(103, wMemberValue3);
StrField(111, strMember1, SizeOf(strMember1));
StrField(112, strMember2, SizeOf(strMember2));
StrField(113, strMember3, SizeOf(strMember3));

Word32Field(201, wNum1);
BooleanField(211, fLimitIt);
StrField(301, strName, SizeOf(strName));
for nn:=1 to 3 do BooleanField(310+nn, afConvert[nn]);

// This line is all what is needed to have a status line.
new(poStatusLine, Init(@Self));
end;  // TMyWindow.Init

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

procedure TMyWindow.Test1;
//========================
var
  nRet        : integer; // return value from the dialog box
begin
// See how simple it is to create a dialog box. Only one line.
// Its description is made in the  .msg  file.
// Link between variables and dialog box field are made in
// the constructor  .init  with the  word32Field, strField, etc.
// For all ...Field, see wVariableNumLink2.pp
nRet:=DialogExecMSG(11199, @Self);
DBW0(1, 'Dlg Ret value =' + ITS(nRet));
end;  // TMyWindow.Test1

procedure TMyWindow.Test2;
//========================
var
  nRet        : integer; // return value from the dialog box
begin
fShowValue:=TRUE;
nRet:=DialogExecMSG(11299, @Self);
DBW0(1, 'Dlg Ret value =' + ITS(nRet));
fShowValue:=FALSE;
end;  // TMyWindow.Test2

procedure TMyWindow.Test3;
//========================
var
  nRet        : integer; // return value from the dialog box
  nMem1,      // before creatoin of the dialog
  nMem2       // after  creatoin of the dialog
              // pMem3 should return to the same value as pMem1
              : int32;
begin
nMem1:=MemAvail; DBW0(128, 'nMem1=' + ITS(nMem1));

fShowValue:=TRUE;
nRet:=DialogExecMSG(11399, @Self);
DBW0(1, 'Dlg Ret value =' + ITS(nRet));
fShowValue:=FALSE;

nMem2:=MemAvail; DBW0(128, 'nMem2=' + ITS(nMem2));
DBW0(128, 'IF nMem2 = nMem1 =' + ITS(nMem1) + ' =' + ITS(nMem2) +
        '  all the memory was correctly disposed.');
end;  // TMyWindow.Test3

procedure TMyWindow.CtrlLooseFocus(poCtrl:PWindowBase0; var wAcceptQuit:word32);
//==============================================================================
begin
{ // This could be done, but a better choice exist.
if (PDialog(poCtrl^.poParent)^.wMsgDescriptor = 11699) then begin
   // notification that the control pointed by  poCtrl
   // is about to loose its focus.
   // We could check it here, but a better place is when
   // we quit the dialog box.
   if (fLimitIt) then begin
      if (wNum1 <   1) or (wNum1 > 100) then wAcceptQuit:=0; // refuse
      end;
   end; // if
}

if (PDialog(poCtrl^.poParent)^.wMsgDescriptor = 11699) and
   (PControl(poCtrl)^.pVarLink = @wMemberValue1) and
   (wMemberValue1 >= 1000) then begin
   wAcceptQuit:=0;
   MessageBeep(0); // just a sound to indicate a reject
   // If we are in the dialog of the Test3 and
   // the focus is on the control associated to the variable wMemberValue1
   // and this value is bigger than 1000, then refuse to loose the focus.
   end; // if
end;  // TMyWindow.CtrlLooseFocus

procedure TMyWindow.DialogAllRestored(poDlg:PWindowBase0);
//========================================================
begin
poDlg:=poDlg; // to avoid a hint
// a variable has changed in a dialog box.
DBW0(32768, '');
DBW0(32768, 'wMemberValue1=' + ITS(wMemberValue1));
DBW0(32768, 'wMemberValue2=' + ITS(wMemberValue2));
DBW0(32768, 'strMember1    ="' + strMember1 + '"');
DBW0(32768, 'strMember2    ="' + strMember2 + '"');
DBW0(32768, 'strMember3    ="' + strMember3 + '"');
end;  // TMyWindow.DialogAllRestored

procedure TMyWindow.CtrlVarUpdate(poCtrl:PWindowBase0; pVar:pointer);
//===================================================================
// a variable has changed in a dialog box.
// pVar = pointer on the variable
// poCtrl = pointer on the control linked to this variable
// poCtrl^.poParent = pointer on the dialog box
// PDialog(poCtrl^.poParent)^.wMsgDescriptor =
// = msg which generated the dialog box
begin
pVar:=pVar;  // to avoid a hint.

if (PDialog(poCtrl^.poParent)^.wMsgDescriptor = 11699) then begin
   // We don't do the range checking here, but only when the the dialog
   // is about to quit.
   // Here we do string conversion
   if (afConvert[2]) then begin
       strName:=UpCase(strName);
       UpdateFromVar;
       end
   else if (afConvert[3]) then begin
       strName:=LowerCase(strName);
       UpdateFromVar;
       end; // if
   end; // if

if fShowValue then Begin
   // As an example, you can change the value of other variables
   // under conditions you can fixe.
   if (wMemberValue1 = 13) then begin
      wMemberValue2 :=131313;
      strMember1:='Changed by the 13';
      // Update the content of all controls of the dialog boxe(s)
      // owned by the window.
      UpdateFromVar;
      end;

   DBW0(32768, '');
   DBW0(32768, 'wMemberValue1=' + ITS(wMemberValue1));
   DBW0(32768, 'wMemberValue2=' + ITS(wMemberValue2));
   DBW0(32768, 'wMemberValue3=' + ITS(wMemberValue3));
   DBW0(32768, 'strMember1    ="' + strMember1 + '"');
   DBW0(32768, 'strMember2    ="' + strMember2 + '"');
   DBW0(32768, 'strMember3    ="' + strMember3 + '"');
   DBW0(65536, 'Dialog generated by number =' +
               ITS(PDialog(poCtrl^.poParent)^.wMsgDescriptor));
   end; // if fShowValue then Begin

end;  // TMyWindow.CtrlVarUpdate

procedure TMyWindow.AskAcceptDlgQuit(poDlg:PWindowBase0; wCtrlIDP:Word32; var wRep:word32);
//=========================================================================================
// notification that the dialog box pointed by  PDialog(lPar)
// is about to quit, accepting its changes (With OK).
// If we refuse to quit, just Set  wRep:=0;
var
  poDlgL      : PDialog;
  poCtrl      : PControl;
  nXPosL, nYPosL,   // position and size of the control linked to wNum1
  nWidthL, nHeightL : Int32;
begin
wCtrlIDP:=wCtrlIDP;  // to avoid a hint
// notification that the dialog box pointed by  pDlg is about to quit.
// Its the best place to check if we accept to quit.
if (PDialog(poDlg)^.wMsgDescriptor = 11699) then begin
   if (fLimitIt) and ((wNum1 < 1) or (wNum1 > 100)) then begin
      wRep:=0; // refuse
      // Then explain why we refused.
      // Show a popup window explaining why we refuse to quit.
      // if positions are (-1, -1) then the mouse cursor position
      // is taken to plac the popup window.
      poDlgL:=PDialog(poDlg);  // we know that it points on a dialog box
      poCtrl:=poDlgL^.GetControlFromVar(wNum1);
      poCtrl^.GetScreenPosSize(nXPosL, nYPosL, nWidthL, nHeightL);

      // Set the focus to the control which needs to be modified to accept to quit.
      // It must be set before we show the popup Window.
      SetFocus(poCtrl^.hWin);

      // If you want that all text is selected.
      // If not, remove this line.
      SendMessage(poCtrl^.hWin, EM_SetSel, 0, -1);

      // Opens the popup window with the text from message 12000 in it.
      PopupWindowMessage(11600, nXPosL, nYPosL + nHeightL + 5, @Self);
      end;
   end; // if (PDialog(poDlg)^.wMsgDescriptor = 11699) then begin
end;  // TMyWindow.AskAcceptDlgQuit

procedure TMyWindow.ButtonClicked(poCtrl:PWindowBase0; wCtrlID:Word32);
//=====================================================================
var
  poBtn       : PButtonPush;
begin
poBtn:=PButtonPush(poCtrl); // We know that it points to a push button object.
DBW0(65536, 'Button has been clicked, id=' + ITS(wCtrlID) + ' = ' + ITS(poBtn^.wCtrlID));
DBW0(65536, 'Button handle   = ' + ITS(poBtn^.hWin));
DBW0(65536, 'Button class    = ' + poBtn^.strClassName);
DBW0(65536, 'Button Win name = ' + poBtn^.strWindowName);
DBW0(65536, 'Button label    = ' + poBtn^.strCtrlLabel);
DBW0(65536, 'Button hint     = ' + poBtn^.strCtrlHint);
// poBtn^.poParent = pointer on the dialog box
end;  // TMyWindow.ButtonClicked

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

// for the menus,  lPar = 0
//=========================
wNrMenu   := LoWord(wPar);
Case wNrMenu Of
   100 : DBW0(0, '');  // just open the debugging window
   101 : Test1;
   102 : Test2;
   103 : Test3;
   104 : DialogExecMSG(11499, @Self); // test the position and interline
   105 : begin
         fShowValue:=TRUE;
         DialogExecMSG(11599, @Self); // test the radio buttons and check boxes.
         fShowValue:=FALSE;
         end;
   106 : DialogExecMSG(11699, @Self);

   111 : DBW0(1, 'This was generated by the help on "strMember1" text string');
   112 : DBW0(1, 'Here could come any wanted action... "strMember2" text string');
         // this is one possible action : DialogExecMSG(11662, @Self);
         // but it is also possible to associate a dialog to a control, and
         // give the menu ID 65531 to access to the dialog associated to the
         // control which generated the context menu.
         // All this with zero lines of programming code.
         // Only lines in the  .msg  file

   401 : MessageBox( hWin,'Test the wDialogCreatorLOW2.pp unit','Just a unit test.',
                     MB_OK Or MB_IconInformation);
   else WMCommand:=inherited WMCommand(wPar, lPar);
   end;  // Case NrMenu Of
end;  // TMyWindow.WMCommand

var
  oApp        : TApplication;
  poMyMainWin : PMyWindow;

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

// Creation of the main window
new(poMyMainWin, Init('tEx038.  Test the wDialogCreator2.pp unit'));

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

