unit wDialogCreator2;

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

  This unit Creates a dialogbox from a description made in
  a text message file '.msg'
  This helps a lot creating dialog boxes.

  USE the parent unit  wDialogCreatorLOW2.pp  to create a dialog box.

  This unit is only inteded to overridde the functionnalities of
  its parent object  TDialogCreatorLOW2.

  This helps to hide constants, type and variables, which are not
  necessary to know for using the  Dialog Creator.
  And allow lower level units to use the dialog creator without
  having to "uses" a high level unit.
----------------------------------}

// 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 wDialog0, wControl0, wWindowBase0, wHashTable2,
     wDialogCreatorLOW2, wGlobals2;

const
  MAXSPECIAL            = 20;
  // maximum of 20 specialisation + specification allowed.
  // This is quite a high limit, and allows programming simplification

type
  RDirective = record
  //"""""""""""""""""
    wDirect   : word32;
    // memorises the directives

    cTab      : char;
    // The character corresponding to the tab

    pstrData : ^ShortString;
    // In some cases, a text string is given as a data.

    end; // RDirective = record

  PRDefinition = ^RDefinition;
  RDefinition = record
  //""""""""""""""""""
    wIndex1,  // code the 8 character identification.
    wIndex2   // It will be used as an index in an HashTable to retreive
              // the corresponding Definition.
              : word32;

    wNbSpec   : word32;
    // number of specialisation + specification corresponding to this
    // definition's identificator

    awSpec    : array[1..MAXSPECIAL] of word32;
    // Specifications corresponding to the identifier,
    // is one of the constant SPEC_...

    awInt1,    // first interger data given in the definition
    awInt2,
    awInt3,
    awInt4
              : array[1..MAXSPECIAL] of word32;

    apstrData : array[1..MAXSPECIAL] of ^ShortString;
    // In some cases, a text string is given as a data.

    end; // RDefinition = record

  PRInstruction = ^RInstruction;
  RInstruction = record
  //"""""""""""""""""""
    poCtrl    : PControl;

    wTabNumber   // Is it the first tabulator of this line, the second one, etc.
                 // If it is zero, this instruction is not followed by a tabulator
              : word32;
    end; // RInstruction = record

const
  // To simplify the programming, we will use an array to memorise the
  // structure of the dialog box's creation info.
  // This implies that we limite ourself to a maximum of MAXLINES lines of description,
  // and a maximum of MAXCOLS different controls per line.
  MAXLINES = 100;
  MAXCOLS  =  20;

  MAXDIRECT   = 50;
  MAXDEF      = 50;
  MAXTABS     = 10; // maximum of 10 tabulators.

  MAXSTRINGS  = 200;
  // Maximum number of strings (Labels) memorised.
  // Seems quit a lot.

type
  PDialogCreator2 = ^TDialogCreator2;
  TDialogCreator2 = object(TDialogCreatorLOW2)
  //""""""""""""""""""""""""""""""""""""""""""
  wError      : word32;
  // error code while creating the dialog box.
  // Error numbers >= 100 are fatal, and no dialog box will be created.

  poDialogParent : PWindowBase;
  // Memorise who is the parent of the dialog box

  arDirect    : array[1..MAXDIRECT] of RDirective;
  // memorise the directives

  wNumDirect    :  word32;
  // number of directives

  arDef       : array[1..MAXDEF] of RDefinition;
  // memorise the definitions

  wNumDef    :  word32;
  // number definitions

  oHTDef      : THashTableW2;
  // HashTable to memorise the definitions.

  arInstr     : array[1..MAXLINES, 0..MAXCOLS] of RInstruction;
  // memorise the instructions, more detailed.
  // To each of these instruction correspond one control.
  // We limit ourselves to a maximum of MAXCOLS controls per line,
  // static controls included.
  // the 0 in the columns is used for lines beginning with a tabulator.

  wNumInstr    :  word32;
  // number of lines of intructions

  awNbCol      : array[1..MAXLINES] of word;
  // number of columns in each line.

  strTabs      : string[MAXTABS];
  // Character used as tabulators

  awTabsType   : array[0..MAXTABS] of word;
  // type of the tabulator :
  // DIR_TAB_BEFORE, or DIR_TAB_AFTER, or DIR_TAB_INVISIBLE

  anTabPosPix  : array[0..MAXCOLS] of int32;
  // position in pixels of the tabulators,
  // relative to the position of the previous tab position.
  // The first one is relative to the left border.
  
  wTabNumber : word32;
  // This count the number of tabulators in the trated line.

  nLineEndPix : int32;
  // Indicate the actual end of the line in pixels.
  // used to compute tabulations.

  nLineTabPosPix : integer;
  // position of the last tabulator in the treated line.

  apstrDataAlloc : array[1..MAXSTRINGS] of ^ShortString;
  // strore here all strings allocated in memory used in labels.

  wNbStrDataAlloc : word;
  // number of strings allocated in memory.
  // these are disposed in the destructor Done

  anDeltaLineHeightCh : array[1..MAXLINES+1] of Int32;
  // Change of the interline, in character height * 100

  awLineHeightPix : array[1..MAXLINES] of Word32;
  // For toolbars having only buttons, it is usefull to be able to define
  // the line height in pixels.
  // This will set to zero the line height in character,
  // for this particular line.

  vInterLineCh : Float;
  // defines in line height in characters. By default is set to 1.8

  wTopMarginCh : word32;
  // Top margin in line height in characters * 100. By default is set to 50

  wLeftMarginCh : word32;
  // Left margin in character width * 100.

  wRightMarginCh : word32;
  // Right margin in character width * 100.

  wDialogWidthCh : word32;
  // Width of the dialog box in character width * 100.
  // Is set to 0 by default, meaning its computed automatically.

  poDialog     : PDialog;
  // pointer on the created dialog box.

  fWithOKButton,       // is there an ok button ? = TRUE by default.
  fWithCancelButton,   // is there a cancel button ? = TRUE by default.
  fDirectivesRidden,   // have the directives been ridden ?
  fDefinitionsRidden,  // have the definitions been ridden ?
//  fDialogTitleRidden,  // have the title been ridden ? useless
  fInstructionsRidden  // have the instructions been ridden ?
              : boolean;

  strL        : ShortString;
  // A line of the dialog's description.

  wPos        : word;
  // position in the strL dialog description.

  wTenCharWidthPix : word32;
  // Width in pixels of 10 '0' characters.
  // usefull to compute the width of an edit box.

  wDefBtnHeightCh : word32;
  // Default button Height in character height * 100

  wBMOrgMsg : word32;
  // For BitMap buttons, this value will be added to the number defining
  // where in the .msg file, the bitmap can be found.

  wBtnWidthPix : word32;
  // For BitMap buttons only, this value defines the width of the button in pixels

  wBtnHeightPix : word32;
  // For all buttons, if this value is different from zero,
  // it defines the height of the button in pixels.
  // It is specially usefull for BitMap buttons.
  // the Width and Height of bitmap buttons can be redefined in the
  // specialisations, with  BtnWidthPix(value)  and  BtnHeightPix(value)

  wDefLineHeightPix : word32;
  // By default is equal to zero.
  // if set to a value, fixe the line height in pixels

  constructor Init;
  // Call Init; at the beggining of a new Init constructor.

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

  procedure SkipSpaces; virtual;
  // Skip some spaces

  function GetSimpleWord32:word32;
  // Gets an unsigned simple word32

  function GetWord32:int32;
  // gets either a simple word32, or a word32 defined in a variable,
  // which is liked to a number.

  function GetInt32:int32;
  // gets either a simple integer, or an integer defined in a variable,
  // which is liked to a number.

  function GetLabel:ShortString;
  // Returns the string from position wPos until the character  "
  // is reached. The caracter  "  is not in the returned string,
  // but it is skipped.  strL[wPos] = first char after the  ".
  // If two  "  follows, the one is taken, the other ignored.
  // If a Word32 is found, take the string corresponding to
  // this line number in the  .msg  file.

  function GetString:ShortString;
  // Get a strings, mixed from texts and variables.

  function GetIdentificator:ShortString;
  // Get an identificator from strL[wPos...]

  procedure ReadDirectives; virtual;
  // read the Directives, and memorise them.

  procedure GetSpecialisation; virtual;
  // Get one Specifiaction or specialisation,
  // Put the result in arDef[wNumDirect+1]
  // wError > 0 if we got an invalid syntax

  procedure ReadDefinitions; virtual;
  // read the Definitions, and memorise them.

  procedure ReadDialogTitle; virtual;
  // read the Dialog title,
  // create the dialog and assign it a title.
  // It is the begining of the dialog's existence.

  procedure ApplySpecialisations(poCtrlP:PControl; prDefP:PRDefinition); virtual;
  // Add the specialisations to the control.
  // For example, a Hint, a Help

  procedure TreatOneCommand; virtual;
  // Treate the command name, in the instructions.
  // They are preceded by @!

  procedure ReadOneInstruction; virtual;
  // read one Instruction, treat it partially and memorise them.

  procedure ReadInstructions; virtual;
  // read the Instructions, treat them partially and memorise them.

  procedure FixePosSizes; virtual;
  // Fixe the size of the dialog box,
  // of some controls if still needed and
  // place the controls at their right place.

  function DialogCreation(wMsgNum:word32; poDialogParentP:PWindowBase):PWindowBase; virtual;
  // This is the main function, which creates the dialog box object.
  // From a word32 number designing lines in the message file,
  // create a dialog box, with controls in it,
  // and return a pointer on it.
  // poDialogParentP is a pointer on the object window owining this dialog.

  function ToolBarCreation(wMsgNum:word32; poParentP:PWindowBase):PWindowBase; virtual;
  // This is the main function, which creates the ToolBar object.
  // From a word32 number designing lines in the message file,
  // create a ToolBar, with controls in it,
  // and return a pointer on it.
  // poParentP is a pointer on the object window owning this ToolBar

  end; // TDialogCreator2 = object(TDialogCreatorLOW2)

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

uses
  wWindow0
// ,wToolBar0
 ,wButtonCheck0
 ,wButtonPush0
 ,wButtonBitMap0
 ,wButtonRadio0
 ,wComboBox0
 ,wEditBox0
 // wRichText0
 ,wStatic0
// ,wStatusLine0
 ,wParamApplic2
 ,wVariableNumLink2, wMessages2, wErrors2, wObjectCreatorLOW2
 ,wGlobals0
 ,wDebug0;
// wUtiles0, wWindowBase0

const
  IDOK      = 1;  // Lable defined in Windows.
  IDCANCEL  = 2;

  // List of all directives
  DIR_TAB_BEFORE        = 1;
  DIR_TAB_AFTER         = 2;
  DIR_TAB_INVISIBLE     = 3;
  DIR_NOOK              = 4;
  DIR_NOCANCEL          = 5;
  DIR_OKLABEL           = 6;
  DIR_CANCELLABEL       = 7;
  DIR_INTERLINE         = 8;
  DIR_TOPMARGIN         = 9;
  DIR_LEFTMARGIN        =10;
  DIR_RIGHTMARGIN       =11;
  DIR_DLGNAME           =13;
  DIR_DLGPOS            =14;
  DIR_QUITID            =15;
  DIR_DLGWIDTH          =16;
  DIR_DefBtnHeight      =17;
  DIR_DefBtnHeightPix   =18;
  DIR_DefBtnWidthPix    =19;
  DIR_DefLineHeightPix  =20;
  DIR_BMOrgMsg          =21;

  // List of all definitions
  SPEC_COMBODROPDOWN     = 1;
  SPEC_COMBODROPDOWNLIST = 2;
  SPEC_STATIC            = 3;
  SPEC_RADIO             = 4;
  SPEC_CHECK             = 5;
//  SPEC_BTN               = 4;
{  SPEC_XPOS              =21;
  SPEC_YPOS              =22;
  SPEC_WIDTH             =23;
  SPEC_HEIGHT            =24;
  SPEC_REFERENCE         =25;
}
  SPEC_SORT              =27; // by default, unsorted
  SPEC_STYLE             =29;
  SPEC_ID                =30;
  SPEC_HINT              =31;
  SPEC_MENU              =32;
  SPEC_HELPPOPUP         =33;
  SPEC_HELPDIALOG        =34;
  SPEC_CENTERED          =35;
  SPEC_RIGHT             =36;
  SPEC_TEXTCOLOR         =41; // for static, radio button, check box
  SPEC_BACKCOLOR         =42; // idem
  SPEC_WINDOWCOLOR       =43;
  SPEC_BtnHeightPix      =45;
  SPEC_BtnWidthPix       =46;
  SPEC_BMOrgMsg          =47;

  // Comand names
  CMD_MENU               = 201;
  CMD_HINT               = 202;
  CMD_HELPPOPUP          = 203;
  CMD_HELPDIALOG         = 204;
  CMD_ID                 = 205;
  CMD_DELTAHEIGHT        = 206;
  CMD_TEXTCOLOR          = 207;
  CMD_DefBtnHeight       = 208;
  CMD_LineHeightPix      = 209;
  CMD_NoNewLine          = 211;
  CMD_INTERLINE          = 212;

  CMD_BTN                = 220;
  CMD_BM                 = 221;
