{ Example of creating dialog boxes.
  In tEx017, we used many controls to see their use.
  Here, we will use the facilities of dialog boxes to do the same thing,
  but with much less code. All the description will be made in the  .msg  file

  See how simple it is to create a dialog box.
  See  tEx044.pp  to define the backcolors of the radio buttons and
  the check boxes, in the  .msg  file.

  See example tEx042.pp for the final touch, i.e. the changing color
  Of the Background.
  tEx042.pp demonstrate also the use of the TObject creator.
  --------------------------------------------}
program tEx041;

// 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
 ,wButtonCheck0
 ,wButtonPush0
 ,wButtonRadio0
 ,wStatic0
// ,wControl0
// ,wPopupWindow0
 ,wDialogCreatorLOW2
 ,wVariableNumLink2
 ,wWindowBase0
 ,wMessages2
 ,wErrors0
 ,wGlobals2
 ,wDebug0
 ,Windows;

type
  PMyWindow = ^TMyWindow;
  TMyWindow = object(TWindow)
  //"""""""""""""""""""""""""
  afCheck : array[1..3] of boolean;
  // For the three checkboxes

  afRadio : array[1..7] of boolean;
  // For the seven radio buttons

  strStatic1,
  strEdit1,
  strCombo1,
  strCombo2 : string[50];
  // Values changed in an edit box or combo box.

  poStatic1 : PStatic;
  // We Keep a pointer on the static control, once for ever,
  // to change its color

  poBtnMy,
  poBtnPopup : PButtonPush;
  // We keep pointer on the two buttons.

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

  procedure WinCreate(strWinClass:ShortString); virtual;
  // When creating the window, we ask to show the dialog box, not the window

  procedure InitDialogBegin(poDlg:PWindowBase0); virtual;
  // At the entrence of the dialog initialisation, its handle has been created,
  // but its child objects has still not created their window, and
  // thus has no handle.
  // the dialog calls this method with a pointer on itself. (it's his parent method)
  // Its a good place to modify any control before its creation.

  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 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.

  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.
  // wCtrlIDP = id used to quit the dialog
  // 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.

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

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

// default values
for nn:=1 to 3 do begin
  booleanField(100+nn, afCheck[nn]);
  afCheck[nn]:=FALSE;
  end;

for nn:=1 to 7 do begin
  booleanField(200+nn, afRadio[nn]);
  afRadio[nn]:=FALSE;
  end;
afRadio[6]:=TRUE;

strStatic1:='Static text';
strEdit1  :='Edit me';
strCombo1 :='to edit too';
strCombo2 :='Line 1';

StrField(301, strStatic1, SizeOf(strStatic1));
StrField(401, strEdit1, SizeOf(strEdit1));
StrField(501, strCombo1, SizeOf(strCombo1));
StrField(502, strCombo2, SizeOf(strCombo2));
end;  // TMyWindow.Init

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

procedure TMyWindow.WinCreate(strWinClass:ShortString);
//=====================================================
Begin
// We don't want to see the main window
wSizeState := SIZE_MINIMIZED;

inherited WinCreate(strWinClass);

// Here calling :  DialogExecMSG(11199, @Self);  doesn't work,
// But posting a message to open the dialog box at startup is possible.
PostMessage(hWin, WM_COMMAND, 101, 0);
end;  // TMyWindow.WinCreate

procedure TMyWindow.InitDialogBegin(poDlg:PWindowBase0);
//======================================================
// Here we can change the controls, just before their window are created.
var
  nn          : integer;
  poDlgL      : PDialog;
  poCheck     : PButtonCheck;
  poRadio     : PButtonRadio;
begin
poDlgL:=PDialog(poDlg); // We know that it is a dialog.

// Add a hint to the default OK button
poBtnMy:=PBUttonPush(poDlgL^.GetControlFromID(IDOK)); // IDOK = 1 is the ID of the OK button. (IDCANCEL = 2)
poBtnMy^.strCtrlHint:=GetMsg(11192);

