V A L I D   C G D   C O M M A N D S
        Version 2006 (c) Jacques Basaldúa
{\} Merge with the following line (more)
{> text } Single text or text to the left of a control (more)
{>> text )} Text to the right of a control (more)
{<ALIAS name >} Variable used for conditional selection (more)
{<ARRAYSIZE name >} Create conditions automatically, depending on a valid {<ALIAS>} (more)
{<BITMAPSHIFTX value >} Bitmap shift value along the X axis in pixels (more)
{<BLANKLINE>} Create a blank line (more)
{<CASE name = value >}
{<CASE
name > value >}
{<CASE
name < value >}
Hide line if condition is false, depending on a valid {<ALIAS>} (more)
{<CBITMAP value >}
{<CBITMAP APPOWNED
value >}
Bitmap aligned with the controls (Center)
Or application owned bitmap aligned with the controls
(more)
{<COPYRIGHT>} Declare file owner and disable reverse engineering (more)
{<CRYPTFILE value >} Encrypt the cgd file and disable reverse engineering (more)
{<DIALOG name >} Include dialog definition to the output file (more)
{<ENDDIALOGS>} Disable compilation and learning (more)
{<ENDMAKEGROUP>} End of {<MAKEGROUP>} section (more)
{<EXTENDTO32>} Makes enumerations 32 bit wide (more)
{<LBITMAP value >}
{<LBITMAP APPOWNED
value >}
Bitmap aligned with left texts (Left)
Or application owned bitmap aligned with left texts
(more)
{<LBOLD>} Display left text as bold (more)
{<LICENSE license code >} Authorize encryption or copyright declaration (more)
{<LITALIC>} Display left text as italic (more)
{<MAKEGROUP>} Force making a group (more)
{<MAX value >} Maximum value for integers and reals (more)
{<MIN value >} Minimum value for integers and reals (more)
{<NOMAKEGROUP>} "Explode" a user-defined structure (opposite of {<MAKEGROUP>}) (more)
{<PRIVATE>} Hide the following item (more)
{<RADIO>} Display a RADIOBUTTON instead of a COMBOBOX (more)
{<RADIOCOLUMNS value >} Override the default row / column arrangement of a RADIOBUTTON (more)
{<RBITMAP value >}
{<RBITMAP APPOWNED
value >}
Bitmap aligned with right texts (Right)
Or application owned bitmap aligned with right texts
(more)
{<RBOLD>} Display right text as bold (more)
{<READONLY>} Make the following item read-only (more)
{<RITALIC>} Display right text as italic (more)
{<STARTDLG CGD20>} Enable compilation and learning (more)
§ Inside a text, select mm or inches according to metric (more)


{\}
 
   Merging lines

    Merges the current line with the following line. Many CGD instructions (e.g. ALIAS) are applied to the variable defined in the same line. Using this preprocessor command, this can be written in two (or more) lines for the sake of clarity. Anyway, the resulting line cannot exceed 255 characters.
 
Example:
{<MAKEGROUP>}                {>Optimization}                     {<LBOLD>}
    opAli     : boolean;     {>Remove aligned points}
    ReTrjIn   : boolean;     {>Revectorize imported trajectories}
    OpTrjIn   : boolean;     {>Optimize imported trajectories}
{<ALIAS opOpPrOptim>}  {\}
    OpCalTr   : boolean;     {>Optimize calculated trajectories}
{<CASE opOpPrOptim>0>} {\}
    OpTrLinkD : single;      {>Linking distance}                  {>>§}  {<MIN 0>}

{<STARTDLG CGD20>}
{<ENDDIALOGS>}

    Beginning/ending compilation

    These two commands must appear once in any source file. They indicate the beginning and the end of the code being compiled. Any source code before or after these instructions is ignored. Note that the compiler assumes the knowledge of all primitive types. The pascal compiler has these types defined in the file cgdTypes.pas
 
 
    PRIMITIVE TYPES (see file cgdTypes.pas)
 Primitive types are: (all other types are packed records of these)

  boolean types:
 boolean   (size= 1)  // True = 255,   false = 0
 cBool     (size= 4)  // !! True = 255 !!  false = 0 (ONLY ONE BYTE MODIFIED !)

  integer types:
 byte      (size= 1)
 word      (size= 2)
 integer   (size= 2)
 longint   (size= 4)

  real types:
 single   (size= 4)
 real     (size= 4)  // same as single
 double   (size= 8)

  string types:
 char     (size= 1)
 string   (size depends on [])

  sets/Enumerations:
 ( )   (size= 1)  as COMBOBOX
 ( )   (size= 1)  as RADIOBUTTONS
 same  (size= 4)  as COMBOBOX      DECLARE {<EXTENDTO32>} before
 same  (size= 4)  as RADIOBUTTONS  DECLARE {<EXTENDTO32>} before

  primitive records:
 point2      (size= 8)
 point3      (size=12)
 date        (size= 6)
 time        (size= 6)
 cgdFileName (only name is edited)
 cgdPath     (only name is edited)
 cgdColor    (size= 4)

 Type limitations:
 -----------------

  Boolean
    description        127 chars

  cgdFileName
    File name          211 chars
    default path       211 chars
    format description 211 chars     212 x 3 = 636 bytes

  cgdPath
    Path name          211 chars
    Caption            211 chars

  Combo (enumeration)
    item list          32 names of 19 chars each 32 x 20 = 640 bytes

  Combo (user defined)
    item list          254 chars description separated by #0 and finished by #0,#0

  Radio (enumeration)
    item list          20 names of 31 chars each 20 x 32 = 640 bytes

  Strings
    contents           as defined, up to 255 chars