//  CMD_RADIO              = 222;
//  CMD_CHECK              = 223;
//  CMD_HSCROLL            = 224;
//  CMD_VSCROLL            = 225;
//  CMD_LISTBOX            = 230;

// Some error constant, not very usefull.
const
// errors local to the unit.
ERR_WORD_OVERFLOW_1     = 1;
ERR_NoDigits_1          = 2;
ERR_BadVarInt_1         = 3;
ERR_INTEGER_OVERFLOW_1  = 4;

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

procedure ConvertIdentificatorIntoIndexes(strS:ShortString; var wInd1,wInd2:word32);
//==================================================================================
// converts the identificator strS into two words wInd1 and wInd2
var nn : integer;
begin
// First identificator
wInd1:=0;
for nn:=4 downto 1 do begin
   if (nn <= length(strS)) then
        wInd1:=256*wInd1 + ord(strS[nn])
   else wInd1:=256*wInd1;
   end;

// Second identificator
wInd2:=0;
for nn:=8 downto 5 do begin
   if (nn <= length(strS)) then
        wInd2:=256*wInd2 + ord(strS[nn])
   else wInd2:=256*wInd2;
   end;
end;  // ConvertIdentificatorIntoIndexes

//***************************************************
// TDialogCreator2 = object
//***************************************************

constructor TDialogCreator2.Init;
//===============================
var nn : integer;
begin
wError        := 0;

poDialogParent:=NIL;

oHTDef.Init(2*MAXDEF);
// a size 2 times max of the number of definitions
// should be enough.

wNumDirect    := 0;
wNumDef       := 0;
wNumInstr     := 0;
strTabs       :='';

wNbStrDataAlloc:=0;

vInterLineCh  :=1.8; // line height
wTopMarginCh  := 50; // top margin
wLeftMarginCh := 50;
wRightMarginCh:=150;
wDialogWidthCh :=0;
wDefBtnHeightCh:=200;

poDialog      :=NIL;

fWithOKButton     :=TRUE;
fWithCancelButton :=TRUE;

fDirectivesRidden   :=FALSE;
fDefinitionsRidden  :=FALSE;
fInstructionsRidden :=FALSE;

// To compute the width of controls like edit boxes.
wTenCharWidthPix:=gglpoMainWindow^.GetTextWidthPix('0000000000');

wBMOrgMsg      :=3000000000;
wBtnWidthPix   :=(wTenCharWidthPix * 4) div 10;
wBtnHeightPix  :=0; // default button heigt in char, if not otherwise specified

wDefLineHeightPix:=0;

// no tabulations to yet.
for nn:=0 to MAXCOLS do anTabPosPix[nn]:=0;

// if no tabulator, type = 0
awTabsType[0]:=0;
end;  // TDialogCreator2.Init

destructor TDialogCreator2.Done;
//==============================
// releases allocated memory to create the dialog box
var
  ww : word;
begin
// Releases allocated memory for the used strings.
for ww:=wNbStrDataAlloc downto 1 do dispose(apstrDataAlloc[ww]);

oHTDef.Done;
end;  // TDialogCreator2.Done

procedure TDialogCreator2.SkipSpaces;
//===================================
// Skip some spaces
begin
while (strL[wPos] = ' ') do inc(wPos);
end;  // TDialogCreator2.SkipSpaces;

function TDialogCreator2.GetSimpleWord32:word32;
//==============================================
// Gets an unsigned simple word32
var
  wInt        // the word32 to be returned;
              : word32;
  ch          : char;

begin
GetSimpleWord32:=0; // this value is returned in case of errors
wInt:=0;

ch:=strL[wPos];
while (ch >= '0') and (ch <= '9') and (wInt < 100000000) do begin
      wInt:=10*wInt + ord(ch) - ord('0');
      inc(wPos);
      ch:=strL[wPos];
      end;

//Must test overflow cases.
if (ch >= '0') and (ch <= '9') then begin
   // the integer is bigger than or equal to 1'000'000'000
   if ((wInt = 429496729) and (ch >= '6')) or
      ((strL[wPos+1] >= '0') and (strL[wPos+1] <= '9')) then begin
      // we have an integer overflow
      ErrorWriteMsg(2000006103);
      wError:=ERR_WORD_OVERFLOW_1;
      exit;
      end;

   // the integer is bigger than or equal to 1'000'000'000
   // But we know it's not an overflow
      wInt:=10*wInt + ord(ch) - ord('0');
      inc(wPos);
      end;

// Here we know that all digits have been ridden
GetSimpleWord32:=wInt;
end;  // TDialogCreator2.GetSimpleWord32

function TDialogCreator2.GetWord32:int32;
//=======================================
// gets either a simple word32, or a word32 defined in a variable,
// which is liked to a number.
var
  wVarType,   // type of the variable, linked to the number.
              // We could test if it is really a word32.
  wVarInt     : word32;

begin
GetWord32:=0; // returned value in case of errors
SkipSpaces;

if (strL[wpos] = '@') then begin
   // the integer is defined in a variable
   inc(wPos);
   wVarInt:=GetSimpleWord32;

   if (wVarInt = 0) then begin
      // Error, a variable cannot be linke with 0
      ErrorWriteMsg(2000006104);
      wError:=ERR_BadVarInt_1;
      exit;
      end;

   // Return the integer coded in the variable.
   // If the type is incompatible with word32, then  0  is returned.
   GetWord32:=ValueWord32(wVarInt, wVarType);
   exit;
   end;

// We must have a simple integer here
if (strL[wPos] < '0') or (strL[wPos] > '9') then begin
   // error, there is no positif number
   ErrorWriteMsg(2000006105);
   wError:=ERR_NoDigits_1;
   exit;
   end;

// return the word
GetWord32:=GetSimpleWord32;
end;  // TDialogCreator2.GetWord32

function TDialogCreator2.GetInt32:int32;
//======================================
// gets either a simple integer, or an integer defined in a variable,
// which is liked to a number.
var
  wVarType,   // type of the variable, linked to the number.
              // We could test if it is really a word32.
  wVarInt,
  nSigne : int32;
  wVal   : word32; // the absolute value.

begin
GetInt32:=0; // returned value in case of errors
SkipSpaces;

if (wError <> 0) then exit; // errors already occured => do nothing.

if (strL[wpos] = '@') then begin
   // the integer is defined in a variable
   inc(wPos);
   wVarInt:=GetSimpleWord32;

   if (wVarInt = 0) then begin
      // Error, a variable cannot be linke with 0
      ErrorWriteMsg(2000006106);
      wError:=ERR_BadVarInt_1;
      exit;
      end;

   // Return the integer coded in the variable.
   // If the type is incompatible with word32, then  0  is returned.
   GetInt32:=ValueInt32(wVarInt, wVarType);
   exit;
   end;

// Here, it must be an integer
nSigne:=1; // by default the integer is assumed to be positif.

// Test if the integer is negative.
if (strL[wPos] = '-') then begin
   // it is a negative integer
   nSigne:=-1;
   inc(wPos);
   end;

if (strL[wPos] = '+') then inc(wPos); // accept also a '+' signe

wVal:=GetSimpleWord32;
if (wError <> 0) then exit;

// overflow testing
if (wVal > 2147483647) then begin
   ErrorWriteMsg(2000006107);
   wError:=ERR_INTEGER_OVERFLOW_1;
   exit;
   end;

if (nSigne > 0) then GetInt32:= int32(wVal)
else                 GetInt32:=-int32(wVal);
end;  // TDialogCreator2.GetInt32

function RGB(wR,wG,wB:word32):word32;
//===================================
begin
RGB:=(wB*256 + wG)*256 + wR;
end;  // RGB

function TDialogCreator2.GetLabel:ShortString;
//============================================
// Returns the string from position wPos until the character cEnd
// is reached. The caracter  cEnd  is not in the returned string,
// but it is skipped.  strL[wPos] = first char after the  cEnd.
// If two  cEnd  follows, the one is taken, the other ignored.
// The label could be coded in a variable, with a "@Number"
var
  strS        : ShortString;
  msgNum      : word32;
begin
strS:='';

SkipSpaces;

if (strL[wPos] = '"') then begin
   // A string follows
   inc(wPos);

   while (wPos <= length(strL)) and
         ((strL[wPos] <> '"') or (strL[wPos+1] = '"')) do begin
      strS:=strS + strL[wPos];
      if (strL[wPos] = '"') then inc(wPos); // skip one, if two  "
      inc(wPos);
      end;

   // Skip the  "  character, if one follows
   if (wPos <= length(strL)) then inc(wPos);
   end
else begin
   // A Msg number follows, which correspond to a text.
   msgNum:=GetWord32;
   strS:=GetMsg(msgNum);
   end;

// Convert the  @Numbers  into strings, and return the string
GetLabel:=Interpret(strS);

SkipSpaces;
end; // TDialogCreator2.GetLabel

function TDialogCreator2.GetString:ShortString;
//=============================================
// Get a strings, mixed from texts and variables.
begin
GetString:=Interpret(Copy(strL, wPos, 255));
end;  // TDialogCreator2.GetString

function TDialogCreator2.GetIdentificator:ShortString;
//====================================================
// Get an identificator from strL[wPos...]
// The identificator cannot have more than 8 characters.
// The rest is skipped.
var
  strToken    // the directive's token
              : ShortString;
  ch          : char;
  nCount      : integer;

begin
// The identificators are not case sensitive
ch:=UpCase(strL[wPos]);

// get the token
nCount:=0;
strToken:='';
while (ch >= 'A') and (ch <= 'Z') and (nCount < 8) do begin
      strToken:=strToken + ch;
      inc(wPos);
      ch:=UpCase(strL[wPos]);
      inc(nCount);
      end;

// Skip simply the rest of the identificator if there is one
while (ch >= 'A') and (ch <= 'Z')do begin
   inc(wPos);
   ch:=UpCase(strL[wPos]);
   end;

GetIdentificator:=strToken;
end; //  TDialogCreator2.GetIdentificator

procedure TDialogCreator2.ReadDirectives;
//=======================================
// read one Directive, and memorise it.
var
  strToken    // the directive's token
              : ShortString;
  ch          : char;
  nn          : integer;
  wValueL,
  wDirectL    : word32; // the directive

begin
strL[length(strL)+1]:=#0;
SkipSpaces;

if (strL[wPos] <> '@') or (strL[wPos+1] <> '$') then begin
   // line to short to have a description or
   // no more descriptions following.
   // We assume that the descriptions are finished.
   fDirectivesRidden:=TRUE;
   exit;
   end;

// the line begins with a '@$', symbol of a directive
wPos:=wPos+2;

// The directives are not case sensitive
ch:=UpCase(strL[wPos]);

// get the token
strToken:='';
while (ch >= 'A') and (ch <= 'Z') do begin
      strToken:=strToken + ch;
      inc(wPos);
      ch:=UpCase(strL[wPos]);
      end;

if (strToken = '') then begin
   // Error. No token after the '@$' signe
   ErrorWriteMsg(2000006116);
   exit;
   end;

// we got one directive
if (wNumDirect < MAXDIRECT) then inc(wNumDirect);
arDirect[wNumDirect].cTab     :=' '; // Default initialisation
arDirect[wNumDirect].pstrData :=NIL; // idem.