// Get a pointer on the static control and two buttons, once for ever
poStatic1  :=PStatic(poDlgL^.GetControlFromID(301));
poBtnMy    :=PBUttonPush(poDlgL^.GetControlFromID(111));
poBtnPopup :=PBUttonPush(poDlgL^.GetControlFromID(1141));

// Change the color of the radio buttons.
for nn:=1 to 3 do begin
   poCheck:=PButtonCheck(poDlgL^.GetControlFromID(100 + nn)); // We know it is a check box
   poCheck^.fUseDefaultColors :=FALSE;
   poCheck^.colTextFont:=RGB(  0,  0,  0);
   poCheck^.colTextTransp :=OPAQUE;
   case nn of
     1 : poCheck^.colTextBack:=RGB(255,  0,  0);
     2 : poCheck^.colTextBack:=RGB(  0,255,  0);
     3 : begin
         poCheck^.colTextBack:=RGB(  0,  0,255);
         poCheck^.colTextFont:=RGB(255,255,255);
         end;
     end; // case

   // we want to complete control wo have the same color
   poCheck^.colWindowBack:=poCheck^.colTextBack;
   end;

for nn:=1 to 7 do begin
   poRadio:=PButtonRadio(poDlgL^.GetControlFromID(200 + nn)); // We know it is a radio button
   poRadio^.fUseDefaultColors :=FALSE;
   poRadio^.colTextFont:=RGB(0,0,0);
   poRadio^.colTextTransp :=OPAQUE;
   case nn of
     1 : poRadio^.colTextBack:=RGB(  0,  0,  0);
     2 : poRadio^.colTextBack:=RGB( 64, 64, 64);
     3 : poRadio^.colTextBack:=RGB(128,128,128);
     4 : poRadio^.colTextBack:=RGB(192,192,192);
     5 : poRadio^.colTextBack:=RGB(255,255,255);
     6 : poRadio^.colTextBack:=RGB(  0,128, 64);
     7 : poRadio^.colTextBack:=RGB(  0,  0,  0);
     end; // case

   if (nn = 1) or (nn = 2) then poRadio^.colTextFont:=RGB(255,255,255);
   if (nn = 7) then poRadio^.colTextTransp :=TRANSPARENT;
   end;
end;  // TMyWindow.InitDialogBegin

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
poCtrl:=poCtrl;  // to avoid a hint.

if (pVar = @strCombo1) then DBW0(1, 'combo = ' + strCombo1);
if (pVar = @strCombo2) then DBW0(1, 'combo = ' + strCombo2);

// This was not in example tEx017.pp, but it is so simple now.
if (pVar = @strEdit1) then DBW0(1, 'edit = ' + strEdit1);

end;  // TMyWindow.CtrlVarUpdate

procedure TMyWindow.ButtonClicked(poCtrl:PWindowBase0; wCtrlID:Word32);
//=====================================================================
var
  poBtn       : PButtonPush;

begin
poBtn:=PButtonPush(poCtrl); // We know that it points to a push button object.

//DBW(1, 'Button clicked=' + ITS(poBtn^.wCtrlID));

// Did we click on a check box ?
if (poBtn^.wCtrlID >= 101) and (wCtrlID <= 103) then begin
   // Changes the color of the text.
   poStatic1^.colTextFont:=RGB(  0,  0,  0); // default = Black
   if afCheck[1] then poStatic1^.colTextFont:=poStatic1^.colTextFont or RGB(255,  0,  0);
   if afCheck[2] then poStatic1^.colTextFont:=poStatic1^.colTextFont or RGB(  0,255,  0);
   if afCheck[3] then poStatic1^.colTextFont:=poStatic1^.colTextFont or RGB(  0,  0,255);

   // the simple way to redraw the control.
   poStatic1^.Redraw;
   end;

// Did we click on a radio button ?
if (poBtn^.wCtrlID >= 201) and (poBtn^.wCtrlID <= 207) then begin
   DBW(1, 'Check Box changed : ' + poBtn^.strCtrlLabel);
   end;