Example:

{<STARTDLG CGD20>}
  {<DIALOG HelpAbout>}
    HelpAbout   = packed record   // Size = 4
      dontcare  : longint  {<PRIVATE>}
    {<MAKEGROUP>}    {>Version} {<LBOLD>}
      {<BLANKLINE>}
      {>             Blabla - 1.0 - US english}
      {<BLANKLINE>}
      {>             F o r   d e m o n s t r a t i o n   p u r p o s e   o n l y  } {<LBOLD>}
      {<BLANKLINE>}
      {>             Resale forbidden}
      {<BLANKLINE>}
    {<ENDMAKEGROUP>}
    {<MAKEGROUP>}    {>Copyright}{<LBOLD>}
      {<BLANKLINE>}
      {>             (c) 1989-2003. Bla-bla-soft}
      {<BLANKLINE>}
      {>             All Rights Reserved.}
      {<BLANKLINE>}
    {<ENDMAKEGROUP>}
  end;
{<ENDDIALOGS>}

{<DIALOG name >}

    Starting a dialog

    The CGD compiler compiles all source code between {<STARTDLG CGD20>} and {<ENDDIALOGS>}. All structures are compiled but not written to the output file, except when explicitly indicated by the {<DIALOG>} command, or when the structure is used inside an other structure which is written to the output file.

    This command writes the following structure to the output file with a public name. This name is used to identify the dialog in cgdDialog(), cgdModelessGetClientX() or cgdInitModelessDlg() calls.

    It is recommended to use the name of the type used in Pascal, but this is not required. Names are limited to 19 chars.
 
Example:

{<DIALOG HelpAbout>}
    HelpAbout   = packed record   // Size = 4
      dontcare  : longint  {<PRIVATE>}
    {<MAKEGROUP>}    {>Copyright}{<LBOLD>}
      {<BLANKLINE>}
      {>             (c) 1989-2003. Bla-bla-soft}
      {<BLANKLINE>}
      {>             All Rights Reserved.}
      {<BLANKLINE>}
    {<ENDMAKEGROUP>}
  end;