if (strToken = 'NOOK')             then wDirectL:=DIR_NOOK;
if (strToken = 'NOCANCEL')         then wDirectL:=DIR_NOCANCEL;
if (strToken = 'TABBEFORE')        then wDirectL:=DIR_TAB_BEFORE;
if (strToken = 'TABAFTER')         then wDirectL:=DIR_TAB_AFTER;
if (strToken = 'TABINVISIBLE')     then wDirectL:=DIR_TAB_INVISIBLE;
if (strToken = 'OKLABEL')          then wDirectL:=DIR_OKLABEL;
if (strToken = 'CANCELLABEL')      then wDirectL:=DIR_CANCELLABEL;
if (strToken = 'INTERLINE')        then wDirectL:=DIR_INTERLINE;
if (strToken = 'DLGNAME')          then wDirectL:=DIR_DLGNAME;
if (strToken = 'DLGPOS')           then wDirectL:=DIR_DLGPOS;
if (strToken = 'QUITID')           then wDirectL:=DIR_QUITID;
if (strToken = 'TOPMARGIN')        then wDirectL:=DIR_TOPMARGIN;
if (strToken = 'LEFTMARGIN')       then wDirectL:=DIR_LEFTMARGIN;
if (strToken = 'RIGHTMARGIN')      then wDirectL:=DIR_RIGHTMARGIN;
if (strToken = 'DLGWIDTH')         then wDirectL:=DIR_DLGWIDTH;
if (strToken = 'DEFBTNHEIGHT')     then wDirectL:=DIR_DefBtnHeight;
if (strToken = 'DEFBTNHEIGHTPIX')  then wDirectL:=DIR_DefBtnHeightPix;
if (strToken = 'DEFBTNWIDTHPIX')   then wDirectL:=DIR_DefBtnWidthPix;
if (strToken = 'DEFLINEHEIGHTPIX') then wDirectL:=DIR_DefLineHeightPix;
if (strToken = 'BMORGMSG')         then wDirectL:=DIR_BMOrgMsg;

// memorise the directive
arDirect[wNumDirect].wDirect:=wDirectL;

if (wDirectL = DIR_NOOK) then begin
   fWithOKButton:=FALSE;
   exit;
   end;

if (wDirectL = DIR_NOCANCEL) then begin
   fWithCancelButton:=FALSE;
   exit;
   end;

// Look for data going with this directive
SkipSpaces;
if (strL[wPos] <> '(') then begin
   // Error. We have the sign of the definition of a directive,
   // but no right directive follows.
   ErrorWriteMsg(2000006117);

   // It can be a mistake, we are not finished with the directives yet
   // thus don't stop : fDirectivesRidden:=TRUE; should not come yet.
   exit;
   end;

// get the data following the token
inc(wPos);

// For a tabulator, get the associated character.
if (wDirectL = DIR_TAB_BEFORE) or
   (wDirectL = DIR_TAB_AFTER)  or (wDirectL = DIR_TAB_INVISIBLE) then begin
   // A new character is used as tabulator
   arDirect[wNumDirect].cTab    :=strL[wPos];

   if (length(strTabs) < MAXTABS) then begin
      strTabs:=strTabs + strL[wPos];
      awTabsType[length(strTabs)]:=wDirectL;
      end;
   exit;
   end;

// Get the label of the OK or CANCEL button.
if (wDirectL = DIR_OKLABEL) or
   (wDirectL = DIR_CANCELLABEL) then begin
   arDirect[wNumDirect].wDirect :=wDirectL;

   // Allocate memory to store the label and get the label
   inc(wNbStrDataAlloc);
   new(apstrDataAlloc[wNbStrDataAlloc]);
   apstrDataAlloc[wNbStrDataAlloc]^:=GetLabel;

   // memorise a pointer on the string containing the label
   arDirect[wNumDirect].pstrData:=apstrDataAlloc[wNbStrDataAlloc];
   exit;
   end; // if (wDirectL = DIR_OKLABEL) or ... DIR_DLGNAME

if (wDirectL = DIR_DLGNAME) then begin
   poDialog^.strWindowName:=GetLabel;
   exit;
   end; // if (wDirectL = DIR_DLGNAME)

if (wDirectL = DIR_INTERLINE) then begin
   vInterLineCh:=GetWord32 / 100.0;
   // Test to have a minimum and maximum interline
   if (vInterLineCh < 0.1) then vInterLineCh:=0.1;
   if (vInterLineCh > 50)  then vInterLineCh:=50;
   exit;
   end; // if (wDirectL = DIR_INTERLINE)

if (wDirectL = DIR_TOPMARGIN) then begin
   wTopMarginCh:=GetWord32;
   // Test to have a maximum
   if (wTopMarginCh > 1000)  then wTopMarginCh:=10;
   exit;
   end; // if (wDirectL = DIR_TOPMARGIN)

if (wDirectL = DIR_LEFTMARGIN) then begin
   wLeftMarginCh:=GetWord32;
   // Test to have a maximum
   if (wLeftMarginCh > 8000)  then wLeftMarginCh:=8000;
   exit;
   end; // if (wDirectL = DIR_LEFTMARGIN)

if (wDirectL = DIR_RIGHTMARGIN) then begin
   wRightMarginCh:=GetWord32;
   // Test to have a maximum
   if (wRightMarginCh > 8000)  then wRightMarginCh:=8000;
   exit;
   end; // if (wDirectL = DIR_RIGHTMARGIN)

if (wDirectL = DIR_DLGWIDTH) then begin
   wDialogWidthCh:=GetWord32;
   // Test to have a maximum
   if (wDialogWidthCh > 20000)  then wDialogWidthCh:=20000;
   exit;
   end; // if (wDirectL = DIR_DLGWIDTH)

if (wDirectL = DIR_DLGPOS) then begin
   // Dialog positions will be set in  FixePosSizes
   // Units are not pixels, but relative :
   //   0 = left or top
   //  50 = centered
   // 100 = right or bottom
   poDialog^.nXPosPix:=GetWord32;
   inc(wPos); // skip the  ,  or  ;
   poDialog^.nYPosPix:=GetWord32;

   // Dialog must be in the screen
   if (poDialog^.nXPosPix > 100) then poDialog^.nXPosPix:=100;
   if (poDialog^.nYPosPix > 100) then poDialog^.nYPosPix:=100;
   exit;
   end; // if (wDirectL = DIR_DLGPOS)

if (wDirectL = DIR_QUITID) then begin
   // list of id wich should quit the dialog box.
   for nn:=1 to 6 do begin
      wValueL:=GetWord32;
      if (wValueL = 0) then exit;
      poDialog^.awIDExit[1]:=wValueL;
      SkipSpaces;
      if (strL[wPos] <> ',') then exit;
      inc(wPos);
      end;
   end; // if (wDirectL = DIR_QUITID) then begin

if (wDirectL = DIR_DefBtnHeight) then begin
   wDefBtnHeightCh:=GetWord32;
   // Test to have a maximum
   if (wDefBtnHeightCh > 8000)  then wDefBtnHeightCh:=8000;
   exit;
   end; // if (wDirectL = DIR_DefBtnHeight)

if (wDirectL = DIR_DefBtnHeightPix) then begin
   wBtnHeightPix:=GetWord32;
   // Test to have a maximum
   if (wBtnHeightPix > 8000)  then wBtnHeightPix:=8000;
   exit;
   end; // if (wDirectL = DIR_DefBtnHeightPix)

if (wDirectL = DIR_DefBtnWidthPix) then begin
   wBtnWidthPix:=GetWord32;
   // Test to have a maximum
   if (wBtnWidthPix > 8000)  then wBtnWidthPix:=8000;
   exit;
   end; // if (wDirectL = DIR_DefBtnWidthPix)

if (wDirectL = DIR_DefLineHeightPix) then begin
   wDefLineHeightPix:=GetWord32;
   // Test to have a maximum
   if (wDefLineHeightPix > 8000)  then wDefLineHeightPix:=8000;
   exit;
   end; // if (wDirectL = DIR_DefLineHeightPix)

if (wDirectL = DIR_BMOrgMsg) then begin
   wBMOrgMsg:=GetWord32;
   exit;
   end; // if (wDirectL = DIR_BMOrgMsg)

// Error. We didn't get a correct directive
ErrorWriteMsg(2000006118);

// It can be a mistake, we are not finished with the directives yet
// thus don't stop : fDirectivesRidden:=TRUE; should not come yet.
end;  // TDialogCreator2.ReadDirectives

procedure TDialogCreator2.GetSpecialisation;
//==========================================
// Get one Specifiaction or specialisation,
// Put the result in arDef[wNumDef]
// wError > 0 if we got an invalid syntax
var
  strToken    : ShortString;
  ch          : char;
  wNbSpecL,   // number of specifications for this definition
  wSpecL,     // The constant designing the specialisation or specification
  wMsgNum     // reference to a number in the  .msg  file
              : word32;

begin
SkipSpaces;

// To simplify, memorise in one variable the number of specialisations
wNbSpecL:=arDef[wNumDef].wNbSpec;

// The Specifications and specialisations are not case sensitive
ch:=UpCase(strL[wPos]);

// get the token defining a Specification or specialisation
strToken:='';
while (ch >= 'A') and (ch <= 'Z') do begin
      strToken:=strToken + ch;
      inc(wPos);
      ch:=UpCase(strL[wPos]);
      end;

// We still don't have a specialisation.
wSpecL:=0;
                                          // we got one specification
if (strToken = 'CENTERED')           then wSpecL :=SPEC_CENTERED;
if (strToken = 'SORT')               then wSpecL :=SPEC_SORT;
if (strToken = 'RIGHT')              then wSpecL :=SPEC_RIGHT;

if (strToken = 'COMBODROPDOWN')      then wSpecL :=SPEC_COMBODROPDOWN;
if (strToken = 'COMBODROPDOWNLIST')  then wSpecL :=SPEC_COMBODROPDOWNLIST;
if (strToken = 'ID')                 then wSpecL :=SPEC_ID;
if (strToken = 'STYLE')              then wSpecL :=SPEC_STYLE;
if (strToken = 'MENU')               then wSpecL :=SPEC_MENU;
if (strToken = 'HELPPOPUP')          then wSpecL :=SPEC_HELPPOPUP;
if (strToken = 'HELPDIALOG')         then wSpecL :=SPEC_HELPDIALOG;

if (strToken = 'HINT')               then wSpecL :=SPEC_HINT;

if (strToken = 'TEXTCOLOR')          then wSpecL :=SPEC_TEXTCOLOR;
if (strToken = 'BACKCOLOR')          then wSpecL :=SPEC_BACKCOLOR;
if (strToken = 'WINDOWCOLOR')        then wSpecL :=SPEC_WINDOWCOLOR;

if (strToken = 'STATIC')             then wSpecL :=SPEC_STATIC;
if (strToken = 'RADIO')              then wSpecL :=SPEC_RADIO;
if (strToken = 'CHECK')              then wSpecL :=SPEC_CHECK;

if (strToken = 'BTNHEIGHTPIX')       then wSpecL :=SPEC_BtnHeightPix;
if (strToken = 'BTNWIDTHPIX')        then wSpecL :=SPEC_BtnWidthPix;
if (strToken = 'BMORGMSG')           then wSpecL :=SPEC_BMOrgMsg;

{ To come :
if (strToken = 'BTN')                then wSpecL :=SPEC_BTN;
if (strToken = 'SCROLL')             then wSpecL :=SPEC_SCROLL;
if (strToken = 'LISTBOX')            then wSpecL :=SPEC_LISTBOX;
}

if (strToken = '') then begin
   // No specifications or specialisations given
   ErrorWriteMsg(2000006121);
   wError:=1;
   exit; // specification is ignored.
   end;

SkipSpaces;
if (strL[wPos] <> '(') then begin
   // The '(' is missign after the specification
   ErrorWriteMsg(2000006122);
   wError:=1;
   exit; // specification is ignored.
   end;

// memorises the specialisation
arDef[wNumDef].awSpec[wNbSpecL]:=wSpecL;

if (wSpecL = SPEC_CENTERED) or
   (wSpecL = SPEC_RIGHT) or
   (wSpecL = SPEC_SORT) then exit; // ok no data.
//""""""""""""""""""""""""""""""""""""

// depending on the specialisation, look for the data going with it.
if (wSpecL = SPEC_HELPPOPUP) or
   (wSpecL = SPEC_HELPDIALOG) or
   (wSpecL = SPEC_MENU) or
   (wSpecL = SPEC_ID) or
   (wSpecL = SPEC_BtnHeightPix) or
   (wSpecL = SPEC_BtnWidthPix) or
   (wSpecL = SPEC_BMOrgMsg) or
   (wSpecL = SPEC_STYLE) or  // more explicit styles could be introduced.
   (wSpecL = SPEC_COMBODROPDOWN) or
   (wSpecL = SPEC_COMBODROPDOWNLIST) then begin
   //"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
   // get the Msg word32 where it says what comes in the combo box.
   inc(wPos);
   wMsgNum:=GetWord32;
   arDef[wNumDef].awInt1[wNbSpecL]:=wMsgNum;

   { We could test here if the number is valide.
     Only for  wSpecL = SPEC_HELPPOPUP, SPEC_HELPDIALOG, SPEC_MENU, SPEC_COMBODROPDOWN, SPEC_COMBODROPDOWNLIST
     If not an error message could be generated.
     But this takes some time ...
   if (not ExistMsgNumber(wMsgNum)) then begin
      wError:=...
      ErrorWriteMsg(wError);
      end;
   --------------------------------------------}

   // Errors are taken into account in  ReadDefinitions.
   exit;
   end; // if (wSpecL = SPEC_HELPPOPUP or ... SPEC_COMBODROPDOWNLIST)