// Did we click on the My Button ?
if (poBtn^.wCtrlID = 111) then begin
    // a button has been clicked.
    DBW0(2, 'Button handle   = ' + ITS(poBtn^.hWin));
    DBW0(2, 'Button ID       = ' + ITS(poBtn^.wCtrlID) + ' = ' + ITS(wCtrlID));
    DBW0(2, 'Button class    = ' + poBtn^.strClassName);
    DBW0(2, 'Button Win name = ' + poBtn^.strWindowName);
    DBW0(2, 'Button label    = ' + poBtn^.strCtrlLabel);
    DBW0(2, 'Button hint     = ' + poBtn^.strCtrlHint);

   // Changes the color of the text.
   if      (poStatic1^.colTextFont = RGB(255,  0,  0)) then
            poStatic1^.colTextFont:= RGB(  0,255,  0)
   else if (poStatic1^.colTextFont = RGB(  0,255,  0)) then
            poStatic1^.colTextFont:= RGB(  0,  0,255)
   else if (poStatic1^.colTextFont = RGB(  0,  0,255)) then
            poStatic1^.colTextFont:= RGB(255,  0,  0);

   // the simple way to redraw the control.
   poStatic1^.Redraw;
   end;

// Did we click on the Popup named button ?
if (poBtn^.wCtrlID = 1141) then begin
   // here poBtn = poBtnPopup
   if (poBtn^.strCtrlLabel = '  Popup  ') then begin
      // must destroy the associated window, before creating a new button window
      poBtnMy^.WindowDestroy;
      poBtnMy^.poParent:=NIL; // no parent => popup window
      poBtnMy^.CtrlCreate;
      // Creates the button
      // It has no parents, thus its position is independent of any window
      // and is positionned on a fix palce on the screen.
      // Since it is a popup window button, it will not notify any parents
      // when you click on it.
      // If you want to treat the messages corresponding to this button,
      // you have to define a descendent of the TButtonPush class, and
      // use the  CtrlWindowProc  method to receive the messages.
      // It is seldom used.

      // changes the label of the button
      poBtn^.strCtrlLabel  :='Child'; // Text on the button
      poBtn^.strCtrlHint   :='Change the "My Button" into a CHILD button';
      poBtn^.NotifyChanges; // to change the caption
      end
   else begin
      // must destroy the associated window, before creating a new button window
      poBtnMy^.WindowDestroy;
      poBtnMy^.poParent:=poBtn^.poParent; // the dialog is the parent
      poBtnMy^.CtrlCreate;
      // Creates the button, it is again a normal child button
      // since it has a parent.

      // changes the label of the button
      poBtn^.strCtrlLabel  :='  Popup  '; // Text on the button
      poBtn^.strCtrlHint   :='Change the "My Button" into a POPUP button';
      poBtn^.NotifyChanges; // to change the caption
      end; // else of if (poBtn^.strCtrlLabel = 'Popup') then begin
   end; // if (poBtn^.wCtrlID = 1141) then begin
end;  // TMyWindow.ButtonClicked

procedure TMyWindow.AskAcceptDlgQuit(poDlg:PWindowBase0; wCtrlIDP:word32; var wRep:word32);
//=========================================================================================
// If we quit the dialog box, we quit the program too
begin
poDlg:=poDlg;  wCtrlIDP:=wCtrlIDP; wRep:=wRep; // to avoid hints
PostQuitMessage (0); // Quit the program.
end;  // TMyWindow.AskAcceptDlgQuit

function TMyWindow.WMCommand(wPar:WPARAM; lPar:LPARAM):LRESULT;
//=============================================================
// There are no menus, only one dialog box
begin
// Execute the dialog box at starting
if (lPar = 0) and (wPar =101) then DialogExecMSG(11199, @Self);

WMCommand:=inherited WMCommand(wPar, lPar);
end;  // TMyWindow.WMCommand

var
  oApp        : TApplication;
  poMyMainWin : PMyWindow;

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

// Creation of the main window
new(poMyMainWin, Init('tEx041.  Example of creating a dialog box'));

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