{> text }
{>>
text }

    Writing text

    Writes text in a CGD dialog. {> writes text to the left of a control, if there is a control in the same line. If not, the text occupies the whole dialog line. {>> writes text to the right of a control. Limits are: 127 chars to the left of a control, 31 chars to the right of a control, 255 chars when it is the only text in a line.

    Read the following two issues to understand metric and formatting details. The font, char size and color are defined via cgdSetOptions().

§

    Text details: (metric)

    This special control character is intended to be used in a field containing real types (single, double, Point2, Point3, etc.). It is also intended for metric based applications. It works this way: The application stores the values (length, radius, 2-D coords or 3-D coords) in millimeters. The user may choose to edit those values either in millimeters or in inches. When the user selects millimeters, the application sets the cgdSetOptions() field .isMetric to true (the default value). When this field is true, the DLL replaces the text § by the text mm, it does not scale the values in any way. When the user selects inches, the application sets the cgdSetOptions() field .isMetric to false. When this field is false, the DLL replaces the text § by the text in, it also scales the values: The original values are converted
mm->in , the user edits the value in inches and, when he accepts the current values, they are converted in->mm .

    You can combine the character with other text. E.g. §/min will be replaced by mm/min or in/min depending on isMetric.

Example:

    OpTrLinkD : single;      {>Linking distance} {>>§}   {<MIN 0>}

   Assuming the value of the variable OpTrLinkD is 25.4,
   When isMetric is true, this shows up as:

   Linking distance [ 25.4 ] mm

   When isMetric is false, this shows up as:

   Linking distance [ 1.0 ] in

   In both cases, if the user presses <Enter> without changing the value, the value returned will be 25.4 (i.e. metric).

{<BLANKLINE>}
{<LBOLD>}
{<RBOLD>}
{<LITALIC>}
{<RITALIC>}

    Text details: (formatting)

    LBOLD (left-text-bold) shows text defined by {> as bold, RBOLD (right-text-bold) shows text defined by {> as bold. Similarly, LITALIC and RITALIC do the same with italic. These commands use the fonts defined via cgdSetOptions(). The default fonts correspond to BOLD, ITALIC and BOLD+ITALIC as expected, user settings may change font settings completely. You have four possible fonts for the combinations: not bold+not italic, bold, italic and bold+italic. Each font can be independently defined in: family, size and attributes. Only four fonts can be used in the same dialog, each text must be written in a font completely.

    BLANKLINE leaves one (vertically) blank line in a dialog to separate different items.

{<MAKEGROUP>}
{<ENDMAKEGROUP>}
{<NOMAKEGROUP>}

    Group (tabbed fields) control

    By default, CGD creates tabbed fields automatically when a structure is nested, as in the following example:

Example 1:
  ISOparagraph  = packed record   // Size = 516
  {<ALIAS isoParLines>}  {\}
    numcol  : byte;    {>Number of lines} {<MAX 8>}
    nul2    : byte;   {<PRIVATE>}
    nul3    : byte;   {<PRIVATE>}
    nul4    : byte;   {<PRIVATE>}
  {<ARRAYSIZE isoParLines>} {\}
    cols    : array [0..7] of string[63] {>Line #} {<LITALIC>}
  end;

  pKmlCNCconfi  = ^kmlCNCconfi;
  {<DIALOG kmlCNCconfi>}
  kmlCNCconfi   = packed record   // Size = 1520

    // ... bla, bla, bla

    {<BLANKLINE>}
    {>    Start and end}   {<LBOLD>} {<LITALIC>}
    prStart : ISOparagraph;  {>Program header}     {<LBOLD>}  // Size = 516
    prEnd   : ISOparagraph;  {>End of program}     {<LBOLD>}  // Size = 516
    {<BLANKLINE>}

    // ... bla, bla, bla

  end;

    Compile and run this example to see how the ISOparagraph records are created in separate tabs. Now, modify it as:

Example 2:

  // ... bla, bla, bla

  pKmlCNCconfi  = ^kmlCNCconfi;
  {<DIALOG kmlCNCconfi>}
  kmlCNCconfi   = packed record   // Size = 1520

    // ... bla, bla, bla

    {<BLANKLINE>}
    {>    Start and end}   {<LBOLD>} {<LITALIC>}
    prStart : ISOparagraph;  {>Program header} {<NOMAKEGROUP>}    {<LBOLD>}  // Size = 516
    prEnd   : ISOparagraph;  {>End of program} {<NOMAKEGROUP>}    {<LBOLD>}  // Size = 516
    {<BLANKLINE>}

    // ... bla, bla, bla

  end;

    Compile and run this example to see how the tabs are removed and the nested structures make part of the parent tab. The opposite effect, i.e. creating tabs intentionally is done as in:

Example 3:
  pProjSettings  = ^kmlProjSettings;
  {<DIALOG kmlProjSettings>}
  kmlProjSettings  = packed record               // Size = 512
    SizeOfPrSet : longint;   {<PRIVATE>}         //    4 = 4  (Must be 512)
    {<MAKEGROUP>}     {>Project}{<LBOLD>}
    FullName  : string [39];  {>Project name}    //   40 =  44
    Vers      : string [7];   {>Version}         // +  8 =  52
    {<ENDMAKEGROUP>}
    {<MAKEGROUP>}    {>Author}{<LBOLD>}
    Author    : string [39];  {>Author}          // + 40 =  92
    Email     : string [39];  {>E-mail}          // + 40 = 132
    Company   : string [39];  {>Company}         // + 40 = 172
    Copyright : string [39];  {>Copyright}       // + 40 = 212
    {<ENDMAKEGROUP>}
    {<MAKEGROUP>}    {>Client}{<LBOLD>}
    Client    : string [31];  {>Client}          // + 32 = 244
    Norms     : string [31];  {>Norms}           // + 32 = 276
    SchedDate : Date;         {>Delivery date}   // +  6 = 282
    {<ENDMAKEGROUP>}

    // ... bla, bla, bla

  end;

   {<MAKEGROUP>}  is followed by the title of the newly created tab. {<ENDMAKEGROUP>} indicates the end of the tab. These commands cannot be nested except by tabs corresponding to actual type definitions. There is no limit for nesting types which use other types.

{<RADIO>}
{<RADIOCOLUMNS
value >}

    Radio button details

    Normal CGD enumerations as:

    typSepWid   = (NoFrames, FixedFrames, Thin, Normal, Solid, ExtraThick);

   are compiled as COMBOBOX controls.

    NOTE: Not leading capitals are used for separating words.
    The example is converted as:
No frames, Fixed frames, Thin, Normal, Solid, Extra thick
    typToolContact  = (Vertical, InARamp, Spiral, TangentArc);     
{<RADIO>}

    The {<RADIO>} modifier converts the previous enumeration as a (2x2) group of RADIOBUTTON controls. In case you want to view the previous four options in a single column, add
{<RADIOCOLUMNS 1>} to the same line. Depending on the number of options, the array of RADIOBUTTON controls is arranged as: (Rows x Columns) 1x1, 2x1, 3x1, 2x2, 5x1, 3x2, 4x2 (7 or 8), 3x3, 5x2, 4x3 (11 or 12), 7x2 (13 or 14), 5x3, 4x4 and 5x4 (17 to 20). Use RADIOCOLUMNS to change these default settings as many times as required.

{<MAX value >}
{<MIN
value >}

    Numeric ranges

    These commands limit the user's range for numeric values. They are applied to a byte, integer, word, longint, single or double field included in the same line. If the user tries to introduce a value that is out of range, he will be warned and the value will not be applied to the structure.

Example:
pubSrfProcessOp  = packed record
    dgNodNrmAng : single;   {>Edge enhancement angle}  {<MIN 0.001>}  {<MAX 180>}   {>>deg}
    mmNodeLnkD  : single    {>Node linking distance}   {<MIN 0.0001>} {<MAX 0.1>}   {>>§}
    {<BLANKLINE>}
end;

{<ALIAS name >}
{<ARRAYSIZE
name >}
{<CASE
name = value >}
{<CASE
name > value >}
{<CASE
name < value >}

    Conditional lines

    CGD lines may be visible or hidden. All lines are by default visible (may be "folded" inside a closed tab, this is considered visible). To always hide a line, use {<PRIVATE>}. Some lines may be visible or not, depending on the value of a byte of the same structure. These lines are called conditional lines.
    The byte used as a conditional selector (byte, boolean or enumeration) is defined by the command {<ALIAS>}. The name used as the ALIAS must be unique in the whole source file. Redefining an ALIAS produces an error.
    Valid conditionals always compare a variable (defined by the ALIAS) and a constant value. The conditions are: < (below), = (equal) and > (above). The syntax is: {<CASE variable condition constant>}. If true, the line is visible.

Example:
    {<DIALOG kmlOpProcessing>}
    kmlOpProcessing  = packed record   // Size = 24
        {<MAKEGROUP>}               {>Optimization}{<LBOLD>}
        opAli     : boolean;        {>Remove aligned points}
        ReTrjIn   : boolean;        {>Revectorize imported trajectories}
        OpTrjIn   : boolean;        {>Optimize imported trajectories}
    {<ALIAS opOpPrOptim>}  {\}
        OpCalTr   : boolean;        {>Optimize calculated trajectories}
    {<CASE opOpPrOptim>0>} {\}
        OpTrLinkD : single;         {>Linking distance}  {>>§}  {<MIN 0>}
        {<ENDMAKEGROUP>}
        {<MAKEGROUP>}               {>Tool entry type}{<LBOLD>}
    {<ALIAS opOpPrEntry>}  {\}
        mode      : typToolContact; {>Tool entry type}
        nul       : byte;{<PRIVATE>}
    {<CASE opOpPrEntry>0>} {\}
        dAng      : single;         {>Angle}    {>>deg.} {<MIN 2.5>}
    {<CASE opOpPrEntry>1>} {\}
        tRad      : single;         {>Radius}   {>>§}    {<MIN 0.1>}
        {<ENDMAKEGROUP>}

    // ... bla, bla, bla

  end;

    NOTE: opOpPrOptim is boolean. Use {<CASE opOpPrOptim>0>} for true, {<CASE opOpPrOptim=0>} for false.

    NOTE: opOpPrEntry is an enumeration:
typToolContact = (Vertical, InARamp, Spiral, TangentArc);

    Use 0 for the first option. In this case, {<CASE opOpPrEntry>0>} is [In a ramp, Spiral or Tangent arc]. {<CASE opOpPrEntry>1>} is [Spiral or Tangent arc] {<CASE opOpPrEntry>2>} is [Tangent arc], same as {<CASE opOpPrEntry=3>}
 
    An array of conditionals can be generated automatically.

Example:
    ISOparagraph  = packed record   // Size = 516
        {<ALIAS isoParLines>}     {\}
        numcol  : byte;    {>Number of lines} {<MAX 8>}
        nul2    : byte;   {<PRIVATE>}
        nul3    : byte;   {<PRIVATE>}
        nul4    : byte;   {<PRIVATE>}
        {<ARRAYSIZE isoParLines>} {\}
        cols    : array [0..7] of string[63] {>Line #} {<LITALIC>}
    end;
    Is the same as:
    ISOparagraph  = packed record   // Size = 516
        {<ALIAS isoParLines>}   {\}
        numcol  : byte;    {>Number of lines} {<MAX 8>}
        nul2    : byte;   {<PRIVATE>}
        nul3    : byte;   {<PRIVATE>}
        nul4    : byte;   {<PRIVATE>}
        {<CASE isoParLines>0>} {\}
        cols0   : string[63] {>Line 1} {<LITALIC>}
        {<CASE isoParLines>1>} {\}
        cols1   : string[63] {>Line 2} {<LITALIC>}
        {<CASE isoParLines>2>} {\}
        cols2   : string[63] {>Line 3} {<LITALIC>}
        {<CASE isoParLines>3>} {\}
        cols3   : string[63] {>Line 4} {<LITALIC>}
        {<CASE isoParLines>4>} {\}
        cols4   : string[63] {>Line 5} {<LITALIC>}
        {<CASE isoParLines>5>} {\}
        cols5   : string[63] {>Line 6} {<LITALIC>}
        {<CASE isoParLines>6>} {\}
        cols6   : string[63] {>Line 7} {<LITALIC>}
        {<CASE isoParLines>7>} {\}
        cols7   : string[63] {>Line 8} {<LITALIC>}
    end;

    NOTE: The # character is replaced by 1, 2, 3, ... automatically.

    NOTE: In Pascal the types:
array [0..7] of string[63] and eight consecutive string[63] have the same binary image. The name cols was renamed as cols0 , cols1 ... to avoid a Pascal compiler error. This name is not used by CGD in any way.

{<CBITMAP value >}
{<CBITMAP APPOWNED
value >}
{<LBITMAP
value >}
{<LBITMAP APPOWNED
value >}
{<RBITMAP
value >}
{<RBITMAP APPOWNED
value >}
{<BITMAPSHIFTX
value >}

    Bitmaps

    When a dialog has one (or many) static bitmaps, these bitmaps must be included as application resources.
 
    1. An application resource is created as follows

    1.a Save the bitmaps in .bmp format using your favorite program (Paint is included with Windows).

    1.b Write a simple text file as myTools.rc
        #include "c:\delphi\common\resID.rc"
        bmpToolTypeFlat     BITMAP "tlrecta.bmp"
        bmpToolTypeTapper   BITMAP "tlpunta.bmp"
        bmpToolTypeFlTapper BITMAP "tlpuntac.bmp"
        bmpToolTypeStSphere BITMAP "tlrectab.bmp"
        bmpToolTypeStTorus  BITMAP "tlrectac.bmp"
        bmpToolTypeTpSphere BITMAP "tlpuntb.bmp"
        bmpToolTypeTpTorus  BITMAP "tlpuntcb.bmp"
    This is a valid .rc file. The missing file resID.rc is a definition of constants, the part mentioned is:
        #define bmpToolTypeFlat     2101
        #define bmpToolTypeTapper   2102
        #define bmpToolTypeFlTapper 2103
        #define bmpToolTypeStSphere 2104
        #define bmpToolTypeStTorus  2105
        #define bmpToolTypeTpSphere 2106
        #define bmpToolTypeTpTorus  2107
    1.c Once you have created both files resID.rc and myTools.rc, compile myTools.rc using:

            Microsoft (R) Windows 32 Resource Compiler, rc.exe

            This compiler is distributed with most programming tools, including Delphi and Visual Studio.
            This creates the file myTools.res

    1.d In any library module of your application, include the following line:

            {$R myTools}
            This links the resource together with your application's .exe file.
 
    2. The DLL must be provided with the application's instance handle. This is required to find the resources. Use the function cgdSetBitmapsHInstance() to pass this value to the library before calling cgdDialog() or cgdInitModelessDlg(). If your application object does not provide an hInstance value, you can call GetModuleHandle(nil) to get one from the Windows API.
 
    3. The dialog identifies the bitmaps by their integer IDs
    typToolType = (FlatEnd, BallMill, CornerRadius, Tapered, FlatTapered, TaperedBallMill, TaperedCornerRad);

    pKmlTool    = ^kmlTool;
    {<DIALOG kmlTool>}
    kmlTool     = packed record   // Size = 60: MUST be kmlAnyNamedRecord compliant!
        name  : ShortName;  {>Name}
        {<BLANKLINE>}
        {<ALIAS kmlToolType>} {\}
        typ   : typToolType; {>Type}
        nul2  : byte;  {<PRIVATE>}
        nul3  : byte;  {<PRIVATE>}
        nul4  : byte;  {<PRIVATE>}
        {<BLANKLINE>}
        {<CASE kmlToolType=0>}  {<CBITMAP 2101>}
        {<CASE kmlToolType=1>}  {<CBITMAP 2104>}
        {<CASE kmlToolType=2>}  {<CBITMAP 2105>}
        {<CASE kmlToolType=3>}  {<CBITMAP 2102>}
        {<CASE kmlToolType=4>}  {<CBITMAP 2103>}
        {<CASE kmlToolType=5>}  {<CBITMAP 2106>}
        {<CASE kmlToolType=6>}  {<CBITMAP 2107>}
        {<BLANKLINE>}
        h    : single;    {>H: Flute length}     {>>§}  {<MIN 0>}
        {<CASE kmlToolType=0>} {\}
        dr   : single;    {>D: Diameter}         {>>§}  {<MIN 0>}
        {<CASE kmlToolType=2>} {\}
        dt   : single;    {>D: End diameter}     {>>§}  {<MIN 0>}
        {<CASE kmlToolType=4>} {\}
        dc   : single;    {>D: Cutting diameter} {>>§}  {<MIN 0>}
        {<CASE kmlToolType=6>} {\}
        dct  : single;    {>D: End diameter}     {>>§}  {<MIN 0>}
        {<CASE kmlToolType>2>} {\}
        ang  : single;    {>w: Taper}            {>>deg}{<MIN 0>}
        {<CASE kmlToolType=1>} {\}
        rb   : single;    {>R: Ball radius}      {>>§}  {<MIN 0>}
        {<CASE kmlToolType=2>} {\}
        rt   : single;    {>R: Corner radius}    {>>§}  {<MIN 0>}
        {<CASE kmlToolType=5>} {\}
        rab  : single;    {>R: Ball radius}      {>>§}  {<MIN 0>}
        {<CASE kmlToolType=6>} {\}
        rat  : single    {>R: Corner radius}     {>>§}  {<MIN 0>}
    end;

    Bitmaps may be conditional (as in this example) or not. To create a conditional bitmap, use conditionals as with any other CGD line.

  CBITMAP indicates a bitmap aligned (in X) with the controls. The other options are: LBITMAP , with the left text and RBITMAP with the right text.

    As aligning (or centering) bitmaps horizontally (along X) may be a somewhat annoying task,  {<BITMAPSHIFTX value >} can be used to "cheat" against the principles of CGD (everything is positioned automatically). {<BITMAPSHIFTX 24>} shifts the bitmap 24 pixels to the right, {<BITMAPSHIFTX -6>} shifts the bitmap 6 pixels to the left. Any {<BITMAPSHIFTX>} overrides any previous {<BITMAPSHIFTX>}. The initial value is 0.

    APPLICATION OWNED BITMAPS

    This is an advanced feature. Application owned bitmaps are not resources and they may be changed during the edition of the dialog. They can be used to preview the result of the record being edited without implementing a paint method as a callback.
 
Example:
    {<DIALOG HeaData>}
    HeaData   = packed record
        {<BLANKLINE>}
        {<BITMAPSHIFTX 12>} {\}
        {<LBITMAP APPOWNED 1>}
        {<BLANKLINE>}
        oName    : lfFaceName;   {<READONLY>} {>Original name}
        oWeight  : tyFonWi;      {<READONLY>} {>Weight}
        oIta     : string[3];    {<READONLY>} {>Italic}
        oUnd     : string[3];    {<READONLY>} {>Underlined}
        oClo     : string[3];    {<READONLY>} {>Is closed}
        oOrg     : typPftOrigin; {<READONLY>} {>Source}
        oCharDef : word          {<READONLY>} {># Character def.}
    end;
    This dialog previews a PFT font.

    Application owned bitmaps are Windows bitmaps created using GDI (Windows Graphic Device Interface)
    DC := GetDC(hWnd_Desktop);
    if DC <> 0 then begin
        memDC := CreateCompatibleDC(DC);
        if memDC <> 0 then begin
           bmpID := CreateCompatibleBitmap(DC, 256, 256);
           SelectObject(memDC, bmpID);

            // ... The following GDI commands paint on the bitmap

           DeleteDC(memDC)
        end;
       ReleaseDC(hWnd_Desktop, DC)
    end
    See the Windows API doc to learn about GDI. The application owns the bitmap, following: It is responsible of destroying it via DeleteObject() when the bitmap is no longer of any use. The bitmap is identified by its handle bmpID .

    If the application owned bitmap is not changed during edition, just call cgdSetAppOwnedBmpHandle() before calling cgdDialog() or cgdInitModelessDlg(). If the bitmap may change during edition, you need to define a callback procedure.

    For the sake of clarity, lets do the first try without a callback procedure:

Example 1:
var BmpEq    : bmpHandleDef;
begin
    BmpEq.appID := 1;                // This is the identifier used in {<LBITMAP APPOWNED 1>}
    BmpEq.winH  := bmpID ;           // A valid application-owned GDI handle
    BmpEq.dlh   := dlhModalDialog;   // A cgdTypes constant used in case of cgdDialog() when dialog is modal

    // ... Set other options, cgdSetBitmapsHInstance() is no longer required.

    cgdSetAppOwnedBmpHandle(dlhModalDialog, BmpEq);
    cgdDialog(hWindow, 'Hello!', 'HeaData', SizeOf(HeaData), @variable)
end;

    And finally, with a callback procedure:

Example 2:
// Evaluation Callback to update previewing bitmaps
// ------------------------------------------------
Procedure EditChangeCallBack   (    pStruc     : pointer;            // Full record
                                    pItem      : pointer;            // Offset to last change
                                var Help       : string;             // Help<>'' will be displayed
                                    pWinObject : pointer); StdCall;
var BmpEq    : bmpHandleDef;
begin
    if The structure pointed by pStruc changed, and a new global bmpID reflects the change then begin
        BmpEq.appID := 1;
        BmpEq.winH  := bmpID ;
        BmpEq.dlh   := prb^.dlgHandle;               // Not necessarily a modal dialog
        cgdSetAppOwnedBmpHandle(BmpEq.dlh, BmpEq)    // Called from inside a callback procedure
    end
end;


// The dialog starts as before, but including the callback
// -------------------------------------------------------
var BmpEq    : bmpHandleDef;
begin
    BmpEq.appID := 1;                // This is the identifier used in {<LBITMAP APPOWNED 1>}
    BmpEq.winH  := bmpID ;           // A valid application-owned GDI handle
    BmpEq.dlh   := dlhModalDialog;   // A cgdTypes constant used in case of cgdDialog() when dialog is modal

    // ... Set other options, cgdSetBitmapsHInstance() is no longer required.

    cgdSetAppOwnedBmpHandle(dlhModalDialog, BmpEq);
    cgdSetEditChangeCallback(dlhModalDialog, @EditChangeCallBack);
    cgdDialog(hWindow, 'Hello!', 'HeaData', SizeOf(HeaData), @variable)
end;

{<LICENSE 0001-JBxx-xxxx-xxxx >}
{<COPYRIGHT>}
{<CRYPTFILE
value >}

    Advanced functions: (Copyrighting & encryption)

    These commands are only available if you are a registered user. The command {<LICENSE xxx>} (where xxx is your license code) must be the first command after {<STARTDLG CGD20>}.
 
    Advanced function: (Copyrighting)

Example:
{<STARTDLG CGD20>}
  {<LICENSE 0001-JBxx-xxxx-xxxx>}
  {<COPYRIGHT>} {>(c) Bla-bla-soft 2003} {<PRIVATE>}
  {<DIALOG HelpAbout>}
    HelpAbout   = packed record   // Size = 4
      dontcare  : longint  {<PRIVATE>}
    {<MAKEGROUP>}    {>Copyright}{<LBOLD>}
      {<BLANKLINE>}
      {>             (c) 1989-2003. Bla-bla-soft}
      {<BLANKLINE>}
      {>             All Rights Reserved.}
      {<BLANKLINE>}
    {<ENDMAKEGROUP>}
  end;
{<ENDDIALOGS>}

    The red line in this example has no apparent effect on the dialog, except that it disables reverse engineering. If you try to source the resulting CGD file, you get the error:

        This is copyrighted material:  (c) Bla-bla-soft 2003
 
    Advanced function: (Encryption)

    If you include this line at the beginning of the CGD file, the compiler scrambles the binary image of the records. Of course, the DLL "unscrambles" it and displays the dialog correctly.

Example:
{<STARTDLG CGD20>}
  {<LICENSE 0001-JBxx-xxxx-xxxx>}
  {<CRYPTFILE 1873221>}
  {<DIALOG HelpAbout>}
    HelpAbout   = packed record   // Size = 4
      dontcare  : longint  {<PRIVATE>}
    {<MAKEGROUP>}    {>Copyright}{<LBOLD>}
      {<BLANKLINE>}
      {>             (c) 1989-2003. Bla-bla-soft}
      {<BLANKLINE>}
      {>             All Rights Reserved.}
      {<BLANKLINE>}
    {<ENDMAKEGROUP>}
  end;
{<ENDDIALOGS>}

    This scrambling is not "heavy" encryption. Since the cyphertext, the key and the deciphering software are all provided together, better encryption would be pointless. The aim of this scrambling is to avoid texts being "visible" to file hackers. (E.g. patching a file containing (c)Alice by (c)Bob.)

       1. When CRYPTFILE is used, the CGD environment disables sourcing (reverse engineering) a CGD file.

       2. When CRYPTFILE is used, compression (e.g. ZIP) of the resulting CGD file will no longer be efficient.

       3. The integer value specified is the seed of a pseudo random generator. The encryption is an XOR of the original file with a random pattern. The value itself is irrelevant, only: The same value produces always the same result (on the same file). Different values produce different results.

{<EXTENDTO32>}

    Advanced function: (Alignment)

    Enumerations are stored in 8-bit (one byte) variables by default. If your compiler cannot create such enumerations, declare {<EXTENDTO32>} before defining any enumeration. This will assume that your enumerations are 32-bit wide. Regardless of the variable size, conditionals using these enumerations may only be in range 0..255.

    If you require 32-bit long booleans, use the type cBool instead of boolean.

    If you require 32-bit long integers, use the type longint instead of integer.

{<READONLY>}

    Advanced function: (Read-only)

    Dialogs may also be used for displaying data, not only for editing. As in the previously defined

Example:
    {<DIALOG HeaData>}
    HeaData   = packed record
        {<BLANKLINE>}
        {<BITMAPSHIFTX 12>} {\}
        {<LBITMAP APPOWNED 1>}
        {<BLANKLINE>}
        oName    : lfFaceName;   {<READONLY>} {>Original name}
        oWeight  : tyFonWi;      {<READONLY>} {>Weight}
        oIta     : string[3];    {<READONLY>} {>Italic}
        oUnd     : string[3];    {<READONLY>} {>Underlined}
        oClo     : string[3];    {<READONLY>} {>Is closed}
        oOrg     : typPftOrigin; {<READONLY>} {>Source}
        oCharDef : word          {<READONLY>} {># Character def.}
    end;

    {<READONLY>} applies to any control in the same line.

    If the control exists in read-only version (e.g. TEXTEDIT control), CGD will display it grayed. If it does not (e.g. COMBOBOX), CGD will restore the original value if the user tries to change it.

    Every time the user tries to modify a read-only control, he will be warned.

{<PRIVATE>}

    Advanced function: (Private)

    If a line is private, it will never be displayed.

    Three reasons to create a PRIVATE line:

    1. Avoid creating a Size=0 record. CGD does not support records of Size=0.

Example:
  {<DIALOG HelpAbout>}
    HelpAbout   = packed record   // Size = 4
      dontcare  : longint  {<PRIVATE>}
    {<MAKEGROUP>}    {>Copyright}{<LBOLD>}
      {<BLANKLINE>}
      {>             (c) 1989-2003. Bla-bla-soft}
      {<BLANKLINE>}
      {>             All Rights Reserved.}
      {<BLANKLINE>}
    {<ENDMAKEGROUP>}
  end;
    2. Hide alignment bytes. Bytes used to match 8-bit and 32-bit variables. (see nul2, nul4 below)

    3. Create a conditional dialog whose conditional selector is not visible to the user.

Example:
    pFontDef  = ^kmlFontDef;
    {<DIALOG kmlFontDef>}
    kmlFontDef  = packed record    // Size = 704: MUST be kmlAnyNamedRecord compliant!
        name        : ShortName;  {>Name}
        {<BLANKLINE>}
        fnNam       : cgdFileName;  {>Font source} // Size = 640
        {<BLANKLINE>}
        cpyFont     : boolean;   {>Embed font in the project}
        nul2        : byte;    {<PRIVATE>}
        {<ALIAS deplFontIdat>} {\}
        ValidFntDat : boolean; {<PRIVATE>}
        nul4        : byte;    {<PRIVATE>}
        {<BLANKLINE>}
        {<CASE deplFontIdat>0>} {\}
        hd          : HeaData   {>Font data} {<LBOLD>}
        {<BLANKLINE>}
    end;

   In this example, the whole hd : HeaData is conditioned to deplFontIdat being true. But the user cannot change deplFontIdat directly, only a callback procedure evaluating the whole structure may change this value. If the structure contains a reference to a valid file, deplFontIdat will be set as true and the font will be previewed.