if (wSpecL = SPEC_HINT) or
   (wSpecL = SPEC_RADIO) or (wSpecL = SPEC_CHECK) then begin
   //"""""""""""""""""""""""""""""""""""""""""""""""""""""""
   // get the text of the hint or label of the control..
   inc(wPos);

   // Allocate memory to store the label and get the label
   inc(wNbStrDataAlloc);
   new(apstrDataAlloc[wNbStrDataAlloc]);
   apstrDataAlloc[wNbStrDataAlloc]^:=GetLabel;

   // memorise a pointer on the string containing the label
   arDef[wNumDef].apstrData[wNbSpecL]:=apstrDataAlloc[wNbStrDataAlloc];

   // Errors are taken into account in  ReadDefinitions.
   exit;
   end; // if (wSpecL = SPEC_HINT) then begin

// depending on the specialisation, look for the data going with it.
if (wSpecL = SPEC_STATIC) or
   (wSpecL = SPEC_TEXTCOLOR) or
   (wSpecL = SPEC_BACKCOLOR) or
   (wSpecL = SPEC_WINDOWCOLOR) then begin
//""""""""""""""""""""""""""""""""""
   // Get the color of the static control
   inc(wPos);
   arDef[wNumDef].awInt1[wNbSpecL]:=GetWord32;
   if (wError <> 0) then exit;

   SkipSpaces;
   if (strL[wPos] <> ',') then begin
      ErrorWriteMsg(2000006123);
      wError:=1;
      exit; // specification is ignored.
      end;

   inc(wPos);
   arDef[wNumDef].awInt2[wNbSpecL]:=GetWord32;
   if (wError <> 0) then exit;

   SkipSpaces;
   if (strL[wPos] <> ',') then begin
      ErrorWriteMsg(2000006123);
      wError:=1;
      exit; // specification is ignored.
      end;

   inc(wPos);
   arDef[wNumDef].awInt3[wNbSpecL]:=GetWord32;
   if (wError <> 0) then exit;

   // we should test that the numbers are in [0..255]

   // Errors are taken into account in  ReadDefinitions.
   exit;
   end; // if .. SPEC_STATIC or ...

// Unknown Token
ErrorWriteMsg(2000006129);
end;  // TDialogCreator2.GetSpecialisation

procedure TDialogCreator2.ReadDefinitions;
//========================================
// read the Definitions, and memorise them.
var
  strIdentif  : string[10];

begin
strL[length(strL)+1]:=#0;
SkipSpaces;

if (strL[wPos] <> '@') then begin
   // no more definitions are following.
   // We assume that the definitions are finished.
   fDefinitionsRidden:=TRUE;
   exit;
   end;

// the line begins with a '@', symbol of a definition
wPos:=wPos+1;

strIdentif:=GetIdentificator;

if (strIdentif = '') then begin
   // Error, no identificators follow the definition simbole.
   // ignore the line, but continues with the definitions.
   ErrorWriteMsg(2000006131);
   exit;
   end;

// converts the identificator into two words
ConvertIdentificatorIntoIndexes( strIdentif,
                                 arDef[wNumDef+1].wIndex1,
                                 arDef[wNumDef+1].wIndex2);

// Look for the meaning of this identificator
SkipSpaces;
if (strL[wPos] <> '=') then begin
   // The '=' is missign after the definition's identificator
   ErrorWriteMsg(2000006132);
   exit;
   end;

// We consider to have one more definition, but ...
if (wNumDef < MAXDEF) then inc(wNumDef);

// We still have no specifications
arDef[wNumDef].wNbSpec:=0;

// Get the specification if any and all specialisations
// corresponding to this identificator.
repeat
   // We suppose that we will get one more specialisation
   if (arDef[wNumDef].wNbSpec < MAXSPECIAL) then inc(arDef[wNumDef].wNbSpec);

   // Get specification or specialisation
   inc(wPos);
   GetSpecialisation;
   SkipSpaces;

   // in case of error, the specialisation is forgotten
   if (wError <> 0) then dec(arDef[wNumDef].wNbSpec);

   wError:=0; // reset the errors to 0

   // Look for the next specialisation
   while (wPos < length(strL)) and (strL[wPos] <> '+') do inc(wPos);

   // Is there another specialisation following ?
   until (strL[wPos] <> '+');

// If we have specifications corresponding to the identificator,
// memorise it in the hash table.
// If not, forget this identificator.
if (arDef[wNumDef].wNbSpec = 0) then dec(wNumDef) // forget it
else oHTDef.AddPointerW2( arDef[wNumDef].wIndex1,    // memorise it
                          arDef[wNumDef].wIndex2,
                          0, // no supplementary information to strore
                          @arDef[wNumDef]);

end;  // TDialogCreator2.ReadDefinitions

procedure TDialogCreator2.ReadDialogTitle;
//========================================
// read the Dialog title, quit simple.
begin
poDialog^.strDlgTitle:=GetString;
// fDialogTitleRidden:=TRUE; useless
end;  // TDialogCreator2.ReadDialogTitle

procedure TDialogCreator2.ApplySpecialisations(poCtrlP:PControl; prDefP:PRDefinition);
//====================================================================================
// Add the specialisations to the control.
// For example, a Hint, HelpPopup, HelpDialog, Menu, ID, ...
var
  ww          : word;

begin
if (poCtrlP = NIL) or (prDefP = NIL) then exit; // nothing to do

// Loop over all specialisations.
for ww:=1 to prDefP^.wNbSpec do begin
   if (prDefP^.awSpec[ww] = SPEC_HINT) then
      poCtrlP^.strCtrlHint:=prDefP^.apstrData[ww]^;

   if (prDefP^.awSpec[ww] = SPEC_HELPPOPUP) then
      poCtrlP^.msgPopupWindowHelp:=prDefP^.awInt1[ww];

   if (prDefP^.awSpec[ww] = SPEC_HELPDIALOG) then
      poCtrlP^.msgDialogHelp:=prDefP^.awInt1[ww];

   if (prDefP^.awSpec[ww] = SPEC_MENU) then
      poCtrlP^.msgMenuPopup:=prDefP^.awInt1[ww];

   if (prDefP^.awSpec[ww] = SPEC_ID) then
      poCtrlP^.wCtrlID:=prDefP^.awInt1[ww];

   // Applies only to some controls
   //""""""""""""""""""""""""""""""
   if (prDefP^.awSpec[ww] =  SPEC_STYLE) then
      poCtrlP^.dwStyle:=poCtrlP^.dwStyle or prDefP^.awInt1[ww];

   // These are styles modification.
   // Do it more generally.

//   if (prDefP^.awSpec[ww] = SPEC_CENTERED) then

   if (prDefP^.awSpec[ww] = SPEC_RIGHT) then begin
      if (poCtrlP^.wWindowType = GGLCTE_CTRL_Static) then
         poCtrlP^.dwStyle:=poCtrlP^.dwStyle or $2; // =SS_RIGHT;

      if (poCtrlP^.wWindowType = GGLCTE_CTRL_EditBox) then
         poCtrlP^.dwStyle:=poCtrlP^.dwStyle or $2; // =ES_RIGHT;

      if (poCtrlP^.wWindowType >= GGLCTE_CTRL_ButtonPush) and
         (poCtrlP^.wWindowType <= GGLCTE_CTRL_ButtonCheck) then
         poCtrlP^.dwStyle:=poCtrlP^.dwStyle or $200; // =BS_RIGHT;

      if (poCtrlP^.wWindowType = GGLCTE_CTRL_ButtonRadio) or
         (poCtrlP^.wWindowType = GGLCTE_CTRL_ButtonCheck) then
         poCtrlP^.dwStyle:=poCtrlP^.dwStyle or $20; // =BS_RIGHTBUTTON;

      end; // if (prDefP^.awSpec[ww] = SPEC_RIGHT) then begin

   if (prDefP^.awSpec[ww] =  SPEC_SORT) and
      (poCtrlP^.wWindowType = GGLCTE_CTRL_ComboBox) then
      poCtrlP^.dwStyle:=poCtrlP^.dwStyle or CBS_SORTbis;

   // Text color of static text, radio buttons, and check boxes
   if (prDefP^.awSpec[ww] =  SPEC_TEXTCOLOR) then begin
      if (poCtrlP^.wWindowType = GGLCTE_CTRL_Static) then
         PStatic(poCtrlP)^.colTextFont:=RGB( prDefP^.awInt1[ww],
                                             prDefP^.awInt2[ww],
                                             prDefP^.awInt3[ww]);
      if (poCtrlP^.wWindowType = GGLCTE_CTRL_ButtonRadio) then
         PButtonRadio(poCtrlP)^.colTextFont:=RGB( prDefP^.awInt1[ww],
                                                  prDefP^.awInt2[ww],
                                                  prDefP^.awInt3[ww]);
      if (poCtrlP^.wWindowType = GGLCTE_CTRL_ButtonCheck) then
         PButtonCheck(poCtrlP)^.colTextFont:=RGB( prDefP^.awInt1[ww],
                                                  prDefP^.awInt2[ww],
                                                  prDefP^.awInt3[ww]);
      end; // if (prDefP^.awSpec[ww] =  SPEC_TEXTCOLOR) then begin

   // Text back color of static text, radio buttons, and check boxes
   if (prDefP^.awSpec[ww] =  SPEC_BACKCOLOR) then begin
      if (poCtrlP^.wWindowType = GGLCTE_CTRL_Static) then begin
         PStatic(poCtrlP)^.colTextBack:=RGB( prDefP^.awInt1[ww],
                                             prDefP^.awInt2[ww],
                                             prDefP^.awInt3[ww]);
         // if a back color is defined, then the background is opaque
         PStatic(poCtrlP)^.colTextTransp:=OPAQUEbis;
         PStatic(poCtrlP)^.fUseDefaultWMPaint:=FALSE;
         end;
      if (poCtrlP^.wWindowType = GGLCTE_CTRL_ButtonRadio) then begin
         PButtonRadio(poCtrlP)^.colTextBack:=RGB( prDefP^.awInt1[ww],
                                                  prDefP^.awInt2[ww],
                                                  prDefP^.awInt3[ww]);
         // if a back color is defined, then the background is opaque
         PButtonRadio(poCtrlP)^.colTextTransp:=OPAQUEbis;
         PButtonRadio(poCtrlP)^.fUseDefaultColors:=FALSE;
         end;
      if (poCtrlP^.wWindowType = GGLCTE_CTRL_ButtonCheck) then begin
         PButtonCheck(poCtrlP)^.colTextBack:=RGB( prDefP^.awInt1[ww],
                                                  prDefP^.awInt2[ww],
                                                  prDefP^.awInt3[ww]);
         // if a back color is defined, then the background is opaque
         PButtonCheck(poCtrlP)^.colTextTransp:=OPAQUEbis;
         PButtonCheck(poCtrlP)^.fUseDefaultColors:=FALSE;
         end;
      end; // if (prDefP^.awSpec[ww] =  SPEC_BACKCOLOR) then begin

   // Window back color of static text, radio buttons, and check boxes
   if (prDefP^.awSpec[ww] =  SPEC_WINDOWCOLOR) then begin
      if (poCtrlP^.wWindowType = GGLCTE_CTRL_Static) then
         PStatic(poCtrlP)^.colWindowBack:=RGB( prDefP^.awInt1[ww],
                                             prDefP^.awInt2[ww],
                                             prDefP^.awInt3[ww]);
      if (poCtrlP^.wWindowType = GGLCTE_CTRL_ButtonRadio) then
         PButtonRadio(poCtrlP)^.colWindowBack:=RGB( prDefP^.awInt1[ww],
                                                    prDefP^.awInt2[ww],
                                                    prDefP^.awInt3[ww]);
      if (poCtrlP^.wWindowType = GGLCTE_CTRL_ButtonCheck) then
         PButtonCheck(poCtrlP)^.colWindowBack:=RGB( prDefP^.awInt1[ww],
                                                    prDefP^.awInt2[ww],
                                                    prDefP^.awInt3[ww]);
      end; // if (prDefP^.awSpec[ww] =  SPEC_WINDOWCOLOR) then begin

   if (prDefP^.awSpec[ww] = SPEC_BtnHeightPix) and
      (poCtrlP^.wWindowType = GGLCTE_CTRL_ButtonBitMap) then begin
      // Change the button height
      PButtonBitMap(poCtrlP)^.nYSizePix:=prDefP^.awInt1[ww];
      PButtonBitMap(poCtrlP)^.vYSizeCh :=0;
      end; // if (prDefP^.awSpec[ww] = SPEC_BtnHeightPix) and

   if (prDefP^.awSpec[ww] = SPEC_BtnWidthPix) and
      (poCtrlP^.wWindowType = GGLCTE_CTRL_ButtonBitMap) then begin
      // Change the button width
      PButtonBitMap(poCtrlP)^.nXSizePix:=prDefP^.awInt1[ww];
      PButtonBitMap(poCtrlP)^.vXSizeCh :=0;
      end; // if (prDefP^.awSpec[ww] = SPEC_BtnWidthPix) and

   if (prDefP^.awSpec[ww] = SPEC_BMOrgMsg) and
      (poCtrlP^.wWindowType = GGLCTE_CTRL_ButtonBitMap) then begin
      // Change the shift number where the image is defined in the .msg file
      // it will be set back to its original value just after return from here
      wBMOrgMsg :=prDefP^.awInt1[ww];
      end; // if (prDefP^.awSpec[ww] = SPEC_BMOrgMsg) and

   end; // for ww:=1 to prDefP^.wNbSpec do begin
 //"""""""""""""""""""""""""""""""""""""""""""""
end;  // TDialogCreator2.ApplySpecialisations

{
procedure TDialogCreator2.AddControl(fFromCommand:boolean);
//=========================================================
// Add a control in the dialog box.
begin
... ?????????
end;  // TDialogCreator2.AddControl
}

procedure TDialogCreator2.TreatOneCommand;
//========================================
// Treate the command name, in the instructions.
// They are preceded by @!
var
  strIdentif, // identificator, spacialising a control.
  strLabelL   // label of a button
              : ShortString;
  wRed,wGreen,wBlue, // to get colors
  wCmdL,      // Command name
  wMsgNo,     // to associate a Hint, a menu, a popup help, a dialog help
              //  to a control
              // usually, to a static text.
  wBtnID,     // Id given to the button. It will be send at the grand parent
              // window, in a WM_COMMAND notification, BN_CLICKED
              // with LoWord(wPar) = id
              // lPar = handle on the button
  wIndex1L,   // To convert an identif. into two words
  wIndex2L,
  wTypeUnusedL
              : word32;
  poBtnPush   : PButtonPush;
  poBtnBM     : PButtonBitMap;
  poCtrlL     : PControl;
  prDefL      : ^RDefinition;

begin
// we have a command name
inc(wPos,2);

// Get the command name
strIdentif:=GetIdentificator;
StrField(2000000011, strIdentif, SizeOf(strIdentif)); // for error reports

if (strIdentif = '') or (strL[wPos] <> '(') then begin
   // Error. We have the sign of the definition of a directive,
   // but no right directive follows.
   ErrorWriteMsg(2000006135);

   // It can be a mistake, we are not finished with the directives yet
   // thus don't stop : fInstructionsRidden:=TRUE; should not come yet.
   exit;
   end;

inc(wPos); // skip the '('

wCmdL:=0;
// Identifier are limited to 8 characters.
if (strIdentif = 'MENU')             then wCmdL:=CMD_MENU;
if (strIdentif = 'HINT')             then wCmdL:=CMD_HINT;
if (strIdentif = 'HELPPOPU')         then wCmdL:=CMD_HELPPOPUP;
if (strIdentif = 'HELPDIAL')         then wCmdL:=CMD_HELPDIALOG;
if (strIdentif = 'ID')               then wCmdL:=CMD_ID;
if (strIdentif = 'BTN')              then wCmdL:=CMD_BTN;
if (strIdentif = 'BM')               then wCmdL:=CMD_BM;
if (strIdentif = 'DELTAHEI')         then wCmdL:=CMD_DELTAHEIGHT;
if (strIdentif = 'NONEWLIN')         then wCmdL:=CMD_NoNewLine;
if (strIdentif = 'DEFBTNHE')         then wCmdL:=CMD_DefBtnHeight;
if (strIdentif = 'TEXTCOLO')         then wCmdL:=CMD_TEXTCOLOR;
if (strIdentif = 'LINEHEIG')         then wCmdL:=CMD_LineHeightPix;
if (strIdentif = 'INTERLIN')         then wCmdL:=CMD_INTERLINE;

if (wCmdL = CMD_DELTAHEIGHT) then begin
//"""""""""""""""""""""""""""""""""""""
   // Changing the line height of one line.
   anDeltaLineHeightCh[wNumInstr]:=GetInt32;

   // No range testing, do not make mistakes, that's it.

   if (strL[wPos] = ')') then inc(wPos); // skip the ')'
   exit;
   end;

if (wCmdL = CMD_NoNewLine) then begin
//"""""""""""""""""""""""""""""""""""
   // The actual line is a continuation of the previous one
   anDeltaLineHeightCh[wNumInstr]:=30001;
   if (strL[wPos] = ')') then inc(wPos); // skip the ')'
   exit;
   end;

if (wCmdL = CMD_LineHeightPix) then begin
//"""""""""""""""""""""""""""""""""""""""
   // Changing the line height of one line.
   awLineHeightPix[wNumInstr]:=GetWord32;

   // No range testing, do not make mistakes, that's it.

   if (strL[wPos] = ')') then inc(wPos); // skip the ')'
   exit;
   end;

if (wCmdL = CMD_INTERLINE) then begin
//"""""""""""""""""""""""""""""""""""""""
   // Changing the line height of one line.
   wDefLineHeightPix:=0;
   vInterLineCh:=GetWord32 / 100.0;
   // Test to have a minimum and maximum interline
   if (vInterLineCh < 0.1) then vInterLineCh:=0.1;
   if (vInterLineCh > 50)  then vInterLineCh:=50;

   if (strL[wPos] = ')') then inc(wPos); // skip the ')'
   exit;
   end;

if (wCmdL = CMD_DefBtnHeight) then begin
//""""""""""""""""""""""""""""""""""""""
   // Changing the default button height
   wDefBtnHeightCh:=GetWord32;

   if (wDefBtnHeightCh = 0) or (wDefBtnHeightCh > 8000) then
      wDefBtnHeightCh:=200; // case of errors

   if (strL[wPos] = ')') then inc(wPos); // skip the ')'
   exit;
   end;

// Get the number following in most cases
if (wCmdL <> CMD_HINT) then begin
   wMsgNo:=GetWord32;

   if (wMsgNo = 0) then begin
      ErrorWriteMsg(2000006136);
      exit;
      end;

   SkipSpaces;
   end;

// First, if the command is the adjuction of a control.
///////////////////////////////////////////////////////
if (wCmdL = CMD_BTN) then begin
//"""""""""""""""""""""""""""""
   // We want to associate a menu to the previous control
   wBtnID:=wMsgNo;

   SkipSpaces;
   inc(wPos); // skip the ',' or the ';' or any chars

   if (wBtnID = 0) then begin
      ErrorWriteMsg(2000006137);
      exit;
      end;

   // Get the label of the button
   strLabelL:=GetLabel;
//   SkipSpaces; done in GetLabel

   if (strL[wPos] = ')') then inc(wPos);
   // else ignore the missing ')'

   // Create the button
   poBtnPush:=gglpoObjCreate^.CreateButtonPush(poDialog);

   // And define its ID, label, size
   poBtnPush^.wCtrlID:=wBtnID;
   poBtnPush^.strCtrlLabel:=strLabelL;
   poBtnPush^.nXSizePix:= (wTenCharWidthPix * length(strLabelL)) div 10;

   // If a default height has been given in pixel use it.
   // If not, use the default height in character size
   if (wBtnHeightPix > 0) then
      poBtnPush^.nYSizePix:=wBtnHeightPix
   else
      poBtnPush^.vYSizeCh:=wDefBtnHeightCh div 100; // standard size = 2

   // Remember the actual end of the line, in pixels.
   nLineEndPix:=nLineEndPix + poBtnPush^.nXSizePix;

   // Tell the button box who is its grand parent object
   poBtnPush^.poGrParent :=poDialogParent;

   // One more control in the dialog.
   if (awNbCol[wNumInstr] < MAXCOLS) then inc(awNbCol[wNumInstr]);
   arInstr[wNumInstr, awNbCol[wNumInstr]].poCtrl:=poBtnPush;
   arInstr[wNumInstr, awNbCol[wNumInstr]].wTabNumber:=0;
   exit;
   end; // if (wCmdL = CMD_BTN) then begin

if (wCmdL = CMD_BM) then begin
//"""""""""""""""""""""""""""""
   // We want to associate a menu to the previous control
   wBtnID:=wMsgNo;

   SkipSpaces;
   inc(wPos); // skip the ',' or the ';' or any chars

   if (wBtnID = 0) then begin
      ErrorWriteMsg(2000006137);
      exit;
      end;

   // Get the message number where the image is defined
   wMsgNo:=GetWord32;

   if (wMsgNo = 0) then begin
      ErrorWriteMsg(2000006136);
      exit;
      end;

   // Look if this bitmap button has a specialisation
   strIdentif:=GetIdentificator;

   if (strIdentif <> '') then begin
      // it has an identificator
      ConvertIdentificatorIntoIndexes(strIdentif,wIndex1L,wIndex2L);
      prDefL:=oHTDef.GetPointerW2(wIndex1L, wIndex2L, wTypeUnusedL);
      end
   else prDefL:=NIL;

   SkipSpaces;

   if (strL[wPos] = ')') then inc(wPos);
   // else ignore the missing ')'

   // Create the button
   poBtnBM:=gglpoObjCreate^.CreateButtonBitMap(poDialog);

   // And define its ID, image, size
   poBtnBM^.wCtrlID:=wBtnID;
   poBtnBM^.wMsgBitMapDef:=wMsgNo;

   // Default button width in pixels
   poBtnBM^.nXSizePix:= wBtnWidthPix;

   // If a default height has been given in pixel use it.
   // If not, use the default height in character size
   if (wBtnHeightPix > 0) then
      poBtnBM^.nYSizePix:=wBtnHeightPix
   else
      poBtnBM^.vYSizeCh:=wDefBtnHeightCh div 100; // standard size = 2

   // Remember the actual end of the line, in pixels.
   nLineEndPix:=nLineEndPix + poBtnBM^.nXSizePix;

   // Tell the button box who is its grand parent object
   poBtnBM^.poGrParent :=poDialogParent;

   // One more control in the dialog.
   if (awNbCol[wNumInstr] < MAXCOLS) then inc(awNbCol[wNumInstr]);
   arInstr[wNumInstr, awNbCol[wNumInstr]].poCtrl:=poBtnBM;
   arInstr[wNumInstr, awNbCol[wNumInstr]].wTabNumber:=0;

   // Remember the value of  wBMOrgMsg
   // It can be changed in  ApplySpecialisations
   wMsgNo:=wBMOrgMsg;

   // Default setting can change for bitmap buttons.
   if (prDefL <> NIL) then ApplySpecialisations(poBtnBM, prDefL);

   // Shift the number where the image is defined.
   // This shift could have been changed in  ApplySpecialisations
   poBtnBM^.wMsgBitMapDef:=poBtnBM^.wMsgBitMapDef + wBMOrgMsg;

   // If  wBMOrgMsg  has been changed, set it to its original value.
   wBMOrgMsg:=wMsgNo;
   exit;
   end; // if (wCmdL = CMD_BM) then begin

// Apply a specialisation, asked in the command.
////////////////////////////////////////////////

// Test that a control is preceding
if (wNumInstr = 0) or
   (awNbCol[wNumInstr] = 0) or
   (arInstr[wNumInstr, awNbCol[wNumInstr]].poCtrl = NIL) then exit; // Noting preceding

if (strL[wPos] = ')') then inc(wPos); // skip the ')'

// the control preceding the command
poCtrlL:=arInstr[wNumInstr, awNbCol[wNumInstr]].poCtrl;

// Error testing
if (wCmdL = CMD_MENU) or (wCmdL = CMD_HELPPOPUP) or (wCmdL = CMD_HELPDIALOG) then begin
   if (not ExistMsgNumber(wMsgNo)) then begin
      ErrorWriteMsg(2000006136);
      exit;
      end;
   end;

if (wCmdL = CMD_TEXTCOLOR) then begin
   // Change the text color of a static text.
   wRed:=wMsgNo; // this one has already been ridden
   SkipSpaces;
   inc(wPos); // skip the , or ;
   if (wPos >= length(strL)) then exit; // error, no colors given
   wGreen:=GetWord32;
   SkipSpaces;
   inc(wPos); // skip the , or ;
   if (wPos >= length(strL)) then exit; // error, no colors given
   wBlue:=GetWord32;
   SkipSpaces;
   if (strL[wPos] = ')') then inc(wPos); // skip the ')'

   if (poCtrlL^.wWindowType = GGLCTE_CTRL_Static) then begin
      PStatic(poCtrlL)^.colTextFont:=RGB(wRed, wGreen, wBlue);
      end;
   // else, ignore ...
   end; // if (wCmdL = CMD_TEXTCOLOR) then begin

// Apply the command
if (wCmdL = CMD_MENU)          then poCtrlL^.msgMenuPopup:=wMsgNo;
if (wCmdL = CMD_HELPPOPUP)     then poCtrlL^.msgPopupWindowHelp:=wMsgNo;
if (wCmdL = CMD_HELPDIALOG)    then poCtrlL^.msgDialogHelp:=wMsgNo;
if (wCmdL = CMD_ID)            then poCtrlL^.wCtrlID:=wMsgNo;

if (wCmdL = CMD_HINT) then begin
//""""""""""""""""""""""""""""""
   // We want to associate a menu to the previous control
   strLabelL:=GetLabel;
{
   if (wMsgNo = 0) or (strL[wPos] <> ')') then begin
      ErrorWriteMsg(2000006136);
      exit;
      end;
}
   if (strL[wPos] = ')') then inc(wPos); // skip the ')'

   // Sets the Hint to the wanted control.
   poCtrlL^.strCtrlHint:=strLabelL;
   exit;
   end; // if (wCmdL = CMD_HINT) then begin

                     // Error. Unknown command.
if (wCmdL = 0) then ErrorWriteMsg(2000006138);
end;  // TDialogCreator2.TreatOneCommand

procedure TDialogCreator2.ReadOneInstruction;
//===========================================
// read one Instruction, treat it partially and memorise them.
var
  strIdentif, // identificator, spacialising a control.
  strS        : ShortString;
  poStatic    : PStatic;
  poEditBox   : PEditBox;
  poComboBox  : PComboBox;
  poRadio     : PButtonRadio;
  poCheck     : PButtonCheck;
  poCtrlL     : PControl; // the newly created control
  prDefL      : ^RDefinition;
  wLengthL,   // length in character of the control
  wLengthDecimalL, // number of digits after the comma for Float numbers
  wIndex1L,   // to convert an identificator into indexes.
  wIndex2L,
  wTypeUnUsedL, // needed as a parameter, but not used.
  wCtrlTypeL, // type of the control.  GGLCTE_CTRL_... defined in wGlobals2.pp
  wTypeVarLinkL, // type of the variable in the control.
  wNumVarLinkL   // link number between a control and a variable of the program
              : word32;
  nn,
  nTabPos     // position of a tabulator, if any is found.
              : int32;
  vNum        // Just to format the Float numbers
              : Float;
//  fFormatted  // If the string variable should be formatted or not
//              : boolean;


begin
poCtrlL:=NIL; // No new control by default.
prDefL :=NIL;

if (strL[wPos] = '@') and (strL[wPos+1] = '!') then begin
   TreatOneCommand;
   exit;
   end;

// ????????  _____>>  PUT IT IN A   procedure AddControl;  methode
// Is it the same for a Command adding a control...  must be similar.

if (strL[wPos] = '@') and (strL[wPos+1] <> '@') then begin
   // it is a control linked with a variable of the program.
   inc(wPos);

   // Link the control to a variable.
   wNumVarLinkL:=GetWord32;

   if (wNumVarLinkL = 0) then begin
      ErrorWriteMsg(2000006141);
      exit;
      end;

   // Test is the number links really to a variable.
   if (GetNumPointer(wNumVarLinkL, wTypeVarLinkL) = NIL) then begin
      ErrorWriteMsg(2000006142);
      exit;
      end;

   if (wError <> 0) then exit; // forget this control

   // We have a control, see if it has a specification or specialisation
   strIdentif:=GetIdentificator;

   // if not otherwise specified, it is an EditBox.
   wCtrlTypeL:=GGLCTE_CTRL_EditBox;

   if (strIdentif <> '') then begin
      // it has an identificator
      ConvertIdentificatorIntoIndexes(strIdentif,wIndex1L,wIndex2L);
      prDefL:=oHTDef.GetPointerW2(wIndex1L, wIndex2L, wTypeUnusedL);

      if (prDefL <> NIL) and (prDefL^.wNbSpec >= 1) then begin
         // Maybe we have a specification.
         // If yes, it must be the first one of the list.
         if (prDefL^.awSpec[1] = SPEC_STATIC) or
            (prDefL^.awSpec[1] = SPEC_RADIO) or
            (prDefL^.awSpec[1] = SPEC_CHECK) or
            (prDefL^.awSpec[1] = SPEC_COMBODROPDOWN) or
            (prDefL^.awSpec[1] = SPEC_COMBODROPDOWNLIST) then
            wCtrlTypeL:=prDefL^.awSpec[1];
         end;
      end;
   // else it has no identificator. Thus it is an edit box

   // See the length it should have
   if (strL[wPos] = '(') then begin
      // Get the length of the identifier
      inc(wPos);
      wLengthL:=GetWord32;
      wLengthDecimalL:=9; // default value
//      fFormatted:=FALSE;  // no formatting for statics, i.e. take the exacte
                          // length of the text

      if (wLengthL = 0) then begin
         // error, the length cannot be zero
         ErrorWriteMsg(2000006145);
         exit;
         end;

      if (strL[wPos] = ')') then inc(wPos);
      // else it's not a problem if the parenthese is not closed.
      end // if (strL[wPos] = '(') then begin
   else if (strL[wPos] = '_') then begin
      // the length is defined with '_'
      wLengthL:=wPos;
      while (strL[wPos] = '_') do inc(wPos);
      // if there are digits after the comma to show for Float numbers.
      wLengthDecimalL:=wPos;
//      fFormatted:=TRUE;  // formatting for statics, i.e. take the lenght
                         // given by the number of characters.

      if (strL[wPos] = '.') then begin
         // it defines a Float number
         inc(wPos);
         wLengthDecimalL:=wPos;

         // reads the wanted number of digits after the comma
         while (strL[wPos] = '_') do inc(wPos);
         end; // if (strL[wPos] = '.') then begin

      wLengthDecimalL:=wPos - wLengthDecimalL;
      wLengthL:=wPos - wLengthL;
      end // if (strL[wPos] = '_') then begin
   else begin
      // length of the control is not specified.
      ErrorWriteMsg(2000006151);
      exit;
      end;

   // we have the control, its type, sizes and specialisations
   if (wCtrlTypeL = GGLCTE_CTRL_EditBox) then begin
   //""""""""""""""""""""""""""""""""""""""""""""""
      poEditBox:=gglpoObjCreate^.CreateEditBox(poDialog);

      poEditBox^.vYSizeCh:=1.5; // standard size for an edit box
      poEditBox^.nXSizePix:= (wTenCharWidthPix * (wLengthL+1)) div 10;

      // Remember the actual end of the line, in pixels.
      nLineEndPix:=nLineEndPix + poEditBox^.nXSizePix;

      // To which variable is the control linked.
      poEditBox^.pVarLink :=GetNumPointer(wNumVarLinkL, wTypeVarLinkL);
      poEditBox^.rVarLinkInfo.wVarType :=wTypeVarLinkL mod 65536;
      poEditBox^.wFloatLength   :=wLengthL;
      poEditBox^.wFloatDecimals :=wLengthDecimalL;

      if (wTypeVarLinkL >= vt_ShortString) then // must indicate its max. size
         poEditBox^.rVarLinkInfo.wStrMaxLen:=wTypeVarLinkL div 65536;

      // Tell the edit box who is its grand parent object
      poEditBox^.poGrParent :=poDialogParent;

      // One more control in the dialog.
      if (awNbCol[wNumInstr] < MAXCOLS) then inc(awNbCol[wNumInstr]);
      arInstr[wNumInstr, awNbCol[wNumInstr]].poCtrl:=poEditBox;
      arInstr[wNumInstr, awNbCol[wNumInstr]].wTabNumber:=0;
      poCtrlL:=poEditBox;
      // the content of the edit box will be set by itself at
      // the creation of its window.
      end; // if (wCtrlTypeL = GGLCTE_CTRL_EditBox) then begin

   // we have the control, its type, sizes and specialisations
   if (wCtrlTypeL = SPEC_COMBODROPDOWN) or
      (wCtrlTypeL = SPEC_COMBODROPDOWNLIST) then begin
   //"""""""""""""""""""""""""""""""""""""""""""""""""
      poComboBox:=gglpoObjCreate^.CreateComboBox(poDialog);

      if (wCtrlTypeL = SPEC_COMBODROPDOWNLIST) then
         // Change the style to be a Drop Down List
         poComboBox^.dwStyle   :=poComboBox^.dwStyle or CBS_DROPDOWNLISTbis;  // see wGlobals0.pp

      poComboBox^.vYPosCtrlRef :=0.0; // Position relative to the Top of the control.

      // To which variable is the control linked.
      poComboBox^.pVarLink :=GetNumPointer(wNumVarLinkL, wTypeVarLinkL);
      poComboBox^.rVarLinkInfo.wVarType :=wTypeVarLinkL;

      if (wTypeVarLinkL >= vt_ShortString) then // must indicate its max. size
         poComboBox^.rVarLinkInfo.wStrMaxLen:=wTypeVarLinkL div 65536;

      // Tell the combo box who is its grand parent object
      poComboBox^.poGrParent :=poDialogParent;

      // Tells the combo where are the lines it should be filled with.
      poComboBox^.wMsgFillNum:=prDefL^.awInt1[1];

      // length and height of the combo box
      poComboBox^.nXSizePix:= (wTenCharWidthPix * (wLengthL+3)) div 10;
      poComboBox^.vYSizeCh:=1.5; // Size when not opend
      poComboBox^.vYSizeOpenCh:=13.0; // To see 10 lines in the combo box

      // Remember the actual end of the line, in pixels.
      nLineEndPix:=nLineEndPix + poComboBox^.nXSizePix;

      // One more control in the dialog.
      if (awNbCol[wNumInstr] < MAXCOLS) then inc(awNbCol[wNumInstr]);
      arInstr[wNumInstr, awNbCol[wNumInstr]].poCtrl:=poComboBox;
      arInstr[wNumInstr, awNbCol[wNumInstr]].wTabNumber:=0;
      poCtrlL:=poComboBox;
      end; // if (wCtrlTypeL = SPEC_COMBODROPDOWN) or ... then begin

   // we have the control, its type, sizes and specialisations
   if (wCtrlTypeL = SPEC_STATIC) then begin
   //""""""""""""""""""""""""""""""""""""""
      poStatic:=gglpoObjCreate^.CreateStatic(poDialog);

      // Formatting of the static text, for Float numbers
      poStatic^.wFloatLength   :=wLengthL;
      poStatic^.wFloatDecimals :=wLengthDecimalL;

      // content of the static text
      poStatic^.strCtrlLabel:=ValueStr( wNumVarLinkL, wLengthL,
                                        wLengthDecimalL, wTypeUnusedL);

{      if (fFormatted) then begin
         // length given by the number of characters.
         poStatic^.nXSizePix:=(wTenCharWidthPix * wLengthL) div 10;
         end
      else begin
         // length is exactly given by the length of the text.
         poStatic^.nXSizePix:=gglpoMainWindow^.GetTextWidthPix(poStatic^.strCtrlLabel);
         end;
}
      // For Float numbers have a special length formatting
      if (wTypeUnusedL = vt_Float) or (wTypeUnusedL = vt_FloatS) then begin
         vNum:=9;
         for nn:=3 to wLengthL - wLengthDecimalL do vNum:=vNum * 10;
         strS:=FloatToStr(vNum+0.8888888888888888, wLengthL, wLengthDecimalL);
         poStatic^.nXSizePix:=gglpoMainWindow^.GetTextWidthPix(strS);
         end
       else poStatic^.nXSizePix:=gglpoMainWindow^.GetTextWidthPix(poStatic^.strCtrlLabel);

      poStatic^.vYSizeCh:=1.0; // standard size for a static text
      poStatic^.vYPosCh  :=0.25; // shift a little to the bottom

      // To which variable is the control linked.
      poStatic^.pVarLink :=GetNumPointer(wNumVarLinkL, wTypeVarLinkL);
      poStatic^.rVarLinkInfo.wVarType :=wTypeVarLinkL mod 65536;

      // Color of the static text
      poStatic^.colTextFont:=( 256*prDefL^.awInt3[1] +
                               prDefL^.awInt2[1]      )*word32(256) +
                               prDefL^.awInt1[1];

      // To have the same back color as the dialog.
      poStatic^.colTextBack        :=-2;
      poStatic^.colWindowBack      :=-2;

      // Remember the actual end of the line, in pixels.
      nLineEndPix:=nLineEndPix + poStatic^.nXSizePix;

      // One more control in the dialog.
      if (awNbCol[wNumInstr] < MAXCOLS) then inc(awNbCol[wNumInstr]);
      arInstr[wNumInstr, awNbCol[wNumInstr]].poCtrl:=poStatic;
      arInstr[wNumInstr, awNbCol[wNumInstr]].wTabNumber:=0;
      poCtrlL:=poStatic;
      end; // if (wCtrlTypeL = SPEC_STATIC) then begin

   // we have the control, its type, sizes and specialisations
   if (wCtrlTypeL = SPEC_RADIO) then begin
   //""""""""""""""""""""""""""""""""""""""
      poRadio:=gglpoObjCreate^.CreateButtonRadio(poDialog);

      poRadio^.vYSizeCh  :=1.0; // standard size
      poRadio^.vYPosCh   :=0.25; // shift a little to the bottom
      poRadio^.nXSizePix := (wTenCharWidthPix * (wLengthL+1)) div 10;

      // Remember the actual end of the line, in pixels.
      nLineEndPix:=nLineEndPix + poRadio^.nXSizePix;

      // To which variable is the control linked.
      poRadio^.pVarLink :=GetNumPointer(wNumVarLinkL, wTypeVarLinkL);
      poRadio^.rVarLinkInfo.wVarType :=wTypeVarLinkL mod 65536;

      if (wTypeVarLinkL >= vt_ShortString) then // must indicate its max. size
         poRadio^.rVarLinkInfo.wStrMaxLen:=wTypeVarLinkL div 65536;

      // Tell the radio button who is its grand parent object
      poRadio^.poGrParent :=poDialogParent;

      // content of the radio button
      poRadio^.strCtrlLabel:=prDefL^.apstrData[1]^;

{      // Color of the text
      poRadio^.colTextFont:=( 256*prDefL^.awInt1[1] +
                               prDefL^.awInt2[1]      )*word32(256) +
                               prDefL^.awInt3[1];
}

      // One more control in the dialog.
      if (awNbCol[wNumInstr] < MAXCOLS) then inc(awNbCol[wNumInstr]);
      arInstr[wNumInstr, awNbCol[wNumInstr]].poCtrl:=poRadio;
      arInstr[wNumInstr, awNbCol[wNumInstr]].wTabNumber:=0;
      poCtrlL:=poRadio;
      end; // if (wCtrlTypeL = SPEC_RADIO) then begin

   // we have the control, its type, sizes and specialisations
   if (wCtrlTypeL = SPEC_CHECK) then begin
   //""""""""""""""""""""""""""""""""""""""
      poCheck:=gglpoObjCreate^.CreateButtonCheck(poDialog);

      poCheck^.vYSizeCh  :=1.0; // standard size
      poCheck^.vYPosCh   :=0.25; // shift a little to the bottom
      poCheck^.nXSizePix:= (wTenCharWidthPix * (wLengthL+1)) div 10;

      // Remember the actual end of the line, in pixels.
      nLineEndPix:=nLineEndPix + poCheck^.nXSizePix;

      // To which variable is the control linked.
      poCheck^.pVarLink :=GetNumPointer(wNumVarLinkL, wTypeVarLinkL);
      poCheck^.rVarLinkInfo.wVarType :=wTypeVarLinkL mod 65536;

      if (wTypeVarLinkL >= vt_ShortString) then // must indicate its max. size
         poCheck^.rVarLinkInfo.wStrMaxLen:=wTypeVarLinkL div 65536;

      // Tell the radio button who is its grand parent object
      poCheck^.poGrParent :=poDialogParent;

      // content of the radio button
      poCheck^.strCtrlLabel:=prDefL^.apstrData[1]^;

{      // Color of the static text
      poCheck^.colTextFont:=( 256*prDefL^.awInt1[1] +
                               prDefL^.awInt2[1]      )*word32(256) +
                               prDefL^.awInt3[1];
}

      // One more control in the dialog.
      if (awNbCol[wNumInstr] < MAXCOLS) then inc(awNbCol[wNumInstr]);
      arInstr[wNumInstr, awNbCol[wNumInstr]].poCtrl:=poCheck;
      arInstr[wNumInstr, awNbCol[wNumInstr]].wTabNumber:=0;
      poCtrlL:=poCheck;
      end; // if (wCtrlTypeL = SPEC_CHECK) then begin

   if (poCtrlL <> NIL) and (prDefL <> NIL) then
      ApplySpecialisations(poCtrlL, prDefL);

   exit;
   end; // if (strL[wPos] = '@') and (strL[wPos] <> '@') then begin

// *************************************************************
//  NEW STATIC CONTROL
// *************************************************************

if (strL[wPos] = '@') then inc(wPos); // skip one of the two '@'

// One more static (control) text in the dialog box.
poStatic:=gglpoObjCreate^.CreateStatic(poDialog);

// Add it in the number of controls used.
// its position will be determined when all instructions
// will have been ridden.
if (awNbCol[wNumInstr] < MAXCOLS) then inc(awNbCol[wNumInstr]);
arInstr[wNumInstr, awNbCol[wNumInstr]].poCtrl:=poStatic;
arInstr[wNumInstr, awNbCol[wNumInstr]].wTabNumber:=0;

strS:='';

// If the string begins with a tabulator DIR_TAB_BEFORE,
// then take this tabulation into account
nTabPos:=Pos(strL[wPos], strTabs);
if (awTabsType[nTabPos] = DIR_TAB_BEFORE) then begin
   // we begin with a tabulator
   strS:=strS + strL[wPos];
   inc(wPos);

   // We have one more tab in this line
   if (wTabNumber < MAXCOLS) then inc(wTabNumber);

   // if the distance between last tabulation increased,
   // memorise it.
   if (anTabPosPix[wTabNumber] < (nLineEndPix - nLineTabPosPix)) then
       anTabPosPix[wTabNumber] := nLineEndPix - nLineTabPosPix;

   // Memorise the position of the tabulator,
   // relative only to this line. i.e. ignoring the other lines.
   nLineTabPosPix:=nLineEndPix;

   // memorises the tab number corresponding to this one.
   // Is it the first tabulator of this line, the second one, the third ... ?
   // it is set to be a tabulator at the end of the previous column
   arInstr[wNumInstr, awNbCol[wNumInstr]-1].wTabNumber:=wTabNumber;

   end; // if (awTabsType[nTabPos] = DIR_TAB_BEFORE) then begin

// reads the string until :
// - the end of the line or
// - the '@' character arrives, signifying a variable arrives
// - a tabulator has been reached.
while (wPos <= length(strL)) and
      ((strL[wPos] <> '@') or (strL[wPos+1] = '@')) and
      (Pos(strL[wPos], strTabs) = 0) do begin
      strS:=strS + strL[wPos];
      if (strL[wPos] = '@') then inc(wPos); // skip one, if two '@'
      inc(wPos);
      end;

poStatic^.strCtrlLabel:=strS;
poStatic^.nXSizePix:=gglpoMainWindow^.GetTextWidthPix(strS);
poStatic^.vYSizeCh :=1.0;
poStatic^.vYPosCh  :=0.25; // shift a little to the bottom

nTabPos:=Pos(strL[wPos], strTabs);

// if a tabulator follows, remember it
// DIR_TAB_BEFORE are taken into account at the beggining of the
// treatment of the static text.
if (nTabPos <> 0) and
   (awTabsType[nTabPos] <> DIR_TAB_BEFORE) then begin
   // a tabulator has been reached.

   // If the tabulator is invisible, just skip it.
   // If not, take it into the static control.
   if (awTabsType[nTabPos] <> DIR_TAB_INVISIBLE) then strS:=strS + strL[wPos];

   inc(wPos);

   // content of the static control, and its width in pixels.
   poStatic^.strCtrlLabel:=strS;
   poStatic^.nXSizePix:=gglpoMainWindow^.GetTextWidthPix(strS);

   // Remember the actual end of the line, in pixels.
   nLineEndPix:=nLineEndPix + poStatic^.nXSizePix;

   // define the tab position
   if (wTabNumber < MAXCOLS) then inc(wTabNumber);

   // if the distance between last tabulation increased,
   // memorise it.
   if (anTabPosPix[wTabNumber] < (nLineEndPix - nLineTabPosPix)) then
       anTabPosPix[wTabNumber] := nLineEndPix - nLineTabPosPix;

   // Memorise the position of the tabulator,
   // relative only to this line. i.e. ignoring the other lines.
   nLineTabPosPix:=nLineEndPix;

   // memorises the tab number corresponding to this one.
   // Is it the first tabulator of this line, the second one, the third ... ?
   arInstr[wNumInstr, awNbCol[wNumInstr]].wTabNumber:=wTabNumber;
   end // if (Pos(strL[wPos], strTabs) <> 0) then begin
else begin
   // no tabulator after the string
   // Remember the actual end of the line, in pixels.
   nLineEndPix:=nLineEndPix + poStatic^.nXSizePix;
   end;
end;  // TDialogCreator2.ReadOneInstruction

procedure TDialogCreator2.ReadInstructions;
//=========================================
// read the Instructions on one line,
// treat them partially and memorise them.
begin
if (strL = '...END') or (wNumInstr >= MAXLINES) then begin
   // finish, the complet description of the dialog has been ridden
   fInstructionsRidden:=TRUE;
   exit;
   end;
strL[length(strL)+1]:=#0;

// At the beginning of a line treatment, there are no tabulations.
wTabNumber:=0;

// At the beginning of a line tratment, the end is at position zero.
nLineEndPix:=0;

// position of the last tabulator in the treated line.
nLineTabPosPix:=0;

// We have one more instruction line.
if (wNumInstr < MAXLINES) then inc(wNumInstr);
awNbCol[wNumInstr]:=0;

// by default, do not change the interline.
anDeltaLineHeightCh[wNumInstr]:=0;

// by default, the line height is defined in character height
// but it can be defined in pixels
awLineHeightPix[wNumInstr]:=wDefLineHeightPix;

// The line doesn't begin with a tabulator, for the moment.
arInstr[wNumInstr, 0].wTabNumber:=0;

// Read the next instruction line
repeat
   ReadOneInstruction;
   wError:=0; // resets the errors.
   until (wPos > length(strL));

end;  // TDialogCreator2.ReadInstructions

procedure TDialogCreator2.FixePosSizes;
//=====================================
// Fixe the size of the dialog box,
// of some controls if still needed and
// place the controls at their right place.
var
  poBtnOK,
  poBtnCancel : PButtonPush;
  nn          : integer;
  vXPosChButtonL, // position for the buttons, on the last line
  vYPosChL        // Y position of the controls, in char units.
              : Float;
  wYPosPixL,  // position in pixels added to the position in character
  wXPosPixL,   // position of the constrols in pixels
  wXPosPixMaxL // maximu position of a control in pixels
               // It will be the width of the dialog box.
              : word32;
  nLineL,     // to loop over the lines and
  nColL       // columns of the dialog box.
              : integer;
begin
// defines the tabulator positon.
// For the moment, the tabulators are only relative to the previous one.
// Compute their position, all relative to the left margin
anTabPosPix[0]:=(wLeftMarginCh * wTenCharWidthPix) div 1000; // left margin.
nColL:=1;
while (anTabPosPix[nColL] <> 0) do begin
   anTabPosPix[nColL]:=anTabPosPix[nColL-1] + anTabPosPix[nColL];
   inc(nColL);
   end;

// Loop over all controls to place them at their right position
// and determine the size of the dialog box.
vYPosChL     :=wTopMarginCh / 100.0; // from the top.
wYPosPixL    :=0; // usually, for dialog boxes, this remains equal to zero
wXPosPixMaxL :=20;  // A minimal width

// The last line has height of vInterLineCh
anDeltaLineHeightCh[wNumInstr+1]:=0;

for nLineL:=1 to wNumInstr do begin
   if (anDeltaLineHeightCh[nLineL] < 30000) then begin // normal case
      // begins with a little margin from the left
      wXPosPixL :=(wLeftMarginCh * wTenCharWidthPix) div 1000;
      vYPosChL:=vYPosChL + anDeltaLineHeightCh[nLineL] / 100.0;

      // If the line begins with a tabulator :
      if (arInstr[nLineL, 0].wTabNumber > 0) then
         wXPosPixL:=anTabPosPix[arInstr[nLineL, 0].wTabNumber];
      end;
   // else, this is the continution given on a new text line

   // loop to position the control in the  nLineL  line.
   for nColL:=1 to awNbCol[nLineL] do begin
      // the Y position for each control is the same.

      if (awLineHeightPix[nLineL] = 0) and
         (arInstr[nLineL, nColL].poCtrl^.vYSizeCh > 0) then begin // normal case
         // To center vertically each control in its line.
         arInstr[nLineL, nColL].poCtrl^.vYPosCh:=
              (vInterLineCh - arInstr[nLineL, nColL].poCtrl^.vYSizeCh) / 2.0 + vYPosChL;
         end
      else begin
         // Here, the line has a fixed line height in pixels.
         arInstr[nLineL, nColL].poCtrl^.vYPosCh:=vYPosChL;
         end;

      arInstr[nLineL, nColL].poCtrl^.nYPosPix:=wYPosPixL;

      // define the X position of each controls.
      arInstr[nLineL, nColL].poCtrl^.nXPosPix :=wXPosPixL;

      // The position of the next control, depends on the size of
      // the actual one.
      wXPosPixL:= wXPosPixL +
                  word32(arInstr[nLineL, nColL].poCtrl^.nXSizePix);

      // if there is a tabulation, it defines the beginning of the next line
      if (arInstr[nLineL, nColL].wTabNumber > 0) then
         wXPosPixL:=anTabPosPix[arInstr[nLineL, nColL].wTabNumber];

      end; // for nColL:=1 to awNbCol[nLineL] do begin

   if (anDeltaLineHeightCh[nLineL+1] < 30000) then begin // normal case
      if (awLineHeightPix[nLineL] = 0) then begin // normal case
         // next line. By default, we take a height of
         // vInterLineCh  character height between two lines.
         vYPosChL:=vYPosChL + vInterLineCh;
         end
      else begin
         // the line height was fixed in pixels.
         wYPosPixL:=wYPosPixL + awLineHeightPix[nLineL];
         end;
      end;
   // else, the comming text line description is a continuation of the previous one

   if (wXPosPixMaxL  < wXPosPixL) then wXPosPixMaxL := wXPosPixL;
   end; // for nLineL:=1 to wNumInstr do begin

if (poDialog^.wWindowType = GGLCTE_ToolBar) then begin
   // For a toolbar, no OK or CANCEL button are defined by default
   fWithOKButton:=FALSE;
   fWithCancelButton:=FALSE;
   end;

// to position the buttons. Relative to the right bottom edge.
vXPosChButtonL:=-0.5;

// Create the Cancel button before the OK button, to have it
// before the OK button while using the TAB key.
if fWithCancelButton then begin
   // Add the CANCEL Button, to the left of the OK button
   // Creation with the object creator, thus it can be a button defined
   // in the final application
   poBtnCancel:=gglpoObjCreate^.CreateButtonPush(poDialog);
   end;

if fWithOKButton then begin
   // Add the OK Button, in the right bottom corner
   // Creation with the object creator, thus it can be a button defined
   // in the final application
   poBtnOK:=gglpoObjCreate^.CreateButtonPush(poDialog);

   with poBtnOK^ do begin
      strCtrlLabel  :='   OK    '; // Text on the button
      wCtrlID:=IDOK; // identifier of the control. IDOK => the OK button.
                     // This value will be used in TMyDialog.WMCOMMAND to
                     // determine which button has been clicked.
      poGrParent :=poDialogParent; // Tell the button who is the grand parent

      // Does the label change ?
      for nn:=1 to wNumDirect do begin
         if (arDirect[nn].wDirect = DIR_OKLABEL) then
            strCtrlLabel:=arDirect[nn].pstrData^;
         end;

      // Position and size of the OK button
      vXSizeCh  := length(strCtrlLabel);
      vYSizeCh  := 2; //   2 characters height, normal for buttons

      vXPosCh    := vXPosChButtonL;
      vYPosCh    := -0.2; // 0.2 char height from the bottom

      // X Position for the next button
      vXPosChButtonL:=vXPosChButtonL - vXSizeCh - 1.0;

      vXPosCtrlRef :=1; // Position relative to the Right  of the control. 0=default
      vYPosCtrlRef :=1; // Position relative to the Bottom of the control. 0=default

      // Defines which point of the parent window is take as the origine
      vXPosParentRef :=1; // Position relative to the Right  of the parent window. 0=default
      vYPosParentRef :=1; // Position relative to the Bottom of the parent window. 0=default
      end; // with poButton^ do begin
   end; // if fWithOKButton then begin

if fWithCancelButton then begin
   // Add the CANCEL Button, to the left of the OK button
   // Creation with the object creator, thus it can be a button defined
   // in the final application
//   poBtnCancel:=gglpoObjCreate^.CreateButtonPush(poDialog);
//   Created before, in order to have
// the TAB key comming to the Cancel button before the OK button.

   with poBtnCancel^ do begin
      strCtrlLabel  :='  Cancel  '; // Text on the button
      wCtrlID:=IDCANCEL; // identifier of the control.
      poGrParent :=poDialogParent; // Tell the button who is the grand parent

      // Does the label change ?
      for nn:=1 to wNumDirect do begin
         if (arDirect[nn].wDirect = DIR_CANCELLABEL) then
            strCtrlLabel:=arDirect[nn].pstrData^;
         end;

      // Size and position of the cancel button
      vXSizeCh  := length(strCtrlLabel);
      vYSizeCh  :=   2; //   2 characters height, normal for buttons

      vXPosCh    := vXPosChButtonL;
      vYPosCh    := -0.2; // 0.2 char height from the bottom

      // X Position for the next button
      vXPosChButtonL:=vXPosChButtonL - vXSizeCh - 0.5;

      vXPosCtrlRef :=1; // Position relative to the Right  of the control. 0=default
      vYPosCtrlRef :=1; // Position relative to the Bottom of the control. 0=default

      // Defines which point of the parent window is take as the origine
      vXPosParentRef :=1; // Position relative to the Right  of the parent window. 0=default
      vYPosParentRef :=1; // Position relative to the Bottom of the parent window. 0=default
      end; // with poButton^ do begin
   end; // if fWithCancelButton then begin

if (poDialog^.wWindowType = GGLCTE_A_DIALOG_Modal) or
   (poDialog^.wWindowType = GGLCTE_A_DIALOG_Modeless) then begin
   // For dialog boxes, the caption height must be added
   vYPosChL    :=vYPosChL + 2.0;
   end;

if (vXPosChButtonL < -1) then begin
   // the line of the buttons must be added. (Only for Dialog box, not for toolbar)
   vYPosChL    :=vYPosChL + 2.2;

   // Test if there is enough space for the buttons.
   wXPosPixL := Round((-vXPosChButtonL) * gglpoPrm^.wWidthPix_Ch);
   if (wXPosPixMaxL < wXPosPixL) then wXPosPixMaxL:= wXPosPixL;
   end;

// Right margin
wXPosPixMaxL:=wXPosPixMaxL + (wRightMarginCh * wTenCharWidthPix) div 1000;

with poDialog^ do begin
   if (wDialogWidthCh = 0) then nXSizePix := wXPosPixMaxL // normal case
   else nXSizePix :=(wDialogWidthCh * wTenCharWidthPix) div 1000;

   nYSizePix := Round(vYPosChL * gglpoPrm^.wHeightPix_Ch) + int32(wYPosPixL);

   // Height and width are computed such that
   // 0 = left or top,  100 = right or bottom
   nXPosPix:=((gglpoPrm^.wScreenWidthPix  - nXSizePix) * nXPosPix) div 100;
   nYPosPix:=((gglpoPrm^.wScreenHeightPix - nYSizePix) * nYPosPix) div 100;
   end; // with
end;  // TDialogCreator2.FixePosSizes

function TDialogCreator2.DialogCreation(wMsgNum:word32; poDialogParentP:PWindowBase):PWindowBase;
//===============================================================================================
// This is the main function.
// From a word32 number designing lines in the message file,
// create a dialog box, with controls in it,
// and return a pointer on it.
// poDialogParentP is a pointer on the object window owining this dialog.
var
  wSecurity   : word;  // security to not loop forever

  // to memorise where we are in the message file
  ptrMSG         : pointer;
  wMSGError,
  wMSGPos        : word32;

   procedure GetNextLine;
   //====================
   // Gets the next line, and memorise where we are in the  .msg  file
   // such that  GetMsg(...)  can be done without perturbing the next GetMsg(msgNext)
   // Before the first call, a  GetMsgPos(ptrMSG, wMSGPos);  must be made.
   begin
   // go back to the original position in the message file.
   SetMsgPos(ptrMSG, wMSGPos, wMSGError);  // ignore any error


   // We add a #0 at the end of the string as a sentinel.
   // It means, we don't have to test the length of the string,
   // testing the #0 will indicate the end of the string.
   strL:=GetMsg(msgNext);  wPos:=1;
   strL[length(strL)+1]:=#0;
//   strL[length(strL)+2]:=#0; // could be made as a security, but useless.

   // memorise the position in the message file
   GetMsgPos(ptrMSG, wMSGPos);
   end;  // GetNextLine

begin // TDialogCreator2.DialogCreation
//"""""""""""""""""""""""""""""""""""""
DialogCreation:=NIL; // in case of errors

// Memorise who is the parent object of this dialog box.
poDialogParent:=poDialogParentP;

// Used in the error messages
StrField( 2000000001, strL, SizeOf(strL));
WordField(2000000002, wPos);
Word32Field(2000000003, wMsgNum);

// go to the begining of the dialog description and Error testing
if (not ExistMsgNumber(wMsgNum)) then begin
   ErrorWriteMsg(2000006197);
   exit;
   end;

// Here, we create the object dialog
// Creation with the object creator, thus it can be a dialog defined
// in the final application
if (poDialog = NIL) then begin
   poDialog:=gglpoObjCreate^.CreateDialog(poDialogParent);
   // poDialog^.strDlgTitle:=''; default
   poDialog^.nXPosPix:=50; // centered by default. will be recomputed
   poDialog^.nYPosPix:=50; // centered.
   end;

// Store in the object dialog box, the number which generated the dialog.
poDialog^.wMsgDescriptor:=wMsgNum;

// We assume that there are less that 200 lines in the description.
wSecurity := 200;

// memorise the position in the message file
GetMsgPos(ptrMSG, wMSGPos);

repeat
   GetNextLine;
   ReadDirectives;
   dec(wSecurity);
   until fDirectivesRidden or (wSecurity = 0);

// begin with  ReadDefinitions, since the last line was not a Directive
ReadDefinitions;
while (not fDefinitionsRidden) and (wSecurity > 0) do begin
   GetNextLine;
   ReadDefinitions;
   dec(wSecurity);
   end;

// The dialog title is only on one line.
ReadDialogTitle;

// Read the instructions.
while (not fInstructionsRidden) and (wSecurity > 0) do begin
   GetNextLine;
   ReadInstructions;
   dec(wSecurity);
   end;

// Place the controls in the dialog box, and
// fixe the size of the dialog box.
FixePosSizes;

// The number 60002 is not more associated to a variable.
ClearField(2000000001);
ClearField(2000000002);
ClearField(2000000003);

// Return a pointer on the created object dialog
DialogCreation:=poDialog;
end;  // TDialogCreator2.DialogCreation

function TDialogCreator2.ToolBarCreation(wMsgNum:word32; poParentP:PWindowBase):PWindowBase;
//==========================================================================================
// This is the main function, which creates the ToolBar object.
// From a word32 number designing lines in the message file,
// create a ToolBar, with controls in it,
// and return a pointer on it.
// poParentP is a pointer on the object window owning this ToolBar
begin
// Create the toolBar object
poDialog:=gglpoObjCreate^.CreateToolBar(poParentP);

// Default values for a toolbar
wTopMarginCh   :=0; // no top margin
wLeftMarginCh  :=0; // no left margin
wRightMarginCh :=0; // no right margin

// Fills the tool bar with controls.
ToolBarCreation:=DialogCreation(wMsgNum, poParentP);

// Add one pixels for the buttons
//poDialog^.nYSizePix := poDialog^.nYSizePix + 1;

if (poDialog^.nXSizePix > poDialog^.nYSizePix) then begin
   // The width is limited only by the parent window
   poDialog^.nXSizePix :=5000;
   end
else begin
   // The height is limited only by the parent window
   poDialog^.nYSizePix :=5000;
   if (poDialogParent = NIL) then exit;
   if (PWindow(poDialogParent)^.wWindowType > GGLCTE_A_WINDOW) then exit;
   if (PWindow(poDialogParent)^.poStatusLine = NIL) then exit;

   // The height is limited by the status bar
   poDialog^.nYSizePix := PWindow(poDialogParent)^.nClientHeight -
                          int32(PWindow(poDialogParent)^.poStatusLine^.wHeight);
   end
end;  // TDialogCreator2.ToolBarCreation

end.  // unit wDialogCreator2;

