Changeset 209


Ignore:
Timestamp:
Aug 19, 2002, 11:23:17 PM (23 years ago)
Author:
umoeller
Message:

Dialog formatter rewrite.

Location:
trunk
Files:
6 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/helpers/apps.h

    r201 r209  
    5555
    5656    APIRET appParseEnvironment(const char *pcszEnv,
    57                                 PDOSENVIRONMENT pEnv);
     57                               PDOSENVIRONMENT pEnv);
    5858
    5959    APIRET appGetEnvironment(PDOSENVIRONMENT pEnv);
    6060
    6161    PSZ* appFindEnvironmentVar(PDOSENVIRONMENT pEnv,
    62                                 PSZ pszVarName);
     62                               PSZ pszVarName);
    6363
    6464    APIRET appSetEnvironmentVar(PDOSENVIRONMENT pEnv,
    65                                  PSZ pszNewEnv,
    66                                  BOOL fAddFirst);
     65                                PSZ pszNewEnv,
     66                                BOOL fAddFirst);
    6767
    6868    APIRET appConvertEnvironment(PDOSENVIRONMENT pEnv,
    69                                   PSZ *ppszEnv,
    70                                   PULONG pulSize);
     69                                 PSZ *ppszEnv,
     70                                 PULONG pulSize);
    7171
    7272    APIRET appFreeEnvironment(PDOSENVIRONMENT pEnv);
     
    8181
    8282        APIRET appQueryAppType(const char *pcszExecutable,
    83                                 PULONG pulDosAppType,
    84                                 PULONG pulWinAppType);
     83                               PULONG pulDosAppType,
     84                               PULONG pulWinAppType);
    8585
    8686        PCSZ appDescribeAppType(PROGCATEGORY progc);
     
    116116                                    PULONG pulExitCode);
    117117
    118         HAPP appQuickStartApp(const char *pcszFile,
    119                               ULONG ulProgType,
    120                               const char *pcszArgs,
    121                               const char *pcszWorkingDir,
    122                               PULONG pulExitCode);
     118        APIRET appQuickStartApp(const char *pcszFile,
     119                                ULONG ulProgType,
     120                                const char *pcszArgs,
     121                                const char *pcszWorkingDir,
     122                                HAPP *phapp,
     123                                PULONG pulExitCode);
    123124
    124         BOOL appOpenURL(PCSZ pcszURL);
     125        APIRET appOpenURL(PCSZ pcszURL,
     126                          PSZ pszAppStarted,
     127                          ULONG cbAppStarted);
    125128
    126129    #endif
  • trunk/include/helpers/comctl.h

    r189 r209  
    3636#ifndef COMCTL_HEADER_INCLUDED
    3737    #define COMCTL_HEADER_INCLUDED
     38
     39    /* ******************************************************************
     40     *
     41     *   "Separator line" control
     42     *
     43     ********************************************************************/
     44
     45    #define WC_SEPARATORLINE        "XwpSeparatorLine"
     46
     47    BOOL ctlRegisterSeparatorLine(HAB hab);
    3848
    3949    /* ******************************************************************
  • trunk/include/helpers/dialog.h

    r201 r209  
    4646    #define DLGERR_ROW_BEFORE_TABLE             (ERROR_DLG_FIRST)
    4747    #define DLGERR_CONTROL_BEFORE_ROW           (ERROR_DLG_FIRST + 1)
    48     #define DLGERR_NULL_CTL_DEF                 (ERROR_DLG_FIRST + 2)
     48    #define DLGERR_NULL_CONTROLDEF              (ERROR_DLG_FIRST + 2)
    4949    #define DLGERR_CANNOT_CREATE_FRAME          (ERROR_DLG_FIRST + 3)
    5050    #define DLGERR_INVALID_CODE                 (ERROR_DLG_FIRST + 4)
     
    5555    #define DLGERR_INVALID_CONTROL_TITLE        (ERROR_DLG_FIRST + 9)
    5656    #define DLGERR_INVALID_STATIC_BITMAP        (ERROR_DLG_FIRST + 10)
    57     #define DLGERR_INTEGRITY_BAD_COLUMN_INDEX   (ERROR_DLG_FIRST + 11)
    58 
    59     #define ERROR_DLG_LAST                      (ERROR_DLG_FIRST + 11)
     57    #define DLGERR_ROOT_TABLE_INHERIT_SIZE      (ERROR_DLG_FIRST + 11)
     58            // TABLE_INHERIT_SIZE set for root table, which is invalid
     59    #define DLGERR_GPIQUERYTEXTBOX              (ERROR_DLG_FIRST + 12)
     60            // GpiQueryTextBox failed
     61    #define DLGERR_GPIQUERYBITMAPINFOHEADER     (ERROR_DLG_FIRST + 13)
     62            // GpiQueryBitmapInfoHeader failed
     63
     64    #define ERROR_DLG_LAST                      (ERROR_DLG_FIRST + 12)
    6065
    6166    /* ******************************************************************
     
    6671
    6772    #define SZL_AUTOSIZE                (-1)
     73    #define SZL_REMAINDER               (0)
    6874
    6975    #define CTL_COMMON_FONT             ((PCSZ)-1)
     
    97103                                        // font specified on input to dlghCreateDlg
    98104
    99         USHORT      usAdjustPosition;
     105        // USHORT      usAdjustPosition;
    100106                // flags for winhAdjustControls; any combination of
    101107                // XAC_MOVEX, XAC_MOVEY, XAC_SIZEX, XAC_SIZEY
    102                 // @@todo not implemented yet
     108                // removed V0.9.21 (2002-08-18) [umoeller]
    103109
    104110        SIZEL       szlDlgUnits;
    105                 // proposed size for the control. Note that starting
    106                 // with V0.9.19, these are now dialog units to
    107                 // finally fix the bad alignment problems with
    108                 // lower resolutions. The dialog formatter applies
    109                 // an internal factor to these things based on
     111                // proposed size for the control content rectangle.
     112                // Starting with V0.9.19, this is specified in
     113                // dialog units to fix the bad alignment problems
     114                // with lower resolutions. The dialog formatter
     115                // applies an internal factor to these things based on
    110116                // what WinMapDlgPoints gives us.
     117                //
     118                // This size then becomes the column's content
     119                // rectangle, to which spacing is applied to get
     120                // the control's box.
     121                //
    111122                // A number of special flags are available per
    112123                // cx and cy field:
     124                //
    113125                // -- SZL_AUTOSIZE (-1): determine size automatically.
    114                 //    Works only for statics with SS_TEXT and
    115                 //    SS_BITMAP.
     126                //    The behavior of this is control-specific:
     127                //    -- Statics with SS_BITMAP or SS_ICON and
     128                //       single-line SS_TEXT statics may
     129                //       specify this for either cx or cy.
     130                //    -- Same applies to pushbuttons, checkboxes
     131                //       and radio buttons.
     132                //    -- Multi-line statics and XTextView controls
     133                //       can specify SZL_AUTOSIZE for cy only because
     134                //       we cannot determine the height without knowing
     135                //       the width.
     136                //
    116137                // -- Any other _negative_ value is considered a
    117138                //    percentage of the largest row width in the
     
    119140                //    the largest row in the table. This is valid
    120141                //    for the CX field only.
     142                //    For this, we take the _box_ of the widest
     143                //    row, subtract the left spacing of the first
     144                //    column in that row and the right spacing of
     145                //    the last column in that row (because this
     146                //    field specifies the content rectangle, but
     147                //    the row already had spacing applied).
     148                //
    121149                // If the CONTROLDEF appears with a START_NEW_TABLE
    122150                // type in _DLGHITEM (to specify a group table)
     
    177205                // TYPE_END_TABLE               // end of table
    178206
    179         const CONTROLDEF *pCtlDef;
     207        ULONG           ul1;        // const CONTROLDEF *pCtlDef;
    180208                // -- with TYPE_START_NEW_TABLE: if NULL, this starts
    181209                //          an invisible table (for formatting only).
     
    186214                //          the table.
    187215
    188         ULONG           fl;
     216        ULONG           ul2;
    189217                // -- with TYPE_START_NEW_TABLE. TABLE_* formatting flags.
    190218                        #define TABLE_ALIGN_COLUMNS         0x0100
     219                                // used with START_TABLE_ALIGN to align the table's
     220                                // columns horizontalle
     221                        #define TABLE_INHERIT_SIZE          0x0200
     222                                // if set, the table width is set to the
     223                                // widest row in the parent table. Useful
     224                                // for making several group boxes align
     225                                // vertically.
     226                                // @@todo get rid of this, remove size
     227                                // from CONTROLDEF, and make size a field
     228                                // of DLGHITEM so that we can finally treat
     229                                // tables like controls WRT size
    191230
    192231                // -- with TYPE_START_NEW_ROW: ROW_* formatting flags.
     
    202241    // a few handy macros for defining templates
    203242
    204     #define START_TABLE                     { TYPE_START_NEW_TABLE, NULL, 0 }
    205 
    206     #define START_TABLE_ALIGN               { TYPE_START_NEW_TABLE, NULL, TABLE_ALIGN_COLUMNS }
    207                 // added V0.9.20 (2002-08-08) [umoeller]
    208 
    209     #define START_GROUP_TABLE(pDef)         { TYPE_START_NEW_TABLE, pDef, 0 }
    210 
    211     #define START_GROUP_TABLE_ALIGN(pDef)   { TYPE_START_NEW_TABLE, pDef, TABLE_ALIGN_COLUMNS }
    212                 // added V0.9.20 (2002-08-08) [umoeller]
    213 
    214     #define END_TABLE                       { TYPE_END_TABLE, NULL, 0 }
    215 
    216     #define START_ROW(fl)                   { TYPE_START_NEW_ROW, NULL, fl }
    217 
    218     #define CONTROL_DEF(pDef)               { TYPE_CONTROL_DEF, pDef, 0 }
     243    #define START_TABLE                     { TYPE_START_NEW_TABLE, (ULONG)NULL, 0 }
     244
     245    #define START_TABLE_EXT(fl)             { TYPE_START_NEW_TABLE, (ULONG)NULL, fl }
     246                // added V0.9.21 (2002-08-16) [umoeller]
     247
     248    #define START_TABLE_ALIGN START_TABLE_EXT(TABLE_ALIGN_COLUMNS)
     249
     250    #define START_GROUP_TABLE(pDef)         { TYPE_START_NEW_TABLE, (ULONG)pDef, 0 }
     251
     252    #define START_GROUP_TABLE_EXT(pDef, fl) { TYPE_START_NEW_TABLE, (ULONG)pDef, fl }
     253                // added V0.9.21 (2002-08-16) [umoeller]
     254
     255    #define START_GROUP_TABLE_ALIGN(pDef) START_GROUP_TABLE_EXT(pDef, TABLE_ALIGN_COLUMNS)
     256
     257    #define END_TABLE                       { TYPE_END_TABLE, (ULONG)NULL, 0 }
     258
     259    #define START_ROW(fl)                   { TYPE_START_NEW_ROW, (ULONG)NULL, fl }
     260
     261    #define CONTROL_DEF(pDef)               { TYPE_CONTROL_DEF, (ULONG)pDef, 0 }
    219262
    220263    /* ******************************************************************
     
    248291    #define DLG_OUTER_SPACING_Y             3
    249292
    250     #define COMMON_SPACING                  1
     293    #ifdef DEBUG_DIALOG_WINDOWS
     294        #define COMMON_SPACING              5
     295    #else
     296        #define COMMON_SPACING              1
     297    #endif
    251298
    252299    #define GROUP_INNER_SPACING_X           3
    253     #define GROUP_OUTER_SPACING_BOTTOM      1
    254300    #define GROUP_INNER_SPACING_BOTTOM      3
    255301    #define GROUP_INNER_SPACING_TOP         8
    256     #define GROUP_OUTER_SPACING_TOP         0
     302    #define GROUP_OUTER_SPACING_X           COMMON_SPACING
     303    #define GROUP_OUTER_SPACING_BOTTOM      COMMON_SPACING
     304    #define GROUP_OUTER_SPACING_TOP         COMMON_SPACING
    257305
    258306    #define STD_BUTTON_WIDTH                50
     
    274322    #define CONTROLDEF_GROUP(pcsz, id, cx, cy) { WC_STATIC, pcsz, \
    275323            WS_VISIBLE | SS_GROUPBOX | DT_MNEMONIC, \
    276             id, CTL_COMMON_FONT, 0, { cx, cy }, COMMON_SPACING }
     324            id, CTL_COMMON_FONT, { cx, cy }, 0 }
    277325
    278326    #define LOADDEF_GROUP(id, cx) CONTROLDEF_GROUP(LOAD_STRING, id, cx, SZL_AUTOSIZE)
     327
     328    #define CONTROLDEF_SPACING(cx, cy) { WC_STATIC, NULL, \
     329            SS_TEXT, \
     330            -1, CTL_COMMON_FONT,  {cx, cy}, COMMON_SPACING }
    279331
    280332    #define CONTROLDEF_TEXT(pcsz, id, cx, cy) { WC_STATIC, pcsz, \
    281333            WS_VISIBLE | SS_TEXT | DT_LEFT | DT_VCENTER | DT_MNEMONIC, \
    282             id, CTL_COMMON_FONT,  0, {cx, cy}, COMMON_SPACING }
     334            id, CTL_COMMON_FONT,  {cx, cy}, COMMON_SPACING }
    283335
    284336    #define LOADDEF_TEXT(id) CONTROLDEF_TEXT(LOAD_STRING, id, SZL_AUTOSIZE, SZL_AUTOSIZE)
     
    286338    #define CONTROLDEF_TEXT_CENTER(pcsz, id, cx, cy) { WC_STATIC, pcsz, \
    287339            WS_VISIBLE | SS_TEXT | DT_CENTER | DT_VCENTER | DT_MNEMONIC, \
    288             id, CTL_COMMON_FONT,  0, {cx, cy}, COMMON_SPACING }
     340            id, CTL_COMMON_FONT,  {cx, cy}, COMMON_SPACING }
    289341
    290342    #define CONTROLDEF_TEXT_RIGHT(pcsz, id, cx, cy) { WC_STATIC, pcsz, \
    291343            WS_VISIBLE | SS_TEXT | DT_RIGHT | DT_VCENTER | DT_MNEMONIC, \
    292             id, CTL_COMMON_FONT,  0, {cx, cy}, COMMON_SPACING }
     344            id, CTL_COMMON_FONT,  {cx, cy}, COMMON_SPACING }
    293345
    294346    #define LOADDEF_TEXT_RIGHT(id) CONTROLDEF_TEXT_RIGHT(LOAD_STRING, id, SZL_AUTOSIZE, SZL_AUTOSIZE)
     
    296348    #define CONTROLDEF_TEXT_WORDBREAK(pcsz, id, cx) { WC_STATIC, pcsz, \
    297349            WS_VISIBLE | SS_TEXT | DT_LEFT | DT_TOP | DT_WORDBREAK, \
    298             id, CTL_COMMON_FONT,  0, {cx, SZL_AUTOSIZE}, COMMON_SPACING }
     350            id, CTL_COMMON_FONT,  {cx, SZL_AUTOSIZE}, COMMON_SPACING }
    299351
    300352    #define CONTROLDEF_TEXT_WORDBREAK_CY(pcsz, id, cx, cy) { WC_STATIC, pcsz, \
    301353            WS_VISIBLE | SS_TEXT | DT_LEFT | DT_TOP | DT_WORDBREAK, \
    302             id, CTL_COMMON_FONT,  0, {cx, cy}, COMMON_SPACING }
     354            id, CTL_COMMON_FONT,  {cx, cy}, COMMON_SPACING }
    303355
    304356    #define LOADDEF_TEXT_WORDBREAK(id, cx) CONTROLDEF_TEXT_WORDBREAK(LOAD_STRING, id, cx)
     
    306358    #define CONTROLDEF_TEXT_WORDBREAK_MNEMONIC(pcsz, id, cx) { WC_STATIC, pcsz, \
    307359            WS_VISIBLE | SS_TEXT | DT_LEFT | DT_TOP | DT_WORDBREAK | DT_MNEMONIC, \
    308             id, CTL_COMMON_FONT,  0, {cx, SZL_AUTOSIZE}, COMMON_SPACING }
     360            id, CTL_COMMON_FONT,  {cx, SZL_AUTOSIZE}, COMMON_SPACING }
    309361
    310362    #define LOADDEF_TEXT_WORDBREAK_MNEMONIC(id, cx) CONTROLDEF_TEXT_WORDBREAK_MNEMONIC(LOAD_STRING, id, cx)
     
    312364    #define CONTROLDEF_ICON(hptr, id) { WC_STATIC, (PCSZ)(hptr), \
    313365            WS_VISIBLE | SS_ICON | DT_LEFT | DT_VCENTER, \
    314             id, CTL_COMMON_FONT, 0, {SZL_AUTOSIZE, SZL_AUTOSIZE}, COMMON_SPACING }
     366            id, CTL_COMMON_FONT, {SZL_AUTOSIZE, SZL_AUTOSIZE}, COMMON_SPACING }
    315367
    316368    #define CONTROLDEF_ICON_WIDER(hptr, id) { WC_STATIC, (PCSZ)(hptr), \
    317369            WS_VISIBLE | SS_ICON | DT_LEFT | DT_VCENTER, \
    318             id, CTL_COMMON_FONT, 0, {SZL_AUTOSIZE, SZL_AUTOSIZE}, 2 * COMMON_SPACING }
     370            id, CTL_COMMON_FONT, {SZL_AUTOSIZE, SZL_AUTOSIZE}, 2 * COMMON_SPACING }
    319371
    320372    #define CONTROLDEF_BITMAP(hbm, id) { WC_STATIC, (PCSZ)(hbm), \
    321373            WS_VISIBLE | SS_BITMAP | DT_LEFT | DT_VCENTER, \
    322             id, CTL_COMMON_FONT, 0, {SZL_AUTOSIZE, SZL_AUTOSIZE}, COMMON_SPACING }
     374            id, CTL_COMMON_FONT, {SZL_AUTOSIZE, SZL_AUTOSIZE}, COMMON_SPACING }
    323375
    324376    // the following require INCL_WINBUTTONS
     
    326378    #define CONTROLDEF_DEFPUSHBUTTON(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \
    327379            WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_DEFAULT, \
    328             id, CTL_COMMON_FONT, 0, {cx, cy}, COMMON_SPACING }
     380            id, CTL_COMMON_FONT, {cx, cy}, COMMON_SPACING }
    329381
    330382    #define LOADDEF_DEFPUSHBUTTON(id) CONTROLDEF_DEFPUSHBUTTON(LOAD_STRING, id, STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT)
     
    332384    #define CONTROLDEF_PUSHBUTTON(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \
    333385            WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, \
    334             id, CTL_COMMON_FONT, 0, {cx, cy}, COMMON_SPACING }
     386            id, CTL_COMMON_FONT, {cx, cy}, COMMON_SPACING }
    335387
    336388    #define LOADDEF_PUSHBUTTON(id) CONTROLDEF_PUSHBUTTON(LOAD_STRING, id, STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT)
     
    338390    #define CONTROLDEF_DEFNOFOCUSBUTTON(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \
    339391            WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_DEFAULT | BS_NOPOINTERFOCUS, \
    340             id, CTL_COMMON_FONT, 0, {cx, cy}, COMMON_SPACING }
     392            id, CTL_COMMON_FONT, {cx, cy}, COMMON_SPACING }
    341393
    342394    #define CONTROLDEF_NOFOCUSBUTTON(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \
    343395            WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_NOPOINTERFOCUS, \
    344             id, CTL_COMMON_FONT, 0, {cx, cy}, COMMON_SPACING }
     396            id, CTL_COMMON_FONT, {cx, cy}, COMMON_SPACING }
    345397
    346398    #define LOADDEF_NOFOCUSBUTTON(id) CONTROLDEF_NOFOCUSBUTTON(LOAD_STRING, id, STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT)
     
    348400    #define CONTROLDEF_HELPPUSHBUTTON(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \
    349401            WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_HELP | BS_NOPOINTERFOCUS, \
    350             id, CTL_COMMON_FONT, 0, {cx, cy}, COMMON_SPACING }
     402            id, CTL_COMMON_FONT, {cx, cy}, COMMON_SPACING }
    351403
    352404    #define LOADDEF_HELPPUSHBUTTON(id) CONTROLDEF_HELPPUSHBUTTON(LOAD_STRING, id, STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT)
     
    354406    #define CONTROLDEF_AUTOCHECKBOX(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \
    355407            WS_VISIBLE | WS_TABSTOP | BS_AUTOCHECKBOX, \
    356             id, CTL_COMMON_FONT, 0, { cx, cy }, COMMON_SPACING }
     408            id, CTL_COMMON_FONT, { cx, cy }, COMMON_SPACING }
    357409
    358410    #define LOADDEF_AUTOCHECKBOX(id) CONTROLDEF_AUTOCHECKBOX(LOAD_STRING, id, SZL_AUTOSIZE, SZL_AUTOSIZE)
     
    360412    #define CONTROLDEF_FIRST_AUTORADIO(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \
    361413            WS_VISIBLE | WS_TABSTOP | BS_AUTORADIOBUTTON | WS_GROUP, \
    362             id, CTL_COMMON_FONT, 0, { cx, cy }, COMMON_SPACING }
    363 
    364     #define LOADDEF_FIRST_AUTORADIO(id) CONTROLDEF_FIRST_AUTORADIO(LOAD_STRING, id, SZL_AUTOSIZE, SZL_AUTOSIZE)
     414            id, CTL_COMMON_FONT, { cx, cy }, COMMON_SPACING }
     415
     416    #define LOADDEF_FIRST_AUTORADIO(id) \
     417            CONTROLDEF_FIRST_AUTORADIO(LOAD_STRING, id, SZL_AUTOSIZE, SZL_AUTOSIZE)
    365418
    366419    #define CONTROLDEF_NEXT_AUTORADIO(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \
    367420            WS_VISIBLE | WS_TABSTOP | BS_AUTORADIOBUTTON, \
    368             id, CTL_COMMON_FONT, 0, { cx, cy }, COMMON_SPACING }
     421            id, CTL_COMMON_FONT, { cx, cy }, COMMON_SPACING }
    369422
    370423    #define LOADDEF_NEXT_AUTORADIO(id) CONTROLDEF_NEXT_AUTORADIO(LOAD_STRING, id, SZL_AUTOSIZE, SZL_AUTOSIZE)
     
    374427    #define CONTROLDEF_ENTRYFIELD(pcsz, id, cx, cy) { WC_ENTRYFIELD, pcsz, \
    375428            WS_VISIBLE | WS_TABSTOP | ES_MARGIN | ES_AUTOSCROLL, \
    376             id, CTL_COMMON_FONT, 0, { cx, cy }, COMMON_SPACING }
     429            id, CTL_COMMON_FONT, { cx, cy }, COMMON_SPACING }
    377430
    378431    #define CONTROLDEF_ENTRYFIELD_RO(pcsz, id, cx, cy) { WC_ENTRYFIELD, pcsz, \
    379432            WS_VISIBLE | WS_TABSTOP | ES_MARGIN | ES_READONLY | ES_AUTOSCROLL, \
    380             id, CTL_COMMON_FONT, 0, { cx, cy }, COMMON_SPACING }
     433            id, CTL_COMMON_FONT, { cx, cy }, COMMON_SPACING }
    381434
    382435    // the following require INCL_WINMLE
     
    384437    #define CONTROLDEF_MLE(pcsz, id, cx, cy) { WC_MLE, pcsz, \
    385438            WS_VISIBLE | WS_TABSTOP | MLS_BORDER | MLS_IGNORETAB | MLS_WORDWRAP, \
    386             id, CTL_COMMON_FONT, 0, { cx, cy }, COMMON_SPACING }
     439            id, CTL_COMMON_FONT, { cx, cy }, COMMON_SPACING }
    387440
    388441    // the following require INCL_WINLISTBOXES
     
    390443    #define CONTROLDEF_LISTBOX(id, cx, cy) { WC_LISTBOX, NULL, \
    391444            WS_VISIBLE | WS_TABSTOP | LS_HORZSCROLL | LS_NOADJUSTPOS, \
    392             id, CTL_COMMON_FONT, 0, { cx, cy }, COMMON_SPACING }
     445            id, CTL_COMMON_FONT, { cx, cy }, COMMON_SPACING }
    393446
    394447    // the following require INCL_WINLISTBOXES and INCL_WINENTRYFIELDS
     
    396449    #define CONTROLDEF_DROPDOWN(id, cx, cy) { WC_COMBOBOX, NULL, \
    397450            WS_VISIBLE | WS_TABSTOP | LS_HORZSCROLL | CBS_DROPDOWN, \
    398             id, CTL_COMMON_FONT, 0, { cx, cy }, COMMON_SPACING }
     451            id, CTL_COMMON_FONT, { cx, cy }, COMMON_SPACING }
    399452
    400453    #define CONTROLDEF_DROPDOWNLIST(id, cx, cy) { WC_COMBOBOX, NULL, \
    401454            WS_VISIBLE | WS_TABSTOP | LS_HORZSCROLL | CBS_DROPDOWNLIST, \
    402             id, CTL_COMMON_FONT, 0, { cx, cy }, COMMON_SPACING }
     455            id, CTL_COMMON_FONT, { cx, cy }, COMMON_SPACING }
    403456
    404457    // the following require INCL_WINSTDSPIN
     
    406459    #define CONTROLDEF_SPINBUTTON(id, cx, cy) { WC_SPINBUTTON, NULL, \
    407460            WS_VISIBLE | WS_TABSTOP | SPBS_MASTER | SPBS_NUMERICONLY | SPBS_JUSTCENTER | SPBS_FASTSPIN, \
    408             id, CTL_COMMON_FONT, 0, {cx, cy}, COMMON_SPACING }
     461            id, CTL_COMMON_FONT, {cx, cy}, COMMON_SPACING }
    409462
    410463    // the following require INCL_WINSTDCNR
     
    412465    #define CONTROLDEF_CONTAINER(id, cx, cy) { WC_CONTAINER, NULL, \
    413466            WS_VISIBLE | WS_TABSTOP | 0, \
    414             id, CTL_COMMON_FONT, 0, {cx, cy}, COMMON_SPACING }
     467            id, CTL_COMMON_FONT, {cx, cy}, COMMON_SPACING }
    415468
    416469    #define CONTROLDEF_CONTAINER_EXTSEL(id, cx, cy) { WC_CONTAINER, NULL, \
    417470            WS_VISIBLE | WS_TABSTOP | CCS_EXTENDSEL, \
    418             id, CTL_COMMON_FONT, 0, {cx, cy}, COMMON_SPACING }
     471            id, CTL_COMMON_FONT, {cx, cy}, COMMON_SPACING }
    419472
    420473    // the following require INCL_WINSTDSLIDER
     
    423476            WS_VISIBLE | WS_TABSTOP | WS_GROUP | SLS_HORIZONTAL | SLS_PRIMARYSCALE1 \
    424477            | SLS_BUTTONSRIGHT | SLS_SNAPTOINCREMENT, \
    425             id, CTL_COMMON_FONT, 0, {cx, cy}, COMMON_SPACING, pctldata }
     478            id, CTL_COMMON_FONT, {cx, cy}, 0, pctldata }
     479            // id, CTL_COMMON_FONT, {cx, cy}, COMMON_SPACING, pctldata }
    426480
    427481    #define CONTROLDEF_VSLIDER(id, cx, cy, pctldata) { WC_SLIDER, NULL, \
    428482            WS_VISIBLE | WS_TABSTOP | WS_GROUP | SLS_VERTICAL | SLS_PRIMARYSCALE1 \
    429483            | SLS_BUTTONSRIGHT | SLS_SNAPTOINCREMENT, \
    430             id, CTL_COMMON_FONT, 0, {cx, cy}, COMMON_SPACING, pctldata }
     484            id, CTL_COMMON_FONT, {cx, cy}, COMMON_SPACING, pctldata }
     485
     486    // the following require #include helpers\comctl.h
     487    #define CONTROLDEF_SEPARATORLINE(id, cx, cy) { WC_SEPARATORLINE, NULL, \
     488            WS_VISIBLE, \
     489            id, NULL, {cx, cy}, COMMON_SPACING }
    431490
    432491    // the following require #include helpers\textview.h
     
    434493    #define CONTROLDEF_XTEXTVIEW(text, id, cx, pctldata) { WC_XTEXTVIEW, text, \
    435494            WS_VISIBLE | XS_STATIC | XS_WORDWRAP, \
    436             id, CTL_COMMON_FONT, 0, {cx, SZL_AUTOSIZE}, COMMON_SPACING, pctldata }
     495            id, CTL_COMMON_FONT, {cx, SZL_AUTOSIZE}, COMMON_SPACING, pctldata }
    437496
    438497    #define CONTROLDEF_XTEXTVIEW_HTML(text, id, cx, pctldata) { WC_XTEXTVIEW, text, \
    439498            WS_VISIBLE | XS_STATIC | XS_WORDWRAP | XS_HTML, \
    440             id, CTL_COMMON_FONT, 0, {cx, SZL_AUTOSIZE}, COMMON_SPACING, pctldata }
     499            id, CTL_COMMON_FONT, {cx, SZL_AUTOSIZE}, COMMON_SPACING, pctldata }
    441500
    442501    /* ******************************************************************
  • trunk/src/helpers/apps.c

    r208 r209  
    879879    // if the path has spaces, or other invalid characters,
    880880    // include it in quotes V0.9.21 (2002-08-12) [umoeller]
    881     if (fQuotes = !!strpbrk(pProgDetails->pszExecutable, " +&|"))
     881    if (fQuotes = !!strpbrk(pProgDetails->pszExecutable, " +&|="))
    882882        xstrcatc(pstrParams, '"');
     883            // @@bugbug "=" still doesn't work
    883884
    884885    #ifdef DEBUG_PROGRAMSTART
     
    11651166 *@@changed V0.9.20 (2002-07-03) [umoeller]: fixed Win-OS/2 full screen breakage
    11661167 *@@changed V0.9.20 (2002-07-03) [umoeller]: fixed broken bat and cmd files when PROG_DEFAULT was set
     1168 *@@changed V0.9.21 (2002-08-18) [umoeller]: fixed cmd and bat files that had "=" in their paths
    11671169 */
    11681170
     
    13471349                        arc = ERROR_PATH_NOT_FOUND;
    13481350                }
     1351
     1352// V0.9.21: this define is never set. I have thus completely
     1353// disabled the batch hacks that we used to provide, that is
     1354// we no longer change the "c:\path\batch.cmd" to "cmd.exe /c c:\path\batch.cmd"
     1355// because it is perfectly valid to call WinStartApp with a
     1356// batch file. The problem with my code was that cmd.exe has
     1357// a weird bug in that if you give it something via /c that
     1358// has an equals character (=) in its path, e.g. "c:\path=path\batch.cmd",
     1359// the command parser apparently stops at the first "=" and
     1360// reports "c:\path" not found or something. What a bitch.
     1361#ifdef ENABLEBATCHHACKS
    13491362
    13501363                // we frequently get here for BAT and CMD files
     
    13991412                    break;
    14001413                } // end switch (Details.progt.progc)
     1414#endif // ENABLEBATCHHACKS
    14011415            }
    14021416        }
     
    20452059 *@@changed V0.9.20 (2002-08-10) [umoeller]: fixed missing destroy window, made wait optional
    20462060 *@@changed V0.9.20 (2002-08-10) [umoeller]: added pcszWorkingDir
    2047  */
    2048 
    2049 HAPP appQuickStartApp(const char *pcszFile,
    2050                       ULONG ulProgType,             // e.g. PROG_PM
    2051                       const char *pcszArgs,         // in: arguments (can be NULL)
    2052                       const char *pcszWorkingDir,   // in: working dir (can be NULL)
    2053                       PULONG pulExitCode)           // out: exit code; if ptr is NULL, we don't wait
     2061 *@@changed V0.9.21 (2002-08-18) [umoeller]: changed prototype to return APIRET
     2062 */
     2063
     2064APIRET appQuickStartApp(const char *pcszFile,
     2065                        ULONG ulProgType,             // e.g. PROG_PM
     2066                        const char *pcszArgs,         // in: arguments (can be NULL)
     2067                        const char *pcszWorkingDir,   // in: working dir (can be NULL)
     2068                        HAPP *phapp,
     2069                        PULONG pulExitCode)           // out: exit code; if ptr is NULL, we don't wait
    20542070{
     2071    APIRET         arc = NO_ERROR;
    20552072    PROGDETAILS    pd = {0};
    2056     HAPP           happ,
    2057                    happReturn = NULLHANDLE;
     2073    HAPP           happReturn = NULLHANDLE;
    20582074    CHAR           szDir[CCHMAXPATH] = "";
    20592075    PCSZ           p;
     
    20772093
    20782094    if (    (hwndObject = winhCreateObjectWindow(WC_STATIC, NULL))
    2079          && (!appStartApp(hwndObject,
    2080                           &pd,
    2081                           0,
    2082                           &happ,
    2083                           0,
    2084                           NULL))
     2095         && (!(arc = appStartApp(hwndObject,
     2096                                 &pd,
     2097                                 0,
     2098                                 phapp,
     2099                                 0,
     2100                                 NULL)))
    20852101       )
    20862102    {
    20872103        if (pulExitCode)
    20882104            appWaitForApp(hwndObject,
    2089                           happ,
     2105                          *phapp,
    20902106                          pulExitCode);
    20912107
    2092         happReturn = happ;
    2093 
    20942108        WinDestroyWindow(hwndObject);       // was missing V0.9.20 (2002-08-10) [umoeller]
    20952109    }
    20962110
    2097     return happReturn;
     2111    return arc;
    20982112}
    20992113
     
    21032117 *      URL.
    21042118 *
     2119 *      We return TRUE if appQuickStartApp succeeded with
     2120 *      that URL.
     2121 *
    21052122 *@@added V0.9.20 (2002-08-10) [umoeller]
    21062123 */
    21072124
    2108 BOOL appOpenURL(PCSZ pcszURL)
     2125APIRET appOpenURL(PCSZ pcszURL,           // in: URL to open
     2126                  PSZ pszAppStarted,      // out: application that was started
     2127                  ULONG cbAppStarted)     // in: size of that buffer
    21092128{
    2110     BOOL        brc = FALSE;
     2129    APIRET      arc = NO_ERROR;
    21112130
    21122131    CHAR        szBrowser[CCHMAXPATH],
     
    21232142                              sizeof(szBrowser)))
    21242143    {
    2125         PSZ pszDefParams;
     2144        PSZ     pszDefParams;
     2145        HAPP    happ;
    21262146
    21272147        if (pszDefParams = prfhQueryProfileData(HINI_USER,
     
    21452165
    21462166
    2147         brc = !!appQuickStartApp(szBrowser,
    2148                                  PROG_DEFAULT,
    2149                                  strParameters.psz,
    2150                                  szStartupDir,
    2151                                  NULL);            // don't wait
     2167        arc = appQuickStartApp(szBrowser,
     2168                               PROG_DEFAULT,
     2169                               strParameters.psz,
     2170                               szStartupDir,
     2171                               &happ,
     2172                               NULL);     // don't wait
     2173
     2174        if (pszAppStarted)
     2175            strhncpy0(pszAppStarted,
     2176                      szBrowser,
     2177                      cbAppStarted);
    21522178    }
    21532179
    21542180    xstrClear(&strParameters);
    21552181
    2156     return brc;
     2182    return arc;
    21572183}
  • trunk/src/helpers/comctl.c

    r196 r209  
    116116
    117117#pragma hdrstop
     118
     119/* ******************************************************************
     120 *
     121 *   "Separator line" control
     122 *
     123 ********************************************************************/
     124
     125PFNWP   G_pfnwpStatic = NULL;
     126
     127/*
     128 *@@ fnwpSeparatorLine:
     129 *      window proc for the subclassed static control that makes
     130 *      the "separator line" control.
     131 *
     132 *@@added V0.9.20 (2002-08-10) [umoeller]
     133 */
     134
     135static MRESULT EXPENTRY fnwpSeparatorLine(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
     136{
     137    MRESULT mrc = 0;
     138
     139    switch (msg)
     140    {
     141        case WM_PAINT:
     142        {
     143            RECTL rcl;
     144            HPS hps;
     145            WinQueryWindowRect(hwnd, &rcl);
     146            if (hps = WinBeginPaint(hwnd, NULLHANDLE, NULL))
     147            {
     148                POINTL ptl;
     149
     150                gpihSwitchToRGB(hps);
     151
     152                GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONLIGHT, 0));
     153
     154                ptl.x = rcl.xLeft;
     155                ptl.y = (rcl.yTop - rcl.yBottom) / 2 - 1;
     156                GpiMove(hps, &ptl);
     157                ptl.x = rcl.xRight;
     158                GpiLine(hps, &ptl);
     159
     160                GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONDARK, 0));
     161
     162                ptl.x = rcl.xLeft;
     163                ++ptl.y;
     164                GpiMove(hps, &ptl);
     165                ptl.x = rcl.xRight;
     166                GpiLine(hps, &ptl);
     167
     168                WinEndPaint(hps);
     169            }
     170        }
     171        break;
     172
     173        default:
     174            mrc = G_pfnwpStatic(hwnd, msg, mp1, mp2);
     175    }
     176
     177    return mrc;
     178}
     179
     180/*
     181 *@@ ctlMakeSeparatorLine:
     182 *      turns the given static control into a 3D separator line.
     183 *
     184 *@@added V0.9.21 (2002-08-12) [umoeller]
     185 */
     186
     187BOOL ctlRegisterSeparatorLine(HAB hab)
     188{
     189    CLASSINFO ciStatic;
     190    if (WinQueryClassInfo(hab,
     191                          WC_STATIC,
     192                          &ciStatic))
     193    {
     194        G_pfnwpStatic = ciStatic.pfnWindowProc;
     195
     196        return WinRegisterClass(hab,
     197                                WC_SEPARATORLINE,
     198                                fnwpSeparatorLine,
     199                                (ciStatic.flClassStyle & ~CS_PUBLIC),
     200                                ciStatic.cbWindowData);
     201
     202    }
     203
     204    return FALSE;
     205}
    118206
    119207/* ******************************************************************
  • trunk/src/helpers/dialog.c

    r202 r209  
    66 *
    77 *      See dlghCreateDlg for details.
     8 *
     9 *      See @dlg_algorithm for the gory details of the new
     10 *      algorithm used since V0.9.21. Even though much
     11 *      of this file was rewritten, the new dialog is
     12 *      backwards-compatible with all the hacks that existing
     13 *      dialogs might use for aligning things properly.
    814 *
    915 *      In addition, this has dlghMessageBox (a WinMessageBox
     
    4147 */
    4248
     49// #define DEBUG_DIALOG_WINDOWS 1
     50                // blue frame is table
     51                // green frame is column
     52                // red frame is control
     53
    4354#define OS2EMX_PLAIN_CHAR
    4455    // this is needed for "os2emx.h"; if this is defined,
     
    8697#pragma hdrstop
    8798
    88 // #define DEBUG_DIALOG_WINDOWS 1
    89 
    9099/*
    91100 *@@category: Helpers\PM helpers\Dialog templates
     
    94103/* ******************************************************************
    95104 *
    96  *   Private declarations
     105 *   Glossary entries
    97106 *
    98107 ********************************************************************/
    99108
    100109/*
    101  *@@ DLGPRIVATE:
    102  *      private data to the dlg manager, allocated
    103  *      by dlghCreateDlg.
    104  *
    105  *      This only exists while the dialog is being
    106  *      created and is not stored with the new dialog.
    107  */
    108 
    109 typedef struct _DLGPRIVATE
    110 {
    111     // public data
    112     HWND        hwndDlg;
    113 
    114     // definition data (private)
    115     LINKLIST    llTables;
    116 
    117     HWND        hwndFirstFocus,
    118                 hwndDefPushbutton;      // V0.9.14 (2001-08-21) [umoeller]
    119 
    120     POINTL      ptlTotalOfs;
    121 
    122     LINKLIST    llTempControls;         // linked list of HWNDs that were
    123                                         // created temporarily to determine
    124                                         // control sizes for SZL_AUTOSIZE
    125                                         // V0.9.20 (2002-08-10) [umoeller]
    126 
    127     PLINKLIST   pllControls;            // linked list of HWNDs in the order
    128                                         // in which controls were created;
    129                                         // ptr can be NULL
    130 
    131     PCSZ        pcszControlsFont;  // from dlghCreateDlg
    132 
    133     // size of the client to be created
    134     SIZEL       szlClient;
    135 
    136     // various cached data V0.9.14 (2001-08-01) [umoeller]
    137     HPS         hps;
    138     PCSZ        pcszFontLast;
    139     LONG        lcidLast;
    140     FONTMETRICS fmLast;
    141 
    142     LONG        cxBorder,
    143                 cyBorder;           // cached now V0.9.19 (2002-04-17) [umoeller]
    144 
    145     double      dFactorX,           // correlation factors for dialog units
    146                 dFactorY;           // V0.9.19 (2002-04-24) [umoeller]
    147 
    148 } DLGPRIVATE, *PDLGPRIVATE;
    149 
    150 // macros for the dlg units conversion;
    151 #define FACTOR_X     (pDlgData->dFactorX)
    152 #ifdef USE_SQUARE_CORRELATION
    153 #define FACTOR_Y     (pDlgData->dFactorX)
    154 #else
    155 #define FACTOR_Y     (pDlgData->dFactorY)
    156 #endif
    157 
    158 typedef struct _COLUMNDEF *PCOLUMNDEF;
    159 typedef struct _ROWDEF *PROWDEF;
    160 typedef struct _TABLEDEF *PTABLEDEF;
    161 
    162 /*
    163  *@@ CONTROLPOS:
    164  *      control position. We don't want to use SWP.
    165  */
    166 
    167 typedef struct _CONTROLPOS
    168 {
    169     LONG        x,
    170                 y,
    171                 cx,
    172                 cy;
    173 } CONTROLPOS, *PCONTROLPOS;
    174 
    175 /*
    176  *@@ COLUMNDEF:
    177  *      representation of a table column.
    178  *      This is stored in a linked list in ROWDEF.
    179  *
    180  *      A table column represents either a PM control
    181  *      window or another table, which may therefore
    182  *      be nested.
    183  */
    184 
    185 typedef struct _COLUMNDEF
    186 {
    187     PROWDEF     pOwningRow;         // row whose linked list this column belongs to
    188 
    189     BOOL        fIsNestedTable;     // if TRUE, pvDefinition points to a nested TABLEDEF;
    190                                     // if FALSE, pvDefinition points to a CONTROLDEF as
    191                                     // specified by the caller
    192 
    193     PVOID       pvDefinition;       // either a PTABLEDEF or a PCONTROLDEF
    194 
    195     CONTROLPOS  cpControl,          // real pos and size of control; if the control is
    196                                     // a subtable, this receives the size of the table
    197                                     // without spacings
    198                 cpColumn;           // pos and size of column; this is the size of the
    199                                     // column plus the spacing from the CONTROLDEF
    200                                     // applied
    201                                     // For PM group controls around tables, this is
    202                                     // receives the following spacings:
    203                                     // x += GROUP_INNER_SPACING_X + CONTROLDEF.ulSpacing
    204                                     // y += GROUP_INNER_SPACING_Y + CONTROLDEF.ulSpacing
    205                                     // cx += 2 * GROUP_INNER_SPACING_X + 2 * CONTROLDEF.ulSpacing
    206                                     // cy +=   2 * GROUP_INNER_SPACING_Y
    207                                     //       + GROUP_INNER_SPACING_EXTRA_TOP
    208                                     //       + 2 * CONTROLDEF.duSpacing
    209 
    210     HWND        hwndControl;        // created control; NULLHANDLE for tables always
    211 
    212 } COLUMNDEF;
    213 
    214 /*
    215  *@@ ROWDEF:
    216  *
    217  */
    218 
    219 typedef struct _ROWDEF
    220 {
    221     PTABLEDEF   pOwningTable;       // table whose linked list this row belongs to
    222 
    223     LINKLIST    llColumns;          // contains COLUMNDEF structs, no auto-free
    224 
    225     ULONG       flRowFormat;        // one of:
    226                                     // -- ROW_VALIGN_BOTTOM           0x0000
    227                                     // -- ROW_VALIGN_CENTER           0x0001
    228                                     // -- ROW_VALIGN_TOP              0x0002
    229 
    230     CONTROLPOS  cpRow;
    231 
    232 } ROWDEF;
    233 
    234 /*
    235  *@@ TABLEDEF:
    236  *
    237  */
    238 
    239 typedef struct _TABLEDEF
    240 {
    241     PCOLUMNDEF  pOwningColumn;      // != NULL if this is a nested table
    242 
    243     LINKLIST    llRows;             // contains ROWDEF structs, no auto-free
    244 
    245     const CONTROLDEF *pCtlDef;      // if != NULL, we create a PM control around the table
    246 
    247     CONTROLPOS  cpTable;
    248 
    249     ULONG       flTable;            // copied from DLGHITEM
    250 
    251 } TABLEDEF;
    252 
    253 /*
    254  *@@ PROCESSMODE:
    255  *
    256  */
    257 
    258 typedef enum _PROCESSMODE
    259 {
    260     PROCESS_1_CALC_SIZES,             // step 1
    261     PROCESS_2_CALC_SIZES_FROM_TABLES, // step 2
    262     PROCESS_3_CALC_FINAL_TABLE_SIZES, // step 3
    263     PROCESS_4_CALC_POSITIONS,         // step 4
    264     PROCESS_5_CREATE_CONTROLS         // step 5
    265 } PROCESSMODE;
    266 
    267 /* ******************************************************************
    268  *
    269  *   Worker routines
    270  *
    271  ********************************************************************/
    272 
    273 static APIRET ProcessTable(PTABLEDEF pTableDef,
    274                            const CONTROLPOS *pcpTable,
    275                            PROCESSMODE ProcessMode,
    276                            PDLGPRIVATE pDlgData);
    277 
    278 /*
    279  *@@ SetDlgFont:
    280  *
    281  *@@added V0.9.16 (2001-10-11) [umoeller]
    282  */
    283 
    284 static VOID SetDlgFont(const CONTROLDEF *pControlDef,
    285                        PDLGPRIVATE pDlgData)
    286 {
    287     LONG lPointSize = 0;
    288     PCSZ pcszFontThis = pControlDef->pcszFont;
    289                     // can be NULL,
    290                     // or CTL_COMMON_FONT
    291 
    292     if (pcszFontThis == CTL_COMMON_FONT)
    293         pcszFontThis = pDlgData->pcszControlsFont;
    294 
    295     if (!pDlgData->hps)
    296         pDlgData->hps = WinGetPS(pDlgData->hwndDlg);
    297 
    298     // check if we can reuse font data from last time
    299     // V0.9.14 (2001-08-01) [umoeller]
    300     if (strhcmp(pcszFontThis,               // can be NULL!
    301                 pDlgData->pcszFontLast))
    302     {
    303         // different font than last time:
    304 
    305         // delete old font?
    306         if (pDlgData->lcidLast)
    307         {
    308             GpiSetCharSet(pDlgData->hps, LCID_DEFAULT);     // LCID_DEFAULT == 0
    309             GpiDeleteSetId(pDlgData->hps, pDlgData->lcidLast);
    310         }
    311 
    312         if (pcszFontThis)
    313         {
    314             // create new font
    315             pDlgData->lcidLast = gpihFindPresFont(NULLHANDLE,        // no window yet
    316                                                   FALSE,
    317                                                   pDlgData->hps,
    318                                                   pcszFontThis,
    319                                                   &pDlgData->fmLast,
    320                                                   &lPointSize);
    321 
    322             GpiSetCharSet(pDlgData->hps, pDlgData->lcidLast);
    323             if (pDlgData->fmLast.fsDefn & FM_DEFN_OUTLINE)
    324                 gpihSetPointSize(pDlgData->hps, lPointSize);
    325         }
    326         else
    327         {
    328             // use default font:
    329             // @@todo handle presparams, maybe inherited?
    330             GpiSetCharSet(pDlgData->hps, LCID_DEFAULT);
    331             GpiQueryFontMetrics(pDlgData->hps,
    332                                 sizeof(pDlgData->fmLast),
    333                                 &pDlgData->fmLast);
    334         }
    335 
    336         pDlgData->pcszFontLast = pcszFontThis;      // can be NULL
    337     }
    338 }
    339 
    340 /*
    341  *@@ CalcAutoSizeText:
    342  *      implementation for CalcAutoSize for static
    343  *      text, single and multi-line.
    344  *
    345  *@@changed V0.9.12 (2001-05-31) [umoeller]: fixed various things with statics
    346  *@@changed V0.9.12 (2001-05-31) [umoeller]: fixed broken fonts
    347  *@@changed V0.9.14 (2001-08-01) [umoeller]: now caching fonts, which is significantly faster
    348  *@@changed V0.9.16 (2001-10-15) [umoeller]: added APIRET
    349  *@@changed V0.9.16 (2002-02-02) [umoeller]: added ulWidth
    350  */
    351 
    352 static APIRET CalcAutoSizeText(const CONTROLDEF *pControlDef,
    353                                BOOL fMultiLine,          // in: if TRUE, multiple lines
    354                                ULONG ulWidth,            // in: proposed width of control
    355                                PSIZEL pszlAuto,          // out: computed size
    356                                PDLGPRIVATE pDlgData)
    357 {
    358     APIRET arc = NO_ERROR;
    359 
    360     SetDlgFont(pControlDef, pDlgData);
    361 
    362     pszlAuto->cy =   pDlgData->fmLast.lMaxBaselineExt
    363                    + pDlgData->fmLast.lExternalLeading;
    364 
    365     // ok, we FINALLY have a font now...
    366     // get the control string and see how much space it needs
    367     if (    (pControlDef->pcszText)
    368          && (pControlDef->pcszText != (PCSZ)-1)
    369        )
    370     {
    371         // do we have multiple lines?
    372         if (fMultiLine)
    373         {
    374             RECTL rcl = {0, 0, 0, 0};
    375             rcl.xRight = ulWidth;
    376             if (pControlDef->szlDlgUnits.cy > 0)
    377                 rcl.yTop = pControlDef->szlDlgUnits.cy * FACTOR_Y;
    378                         // V0.9.12 (2001-05-31) [umoeller]
    379             else
    380                 rcl.yTop = winhQueryScreenCY() * 2 / 3;
    381 
    382             winhDrawFormattedText(pDlgData->hps,
    383                                   &rcl,
    384                                   pControlDef->pcszText,
    385                                   DT_LEFT | DT_TOP | DT_WORDBREAK | DT_QUERYEXTENT);
    386             pszlAuto->cx = rcl.xRight - rcl.xLeft;
    387             pszlAuto->cy = rcl.yTop - rcl.yBottom;
    388         }
    389         else
    390         {
    391             POINTL aptl[TXTBOX_COUNT];
    392             GpiQueryTextBox(pDlgData->hps,
    393                             strlen(pControlDef->pcszText),
    394                             (PCH)pControlDef->pcszText,
    395                             TXTBOX_COUNT,
    396                             aptl);
    397             pszlAuto->cx = aptl[TXTBOX_TOPRIGHT].x - aptl[TXTBOX_BOTTOMLEFT].x;
    398         }
    399     }
    400     else
    401         arc = DLGERR_INVALID_CONTROL_TITLE;
    402 
    403     return arc;
    404 }
    405 
    406 /*
    407  *@@ CalcAutoSizeTextView:
    408  *      implementation for CalcAutoSize for the XTextView
    409  *      control.
    410  *
    411  *      This is slightly sick. We create the control already
    412  *      here in order to be able to have it format the text
    413  *      and then send TXM_QUERYTEXTEXTENT to it. The control
    414  *      that was created here will then be used by
    415  *      ColumnCreateControls and not be recreated, which would
    416  *      be way too expensive.
    417  *
    418  *@@added V0.9.20 (2002-08-10) [umoeller]
    419  */
    420 
    421 static APIRET CalcAutoSizeTextView(const CONTROLDEF *pControlDef,
    422                                    ULONG ulWidth,            // in: proposed width of control
    423                                    PSIZEL pszlAuto,          // out: computed size
    424                                    PDLGPRIVATE pDlgData)
    425 {
    426     APIRET arc = NO_ERROR;
    427 
    428     HWND hwnd = NULLHANDLE;
    429     PCSZ pcszTitle;
    430 
    431     PLISTNODE pTempNode;
    432     HWND hwndFound = NULLHANDLE;
    433     FOR_ALL_NODES(&pDlgData->llTempControls, pTempNode)
    434     {
    435         HWND hwndThis = (HWND)pTempNode->pItemData;
    436         if (WinQueryWindowUShort(hwndThis, QWS_ID) == pControlDef->usID)
    437         {
    438             hwnd = hwndThis;
    439 
    440             // resize it to what we really need
    441             WinSetWindowPos(hwndThis,
    442                             HWND_BOTTOM,
    443                             0,
    444                             0,
    445                             ulWidth,
    446                             2000,
    447                             SWP_SIZE);
    448             break;
    449         }
    450     }
    451 
    452     if (!hwnd)
    453     {
    454         if (hwnd = WinCreateWindow(pDlgData->hwndDlg,   // parent
    455                                    (PSZ)pControlDef->pcszClass,
    456                                    NULL,
    457                                    pControlDef->flStyle,
    458                                    0,
    459                                    0,
    460                                    ulWidth,
    461                                    2000,         // cy, for now
    462                                    pDlgData->hwndDlg,   // owner
    463                                    HWND_BOTTOM,
    464                                    pControlDef->usID,
    465                                    pControlDef->pvCtlData,
    466                                    NULL))
    467         {
    468             PCSZ pcszFont = pControlDef->pcszFont;
    469                             // can be NULL, or CTL_COMMON_FONT
    470             if (pcszFont == CTL_COMMON_FONT)
    471                 pcszFont = pDlgData->pcszControlsFont;
    472 
    473             if (pcszFont)
    474                 winhSetWindowFont(hwnd,
    475                                   pcszFont);
    476 
    477             WinSetWindowText(hwnd,
    478                              (pcszTitle = pControlDef->pcszText)
    479                                  ? (PSZ)pcszTitle
    480                                  : "");
    481 
    482             // store the window we have created in the temp
    483             // windows list so it can be reused in
    484             // ColumnCreateControls
    485             lstAppendItem(&pDlgData->llTempControls,
    486                           (PVOID)hwnd);
    487         }
    488         else
    489             arc = DLGERR_CANNOT_CREATE_CONTROL;
    490     }
    491 
    492     if (hwnd)
    493     {
    494         SIZEL szlTemp;
    495         WinSendMsg(hwnd,
    496                    TXM_QUERYTEXTEXTENT,
    497                    (MPARAM)&szlTemp,
    498                    0);
    499 
    500         pszlAuto->cy = szlTemp.cy;
    501     }
    502 
    503     return arc;
    504 }
    505 
    506 /*
    507  *@@ CalcAutoSize:
    508  *      helper func that gets called from ColumnCalcSizes for
    509  *      every control that has set SZL_AUTOSIZE for its size.
    510  *
    511  *      We try to be smart and set a correct size for the
    512  *      control, depending on its class and data.
    513  *
    514  *      Presently this works for
    515  *
    516  *      --  static text, single and multiline
    517  *
    518  *      --  static icons and bitmaps
    519  *
    520  *      --  pushbuttons, radio buttons, and checkboxes
    521  *
    522  *      --  the XTextView control (yes! V0.9.20).
    523  *
    524  *@@changed V0.9.12 (2001-05-31) [umoeller]: fixed various things with statics
    525  *@@changed V0.9.16 (2001-10-15) [umoeller]: added APIRET
    526  *@@changed V0.9.20 (2002-08-10) [umoeller]: added support for textview
    527  */
    528 
    529 static APIRET CalcAutoSize(const CONTROLDEF *pControlDef,
    530                            ULONG ulWidth,            // in: proposed width of control
    531                            PSIZEL pszlAuto,          // out: computed size
    532                            PDLGPRIVATE pDlgData)
    533 {
    534     APIRET arc = NO_ERROR;
    535 
    536     // dumb defaults
    537     pszlAuto->cx = 100;
    538     pszlAuto->cy = 30;
    539 
    540     switch ((ULONG)pControlDef->pcszClass)
    541     {
    542         case 0xffff0003L: // WC_BUTTON:
    543             if (!(arc = CalcAutoSizeText(pControlDef,
    544                                          FALSE,         // no multiline
    545                                          ulWidth,
    546                                          pszlAuto,
    547                                          pDlgData)))
    548             {
    549                 if (pControlDef->flStyle & (  BS_AUTOCHECKBOX
    550                                             | BS_AUTORADIOBUTTON
    551                                             | BS_AUTO3STATE
    552                                             | BS_3STATE
    553                                             | BS_CHECKBOX
    554                                             | BS_RADIOBUTTON))
    555                 {
    556                     // give a little extra width for the box bitmap
    557                     // V0.9.19 (2002-04-24) [umoeller]
    558                     pszlAuto->cx += ctlQueryCheckboxSize() + 4;
    559                     // and height
    560                     pszlAuto->cy += 2;
    561                 }
    562                 else if (pControlDef->flStyle & BS_BITMAP)
    563                     ;
    564                 else if (pControlDef->flStyle & (BS_ICON | BS_MINIICON))
    565                     ;
    566                 // we can't test for BS_PUSHBUTTON because that's 0x0000
    567                 else if (!(pControlDef->flStyle & BS_USERBUTTON))
    568                 {
    569                     pszlAuto->cx += (2 * pDlgData->cxBorder + 15);
    570                     pszlAuto->cy += (2 * pDlgData->cyBorder + 15);
    571                 }
    572             }
    573         break;
    574 
    575         case 0xffff0005L: // WC_STATIC:
    576             if ((pControlDef->flStyle & 0x0F) == SS_TEXT)
    577                 arc = CalcAutoSizeText(pControlDef,
    578                                        ((pControlDef->flStyle & DT_WORDBREAK) != 0),
    579                                        ulWidth,
    580                                        pszlAuto,
    581                                        pDlgData);
    582             else if ((pControlDef->flStyle & 0x0F) == SS_BITMAP)
    583             {
    584                 HBITMAP hbm;
    585                 if (hbm = (HBITMAP)pControlDef->pcszText)
    586                 {
    587                     BITMAPINFOHEADER2 bmih2;
    588                     ZERO(&bmih2);
    589                     bmih2.cbFix = sizeof(bmih2);
    590                     if (GpiQueryBitmapInfoHeader(hbm,
    591                                                  &bmih2))
    592                     {
    593                         pszlAuto->cx = bmih2.cx;
    594                         pszlAuto->cy = bmih2.cy;
    595                     }
    596                     else
    597                         arc = DLGERR_INVALID_STATIC_BITMAP;
    598                 }
    599             }
    600             else if ((pControlDef->flStyle & 0x0F) == SS_ICON)
    601             {
    602                 pszlAuto->cx = WinQuerySysValue(HWND_DESKTOP, SV_CXICON);
    603                 pszlAuto->cy = WinQuerySysValue(HWND_DESKTOP, SV_CYICON);
    604             }
    605         break;
    606 
    607         default:
    608             // added support for textview V0.9.20 (2002-08-10) [umoeller]
    609             if (    (((ULONG)pControlDef->pcszClass & 0xFFFF0000) != 0xFFFF0000)
    610                  && (!strcmp(pControlDef->pcszClass, WC_XTEXTVIEW))
    611                )
    612             {
    613                 arc = CalcAutoSizeTextView(pControlDef,
    614                                            ulWidth,
    615                                            pszlAuto,
    616                                            pDlgData);
    617             }
    618             else
    619             {
    620                 // any other control (just to be safe):
    621                 SetDlgFont(pControlDef, pDlgData);
    622                 pszlAuto->cx = 50;
    623                 pszlAuto->cy =   pDlgData->fmLast.lMaxBaselineExt
    624                                + pDlgData->fmLast.lExternalLeading
    625                                + 7;         // some space
    626             }
    627     }
    628 
    629     return arc;
    630 }
    631 
    632 /*
    633  *@@ ColumnCalcSizes:
    634  *      implementation for PROCESS_1_CALC_SIZES in
    635  *      ProcessColumn.
    636  *
    637  *      This gets called a second time for
    638  *      PROCESS_3_CALC_FINAL_TABLE_SIZES (V0.9.16).
    639  *
    640  *@@added V0.9.15 (2001-08-26) [umoeller]
    641  *@@changed V0.9.16 (2001-10-15) [umoeller]: fixed ugly group table spacings
    642  *@@changed V0.9.16 (2001-10-15) [umoeller]: added APIRET
    643  *@@changed V0.9.16 (2002-02-02) [umoeller]: added support for explicit group size
    644  *@@changed V0.9.19 (2002-04-17) [umoeller]: fixes for the STUPID drop-down comboboxes
    645  *@@changed V0.9.19 (2002-04-24) [umoeller]: fixed PM groups alignment
    646  *@@changed V0.9.19 (2002-04-24) [umoeller]: added resolution correlation
    647  */
    648 
    649 static APIRET ColumnCalcSizes(PCOLUMNDEF pColumnDef,
    650                               PROCESSMODE ProcessMode,     // in: PROCESS_1_CALC_SIZES or PROCESS_3_CALC_FINAL_TABLE_SIZES
    651                               PDLGPRIVATE pDlgData)
    652 {
    653     APIRET      arc = NO_ERROR;
    654     const CONTROLDEF *pControlDef = NULL;
    655     ULONG       xExtraColumn = 0,
    656                 yExtraColumn = 0;
    657 
    658     if (pColumnDef->fIsNestedTable)
    659     {
    660         // nested table: recurse!!
    661         PTABLEDEF pTableDef = (PTABLEDEF)pColumnDef->pvDefinition;
    662         if (!(arc = ProcessTable(pTableDef,
    663                                  NULL,
    664                                  ProcessMode,
    665                                  pDlgData)))
    666         {
    667             // store the size of the sub-table
    668             pColumnDef->cpControl.cx = pTableDef->cpTable.cx;
    669             pColumnDef->cpControl.cy = pTableDef->cpTable.cy;
    670 
    671             // should we create a PM control around the table?
    672             if (pControlDef = pTableDef->pCtlDef)
    673             {
    674                 // yes:
    675                 LONG cxCalc = pControlDef->szlDlgUnits.cx * FACTOR_X,
    676                      cyCalc = pControlDef->szlDlgUnits.cy * FACTOR_Y;
    677 
    678                 // check if maybe an explicit size was specified
    679                 // for the group; only if that is larger than what
    680                 // we've calculated above, use it instead
    681                 if (cxCalc > pColumnDef->cpControl.cx)
    682                         // should be -1 for auto-size
    683                     pColumnDef->cpControl.cx = cxCalc;
    684 
    685                 if (cyCalc > pColumnDef->cpControl.cy)
    686                         // should be -1 for auto-size
    687                     pColumnDef->cpControl.cy = cyCalc;
    688 
    689                 // in any case, add the inner spacing so that the group
    690                 // will be large enough
    691                 // fixed V0.9.19 (2002-04-24) [umoeller]
    692                 xExtraColumn =  (   (2 * pControlDef->duSpacing)
    693                                   + 2 * GROUP_INNER_SPACING_X
    694                                 ) * FACTOR_X;
    695                 yExtraColumn =  (   (2 * pControlDef->duSpacing)
    696                                   + GROUP_OUTER_SPACING_BOTTOM
    697                                   + GROUP_INNER_SPACING_BOTTOM
    698                                   + GROUP_INNER_SPACING_TOP
    699                                   + GROUP_OUTER_SPACING_TOP
    700                                 ) * FACTOR_Y;
    701             }
    702         }
    703     }
    704     else
    705     {
    706         // no nested table, but control:
    707         SIZEL       szlAuto;
    708 
    709         pControlDef = (const CONTROLDEF *)pColumnDef->pvDefinition;
    710 
    711         // do auto-size calculations only on the first loop
    712         // V0.9.16 (2002-02-02) [umoeller]
    713         if (ProcessMode == PROCESS_1_CALC_SIZES)
    714         {
    715             // V0.9.19 (2002-04-24) [umoeller]: added resolution correlation
    716             LONG cxCalc = pControlDef->szlDlgUnits.cx * FACTOR_X,
    717                  cyCalc = pControlDef->szlDlgUnits.cy * FACTOR_Y;
    718 
    719             if (    (pControlDef->szlDlgUnits.cx == -1)
    720                  || (pControlDef->szlDlgUnits.cy == -1)
    721                )
    722             {
    723                 ULONG ulWidth;
    724                 if (pControlDef->szlDlgUnits.cx == -1)
    725                     ulWidth = 1000;
    726                 else
    727                     ulWidth = cxCalc;
    728                 arc = CalcAutoSize(pControlDef,
    729                                    ulWidth,
    730                                    &szlAuto,
    731                                    pDlgData);
    732             }
    733 
    734             if (    (pControlDef->szlDlgUnits.cx < -1)
    735                  && (pControlDef->szlDlgUnits.cx >= -100)
    736                )
    737             {
    738                 // other negative CX value:
    739                 // this is then a percentage of the table width... ignore for now
    740                 // V0.9.16 (2002-02-02) [umoeller]
    741                 szlAuto.cx = 0;
    742             }
    743 
    744             if (    (pControlDef->szlDlgUnits.cy < -1)
    745                  && (pControlDef->szlDlgUnits.cy >= -100)
    746                )
    747             {
    748                 // other negative CY value:
    749                 // this is then a percentage of the row height... ignore for now
    750                 // V0.9.16 (2002-02-02) [umoeller]
    751                 szlAuto.cy = 0;
    752             }
    753 
    754             if (!arc)
    755             {
    756                 if (pControlDef->szlDlgUnits.cx < 0)
    757                     // this was autosize:
    758                     pColumnDef->cpControl.cx = szlAuto.cx;
    759                 else
    760                     // this was explicit: use converted size
    761                     // V0.9.19 (2002-04-24) [umoeller]
    762                     pColumnDef->cpControl.cx = cxCalc;
    763 
    764                 if (pControlDef->szlDlgUnits.cy < 0)
    765                     // this was autosize:
    766                     pColumnDef->cpControl.cy = szlAuto.cy;
    767                 else
    768                     // this was explicit: use converted size
    769                     // V0.9.19 (2002-04-24) [umoeller]
    770                     pColumnDef->cpControl.cy = cyCalc;
    771             }
    772 
    773         } // end if (ProcessMode == PROCESS_1_CALC_SIZES)
    774 
    775         xExtraColumn = 2 * (pControlDef->duSpacing * FACTOR_X);
    776         yExtraColumn = 2 * (pControlDef->duSpacing * FACTOR_Y);
    777     }
    778 
    779     pColumnDef->cpColumn.cx =   pColumnDef->cpControl.cx
    780                               + xExtraColumn;
    781     pColumnDef->cpColumn.cy =   pColumnDef->cpControl.cy
    782                               + yExtraColumn;
    783 
    784     if (    (pControlDef)
    785          && ((ULONG)pControlDef->pcszClass == 0xffff0002L)
    786        )
    787     {
    788         // hack the stupid drop-down combobox where the
    789         // size of the drop-down is the full size of the
    790         // control: when creating the control, we _do_
    791         // specify the full size, but for the column,
    792         // we must rather use a single line with
    793         // the current font
    794         // V0.9.19 (2002-04-17) [umoeller]
    795         if (pControlDef->flStyle & (CBS_DROPDOWN | CBS_DROPDOWNLIST))
    796         {
    797             LONG cyMargin = 3 * pDlgData->cyBorder;
    798 
    799             SetDlgFont(pControlDef, pDlgData);
    800 
    801             pColumnDef->cpColumn.cy
    802                 =   pDlgData->fmLast.lMaxBaselineExt
    803                   + pDlgData->fmLast.lExternalLeading
    804                   + 2 * cyMargin
    805                   + yExtraColumn;
    806         }
    807     }
    808 
    809     return arc;
    810 }
    811 
    812 /*
    813  *@@ ColumnCalcPositions:
    814  *      implementation for PROCESS_4_CALC_POSITIONS in
    815  *      ProcessColumn.
    816  *
    817  *@@added V0.9.15 (2001-08-26) [umoeller]
    818  *@@changed V0.9.16 (2001-10-15) [umoeller]: added APIRET
    819  *@@changed V0.9.19 (2002-04-24) [umoeller]: fixed PM groups alignment
    820  */
    821 
    822 static APIRET ColumnCalcPositions(PCOLUMNDEF pColumnDef,
    823                                   PROWDEF pOwningRow,          // in: current row from ProcessRow
    824                                   PLONG plX,                   // in/out: PROCESS_4_CALC_POSITIONS only
    825                                   PDLGPRIVATE pDlgData)
    826 {
    827     APIRET arc = NO_ERROR;
    828 
    829     // calculate column position: this includes spacing
    830     LONG   xSpacingControl = 0,
    831            ySpacingControl = 0;
    832 
    833     // column position = *plX on ProcessRow stack
    834     pColumnDef->cpColumn.x = *plX;
    835     pColumnDef->cpColumn.y = pOwningRow->cpRow.y;
    836 
    837     // check vertical alignment of row;
    838     // we might need to increase column y
    839     switch (pOwningRow->flRowFormat & ROW_VALIGN_MASK)
    840     {
    841         // case ROW_VALIGN_BOTTOM:      // do nothing
    842 
    843         case ROW_VALIGN_CENTER:
    844             if (pColumnDef->cpColumn.cy < pOwningRow->cpRow.cy)
    845                 pColumnDef->cpColumn.y
    846                     += (   (pOwningRow->cpRow.cy - pColumnDef->cpColumn.cy)
    847                          / 2);
    848         break;
    849 
    850         case ROW_VALIGN_TOP:
    851             if (pColumnDef->cpColumn.cy < pOwningRow->cpRow.cy)
    852                 pColumnDef->cpColumn.y
    853                     += (pOwningRow->cpRow.cy - pColumnDef->cpColumn.cy);
    854         break;
    855     }
    856 
    857     if (pColumnDef->fIsNestedTable)
    858     {
    859         PTABLEDEF pTableDef = (PTABLEDEF)pColumnDef->pvDefinition;
    860         // should we create a PM control around the table?
    861         if (pTableDef->pCtlDef)
    862         {
    863             // yes:
    864             // V0.9.19 (2002-04-24) [umoeller]
    865             xSpacingControl = (   pTableDef->pCtlDef->duSpacing
    866                                 + GROUP_INNER_SPACING_X
    867                               ) * FACTOR_X;
    868             ySpacingControl = (   pTableDef->pCtlDef->duSpacing
    869                                 + GROUP_OUTER_SPACING_BOTTOM
    870                                 + GROUP_INNER_SPACING_BOTTOM
    871                               ) * FACTOR_Y;
    872         }
    873     }
    874     else
    875     {
    876         // no nested table, but control:
    877         const CONTROLDEF *pControlDef = (const CONTROLDEF *)pColumnDef->pvDefinition;
    878         xSpacingControl = pControlDef->duSpacing * FACTOR_X;
    879         ySpacingControl = pControlDef->duSpacing * FACTOR_Y;
    880     }
    881 
    882     // increase plX by column width
    883     *plX += pColumnDef->cpColumn.cx;
    884 
    885     // calculate CONTROL pos from COLUMN pos by applying spacing
    886     pColumnDef->cpControl.x =   (LONG)pColumnDef->cpColumn.x
    887                               + xSpacingControl;
    888     pColumnDef->cpControl.y =   (LONG)pColumnDef->cpColumn.y
    889                               + ySpacingControl;
    890 
    891     if (pColumnDef->fIsNestedTable)
    892     {
    893         // nested table:
    894         PTABLEDEF pTableDef = (PTABLEDEF)pColumnDef->pvDefinition;
    895 
    896         // recurse!! to create windows for the sub-table
    897         arc = ProcessTable(pTableDef,
    898                            &pColumnDef->cpControl,   // start pos for new table
    899                            PROCESS_4_CALC_POSITIONS,
    900                            pDlgData);
    901     }
    902 
    903     return arc;
    904 }
    905 
    906 /*
    907  *@@ ColumnCreateControls:
    908  *      implementation for PROCESS_5_CREATE_CONTROLS in
    909  *      ProcessColumn.
    910  *
    911  *@@added V0.9.15 (2001-08-26) [umoeller]
    912  *@@changed V0.9.16 (2001-10-15) [umoeller]: fixed ugly group table spacings
    913  *@@changed V0.9.16 (2001-12-08) [umoeller]: fixed entry field ES_MARGIN positioning
    914  *@@changed V0.9.19 (2002-04-17) [umoeller]: fixes for the STUPID drop-down comboboxes
    915  *@@changed V0.9.19 (2002-04-24) [umoeller]: fixed PM groups alignment
    916  */
    917 
    918 static APIRET ColumnCreateControls(PCOLUMNDEF pColumnDef,
    919                                    PDLGPRIVATE pDlgData)
    920 {
    921     APIRET      arc = NO_ERROR;
    922 
    923     const CONTROLDEF *pControlDef = NULL;
    924 
    925     PCSZ        pcszClass = NULL;
    926     PCSZ        pcszTitle = NULL;
    927     ULONG       flStyle = 0;
    928     LHANDLE     lHandleSet = NULLHANDLE;
    929     ULONG       flOld = 0;
    930 
    931     LONG        x, cx, y, cy;              // for combo box hacks
    932 
    933     if (pColumnDef->fIsNestedTable)
    934     {
    935         // nested table:
    936         PTABLEDEF pTableDef = (PTABLEDEF)pColumnDef->pvDefinition;
    937 
    938         // recurse!!
    939         if (!(arc = ProcessTable(pTableDef,
    940                                  NULL,
    941                                  PROCESS_5_CREATE_CONTROLS,
    942                                  pDlgData)))
    943         {
    944             // should we create a PM control around the table?
    945             // (do this AFTER the other controls from recursing,
    946             // otherwise the stupid container doesn't show up)
    947             if (pControlDef = pTableDef->pCtlDef)
    948             {
    949                 // yes:
    950                 // pcp  = &pColumnDef->cpColumn;  // !! not control
    951                 pcszClass = pControlDef->pcszClass;
    952                 pcszTitle = pControlDef->pcszText;
    953                 flStyle = pControlDef->flStyle;
    954 
    955                 // note: we do use cpControl, which is cpColumn plus
    956                 // spacings applied. But for groups, this is the
    957                 // following (see ColumnCalcPositions):
    958                 // V0.9.19 (2002-04-24) [umoeller]
    959                 // x is cpColumn.x plus GROUP_INNER_SPACING_X plus group control spacing
    960                 // y is cpColumn.y plus GROUP_INNER_SPACING_Y plus group control spacing
    961                 // cx is cpColumn.cx plus 2 * GROUP_INNER_SPACING_Y plus 2 * group control spacing
    962                 // cy is cpColumn.cy plus 2 * GROUP_INNER_SPACING_Y
    963                 //      plus GROUP_INNER_SPACING_TOP
    964                 //      plus 2 * group control spacing
    965                 // so this needs some hacks again
    966                 x  =   pColumnDef->cpControl.x
    967                      + pDlgData->ptlTotalOfs.x
    968                      - (GROUP_INNER_SPACING_X * FACTOR_X);
    969                      ;
    970                 cx =   pColumnDef->cpControl.cx
    971                      + (2 * (GROUP_INNER_SPACING_X * FACTOR_X));
    972                      ;
    973                 y  =   pColumnDef->cpControl.y
    974                      + pDlgData->ptlTotalOfs.y
    975                      - (GROUP_INNER_SPACING_BOTTOM * FACTOR_Y);
    976                      ;
    977                 cy =   pColumnDef->cpControl.cy
    978                      + ( (   GROUP_INNER_SPACING_BOTTOM
    979                            + GROUP_INNER_SPACING_TOP
    980                          ) * FACTOR_Y);
    981                      ;
    982             }
    983 
    984 #ifdef DEBUG_DIALOG_WINDOWS
    985             {
    986                 HWND hwndDebug;
    987                 // debug: create a frame with the exact size
    988                 // of the _column_ (not the control), so this
    989                 // includes spacing
    990                 hwndDebug =
    991                    WinCreateWindow(pDlgData->hwndDlg,   // parent
    992                                 WC_STATIC,
    993                                 "",
    994                                 WS_VISIBLE | SS_FGNDFRAME,
    995                                 pTableDef->cpTable.x + pDlgData->ptlTotalOfs.x,
    996                                 pTableDef->cpTable.y + pDlgData->ptlTotalOfs.y,
    997                                 pTableDef->cpTable.cx,
    998                                 pTableDef->cpTable.cy,
    999                                 pDlgData->hwndDlg,   // owner
    1000                                 HWND_BOTTOM,
    1001                                 -1,
    1002                                 NULL,
    1003                                 NULL);
    1004                 winhSetPresColor(hwndDebug, PP_FOREGROUNDCOLOR, RGBCOL_BLUE);
    1005             }
    1006 #endif
    1007         }
    1008     }
    1009     else
    1010     {
    1011         // no nested table, but control:
    1012         pControlDef = (const CONTROLDEF *)pColumnDef->pvDefinition;
    1013         // pcp = &pColumnDef->cpControl;
    1014         pcszClass = pControlDef->pcszClass;
    1015         pcszTitle = pControlDef->pcszText;
    1016         flStyle = pControlDef->flStyle;
    1017 
    1018         x  =   pColumnDef->cpControl.x
    1019              + pDlgData->ptlTotalOfs.x;
    1020         cx =   pColumnDef->cpControl.cx;
    1021         y  =   pColumnDef->cpControl.y
    1022              + pDlgData->ptlTotalOfs.y;
    1023         cy =   pColumnDef->cpControl.cy;
    1024 
    1025         // now implement hacks for certain controls
    1026         switch ((ULONG)pControlDef->pcszClass)
    1027         {
    1028             case 0xffff0005L: // WC_STATIC:
    1029                 // change the title if this is a static with SS_BITMAP;
    1030                 // we have used a HBITMAP in there!
    1031                 if (    (    ((flStyle & 0x0F) == SS_BITMAP)
    1032                           || ((flStyle & 0x0F) == SS_ICON)
    1033                         )
    1034                    )
    1035                 {
    1036                     // change style flag to not use SS_BITMAP nor SS_ICON;
    1037                     // control creation fails otherwise (stupid, stupid PM)
    1038                     flOld = flStyle;
    1039                     flStyle = ((flStyle & ~0x0F) | SS_FGNDFRAME);
    1040                     pcszTitle = "";
    1041                     lHandleSet = (LHANDLE)pControlDef->pcszText;
    1042                 }
    1043             break;
    1044 
    1045             case 0xffff0002L:   // combobox
    1046             {
    1047                 if (flStyle & (CBS_DROPDOWN | CBS_DROPDOWNLIST))
    1048                 {
    1049                     // in ColumnCalcSizes, we have set pColumnDef->cpColumn.cy
    1050                     // to the height of a single line to get the position
    1051                     // calculations right...
    1052                     // present cy is pColumnDef->cpControl.cy,
    1053                     // the user-specified size of the expanded combo
    1054                     // present y is the bottom of the combo's entry field
    1055                     ULONG cyDelta = pColumnDef->cpControl.cy - pColumnDef->cpColumn.cy;
    1056                     _Pmpf((__FUNCTION__ ": combo cpColumn.cy = %d, cpControl.cy = %d",
    1057                             pColumnDef->cpColumn.cy,
    1058                             pColumnDef->cpControl.cy));
    1059                     _Pmpf(("   cyDelta = %d", cyDelta));
    1060                     y -=   cyDelta
    1061                          + 3 * pDlgData->cyBorder
    1062                          + pControlDef->duSpacing * FACTOR_Y;
    1063                     // cy += cyDelta;
    1064                 }
    1065             }
    1066             break;
    1067 
    1068             case 0xffff0006L:   // entry field
    1069             case 0xffff000AL:   // MLE:
    1070                 // the stupid entry field resizes itself if it has
    1071                 // the ES_MARGIN style, so correlate that too... dammit
    1072                 // V0.9.16 (2001-12-08) [umoeller]
    1073                 if (flStyle & ES_MARGIN)
    1074                 {
    1075                     LONG cxMargin = 3 * pDlgData->cxBorder;
    1076                     LONG cyMargin = 3 * pDlgData->cyBorder;
    1077 
    1078                     x += cxMargin;
    1079                     y += cyMargin;
    1080                     cx -= 2 * cxMargin;
    1081                     cy -= 2 * cyMargin;
    1082                     // cy -= cxMargin;
    1083                 }
    1084             break;
    1085         } // end switch ((ULONG)pControlDef->pcszClass)
    1086     }
    1087 
    1088     if (pControlDef)
    1089     {
    1090         // create something:
    1091 
    1092         // check if we have the window on the temp list from
    1093         // CalcAutoSize V0.9.20 (2002-08-10) [umoeller]
    1094         PLISTNODE pTempNode;
    1095         HWND hwndFound = NULLHANDLE;
    1096         FOR_ALL_NODES(&pDlgData->llTempControls, pTempNode)
    1097         {
    1098             HWND hwndThis = (HWND)pTempNode->pItemData;
    1099             if (WinQueryWindowUShort(hwndThis, QWS_ID) == pControlDef->usID)
    1100             {
    1101                 hwndFound
    1102                     = pColumnDef->hwndControl
    1103                     = hwndThis;
    1104 
    1105                 // resize it to what we really need
    1106                 WinSetWindowPos(hwndThis,
    1107                                 HWND_BOTTOM,
    1108                                 x,
    1109                                 y,
    1110                                 cx,
    1111                                 cy,
    1112                                 SWP_SIZE | SWP_MOVE | SWP_ZORDER);
    1113 
    1114                 lstRemoveNode(&pDlgData->llTempControls, pTempNode);
    1115                 break;
    1116             }
    1117         }
    1118 
    1119         if (    (!hwndFound)
    1120              && (!(pColumnDef->hwndControl = WinCreateWindow(pDlgData->hwndDlg,   // parent
    1121                                                              (PSZ)pcszClass,   // hacked
    1122                                                              (pcszTitle)   // hacked
    1123                                                                    ? (PSZ)pcszTitle
    1124                                                                    : "",
    1125                                                              flStyle,      // hacked
    1126                                                              x,
    1127                                                              y,
    1128                                                              cx,
    1129                                                              cy,
    1130                                                              pDlgData->hwndDlg,   // owner
    1131                                                              HWND_BOTTOM,
    1132                                                              pControlDef->usID,
    1133                                                              pControlDef->pvCtlData,
    1134                                                              NULL)))
    1135            )
    1136             arc = DLGERR_CANNOT_CREATE_CONTROL;
    1137 
    1138         if (!arc)
    1139         {
    1140             PCSZ pcszFont = pControlDef->pcszFont;
    1141                             // can be NULL, or CTL_COMMON_FONT
    1142             if (pcszFont == CTL_COMMON_FONT)
    1143                 pcszFont = pDlgData->pcszControlsFont;
    1144 
    1145             if (lHandleSet)
    1146             {
    1147                 // subclass the damn static
    1148                 if ((flOld & 0x0F) == SS_ICON)
    1149                     // this was a static:
    1150                     ctlPrepareStaticIcon(pColumnDef->hwndControl,
    1151                                          1);
    1152                 else
    1153                     // this was a bitmap:
    1154                     ctlPrepareStretchedBitmap(pColumnDef->hwndControl,
    1155                                               TRUE);
    1156 
    1157                 WinSendMsg(pColumnDef->hwndControl,
    1158                            SM_SETHANDLE,
    1159                            (MPARAM)lHandleSet,
    1160                            0);
    1161             }
    1162             else if (pcszFont)
    1163                 // we must set the font explicitly here...
    1164                 // doesn't always work with WinCreateWindow
    1165                 // presparams parameter, for some reason
    1166                 // V0.9.12 (2001-05-31) [umoeller]
    1167                 winhSetWindowFont(pColumnDef->hwndControl,
    1168                                   pcszFont);
    1169 
    1170 #ifdef DEBUG_DIALOG_WINDOWS
    1171             {
    1172                 HWND hwndDebug;
    1173                 // debug: create a frame with the exact size
    1174                 // of the _column_ (not the control), so this
    1175                 // includes spacing
    1176                 hwndDebug =
    1177                    WinCreateWindow(pDlgData->hwndDlg,   // parent
    1178                                 WC_STATIC,
    1179                                 "",
    1180                                 WS_VISIBLE | SS_FGNDFRAME,
    1181                                 pColumnDef->cpColumn.x + pDlgData->ptlTotalOfs.x,
    1182                                 pColumnDef->cpColumn.y + pDlgData->ptlTotalOfs.y,
    1183                                 pColumnDef->cpColumn.cx,
    1184                                 pColumnDef->cpColumn.cy,
    1185                                 pDlgData->hwndDlg,   // owner
    1186                                 HWND_BOTTOM,
    1187                                 -1,
    1188                                 NULL,
    1189                                 NULL);
    1190                 winhSetPresColor(hwndDebug, PP_FOREGROUNDCOLOR, RGBCOL_DARKGREEN);
    1191 
    1192                 // and another one for the control size
    1193                 hwndDebug =
    1194                    WinCreateWindow(pDlgData->hwndDlg,   // parent
    1195                                 WC_STATIC,
    1196                                 "",
    1197                                 WS_VISIBLE | SS_FGNDFRAME,
    1198                                 pColumnDef->cpControl.x + pDlgData->ptlTotalOfs.x,
    1199                                 pColumnDef->cpControl.y + pDlgData->ptlTotalOfs.y,
    1200                                 pColumnDef->cpControl.cx,
    1201                                 pColumnDef->cpControl.cy,
    1202                                 pDlgData->hwndDlg,   // owner
    1203                                 HWND_BOTTOM,
    1204                                 -1,
    1205                                 NULL,
    1206                                 NULL);
    1207                 winhSetPresColor(hwndDebug, PP_FOREGROUNDCOLOR, RGBCOL_RED);
    1208             }
    1209 #endif
    1210             // append window that was created
    1211             // V0.9.18 (2002-03-03) [umoeller]
    1212             if (pDlgData->pllControls)
    1213                 lstAppendItem(pDlgData->pllControls,
    1214                               (PVOID)pColumnDef->hwndControl);
    1215 
    1216             // if this is the first control with WS_TABSTOP,
    1217             // we give it the focus later
    1218             if (    (flStyle & WS_TABSTOP)
    1219                  && (!pDlgData->hwndFirstFocus)
    1220                )
    1221                 pDlgData->hwndFirstFocus = pColumnDef->hwndControl;
    1222 
    1223             // if this is the first default push button,
    1224             // go store it too
    1225             // V0.9.14 (2001-08-21) [umoeller]
    1226             if (    (!pDlgData->hwndDefPushbutton)
    1227                  && ((ULONG)pControlDef->pcszClass == 0xffff0003L)
    1228                  && (pControlDef->flStyle & BS_DEFAULT)
    1229                )
    1230                 pDlgData->hwndDefPushbutton = pColumnDef->hwndControl;
    1231         }
    1232         else
    1233             // V0.9.14 (2001-08-03) [umoeller]
    1234             arc = DLGERR_CANNOT_CREATE_CONTROL;
    1235     }
    1236 
    1237     return arc;
    1238 }
    1239 
    1240 /*
    1241  *@@ ProcessColumn:
    1242  *      processes a column, which per definition is either
    1243  *      a control or a nested subtable.
    1244  *
    1245  *      A column is part of a row, which in turn is part
    1246  *      of a table. There can be several columns in a row,
    1247  *      and several rows in a table.
    1248  *
    1249  *      Since tables may be specified as columns, it is
    1250  *      possible to produce complex dialog layouts by
    1251  *      nesting tables.
    1252  *
    1253  *      This does the following:
    1254  *
    1255  *      -- PROCESS_1_CALC_SIZES: size is taken from control def,
    1256  *         or for tables, this produces a recursive ProcessTable
    1257  *         call.
    1258  *         Preconditions: none.
    1259  *
    1260  *      -- PROCESS_4_CALC_POSITIONS: position of each column
    1261  *         is taken from *plX, which is increased by the
    1262  *         column width by this call.
    1263  *
    1264  *         Preconditions: Owning row must already have its
    1265  *         y position properly set, or we can't compute
    1266  *         ours. Besides, plX must point to the current X
    1267  *         in the row and will be incremented by the columns
    1268  *         size here.
    1269  *
    1270  *      -- PROCESS_5_CREATE_CONTROLS: well, creates the controls.
    1271  *
    1272  *         For tables, this recurses again. If the table has
    1273  *         a string assigned, this also produces a group box
    1274  *         after the recursion.
    1275  *
    1276  *@@changed V0.9.12 (2001-05-31) [umoeller]: added control data
    1277  *@@changed V0.9.12 (2001-05-31) [umoeller]: fixed font problems
    1278  *@@changed V0.9.20 (2002-08-08) [umoeller]: added support for aligning columns horizontally
    1279  */
    1280 
    1281 static APIRET ProcessColumn(PCOLUMNDEF pColumnDef,
    1282                             PROWDEF pOwningRow,          // in: current row from ProcessRow
    1283                             PROCESSMODE ProcessMode,     // in: processing mode (see ProcessAll)
    1284                             PLONG plX,                   // in/out: PROCESS_4_CALC_POSITIONS only
    1285                             PDLGPRIVATE pDlgData)
    1286 {
    1287     APIRET arc = NO_ERROR;
    1288 
    1289     pColumnDef->pOwningRow = pOwningRow;
    1290 
    1291     switch (ProcessMode)
    1292     {
    1293         /*
    1294          * PROCESS_1_CALC_SIZES:
    1295          *      step 1.
    1296          */
    1297 
    1298         case PROCESS_1_CALC_SIZES:
    1299             arc = ColumnCalcSizes(pColumnDef,
    1300                                   ProcessMode,
    1301                                   pDlgData);
    1302         break;
    1303 
    1304         /*
    1305          * PROCESS_2_CALC_SIZES_FROM_TABLES:
    1306          *
    1307          */
    1308 
    1309         case PROCESS_2_CALC_SIZES_FROM_TABLES:
    1310             if (pColumnDef->fIsNestedTable)
    1311             {
    1312                 PTABLEDEF pTableDef = (PTABLEDEF)pColumnDef->pvDefinition;
    1313                 if (!(arc = ProcessTable(pTableDef,
    1314                                          NULL,
    1315                                          PROCESS_2_CALC_SIZES_FROM_TABLES,
    1316                                          pDlgData)))
    1317                     ;
    1318             }
    1319             else
    1320             {
    1321                 // no nested table, but control:
    1322                 const CONTROLDEF *pControlDef = (const CONTROLDEF *)pColumnDef->pvDefinition;
    1323 
    1324                 if (    (pControlDef->szlDlgUnits.cx < -1)
    1325                      && (pControlDef->szlDlgUnits.cx >= -100)
    1326                    )
    1327                 {
    1328                     // other negative CX value:
    1329                     // this we ignored during PROCESS_1_CALC_SIZES
    1330                     // (see ColumnCalcSizes); now set it to the
    1331                     // percentage of the table width!
    1332                     ULONG cxThis = pOwningRow->pOwningTable->cpTable.cx
    1333                                     * -pControlDef->szlDlgUnits.cx
    1334                                     / 100;
    1335 
    1336                     // but the table already has spacing applied,
    1337                     // so reduce that
    1338                     pColumnDef->cpControl.cx = cxThis
    1339                                             - (2 * (pControlDef->duSpacing * FACTOR_X));
    1340 
    1341                     pColumnDef->cpColumn.cx = cxThis;
    1342 
    1343                     // now we might have to re-compute auto-size
    1344                     if (pControlDef->szlDlgUnits.cy == -1)
    1345                     {
    1346                         SIZEL   szlAuto;
    1347                         if (!(arc = CalcAutoSize(pControlDef,
    1348                                                  // now that we now the width,
    1349                                                  // use that!
    1350                                                  pColumnDef->cpControl.cx,
    1351                                                  &szlAuto,
    1352                                                  pDlgData)))
    1353                         {
    1354                             LONG cyColumnOld = pColumnDef->cpColumn.cy;
    1355                             LONG lDelta;
    1356                             PROWDEF pRowThis;
    1357 
    1358                             pColumnDef->cpControl.cy = szlAuto.cy;
    1359                             pColumnDef->cpColumn.cy =   szlAuto.cy
    1360                                                       + (2 * (pControlDef->duSpacing * FACTOR_Y));
    1361                         }
    1362                     }
    1363                 }
    1364 
    1365                 if (    (pControlDef->szlDlgUnits.cy < -1)
    1366                      && (pControlDef->szlDlgUnits.cy >= -100)
    1367                    )
    1368                 {
    1369                     // same thing for CY, but this time we
    1370                     // take the percentage of the row height
    1371                     ULONG cyThis = pOwningRow->cpRow.cy
    1372                                     * -pControlDef->szlDlgUnits.cy
    1373                                     / 100;
    1374 
    1375                     // but the table already has spacing applied,
    1376                     // so reduce that
    1377                     pColumnDef->cpControl.cy =   cyThis
    1378                                                - (2 * (pControlDef->duSpacing * FACTOR_Y));
    1379 
    1380                     pColumnDef->cpColumn.cy = cyThis;
    1381                 }
    1382             }
    1383         break;
    1384 
    1385         /*
    1386          * PROCESS_3_CALC_FINAL_TABLE_SIZES:
    1387          *
    1388          */
    1389 
    1390         case PROCESS_3_CALC_FINAL_TABLE_SIZES:
    1391         {
    1392             PTABLEDEF pOwningTable;
    1393             // re-run calc sizes since we now know all
    1394             // the auto-size items
    1395             arc = ColumnCalcSizes(pColumnDef,
    1396                                   ProcessMode,
    1397                                   pDlgData);
    1398 
    1399 
    1400             // now check if the table has TABLE_ALIGN_COLUMNS enabled
    1401             // (START_TABLE_ALIGN or START_GROUP_TABLE_ALIGN macros)
    1402             // and, if so, align the colums horizontally by making all
    1403             // columns as wide as the widest column in the table
    1404             // V0.9.20 (2002-08-08) [umoeller]
    1405             if (    (pOwningRow)
    1406                  && (pOwningTable = pOwningRow->pOwningTable)
    1407                  && (pOwningTable->flTable & TABLE_ALIGN_COLUMNS)
    1408                )
    1409             {
    1410                 // determine the index of this column in the current row
    1411                 ULONG ulMyIndex = lstIndexFromItem(&pOwningRow->llColumns,
    1412                                                    pColumnDef);
    1413                 if (ulMyIndex == -1)
    1414                     arc = DLGERR_INTEGRITY_BAD_COLUMN_INDEX;
    1415                 else
    1416                 {
    1417                     // find the widest column with this index in the table
    1418                     PLISTNODE pRowNode;
    1419                     FOR_ALL_NODES(&pOwningTable->llRows, pRowNode)
    1420                     {
    1421                         PROWDEF     pRowThis = (PROWDEF)pRowNode->pItemData;
    1422                         PCOLUMNDEF  pCorrespondingColumn;
    1423                         if (    (pCorrespondingColumn = (PCOLUMNDEF)lstItemFromIndex(&pRowThis->llColumns,
    1424                                                                                      ulMyIndex))
    1425                              && (pCorrespondingColumn->cpColumn.cx > pColumnDef->cpColumn.cx)
    1426                            )
    1427                             pColumnDef->cpColumn.cx = pCorrespondingColumn->cpColumn.cx;
    1428                     }
    1429                 }
    1430             }
    1431         }
    1432         break;
    1433 
    1434         /*
    1435          * PROCESS_4_CALC_POSITIONS:
    1436          *      step 4.
    1437          */
    1438 
    1439         case PROCESS_4_CALC_POSITIONS:
    1440             arc = ColumnCalcPositions(pColumnDef,
    1441                                       pOwningRow,
    1442                                       plX,
    1443                                       pDlgData);
    1444         break;
    1445 
    1446         /*
    1447          * PROCESS_5_CREATE_CONTROLS:
    1448          *      step 5.
    1449          */
    1450 
    1451         case PROCESS_5_CREATE_CONTROLS:
    1452             arc = ColumnCreateControls(pColumnDef,
    1453                                        pDlgData);
    1454         break;
    1455     }
    1456 
    1457     return arc;
    1458 }
    1459 
    1460 /*
    1461  *@@ ProcessRow:
    1462  *      level-3 procedure (called from ProcessTable),
    1463  *      which in turn calls ProcessColumn for each column
    1464  *      in the row.
    1465  *
    1466  *      See ProcessAll for the meaning of ProcessMode.
    1467  */
    1468 
    1469 static APIRET ProcessRow(PROWDEF pRowDef,
    1470                          PTABLEDEF pOwningTable,     // in: current table from ProcessTable
    1471                          PROCESSMODE ProcessMode,    // in: processing mode (see ProcessAll)
    1472                          PLONG plY,                  // in/out: current y position (decremented)
    1473                          PDLGPRIVATE pDlgData)
    1474 {
    1475     APIRET  arc = NO_ERROR;
    1476     LONG    lX;
    1477     PLISTNODE pNode;
    1478 
    1479     pRowDef->pOwningTable = pOwningTable;
    1480 
    1481     switch (ProcessMode)
    1482     {
    1483         case PROCESS_1_CALC_SIZES:
    1484         case PROCESS_3_CALC_FINAL_TABLE_SIZES:
    1485             pRowDef->cpRow.cx = 0;
    1486             pRowDef->cpRow.cy = 0;
    1487         break;
    1488 
    1489         case PROCESS_4_CALC_POSITIONS:
    1490             // set up x and y so that the columns can
    1491             // base on that
    1492             pRowDef->cpRow.x = pOwningTable->cpTable.x;
    1493             // decrease y by row height
    1494             *plY -= pRowDef->cpRow.cy;
    1495             // and use that for our bottom position
    1496             pRowDef->cpRow.y = *plY;
    1497 
    1498             // set lX to left of row; used by column calls below
    1499             lX = pRowDef->cpRow.x;
    1500         break;
    1501     }
    1502 
    1503     FOR_ALL_NODES(&pRowDef->llColumns, pNode)
    1504     {
    1505         PCOLUMNDEF  pColumnDefThis = (PCOLUMNDEF)pNode->pItemData;
    1506 
    1507         if (!(arc = ProcessColumn(pColumnDefThis, pRowDef, ProcessMode, &lX, pDlgData)))
    1508         {
    1509             if (    (ProcessMode == PROCESS_1_CALC_SIZES)
    1510                  || (ProcessMode == PROCESS_3_CALC_FINAL_TABLE_SIZES)
    1511                )
    1512             {
    1513                 // row width = sum of all columns
    1514                 pRowDef->cpRow.cx += pColumnDefThis->cpColumn.cx;
    1515 
    1516                 // row height = maximum height of a column
    1517                 if (pRowDef->cpRow.cy < pColumnDefThis->cpColumn.cy)
    1518                     pRowDef->cpRow.cy = pColumnDefThis->cpColumn.cy;
    1519             }
    1520         }
    1521         // we should stop on errors V0.9.20 (2002-08-10) [umoeller]
    1522         else
    1523             break;
    1524     }
    1525 
    1526     return arc;
    1527 }
    1528 
    1529 /*
    1530  *@@ ProcessTable:
    1531  *      level-2 procedure (called from ProcessAll),
    1532  *      which in turn calls ProcessRow for each row
    1533  *      in the table (which in turn calls ProcessColumn
    1534  *      for each column in the row).
    1535  *
    1536  *      See ProcessAll for the meaning of ProcessMode.
    1537  *
    1538  *      This routine is a bit sick because it can even be
    1539  *      called recursively from ProcessColumn (!) if a
    1540  *      nested table is found in a COLUMNDEF.
    1541  *
    1542  *      With PROCESS_4_CALC_POSITIONS, pptl must specify
    1543  *      the lower left corner of the table. For the
    1544  *      root call, this will be {0, 0}; for nested calls,
    1545  *      this must be the lower left corner of the column
    1546  *      to which the nested table belongs.
    1547  *
    1548  */
    1549 
    1550 static APIRET ProcessTable(PTABLEDEF pTableDef,
    1551                            const CONTROLPOS *pcpTable,       // in: table position with PROCESS_4_CALC_POSITIONS
    1552                            PROCESSMODE ProcessMode,          // in: processing mode (see ProcessAll)
    1553                            PDLGPRIVATE pDlgData)
    1554 {
    1555     APIRET  arc = NO_ERROR;
    1556     LONG    lY;
    1557     PLISTNODE pNode;
    1558 
    1559     switch (ProcessMode)
    1560     {
    1561         case PROCESS_1_CALC_SIZES:
    1562             pTableDef->cpTable.cx = 0;
    1563             pTableDef->cpTable.cy = 0;
    1564         break;
    1565 
    1566         case PROCESS_3_CALC_FINAL_TABLE_SIZES:
    1567             pTableDef->cpTable.cx = 0;
    1568             pTableDef->cpTable.cy = 0;
    1569         break;
    1570 
    1571         case PROCESS_4_CALC_POSITIONS:
    1572             pTableDef->cpTable.x = pcpTable->x;
    1573             pTableDef->cpTable.y = pcpTable->y;
    1574 
    1575             // start the rows on top
    1576             lY = pcpTable->y + pTableDef->cpTable.cy;
    1577         break;
    1578     }
    1579 
    1580     FOR_ALL_NODES(&pTableDef->llRows, pNode)
    1581     {
    1582         PROWDEF pRowDefThis = (PROWDEF)pNode->pItemData;
    1583 
    1584         if (!(arc = ProcessRow(pRowDefThis, pTableDef, ProcessMode, &lY, pDlgData)))
    1585         {
    1586             if (    (ProcessMode == PROCESS_1_CALC_SIZES)
    1587                  || (ProcessMode == PROCESS_3_CALC_FINAL_TABLE_SIZES)
    1588                )
    1589             {
    1590                 // table width = maximum width of a row
    1591                 if (pTableDef->cpTable.cx < pRowDefThis->cpRow.cx)
    1592                     pTableDef->cpTable.cx = pRowDefThis->cpRow.cx;
    1593 
    1594                 // table height = sum of all rows
    1595                 pTableDef->cpTable.cy += pRowDefThis->cpRow.cy;
    1596             }
    1597         }
    1598         else
    1599             break;
    1600     }
    1601 
    1602     return arc;
    1603 }
    1604 
    1605 /*
    1606  *@@ ProcessAll:
    1607  *      level-1 procedure, which in turn calls ProcessTable
    1608  *      for each root-level table found (which in turn
    1609  *      calls ProcessRow for each row in the table, which
    1610  *      in turn calls ProcessColumn for each column in
    1611  *      the row).
    1612  *
    1613  *      The first trick to formatting is that ProcessAll will
    1614  *      get FIVE times, thus going down the entire tree FIVE
    1615  *      times, with ProcessMode being set to one of the
    1616  *      following for each call (in this order):
    1617  *
    1618  *      --  PROCESS_1_CALC_SIZES: calculates the preliminary
    1619  *          sizes of all tables, rows, columns, and controls
    1620  *          except those controls that have specified that
    1621  *          their size should depend on others.
    1622  *
    1623  *      --  PROCESS_2_CALC_SIZES_FROM_TABLES: calculates the
    1624  *          sizes of those controls that want to depend on
    1625  *          others.
    1626  *
    1627  *      --  PROCESS_3_CALC_FINAL_TABLE_SIZES: since the table
    1628  *          and row sizes might have changed during
    1629  *          PROCESS_2_CALC_SIZES_FROM_TABLES, we need to re-run
    1630  *          to re-calculate the size of all rows and tables.
    1631  *          After this first call, we know _all_ the sizes
    1632  *          and can then calculate the positions.
    1633  *
    1634  *      --  PROCESS_4_CALC_POSITIONS: calculates the positions
    1635  *          based on the sizes calculated before.
    1636  *
    1637  *      --  PROCESS_5_CREATE_CONTROLS: creates the controls with the
    1638  *          positions and sizes calculated before.
    1639  *
    1640  *      The second trick is the precondition that tables may
    1641  *      nest by allowing another table definition in a column.
    1642  *      This way we can recurse from ProcessColumn back into
    1643  *      ProcessTable and thus know the size and position of a
    1644  *      nested table column just as if it were a regular control.
    1645  */
    1646 
    1647 static APIRET ProcessAll(PDLGPRIVATE pDlgData,
    1648                          PROCESSMODE ProcessMode)
    1649 {
    1650     APIRET arc = NO_ERROR;
    1651     PLISTNODE pNode;
    1652     CONTROLPOS cpTable;
    1653     ZERO(&cpTable);
    1654 
    1655     switch (ProcessMode)
    1656     {
    1657         case PROCESS_1_CALC_SIZES:
    1658         case PROCESS_3_CALC_FINAL_TABLE_SIZES:
    1659             pDlgData->szlClient.cx = 0;
    1660             pDlgData->szlClient.cy = 0;
    1661         break;
    1662 
    1663         case PROCESS_4_CALC_POSITIONS:
    1664             // start with the table on top
    1665             cpTable.y = pDlgData->szlClient.cy;
    1666         break;
    1667     }
    1668 
    1669     FOR_ALL_NODES(&pDlgData->llTables, pNode)
    1670     {
    1671         PTABLEDEF pTableDefThis = (PTABLEDEF)pNode->pItemData;
    1672 
    1673         if (ProcessMode == PROCESS_4_CALC_POSITIONS)
    1674         {
    1675             cpTable.x = 0;
    1676             cpTable.y -= pTableDefThis->cpTable.cy;
    1677         }
    1678 
    1679         if (!(arc = ProcessTable(pTableDefThis,
    1680                                  &cpTable,      // start pos
    1681                                  ProcessMode,
    1682                                  pDlgData)))
    1683         {
    1684             if (    (ProcessMode == PROCESS_2_CALC_SIZES_FROM_TABLES)
    1685                  || (ProcessMode == PROCESS_3_CALC_FINAL_TABLE_SIZES)
    1686                )
    1687             {
    1688                 // all sizes have now been computed:
    1689                 pDlgData->szlClient.cx += pTableDefThis->cpTable.cx;
    1690                 pDlgData->szlClient.cy += pTableDefThis->cpTable.cy;
    1691             }
    1692         }
    1693         // we should stop on errors V0.9.20 (2002-08-10) [umoeller]
    1694         else
    1695             break;
    1696     }
    1697 
    1698     return arc;
    1699 }
    1700 
    1701 /*
    1702  *@@ CreateColumn:
    1703  *
    1704  */
    1705 
    1706 static APIRET CreateColumn(PROWDEF pCurrentRow,
    1707                            BOOL fIsNestedTable,
    1708                            PVOID pvDefinition,       // in: either PTABLEDEF or PCONTROLDEF
    1709                            PCOLUMNDEF *ppColumnDef)    // out: new COLUMNDEF
    1710 {
    1711     APIRET arc = NO_ERROR;
    1712 
    1713     if (!pCurrentRow)
    1714         arc = DLGERR_CONTROL_BEFORE_ROW;
    1715     else
    1716     {
    1717         // append the control def
    1718         if (!pvDefinition)
    1719             arc = DLGERR_NULL_CTL_DEF;
    1720         else
    1721         {
    1722             // create column and store ctl def
    1723             PCOLUMNDEF pColumnDef;
    1724             if (!(pColumnDef = NEW(COLUMNDEF)))
    1725                 arc = ERROR_NOT_ENOUGH_MEMORY;
    1726             else
    1727             {
    1728                 memset(pColumnDef, 0, sizeof(COLUMNDEF));
    1729                 pColumnDef->pOwningRow = pCurrentRow;
    1730                 pColumnDef->fIsNestedTable = fIsNestedTable;
    1731                 pColumnDef->pvDefinition = pvDefinition;
    1732 
    1733                 *ppColumnDef = pColumnDef;
    1734             }
    1735         }
    1736     }
    1737 
    1738     return arc;
    1739 }
    1740 
    1741 /*
    1742  *@@ FreeTable:
    1743  *      frees the specified table and recurses
    1744  *      into nested tables, if necessary.
    1745  *
    1746  *      This was added with V0.9.14 to fix the
    1747  *      bad memory leaks with nested tables.
    1748  *
    1749  *@@added V0.9.14 (2001-08-01) [umoeller]
    1750  */
    1751 
    1752 static VOID FreeTable(PTABLEDEF pTable)
    1753 {
    1754     // for each table, clean up the rows
    1755     PLISTNODE pRowNode;
    1756     FOR_ALL_NODES(&pTable->llRows, pRowNode)
    1757     {
    1758         PROWDEF pRow = (PROWDEF)pRowNode->pItemData;
    1759 
    1760         // for each row, clean up the columns
    1761         PLISTNODE pColumnNode;
    1762         FOR_ALL_NODES(&pRow->llColumns, pColumnNode)
    1763         {
    1764             PCOLUMNDEF pColumn = (PCOLUMNDEF)pColumnNode->pItemData;
    1765 
    1766             if (pColumn->fIsNestedTable)
    1767             {
    1768                 // nested table: recurse!
    1769                 PTABLEDEF pNestedTable = (PTABLEDEF)pColumn->pvDefinition;
    1770                 FreeTable(pNestedTable);
    1771             }
    1772 
    1773             free(pColumn);
    1774         }
    1775         lstClear(&pRow->llColumns);
    1776 
    1777         free(pRow);
    1778     }
    1779     lstClear(&pTable->llRows);
    1780 
    1781     free(pTable);
    1782 }
    1783 
    1784 /* ******************************************************************
    1785  *
    1786  *   Dialog formatter engine
    1787  *
    1788  ********************************************************************/
    1789 
    1790 /*
    1791  *@@ STACKITEM:
    1792  *
    1793  */
    1794 
    1795 typedef struct _STACKITEM
    1796 {
    1797     PTABLEDEF       pLastTable;
    1798     PROWDEF         pLastRow;
    1799 
    1800 } STACKITEM, *PSTACKITEM;
    1801 
    1802 /*
    1803  *@@ Dlg0_Init:
    1804  *
    1805  *@@added V0.9.15 (2001-08-26) [umoeller]
    1806  *@@changed V0.9.18 (2002-03-03) [umoeller]: added pllWindows
    1807  *@@changed V0.9.19 (2002-04-24) [umoeller]: added resolution correlation
    1808  */
    1809 
    1810 static APIRET Dlg0_Init(PDLGPRIVATE *ppDlgData,
    1811                         PCSZ pcszControlsFont,
    1812                         PLINKLIST pllControls)
    1813 {
    1814     PDLGPRIVATE     pDlgData;
    1815     POINTL          ptl = {100, 100};
    1816 
    1817     if (!(pDlgData = NEW(DLGPRIVATE)))
    1818         return (ERROR_NOT_ENOUGH_MEMORY);
    1819     ZERO(pDlgData);
    1820     lstInit(&pDlgData->llTables, FALSE);
    1821 
    1822     lstInit(&pDlgData->llTempControls, FALSE);     // V0.9.20 (2002-08-10) [umoeller]
    1823 
    1824     if (pllControls)
    1825         pDlgData->pllControls = pllControls;
    1826 
    1827     pDlgData->pcszControlsFont = pcszControlsFont;
    1828 
    1829     // cache these now too V0.9.19 (2002-04-17) [umoeller]
    1830     pDlgData->cxBorder = WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
    1831     pDlgData->cyBorder = WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);
    1832 
    1833     // check how many pixels we get out of the
    1834     // dlgunits (100/100) for mapping all sizes
    1835     // V0.9.19 (2002-04-24) [umoeller]
    1836     if (WinMapDlgPoints(NULLHANDLE,
    1837                         &ptl,
    1838                         1,
    1839                         TRUE))
    1840     {
    1841         // this worked:
    1842         // for 1024x768, I get 200/250 out of the above,
    1843         // so calculate a factor from that; we multiply
    1844         // szlDlgUnits with this factor when calculating
    1845         // the sizes
    1846         pDlgData->dFactorX = (double)ptl.x / (double)100;       // 2   on 1024x768
    1847         pDlgData->dFactorY = (double)ptl.y / (double)100;       // 2.5 on 1024x768
    1848     }
    1849     else
    1850     {
    1851         // didn't work:
    1852         pDlgData->dFactorX = 2;
    1853         pDlgData->dFactorY = 2.5;
    1854     }
    1855 
    1856     *ppDlgData = pDlgData;
    1857 
    1858     return NO_ERROR;
    1859 }
    1860 
    1861 /*
    1862  *@@ Dlg1_ParseTables:
    1863  *
    1864  *@@added V0.9.15 (2001-08-26) [umoeller]
    1865  */
    1866 
    1867 static APIRET Dlg1_ParseTables(PDLGPRIVATE pDlgData,
    1868                                PCDLGHITEM paDlgItems,      // in: definition array
    1869                                ULONG cDlgItems)           // in: array item count (NOT array size)
    1870 {
    1871     APIRET      arc = NO_ERROR;
    1872 
    1873     LINKLIST    llStack;
    1874     ULONG       ul;
    1875     PTABLEDEF   pCurrentTable = NULL;
    1876     PROWDEF     pCurrentRow = NULL;
    1877 
    1878     lstInit(&llStack, TRUE);      // this is our stack for nested table definitions
    1879 
    1880     for (ul = 0;
    1881          ul < cDlgItems;
    1882          ul++)
    1883     {
    1884         PCDLGHITEM   pItemThis = &paDlgItems[ul];
    1885 
    1886         switch (pItemThis->Type)
    1887         {
    1888             /*
    1889              * TYPE_START_NEW_TABLE:
    1890              *
    1891              */
    1892 
    1893             case TYPE_START_NEW_TABLE:
    1894             {
    1895                 // root table or nested?
    1896                 BOOL fIsRoot = (pCurrentTable == NULL);
    1897 
    1898                 // push the current table on the stack
    1899                 PSTACKITEM pStackItem;
    1900                 if (!(pStackItem = NEW(STACKITEM)))
    1901                 {
    1902                     arc = ERROR_NOT_ENOUGH_MEMORY;
    1903                     break;
    1904                 }
    1905                 else
    1906                 {
    1907                     pStackItem->pLastTable = pCurrentTable;
    1908                     pStackItem->pLastRow = pCurrentRow;
    1909                     lstPush(&llStack, pStackItem);
    1910                 }
    1911 
    1912                 // create new table
    1913                 if (!(pCurrentTable = NEW(TABLEDEF)))
    1914                     arc = ERROR_NOT_ENOUGH_MEMORY;
    1915                 else
    1916                 {
    1917                     ZERO(pCurrentTable);
    1918 
    1919                     lstInit(&pCurrentTable->llRows, FALSE);
    1920 
    1921                     // if control specified: store it (this will become a PM group)
    1922                     pCurrentTable->pCtlDef = pItemThis->pCtlDef;        // can be NULL for plain table
    1923 
    1924                     pCurrentTable->flTable = pItemThis->fl;         // V0.9.20 (2002-08-08) [umoeller]
    1925 
    1926                     if (fIsRoot)
    1927                         // root table:
    1928                         // append to dialog data list
    1929                         lstAppendItem(&pDlgData->llTables, pCurrentTable);
    1930                     else
    1931                     {
    1932                         // nested table:
    1933                         // create "table" column for this
    1934                         PCOLUMNDEF pColumnDef;
    1935                         if (!(arc = CreateColumn(pCurrentRow,
    1936                                                  TRUE,        // nested table
    1937                                                  pCurrentTable,
    1938                                                  &pColumnDef)))
    1939                         {
    1940                             pCurrentTable->pOwningColumn = pColumnDef;
    1941                             lstAppendItem(&pCurrentRow->llColumns,
    1942                                           pColumnDef);
    1943                         }
    1944                     }
    1945                 }
    1946 
    1947                 pCurrentRow = NULL;
    1948             }
    1949             break;
    1950 
    1951             /*
    1952              * TYPE_START_NEW_ROW:
    1953              *
    1954              */
    1955 
    1956             case TYPE_START_NEW_ROW:
    1957             {
    1958                 if (!pCurrentTable)
    1959                     arc = DLGERR_ROW_BEFORE_TABLE;
    1960                 else
    1961                 {
    1962                     // create new row
    1963                     if (!(pCurrentRow = NEW(ROWDEF)))
    1964                         arc = ERROR_NOT_ENOUGH_MEMORY;
    1965                     else
    1966                     {
    1967                         ZERO(pCurrentRow);
    1968 
    1969                         pCurrentRow->pOwningTable = pCurrentTable;
    1970                         lstInit(&pCurrentRow->llColumns, FALSE);
    1971 
    1972                         pCurrentRow->flRowFormat = pItemThis->fl;
    1973 
    1974                         lstAppendItem(&pCurrentTable->llRows, pCurrentRow);
    1975                     }
    1976                 }
    1977             }
    1978             break;
    1979 
    1980             /*
    1981              * TYPE_CONTROL_DEF:
    1982              *
    1983              */
    1984 
    1985             case TYPE_CONTROL_DEF:
    1986             {
    1987                 PCOLUMNDEF pColumnDef;
    1988                 if (!(arc = CreateColumn(pCurrentRow,
    1989                                          FALSE,        // no nested table
    1990                                          (PVOID)pItemThis->pCtlDef,
    1991                                          &pColumnDef)))
    1992                     lstAppendItem(&pCurrentRow->llColumns,
    1993                                   pColumnDef);
    1994             }
    1995             break;
    1996 
    1997             /*
    1998              * TYPE_END_TABLE:
    1999              *
    2000              */
    2001 
    2002             case TYPE_END_TABLE:
    2003             {
    2004                 PLISTNODE pNode = lstPop(&llStack);
    2005                 if (!pNode)
    2006                     // nothing on the stack:
    2007                     arc = DLGERR_TOO_MANY_TABLES_CLOSED;
    2008                 else
    2009                 {
    2010                     PSTACKITEM pStackItem = (PSTACKITEM)pNode->pItemData;
    2011                     pCurrentTable = pStackItem->pLastTable;
    2012                     pCurrentRow = pStackItem->pLastRow;
    2013 
    2014                     lstRemoveNode(&llStack, pNode);
    2015                 }
    2016             }
    2017             break;
    2018 
    2019             default:
    2020                 arc = DLGERR_INVALID_CODE;
    2021         }
    2022 
    2023         if (arc)
    2024             break;
    2025     }
    2026 
    2027     if ((!arc) && (lstCountItems(&llStack)))
    2028         arc = DLGERR_TABLE_NOT_CLOSED;
    2029 
    2030     lstClear(&llStack);
    2031 
    2032     return arc;
    2033 }
    2034 
    2035 /*
    2036  *@@ Dlg2_CalcSizes:
    2037  *
    2038  *      After this, DLGPRIVATE.szlClient is valid.
    2039  *
    2040  *@@added V0.9.15 (2001-08-26) [umoeller]
    2041  */
    2042 
    2043 static APIRET Dlg2_CalcSizes(PDLGPRIVATE pDlgData)
    2044 {
    2045     APIRET arc;
    2046 
    2047     if (!(arc = ProcessAll(pDlgData,
    2048                            PROCESS_1_CALC_SIZES)))
    2049                      // this goes into major recursions...
    2050         // run again to compute sizes that depend on tables
    2051         if (!(arc = ProcessAll(pDlgData,
    2052                                PROCESS_2_CALC_SIZES_FROM_TABLES)))
    2053             arc = ProcessAll(pDlgData,
    2054                              PROCESS_3_CALC_FINAL_TABLE_SIZES);
    2055 
    2056     // free the cached font resources that
    2057     // might have been created here
    2058     if (pDlgData->hps)
    2059     {
    2060         if (pDlgData->lcidLast)
    2061         {
    2062             GpiSetCharSet(pDlgData->hps, LCID_DEFAULT);
    2063             GpiDeleteSetId(pDlgData->hps, pDlgData->lcidLast);
    2064         }
    2065         WinReleasePS(pDlgData->hps);
    2066     }
    2067 
    2068     return arc;
    2069 }
    2070 
    2071 /*
    2072  *@@ Dlg3_PositionAndCreate:
    2073  *
    2074  *@@added V0.9.15 (2001-08-26) [umoeller]
    2075  *@@changed V0.9.15 (2001-08-26) [umoeller]: BS_DEFAULT for other than first button was ignored, fixed
    2076  *@@changed V0.9.20 (2002-08-10) [umoeller]: return code checking was missing, fixed
    2077  */
    2078 
    2079 static APIRET Dlg3_PositionAndCreate(PDLGPRIVATE pDlgData,
    2080                                      HWND *phwndFocusItem)       // out: item to give focus to
    2081 {
    2082     APIRET arc = NO_ERROR;
    2083 
    2084     /*
    2085      *  5) compute _positions_ of all controls
    2086      *
    2087      */
    2088 
    2089     // this was missing a return code, fixed V0.9.20 (2002-08-10) [umoeller]
    2090     if (!(arc = ProcessAll(pDlgData,
    2091                            PROCESS_4_CALC_POSITIONS)))
    2092     {
    2093         /*
    2094          *  6) create control windows, finally
    2095          *
    2096          */
    2097 
    2098         pDlgData->ptlTotalOfs.x = DLG_OUTER_SPACING_X * FACTOR_X;
    2099         pDlgData->ptlTotalOfs.y = DLG_OUTER_SPACING_Y * FACTOR_Y;
    2100 
    2101         // this was missing a return code, fixed V0.9.20 (2002-08-10) [umoeller]
    2102         if (!(arc = ProcessAll(pDlgData,
    2103                                PROCESS_5_CREATE_CONTROLS)))
    2104         {
    2105             if (pDlgData->hwndDefPushbutton)
    2106             {
    2107                 // we had a default pushbutton:
    2108                 // go set it V0.9.14 (2001-08-21) [umoeller]
    2109                 WinSetWindowULong(pDlgData->hwndDlg,
    2110                                   QWL_DEFBUTTON,
    2111                                   pDlgData->hwndDefPushbutton);
    2112                 *phwndFocusItem = pDlgData->hwndDefPushbutton;
    2113                         // V0.9.15 (2001-08-26) [umoeller]
    2114             }
    2115             else
    2116                 *phwndFocusItem = (pDlgData->hwndFirstFocus)
    2117                                     ? pDlgData->hwndFirstFocus
    2118                                     : pDlgData->hwndDlg;
    2119         }
    2120     }
    2121 
    2122     return arc;
    2123 }
    2124 
    2125 /*
    2126  *@@ Dlg9_Cleanup:
    2127  *
    2128  *@@added V0.9.15 (2001-08-26) [umoeller]
    2129  */
    2130 
    2131 static VOID Dlg9_Cleanup(PDLGPRIVATE *ppDlgData)
    2132 {
    2133     PDLGPRIVATE pDlgData;
    2134     if (    (ppDlgData)
    2135          && (pDlgData = *ppDlgData)
    2136        )
    2137     {
    2138         PLISTNODE pTableNode;
    2139 
    2140         // in any case, clean up our mess:
    2141 
    2142         // clean up the tables
    2143         FOR_ALL_NODES(&pDlgData->llTables, pTableNode)
    2144         {
    2145             PTABLEDEF pTable = (PTABLEDEF)pTableNode->pItemData;
    2146 
    2147             FreeTable(pTable);
    2148                     // this may recurse for nested tables
    2149         }
    2150 
    2151         lstClear(&pDlgData->llTempControls);     // V0.9.20 (2002-08-10) [umoeller]
    2152 
    2153         lstClear(&pDlgData->llTables);
    2154 
    2155         free(pDlgData);
    2156 
    2157         *ppDlgData = NULL;
    2158     }
    2159 }
    2160 
    2161 /* ******************************************************************
    2162  *
    2163  *   Dialog formatter entry points
    2164  *
    2165  ********************************************************************/
    2166 
    2167 /*
    2168  *@@ dlghCreateDlg:
    2169  *      replacement for WinCreateDlg/WinLoadDlg for creating a
    2170  *      dialog from a settings array in memory, which is
    2171  *      formatted automatically.
    2172  *
    2173  *      This does NOT use regular dialog templates from
    2174  *      module resources. Instead, you pass in an array
    2175  *      of DLGHITEM structures, which define the controls
    2176  *      and how they are to be formatted.
    2177  *
    2178  *      The main advantage compared to dialog resources is
    2179  *      that with this function, you will never have to
    2180  *      define control _positions_. Instead, you only specify
    2181  *      the control _sizes_, and all positions are computed
    2182  *      automatically here. Even better, for many controls,
    2183  *      auto-sizing is supported according to the control's
    2184  *      text (e.g. for statics and checkboxes). This is
    2185  *      quite similar to HTML tables.
    2186  *
    2187  *      A regular standard dialog would use something like
    2188  *
    2189  +          FCF_TITLEBAR | FCF_SYSMENU | FCF_DLGBORDER | FCF_NOBYTEALIGN | FCF_CLOSEBUTTON
    2190  *
    2191  *      for flCreateFlags. To make the dlg sizeable, specify
    2192  *      FCF_SIZEBORDER instead of FCF_DLGBORDER.
    2193  *
    2194  *      dialog.h defines FCF_FIXED_DLG and FCF_SIZEABLE_DLG
    2195  *      to make this more handy.
    2196  *
    2197  *      <B>Usage:</B>
    2198  *
    2199  *      Like WinLoadDlg, this creates a standard WC_FRAME and
    2200  *      subclasses it with fnwpMyDlgProc. It then sends WM_INITDLG
    2201  *      to the dialog with pCreateParams in mp2.
    2202  *
    2203  *      If this func returns no error, you can then use
    2204  *      WinProcessDlg with the newly created dialog as usual. In
    2205  *      your dlg proc, use WinDefDlgProc as usual.
    2206  *
    2207  *      There is NO run-time overhead for either code or memory
    2208  *      after dialog creation; after this function returns, the
    2209  *      dialog is a standard dialog as if loaded from WinLoadDlg.
    2210  *      The array of DLGHITEM structures defines how the
    2211  *      dialog is set up. All this is ONLY used by this function
    2212  *      and NOT needed after the dialog has been created.
    2213  *
    2214  *      In DLGHITEM, the "Type" field determines what this
    2215  *      structure defines. A number of handy macros have been
    2216  *      defined to make this easier and to provide type-checking
    2217  *      at compile time. See dialog.h for more.
    2218  *
    2219  *      Essentially, such a dialog item operates similarly to
    2220  *      HTML tables. There are rows and columns in the table,
    2221  *      and each control which is specified must be a column
    2222  *      in some table. Tables may also nest (see below).
     110 *@@gloss: dlg_using_macros Using the Dialog Formatter Macros
    2223111 *
    2224112 *      The DLGHITEM macros are:
     
    2357245 +          º                                   º
    2358246 +          ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
     247 */
     248
     249/*
     250 *@@gloss: dlg_boxmodel Dialog formatter box model
     251 *
     252 *      We now use the CSS box model for the dialog
     253 *      formatter (V0.9.21).
     254 *
     255 +      ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
     256 +      ³  margin                  ³
     257 +      ³  ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿  ³
     258 +      ³  ³# border ###########³  ³
     259 +      ³  ³##ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿##³  ³
     260 +      ³  ³##³  padding     ³##³  ³
     261 +      ³  ³##³  ÚÄÄÄÄÄÄÄÄÄ¿ ³##³  ³
     262 +      ³  ³##³  ³ content ³ ³##³  ³
     263 +      ³  ³##³  ÀÄÄÄÄÄÄÄÄÄÙ ³##³  ³
     264 +      ³  ³##³              ³##³  ³
     265 +      ³  ³##ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ##³  ³
     266 +      ³  ³####################³  ³
     267 +      ³  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ  ³
     268 +      ³                          ³
     269 +      ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
     270 *
     271 *      See "http://www.w3.org/TR/REC-CSS1#formatting-model".
     272 *
     273 *      Remark on the box model for subtables:
     274 *
     275 *      We do not want to apply spacing twice for nested tables. This
     276 *      is especially important for group boxes (i.e. tables which
     277 *      have a PM group static control created around them). As a
     278 *      result, the definition is that ONLY COLUMNS HAVE SPACING,
     279 *      EVER. Neither tables nor rows do.
     280 */
     281
     282/*
     283 *@@gloss: dlg_algorithm Dialog formatter algorithm
     284 *
     285 *      See @dlg_boxmodel for information about how the
     286 *      rectangles are defined.
     287 *
     288 *      The dialog formatter allows you to specify PM dialog layouts
     289 *      as nested tables, without having to specify a single control
     290 *      position. In fact, it is impossible to give the dialog
     291 *      formatter fixed positions. Instead, you give the formatter
     292 *      the control _sizes_, and everything is layed out automatically.
     293 *      You may even have the formatter compute the sizes automatically
     294 *      based on the control classes and values; it is possible to
     295 *      create dialogs without specifying a single size also.
     296 *
     297 *      There are several tricks to how this works.
     298 *
     299 *      1)  The dialog is supposed to consist of one outer table,
     300 *          which in turn has rows. The rows in turn have columns.
     301 *          We process the outer table by iterating over its rows
     302 *          (see ProcessTable). For each row, we iterate over the
     303 *          columns (see ProcessRow). Most of the processing then
     304 *          actually occurs in ProcessColumn.
     305 *
     306 *      2)  Each column can contain a PM control, as specified in a
     307 *          CONTROLDEF structure on input. Alternatively, a column
     308 *          can be a nested subtable (with more rows and columns).
     309 *          If so, ProcessColumn recurses back into ProcessTable
     310 *          (which again goes into ProcessRow and ProcessColumn).
     311 *          There is no limit to how deep tables may nest, except
     312 *          the stack size of the current thread. ;-)
     313 *
     314 *      3)  This whole recursive iteration is performed several times.
     315 *          In fact, we run through the entire data up to seven times
     316 *          presently. Only in the last run, we actually create the
     317 *          controls. Details follow.
     318 *
     319 *      4)  We have sophisticated means for computing the size of
     320 *          certain controls automatically. See CalcAutoSize.
     321 *
     322 *      The algorithm used here has been greatly reworked with V0.9.21.
     323 *      Essentially, the new trick is that we first compute all widths
     324 *      (which requires several iterations since widths may now inherit
     325 *      from each other), then all heights (which, for many controls,
     326 *      depend on the widths), then all positions. The previous approach
     327 *      to calculate widths and heights at the same time has turned out
     328 *      to not work very well.
     329 *
     330 *      With each of the seven recursive iterations, ProcessTable,
     331 *      ProcessRow, and ProcessColumn receive a ProcessMode variable,
     332 *      which is just an integer that is raised with each run. These
     333 *      are the PROCESS_* constants all over the code.
     334 *
     335 *      In the seven iterations, the following happens:
     336 *
     337 *      1)  PROCESS_1_CALC_MIN_WIDTHS: calculates cxMinContent of all
     338 *          columns, rows, and tables from the inside to the outside
     339 *          recursively. cxMinContent specifies the minimum width of
     340 *          the column, row, and table, respectively. This value is
     341 *          required for all subsequent computations.
     342 *
     343 *          This works as follows:
     344 *
     345 *          --  From the root table, process all rows. [1]
     346 *
     347 *              --  From each row, process all columns.
     348 *
     349 *                  --  For each column, calculate the minimum size of
     350 *                      the content.
     351 *
     352 *                      (*) If the column is a control leaf node (i.e.
     353 *                          does not hold a subtable), get the minimum
     354 *                          size of the control.
     355 *
     356 *                          (*) If the CONTROLDEF specified an explicit
     357 *                              width, copy it to cxMinContent.
     358 *
     359 *                          (*) If the CONTROLDEF specified SZL_AUTOSIZE
     360 *                              for cx, evaluate the control type (icon,
     361 *                              bitmap, text etc.) and set the minimum size
     362 *                              to the result. See CalcAutoSize.
     363 *
     364 *                          (*) The control may specify its desired width
     365 *                              as a percentage of the parent table's
     366 *                              width. In that case, set the cxMinContent
     367 *                              to 0 for now because it is to be ignored
     368 *                              in the computation of the parent row and
     369 *                              table widths.
     370 *
     371 *                      (*) If the column is a subtable, recurse with
     372 *                          the subtable ([1] above) by calling ProcessTable
     373 *                          again. Then set the control's cxMinContent to
     374 *                          the table's cxMinBox, which was set by the
     375 *                          subtable's ProcessTable (see below).
     376 *
     377 *                      After this, we have set the column's cxMinContent
     378 *                      to either a minimum size (explicit or automatic )
     379 *                      or 0.
     380 *
     381 *                  --  Set the row's cxMinBox to the sum of the minimum
     382 *                      widths of the contained columns, with padding,
     383 *                      border, and margin applied to each column.
     384 *
     385 *              --  Set the table's cxMinBox to the cxMinBox of the table's
     386 *                  widest row.
     387 *
     388 *      2)  PROCESS_2_CALC_RELATIVE_WIDTHS: calculates the widths of
     389 *          those columns that have specified that their size should
     390 *          be a percentage of the parent table's width, and calculate
     391 *          the content rectangles of all columns and the box rectangles
     392 *          of the parent rows and tables. Again, do this recursively
     393 *          from the inside columns to the outside tables.
     394 *
     395 *          First, we inherit table sizes from parent tables in
     396 *          ProcessTable. If a column has a subtable that has the
     397 *          TABLE_INHERIT_SIZE table flag set, compute a new cxMinBox
     398 *          for that table. _After_ that, recurse into the table to allow
     399 *          subtables of that subtable to inherit that size as well.
     400 *
     401 *          In the columns, this then sets cpContent.cx in the columns,
     402 *          with the following processing in the control leaf columns:
     403 *
     404 *          (*) If the control has specified an explicit or automatic
     405 *              width, we have set cxMinContent in PROCESS_1_CALC_MIN_WIDTHS;
     406 *              copy that width to cpContent.cx.
     407 *
     408 *          (*) However, if the control had specified its desired
     409 *              width as a percentage of the parent table's width,
     410 *              calculate the cpContent.cx for the control from the
     411 *              table's cxMinBox (from PROCESS_1_CALC_MIN_WIDTHS).
     412 *
     413 *          In the rows and tables, cpBox.cx and cpTable.cx is set as
     414 *          above from the column cpContent.cx values, with spacing applied.
     415 *
     416 *      3)  PROCESS_3_ALIGN_COLUMNS: if the table has the TABLE_ALIGN_COLUMNS
     417 *          flag set, for each column in the table, find the widest
     418 *          instance in all rows, and set the cpContent.cx of all
     419 *          columns in that row to that width.
     420 *
     421 *      4)  PROCESS_4_REMAINDER_WIDTHS: for all controls that have
     422 *          SZL_REMAINDER set for their widths, fill those so that
     423 *          they can use up the remaining width in the row.
     424 *
     425 *      5)  PROCESS_5_CALC_HEIGHTS: Now that we know all widths,
     426 *          calculate the heights. We set cpContent.cy of all columns,
     427 *          cpRowBox.cy of all rows, and cpTableBox.cy of the tables,
     428 *          with the following processing in the control leaf columns:
     429 *
     430 *          (*) If the control has specified an explicit or automatic
     431 *              height, use or compute that. In the case of autosize
     432 *              height, we now know the final width of the control,
     433 *              which is important for computing the height of multi-line
     434 *              static controls (which depend on the width, obviously).
     435 *              The new approach finally works for the case where a
     436 *              multi-line static control specifies its width as a
     437 *              percentage of the parent table, but still wants an
     438 *              autosize height.
     439 *
     440 *      6)  PROCESS_6_CALC_POSITIONS: Now that we know all heights and
     441 *          widths, for each column, calculate cpContent.x and y.
     442 *
     443 *      7)  PROCESS_7_CREATE_CONTROLS: finally creates the controls
     444 *          at the cpContent.x and y position, with the cpContent.cx
     445 *          and cy size.
     446 */
     447
     448/* ******************************************************************
     449 *
     450 *   Private declarations
     451 *
     452 ********************************************************************/
     453
     454/*
     455 *@@ DLGPRIVATE:
     456 *      private data to the dlg manager, allocated
     457 *      by dlghCreateDlg.
     458 *
     459 *      This only exists while the dialog is being
     460 *      created and is not stored with the new dialog.
     461 */
     462
     463typedef struct _DLGPRIVATE
     464{
     465    HWND        hwndDlg;                // dialog frame
     466
     467    // definition data
     468    LINKLIST    llTables;               // linked list of TABLEDEF structs
     469
     470    HWND        hwndFirstFocus,
     471                hwndDefPushbutton;      // V0.9.14 (2001-08-21) [umoeller]
     472
     473    POINTL      ptlTotalOfs;
     474
     475    PLINKLIST   pllControls;            // linked list of HWNDs in the order
     476                                        // in which controls were created;
     477                                        // ptr can be NULL
     478
     479    PCSZ        pcszControlsFont;       // from dlghCreateDlg
     480
     481    // size of the client to be created
     482    SIZEL       szlClient;
     483
     484    // various cached data V0.9.14 (2001-08-01) [umoeller]
     485    HPS         hps;
     486    PCSZ        pcszFontLast;
     487    LONG        lcidLast;
     488    FONTMETRICS fmLast;
     489
     490    LONG        cxBorder,
     491                cyBorder;               // cached now V0.9.19 (2002-04-17) [umoeller]
     492
     493    double      dFactorX,               // correlation factors for dialog units
     494                dFactorY;               // V0.9.19 (2002-04-24) [umoeller]
     495
     496    ULONG       flNeedsProcessing;      // flags to avoid unnecessary recursions:
     497            #define FL_REMAINDER_WIDTHS       0x0001
     498                        // dialog needs PROCESS_4_REMAINDER_WIDTHS processing
     499
     500} DLGPRIVATE, *PDLGPRIVATE;
     501
     502// macros for the dlg units conversion;
     503#define FACTOR_X     (pDlgData->dFactorX)
     504#ifdef USE_SQUARE_CORRELATION
     505#define FACTOR_Y     (pDlgData->dFactorX)
     506#else
     507#define FACTOR_Y     (pDlgData->dFactorY)
     508#endif
     509
     510typedef struct _COLUMNDEF *PCOLUMNDEF;
     511typedef struct _ROWDEF *PROWDEF;
     512typedef struct _TABLEDEF *PTABLEDEF;
     513
     514/*
     515 *@@ CONTROLPOS:
     516 *      control position. We don't want to use SWP.
     517 *      We could have used RECTL, but the xRight
     518 *      etc. fields are always confusing with what
     519 *      we're doing... so we just define this.
     520 */
     521
     522typedef struct _CONTROLPOS
     523{
     524    LONG        x,
     525                y,
     526                cx,
     527                cy;
     528} CONTROLPOS, *PCONTROLPOS;
     529
     530/*
     531 *@@ enProcessMode:
     532 *      enumeration that specifies the current processing
     533 *      mode while recursing through the tables, rows,
     534 *      and columns.
     535 *
     536 *      For each processing mode, ProcessAll gets called
     537 *      while the dialog is being set up, which in turn
     538 *      calls ProcessTable for all tables, which in turn
     539 *      calls ProcessRow for all rows in that table,
     540 *      which in turn calls ProcessColumn for all rows
     541 *      in that column. ProcessColumn will recurse back
     542 *      into ProcessTable if a column represents a
     543 *      subtable.
     544 *
     545 *      See @dlg_algorithm for what processing takes
     546 *      place with each of the process modes.
     547 */
     548
     549typedef enum _enProcessMode
     550{
     551    PROCESS_1_CALC_MIN_WIDTHS,
     552    PROCESS_2_CALC_RELATIVE_WIDTHS,
     553    PROCESS_3_ALIGN_COLUMNS,
     554    PROCESS_4_REMAINDER_WIDTHS,
     555    PROCESS_5_CALC_HEIGHTS,
     556    PROCESS_6_CALC_POSITIONS,
     557    PROCESS_7_CREATE_CONTROLS
     558} enProcessMode;
     559
     560/*
     561 *@@ COLUMNDEF:
     562 *      representation of a column in a table row.
     563 *
     564 *      Each COLUMNDEF is stored in a linked list
     565 *      in ROWDEF.llColumns.
     566 *
     567 *      Such a column represents either a PM control
     568 *      window or another table, which may therefore
     569 *      be nested.
     570 *
     571 *      See @dlg_algorithm for the new algorithm
     572 *      used since V0.9.21.
     573 *
     574 *      With V0.9.21, we now follow the CSS box model
     575 *      to render these things better without all
     576 *      the hacks I am no longer able to understand
     577 *      myself. See @dlg_box_model for details.
     578 *
     579 *@@changed V0.9.21 (2002-08-18) [umoeller]: completely replaced
     580 */
     581
     582typedef struct _COLUMNDEF
     583{
     584    // 1) input table set up by the DLGHITEM parser (CreateColumn):
     585
     586    // a) column position in recursion hierarchy
     587
     588    PROWDEF     pOwningRow;         // row whose linked list this column belongs to
     589
     590    PTABLEDEF   pNestedTable;       // if != NULL, this column represents a nested table,
     591                                    // and this points to the contained table definition
     592                                    // with which we must recurse back into ProcessTable().
     593                                    // In that case, if (pcszClass != NULL) also, it
     594                                    // must represent the PM static group control to
     595                                    // create around the table.
     596                                    // If (pNestedTable == NULL), this column is a control
     597                                    // leaf node, and pcszClass and the following represent
     598                                    // the control to create for the column.
     599
     600    ULONG       ulColumnIndex;      // zero-based column index in parent row
     601                                    // V0.9.21 (2002-08-18) [umoeller]
     602
     603    // b) information for control window to be created:
     604
     605    PCSZ        pcszClass;          // class of control to create; if NULL, create no
     606                                    // control; NULL is valid only for subtable columns
     607    PCSZ        pcszText;           // window text; if NULL, it is replaced with "" in
     608                                    // ColumnCreateControl
     609    ULONG       flStyle;            // window style (should have at least WS_VISIBLE)
     610    USHORT      usID;               // window ID or -1 for "don't care"
     611    PCSZ        pcszFont;           // font to use for this window; this has CTL_COMMON_FONT
     612                                    // resolved to the dialog default font already
     613    SIZEL       szlProposed;        // proposed size for the control; copied from the
     614                                    // CONTROLDEF with the dialog units already converted
     615                                    // to pixels. Can be
     616                                    // -- SZL_AUTOSIZE (-1) if the control wants to be autosized,
     617                                    // -- SZL_REMAINDER (0) if the control wants the remaining
     618                                    //    space in its column,
     619                                    // -- a negative number from [-100, -1] to specify the width
     620                                    //    as a percentage of the parent table _box_.
     621    PVOID       pvCtlData;          // control-specific data for WinCreateWindow
     622
     623    // c) spacing:
     624
     625    RECTL       rclPadding,         // spacing, in pixels, to apply to the four borders of
     626                rclMargin;          // the content to get the box; calculated from CONTROLDEF
     627                                    // V0.9.21 (2002-08-16) [umoeller]
     628
     629    LONG        cxSpacingTotal;     // sum of rclPadding and rclMargin xLeft and
     630                                    // xRight, respectively
     631
     632    // 2) data from CalcAutoSize:
     633
     634    SIZEL       szlAuto;
     635
     636    // 3) result data after recursion:
     637
     638    LONG        cxMinContent;       // minimum width of the content box;
     639                                    // computed in PROCESS_1_CALC_MIN_WIDTHS
     640
     641    CONTROLPOS  cpContent;          // cx computed in PROCESS_2_CALC_RELATIVE_WIDTHS,
     642                                    // cy computed in PROCESS_5_CALC_HEIGHTS,
     643                                    // x and y computed in PROCESS_6_CALC_POSITIONS;
     644                                    // this is where the control will be created
     645
     646    CONTROLPOS  cpBox;              // cx and cy computed in PROCESS_5_CALC_HEIGHTS,
     647                                    // x and y computed in PROCESS_6_CALC_POSITIONS
     648
     649    HWND        hwndControl;        // created control after PROCESS_7_CREATE_CONTROLS;
     650                                    // for tables, this is only set if we have created
     651                                    // a PM group around them. Note: For text box
     652                                    // controls, we create the control earlier,
     653                                    // in CalcAutoSizeTextView during PROCESS_5_CALC_HEIGHTS,
     654                                    // because only then we can ask the control for
     655                                    // its required height.
     656
     657} COLUMNDEF;
     658
     659/*
     660 *@@ ROWDEF:
     661 *      representation of a row in a table.
     662 *
     663 *      Each ROWDEF is stored in a linked list in
     664 *      TABLEDEF.llRows and in turn contains a
     665 *      linked list of the contained COLUMNDEF structs
     666 *      in its llColumns member.
     667 */
     668
     669typedef struct _ROWDEF
     670{
     671    // input table set up by the DLGHITEM parser:
     672
     673    PTABLEDEF   pOwningTable;       // table whose linked list this row belongs to
     674
     675    LINKLIST    llColumns;          // contains COLUMNDEF structs, no auto-free
     676
     677    ULONG       flRowFormat;        // one of:
     678                                    // -- ROW_VALIGN_BOTTOM           0x0000
     679                                    // -- ROW_VALIGN_CENTER           0x0001
     680                                    // -- ROW_VALIGN_TOP              0x0002
     681
     682    ULONG       cColumns;           // no. of columns in this row
     683                                    // V0.9.21 (2002-08-18) [umoeller]
     684
     685    // result data after recursion:
     686
     687    LONG        cxMinBox;           // set by PROCESS_1_CALC_MIN_WIDTHS to the sum of
     688                                    // the minimum widths of the contained columns,
     689                                    // with padding, border, and margin applied to each
     690                                    // column
     691
     692    CONTROLPOS  cpRowBox;           // cx computed in PROCESS_2_CALC_RELATIVE_WIDTHS,
     693                                    // cy computed in PROCESS_5_CALC_HEIGHTS,
     694                                    // x and y computed in PROCESS_6_CALC_POSITIONS
     695
     696    ULONG       cWantRemainders;    // count of controls in the row that have
     697                                    // SZL_REMAINDER set; counted in ProcessColumn
     698                                    // with PROCESS_2_CALC_RELATIVE_WIDTHS
     699                                    // so that we can quickly process
     700                                    // PROCESS_4_REMAINDER_WIDTHS
     701
     702    LONG        cxNonRemainder;     // sum of the widths of those controls that do
     703                                    // not have SZL_REMAINDER set; counted in
     704                                    // ProcessColumn with PROCESS_3_ALIGN_COLUMNS
     705                                    // so that we can quickly process
     706                                    // PROCESS_4_REMAINDER_WIDTHS
     707
     708} ROWDEF;
     709
     710/*
     711 *@@ TABLEDEF:
     712 *      representation of a table. If pOwningColumn
     713 *      is NULL, this is the dialog's root table.
     714 *      Otherwise this is a nested subtable in the
     715 *      specified column.
     716 *
     717 *      Each TABLEDEF has its contained rows
     718 *      in the llRows member.
     719 */
     720
     721typedef struct _TABLEDEF
     722{
     723    // input table set up by the DLGHITEM parser:
     724
     725    PCOLUMNDEF  pOwningColumn;      // != NULL if this is a nested table
     726
     727    LINKLIST    llRows;             // contains ROWDEF structs, no auto-free
     728
     729    ULONG       flTable;            // TABLE_* flags, copied from DLGHITEM
     730
     731    // result data after recursion:
     732
     733    LONG        cxMinBox;           // set by PROCESS_1_CALC_MIN_WIDTHS to the cxMinBox of
     734                                    // the widest row
     735
     736    PROWDEF     pWidestRow;         // used during PROCESS_2_CALC_RELATIVE_WIDTHS to
     737                                    // calculate percentage widths
     738
     739    CONTROLPOS  cpTableBox;         // cx computed in PROCESS_2_CALC_RELATIVE_WIDTHS,
     740                                    // cy computed in PROCESS_5_CALC_HEIGHTS,
     741                                    // x and y computed in PROCESS_6_CALC_POSITIONS
     742
     743} TABLEDEF;
     744
     745/* ******************************************************************
     746 *
     747 *   Debug frames
     748 *
     749 ********************************************************************/
     750
     751#ifdef DEBUG_DIALOG_WINDOWS
     752
     753static PFNWP G_pfnwpStatic = NULL;
     754
     755/*
     756 *@@ fnwpDebugFrame:
     757 *      window proc for the subclassed static that is used in
     758 *      debug mode to mark rectangles in the dialog. This
     759 *      was added to support painting dotted rectangles. The
     760 *      line type is expected to sit in QWL_USER. We use
     761 *      PP_FOREGROUNDCOLOR as the paint color for the rectangle.
     762 *
     763 *      This is only compiled if DEBUG_DIALOG_WINDOWS is
     764 *      set.
     765 *
     766 *@@added V0.9.21 (2002-08-16) [umoeller]
     767 */
     768
     769static MRESULT EXPENTRY fnwpDebugFrame(HWND hwndBox, ULONG msg, MPARAM mp1, MPARAM mp2)
     770{
     771    MRESULT mrc = 0;
     772
     773    switch (msg)
     774    {
     775        case WM_PAINT:
     776        {
     777            LONG lcol = winhQueryPresColor2(hwndBox,
     778                                            PP_FOREGROUNDCOLOR,
     779                                            PP_FOREGROUNDCOLORINDEX,
     780                                            FALSE,
     781                                            -1);
     782            LONG lLineType = WinQueryWindowULong(hwndBox, QWL_USER);
     783
     784            HPS hps;
     785            if (hps = WinBeginPaint(hwndBox, NULLHANDLE, NULL))
     786            {
     787                RECTL rcl;
     788                POINTL ptl;
     789                WinQueryWindowRect(hwndBox, &rcl);
     790
     791                gpihSwitchToRGB(hps);
     792
     793                GpiSetColor(hps, lcol);
     794                GpiSetLineType(hps, lLineType);
     795                ptl.x = 0;
     796                ptl.y = 0;
     797                GpiMove(hps, &ptl);
     798                ptl.x = rcl.xRight - 1;
     799                ptl.y = rcl.yTop - 1;
     800                GpiBox(hps,
     801                       DRO_OUTLINE,
     802                       &ptl,
     803                       0,
     804                       0);
     805                WinEndPaint(hps);
     806            }
     807        }
     808        break;
     809
     810        default:
     811            mrc = G_pfnwpStatic(hwndBox, msg, mp1, mp2);
     812    }
     813
     814    return mrc;
     815}
     816
     817/*
     818 *@@ CreateDebugFrame:
     819 *      in debug mode, creates a subclassed static that
     820 *      shows the rectangles that were produced in the
     821 *      dialog. See fnwpDebugFrame.
     822 *
     823 *      This is only compiled if DEBUG_DIALOG_WINDOWS is
     824 *      set.
     825 *
     826 *@@added V0.9.21 (2002-08-16) [umoeller]
     827 */
     828
     829HWND CreateDebugFrame(HWND hwndParent,
     830                      LONG x,
     831                      LONG y,
     832                      LONG cx,
     833                      LONG cy,
     834                      LONG lcol,
     835                      LONG lLineType)
     836{
     837    HWND hwndDebug;
     838    if (hwndDebug = WinCreateWindow(hwndParent,
     839                                    WC_STATIC,
     840                                    "",
     841                                    WS_VISIBLE,
     842                                    x,
     843                                    y,
     844                                    cx,
     845                                    cy,
     846                                    hwndParent,     // owner
     847                                    HWND_BOTTOM,
     848                                    -1,
     849                                    NULL,
     850                                    NULL))
     851    {
     852        G_pfnwpStatic = WinSubclassWindow(hwndDebug, fnwpDebugFrame);
     853        winhSetPresColor(hwndDebug, PP_FOREGROUNDCOLOR, lcol);
     854        WinSetWindowULong(hwndDebug, QWL_USER, lLineType);
     855    }
     856
     857    return hwndDebug;
     858}
     859
     860#endif // DEBUG_DIALOG_WINDOWS
     861
     862/* ******************************************************************
     863 *
     864 *   Column processing
     865 *
     866 ********************************************************************/
     867
     868// forward declaration so we can recurse into tables from columns
     869
     870static APIRET ProcessTable(PTABLEDEF pTableDef,
     871                           const CONTROLPOS *pcpTableBox,
     872                           enProcessMode ProcessMode,
     873                           PDLGPRIVATE pDlgData);
     874
     875/*
     876 *@@ SetDlgFont:
     877 *      refreshes the cached font data in DLGPRIVATE
     878 *      for the given font. Used all the time with
     879 *      CalcAutoSize.
     880 *
     881 *      In DLGPRIVATE, this modifies hps, lcidLast,
     882 *      and pcszFontLast. After this, the FONTMETRICS
     883 *      in fmLast are set.
     884 *
     885 *@@added V0.9.16 (2001-10-11) [umoeller]
     886 */
     887
     888static VOID SetDlgFont(PCSZ pcszFontThis,
     889                       PDLGPRIVATE pDlgData)
     890{
     891    LONG lPointSize = 0;
     892
     893    if (!pDlgData->hps)
     894        pDlgData->hps = WinGetPS(pDlgData->hwndDlg);
     895
     896    // check if we can reuse font data from last time
     897    // V0.9.14 (2001-08-01) [umoeller]
     898    if (strhcmp(pcszFontThis,               // can be NULL!
     899                pDlgData->pcszFontLast))
     900    {
     901        // different font than last time:
     902
     903        // delete old font?
     904        if (pDlgData->lcidLast)
     905        {
     906            GpiSetCharSet(pDlgData->hps, LCID_DEFAULT);     // LCID_DEFAULT == 0
     907            GpiDeleteSetId(pDlgData->hps, pDlgData->lcidLast);
     908        }
     909
     910        if (pcszFontThis)
     911        {
     912            // create new font
     913            pDlgData->lcidLast = gpihFindPresFont(NULLHANDLE,        // no window yet
     914                                                  FALSE,
     915                                                  pDlgData->hps,
     916                                                  pcszFontThis,
     917                                                  &pDlgData->fmLast,
     918                                                  &lPointSize);
     919
     920            GpiSetCharSet(pDlgData->hps, pDlgData->lcidLast);
     921            if (pDlgData->fmLast.fsDefn & FM_DEFN_OUTLINE)
     922                gpihSetPointSize(pDlgData->hps, lPointSize);
     923        }
     924        else
     925        {
     926            // use default font:
     927            // @@todo handle presparams, maybe inherited?
     928            GpiSetCharSet(pDlgData->hps, LCID_DEFAULT);
     929            GpiQueryFontMetrics(pDlgData->hps,
     930                                sizeof(pDlgData->fmLast),
     931                                &pDlgData->fmLast);
     932        }
     933
     934        pDlgData->pcszFontLast = pcszFontThis;      // can be NULL
     935    }
     936}
     937
     938/*
     939 *@@ CalcAutoSizeTextSingle:
     940 *      implementation for CalcAutoSize for single-line
     941 *      static text controls.
     942 *
     943 *@@changed V0.9.12 (2001-05-31) [umoeller]: fixed various things with statics
     944 *@@changed V0.9.12 (2001-05-31) [umoeller]: fixed broken fonts
     945 *@@changed V0.9.14 (2001-08-01) [umoeller]: now caching fonts, which is significantly faster
     946 *@@changed V0.9.16 (2001-10-15) [umoeller]: added APIRET
     947 *@@changed V0.9.16 (2002-02-02) [umoeller]: added ulWidth
     948 *@@changed V0.9.21 (2002-08-18) [umoeller]: renamed; moved multi-line processing to CalcAutoSizeTextMulti
     949 */
     950
     951static APIRET CalcAutoSizeTextSingle(PCOLUMNDEF pColumn,
     952                                     PDLGPRIVATE pDlgData)
     953{
     954    SetDlgFont(pColumn->pcszFont, pDlgData);
     955
     956    pColumn->szlAuto.cy =   pDlgData->fmLast.lMaxBaselineExt
     957                          + pDlgData->fmLast.lExternalLeading;
     958
     959    // get the control string and see how much space it needs
     960    if (pColumn->pcszText)
     961    {
     962        POINTL aptl[TXTBOX_COUNT];
     963        if (!GpiQueryTextBox(pDlgData->hps,
     964                             strlen(pColumn->pcszText),
     965                             (PCH)pColumn->pcszText,
     966                             TXTBOX_COUNT,
     967                             aptl))
     968            return DLGERR_GPIQUERYTEXTBOX;
     969
     970        pColumn->szlAuto.cx = aptl[TXTBOX_TOPRIGHT].x - aptl[TXTBOX_BOTTOMLEFT].x;
     971
     972        return NO_ERROR;
     973    }
     974
     975    return DLGERR_INVALID_CONTROL_TITLE;
     976}
     977
     978/*
     979 *@@ CalcAutoSizeTextMulti:
     980 *      implementation for CalcAutoSize for multi-line
     981 *      static text controls.
     982 *
     983 *@@added V0.9.21 (2002-08-18) [umoeller]
     984 */
     985
     986static APIRET CalcAutoSizeTextMulti(PCOLUMNDEF pColumn,
     987                                    ULONG ulWidth,            // in: proposed width of control (req.)
     988                                    PDLGPRIVATE pDlgData)
     989{
     990    SetDlgFont(pColumn->pcszFont, pDlgData);
     991
     992    // get the control string and see how much space it needs
     993    if (pColumn->pcszText)
     994    {
     995        RECTL rcl = {0, 0, 0, 0};
     996        rcl.xRight = ulWidth;
     997        if (pColumn->szlProposed.cy > 0)
     998            rcl.yTop = pColumn->szlProposed.cy;
     999        else
     1000            rcl.yTop = winhQueryScreenCY() * 2 / 3;
     1001
     1002        winhDrawFormattedText(pDlgData->hps,
     1003                              &rcl,
     1004                              pColumn->pcszText,
     1005                              DT_LEFT | DT_TOP | DT_WORDBREAK | DT_QUERYEXTENT);
     1006        pColumn->szlAuto.cx = rcl.xRight - rcl.xLeft;
     1007        pColumn->szlAuto.cy = rcl.yTop - rcl.yBottom;
     1008
     1009        return NO_ERROR;
     1010    }
     1011
     1012    return DLGERR_INVALID_CONTROL_TITLE;
     1013}
     1014
     1015/*
     1016 *@@ CalcAutoSizeTextView:
     1017 *      implementation for CalcAutoSize for the XTextView
     1018 *      control.
     1019 *
     1020 *      This is slightly sick. We create the control already
     1021 *      here in order to be able to have it format the text
     1022 *      and then send TXM_QUERYTEXTEXTENT to it, which was
     1023 *      added to the control with V0.9.20 for this very
     1024 *      purpose. The control that we create here will then be
     1025 *      reused by ColumnCreateControl and not be recreated,
     1026 *      which would be way too expensive.
     1027 *
     1028 *@@added V0.9.20 (2002-08-10) [umoeller]
     1029 *@@changed V0.9.21 (2002-08-18) [umoeller]: removed temp windows list
     1030 */
     1031
     1032static APIRET CalcAutoSizeTextView(PCOLUMNDEF pColumn,
     1033                                   ULONG ulWidth,            // in: proposed width of control (req.)
     1034                                   PDLGPRIVATE pDlgData)
     1035{
     1036    APIRET arc = NO_ERROR;
     1037
     1038    PCSZ pcszTitle;
     1039
     1040    if (    (pColumn->hwndControl)
     1041         || (pColumn->hwndControl = WinCreateWindow(pDlgData->hwndDlg,   // parent
     1042                                                    (PSZ)pColumn->pcszClass,
     1043                                                    NULL,
     1044                                                    pColumn->flStyle,
     1045                                                    0,
     1046                                                    0,
     1047                                                    ulWidth,
     1048                                                    2000,         // cy, for now
     1049                                                    pDlgData->hwndDlg,   // owner
     1050                                                    HWND_BOTTOM,
     1051                                                    pColumn->usID,
     1052                                                    pColumn->pvCtlData,
     1053                                                    NULL))
     1054       )
     1055    {
     1056        HWND hwnd = pColumn->hwndControl;
     1057        SIZEL szlTemp;
     1058
     1059        if (pColumn->pcszFont)
     1060            winhSetWindowFont(hwnd,
     1061                              pColumn->pcszFont);
     1062
     1063        WinSetWindowText(hwnd,
     1064                         (pcszTitle = pColumn->pcszText)
     1065                             ? (PSZ)pcszTitle
     1066                             : "");
     1067
     1068        WinSendMsg(hwnd,
     1069                   TXM_QUERYTEXTEXTENT,
     1070                   (MPARAM)&szlTemp,
     1071                   0);
     1072
     1073        pColumn->szlAuto.cy = szlTemp.cy;
     1074    }
     1075    else
     1076        arc = DLGERR_CANNOT_CREATE_CONTROL;
     1077
     1078    return arc;
     1079}
     1080
     1081/*
     1082 *@@ CalcAutoSize:
     1083 *      helper func that gets called from ColumnCalcSizes for
     1084 *      every control that has set SZL_AUTOSIZE for its size.
     1085 *
     1086 *      We try to be smart and set a correct size for the
     1087 *      control, depending on its class and data.
     1088 *
     1089 *      This sets pColumn->szlAuto and possibly pre-creates
     1090 *      a window for the control and stores the window
     1091 *      in pColumn->hwndControl.
     1092 *
     1093 *      Presently this works for
     1094 *
     1095 *      --  static text, single and multiline
     1096 *
     1097 *      --  static icons and bitmaps
     1098 *
     1099 *      --  pushbuttons, radio buttons, and checkboxes
     1100 *
     1101 *      --  the XTextView control (yes! V0.9.20).
     1102 *
     1103 *@@changed V0.9.12 (2001-05-31) [umoeller]: fixed various things with statics
     1104 *@@changed V0.9.16 (2001-10-15) [umoeller]: added APIRET
     1105 *@@changed V0.9.20 (2002-08-10) [umoeller]: added support for textview
     1106 */
     1107
     1108static APIRET CalcAutoSize(PCOLUMNDEF pColumn,
     1109                           ULONG ulWidth,            // in: proposed width of control
     1110                           PDLGPRIVATE pDlgData)
     1111{
     1112    APIRET arc = NO_ERROR;
     1113
     1114    switch ((ULONG)pColumn->pcszClass)
     1115    {
     1116        case 0xffff0003L: // WC_BUTTON:
     1117            if (!(arc = CalcAutoSizeTextSingle(pColumn,
     1118                                               pDlgData)))
     1119            {
     1120                if (pColumn->flStyle & (   BS_AUTOCHECKBOX
     1121                                         | BS_AUTORADIOBUTTON
     1122                                         | BS_AUTO3STATE
     1123                                         | BS_3STATE
     1124                                         | BS_CHECKBOX
     1125                                         | BS_RADIOBUTTON))
     1126                {
     1127                    // give a little extra width for the box bitmap
     1128                    // V0.9.19 (2002-04-24) [umoeller]
     1129                    pColumn->szlAuto.cx += ctlQueryCheckboxSize() + 4;
     1130                    // and height
     1131                    pColumn->szlAuto.cy += 2;
     1132                }
     1133                else if (pColumn->flStyle & BS_BITMAP)
     1134                    ;       // @@todo
     1135                else if (pColumn->flStyle & (BS_ICON | BS_MINIICON))
     1136                    ;       // @@todo
     1137                // we can't test for BS_PUSHBUTTON because that's 0x0000
     1138                else if (!(pColumn->flStyle & BS_USERBUTTON))
     1139                {
     1140                    pColumn->szlAuto.cx += (2 * pDlgData->cxBorder + 15);
     1141                    pColumn->szlAuto.cy += (2 * pDlgData->cyBorder + 15);
     1142                }
     1143            }
     1144        break;
     1145
     1146        case 0xffff0005L: // WC_STATIC:
     1147            switch (pColumn->flStyle & 0x0F)
     1148            {
     1149                case SS_TEXT:
     1150                    if (pColumn->flStyle & DT_WORDBREAK)
     1151                        // multi-line:
     1152                        arc = CalcAutoSizeTextMulti(pColumn,
     1153                                                    ulWidth,
     1154                                                    pDlgData);
     1155                    else
     1156                        // single-line:
     1157                        arc = CalcAutoSizeTextSingle(pColumn,
     1158                                                     pDlgData);
     1159                break;
     1160
     1161                case SS_BITMAP:
     1162                {
     1163                    HBITMAP hbm;
     1164                    if (hbm = (HBITMAP)pColumn->pcszText)
     1165                    {
     1166                        BITMAPINFOHEADER2 bmih2;
     1167                        ZERO(&bmih2);
     1168                        bmih2.cbFix = sizeof(bmih2);
     1169                        if (GpiQueryBitmapInfoHeader(hbm,
     1170                                                     &bmih2))
     1171                        {
     1172                            pColumn->szlAuto.cx = bmih2.cx;
     1173                            pColumn->szlAuto.cy = bmih2.cy;
     1174                        }
     1175                        else
     1176                            arc = DLGERR_GPIQUERYBITMAPINFOHEADER;
     1177                    }
     1178                    else
     1179                        arc = DLGERR_INVALID_STATIC_BITMAP;
     1180                }
     1181                break;
     1182
     1183                case SS_ICON:
     1184                    pColumn->szlAuto.cx = WinQuerySysValue(HWND_DESKTOP, SV_CXICON);
     1185                    pColumn->szlAuto.cy = WinQuerySysValue(HWND_DESKTOP, SV_CYICON);
     1186                break;
     1187            }
     1188        break;
     1189
     1190        default:
     1191            // added support for textview V0.9.20 (2002-08-10) [umoeller]
     1192            if (    (((ULONG)pColumn->pcszClass & 0xFFFF0000) != 0xFFFF0000)
     1193                            // don't run strcmp on the PM pseudo-strings
     1194                 && (!strcmp(pColumn->pcszClass, WC_XTEXTVIEW))
     1195               )
     1196            {
     1197                arc = CalcAutoSizeTextView(pColumn,
     1198                                           ulWidth,
     1199                                           pDlgData);
     1200            }
     1201            else
     1202            {
     1203                // any other control (just to be safe):
     1204                SetDlgFont(pColumn->pcszFont, pDlgData);
     1205                pColumn->szlAuto.cx = 50;
     1206                pColumn->szlAuto.cy =   pDlgData->fmLast.lMaxBaselineExt
     1207                                      + pDlgData->fmLast.lExternalLeading
     1208                                      + 7;         // some space
     1209            }
     1210    }
     1211
     1212    return arc;
     1213}
     1214
     1215/*
     1216 *@@ ColumnCalcPositions:
     1217 *      implementation for PROCESS_6_CALC_POSITIONS in
     1218 *      ProcessColumn.
     1219 *
     1220 *@@added V0.9.15 (2001-08-26) [umoeller]
     1221 *@@changed V0.9.16 (2001-10-15) [umoeller]: added APIRET
     1222 *@@changed V0.9.19 (2002-04-24) [umoeller]: fixed PM groups alignment
     1223 *@@changed V0.9.21 (2002-08-16) [umoeller]: adjusted for new algorithm
     1224 */
     1225
     1226static APIRET ColumnCalcPositions(PCOLUMNDEF pColumn,
     1227                                  PROWDEF pOwningRow,          // in: current row from ProcessRow
     1228                                  PLONG plX,                   // in/out: PROCESS_6_CALC_POSITIONS only
     1229                                  PDLGPRIVATE pDlgData)
     1230{
     1231    APIRET arc = NO_ERROR;
     1232
     1233    // column box = *plX on ProcessRow stack
     1234    pColumn->cpBox.x = *plX;
     1235    pColumn->cpBox.y = pOwningRow->cpRowBox.y;
     1236
     1237    // check vertical alignment of row;
     1238    // we might need to increase column y
     1239    switch (pOwningRow->flRowFormat & ROW_VALIGN_MASK)
     1240    {
     1241        // case ROW_VALIGN_BOTTOM:      // do nothing
     1242
     1243        case ROW_VALIGN_CENTER:
     1244            if (pColumn->cpBox.cy < pOwningRow->cpRowBox.cy)
     1245                pColumn->cpBox.y += (   (pOwningRow->cpRowBox.cy - pColumn->cpBox.cy)
     1246                                      / 2);
     1247        break;
     1248
     1249        case ROW_VALIGN_TOP:
     1250            if (pColumn->cpBox.cy < pOwningRow->cpRowBox.cy)
     1251                pColumn->cpBox.y += (pOwningRow->cpRowBox.cy - pColumn->cpBox.cy);
     1252        break;
     1253    }
     1254
     1255    // increase plX by box width
     1256    *plX += pColumn->cpBox.cx;
     1257
     1258    // calculate CONTROL pos from COLUMN pos by applying spacing
     1259    pColumn->cpContent.x =   pColumn->cpBox.x
     1260                           + pColumn->rclPadding.xLeft
     1261                           + pColumn->rclMargin.xLeft;
     1262    pColumn->cpContent.y =   pColumn->cpBox.y
     1263                           + pColumn->rclPadding.yBottom
     1264                           + pColumn->rclMargin.yBottom;
     1265
     1266    if (pColumn->pNestedTable)
     1267    {
     1268        // nested table:
     1269        // recurse!! to create windows for the sub-table
     1270        arc = ProcessTable(pColumn->pNestedTable,
     1271                           &pColumn->cpContent,   // start pos for new table
     1272                           PROCESS_6_CALC_POSITIONS,
     1273                           pDlgData);
     1274    }
     1275
     1276    return arc;
     1277}
     1278
     1279/*
     1280 *@@ ColumnCreateControl:
     1281 *      implementation for PROCESS_7_CREATE_CONTROLS in
     1282 *      ProcessColumn.
     1283 *
     1284 *@@added V0.9.15 (2001-08-26) [umoeller]
     1285 *@@changed V0.9.16 (2001-10-15) [umoeller]: fixed ugly group table spacings
     1286 *@@changed V0.9.16 (2001-12-08) [umoeller]: fixed entry field ES_MARGIN positioning
     1287 *@@changed V0.9.19 (2002-04-17) [umoeller]: fixes for the STUPID drop-down comboboxes
     1288 *@@changed V0.9.19 (2002-04-24) [umoeller]: fixed PM groups alignment
     1289 *@@changed V0.9.21 (2002-08-16) [umoeller]: adjusted for new algorithm
     1290 *@@changed V0.9.21 (2002-08-18) [umoeller]: setting entry field length to CCHMAXPATH per default now
     1291 */
     1292
     1293static APIRET ColumnCreateControl(PCOLUMNDEF pColumn,
     1294                                  PDLGPRIVATE pDlgData)
     1295{
     1296    APIRET      arc = NO_ERROR;
     1297
     1298    PCSZ        pcszClass = NULL;
     1299    PCSZ        pcszText = NULL;
     1300    ULONG       flStyle = 0;
     1301    LHANDLE     lHandleSet = NULLHANDLE;
     1302    ULONG       flOld = 0;
     1303
     1304    if (pColumn->pNestedTable)
     1305    {
     1306        // nested table:
     1307        // recurse!!
     1308        if (!(arc = ProcessTable(pColumn->pNestedTable,
     1309                                 NULL,
     1310                                 PROCESS_7_CREATE_CONTROLS,
     1311                                 pDlgData)))
     1312        {
     1313            // should we create a PM control around the table?
     1314            // (do this AFTER the other controls from recursing,
     1315            // otherwise the stupid container doesn't show up)
     1316            if (pcszClass = pColumn->pcszClass)
     1317            {
     1318                // yes:
     1319                pcszText = pColumn->pcszText;
     1320                flStyle = pColumn->flStyle;
     1321
     1322                // V0.9.21 (2002-08-16) [umoeller]
     1323                // Removed all the terrible hacks for the PM group
     1324                // control. We now use rclPadding and rclMargin
     1325                // in the CONTROLDEF for determining the group
     1326                // box position and size. Those were set initially
     1327                // by the DLGHITEM parser. See CreateColumn().
     1328                // If the group box had an explicit size set,
     1329                // that is used by ProcessTable for the table
     1330                // box also.
     1331            }
     1332
     1333#ifdef DEBUG_DIALOG_WINDOWS
     1334            // debug: create a frame with the exact size
     1335            // of the table in blue
     1336            CreateDebugFrame(pDlgData->hwndDlg,        // parent
     1337                             pTableDef->cpTableBox.x + pDlgData->ptlTotalOfs.x,
     1338                             pTableDef->cpTableBox.y + pDlgData->ptlTotalOfs.y,
     1339                             pTableDef->cpTableBox.cx,
     1340                             pTableDef->cpTableBox.cy,
     1341                             RGBCOL_BLUE,
     1342                             LINETYPE_DOT);
     1343#endif
     1344        }
     1345    }
     1346    else
     1347    {
     1348        // no nested table, but control:
     1349        pcszClass = pColumn->pcszClass;
     1350        pcszText = pColumn->pcszText;
     1351        flStyle = pColumn->flStyle;
     1352    }
     1353
     1354    if (    (!arc)            // check error code V0.9.21 (2002-08-16) [umoeller]
     1355         && (pcszClass)
     1356       )
     1357    {
     1358        // create something:
     1359        LONG        x, cx, y, cy;               // for control hacks
     1360        HWND        hwndFound = NULLHANDLE;
     1361        LONG        cxUse;
     1362        PCSZ        pcszTextEF = NULL;          // for entry field
     1363
     1364        // V0.9.21 (2002-08-16) [umoeller]
     1365        // determine the position where to create the
     1366        // control; this is the content box, to which
     1367        // we add the absolute position on the dlgdata
     1368        // stack, and padding. Padding is presently
     1369        // only set for the group box around tables.
     1370
     1371        // To create the control, we use the explicit
     1372        // or automatic size of the control instead
     1373        // of the column width. Otherwise all buttons
     1374        // are expanded to the column width, for example.
     1375        if (    (!(cxUse = pColumn->cxMinContent))
     1376             || (pColumn->pNestedTable)
     1377           )
     1378            cxUse = pColumn->cpContent.cx;
     1379
     1380        x  =   pColumn->cpContent.x
     1381             - pColumn->rclPadding.xLeft
     1382             + pDlgData->ptlTotalOfs.x;
     1383        cx =   cxUse
     1384             + pColumn->rclPadding.xLeft
     1385             + pColumn->rclPadding.xRight;
     1386        y  =   pColumn->cpContent.y
     1387             - pColumn->rclPadding.yBottom
     1388             + pDlgData->ptlTotalOfs.y;
     1389        cy =   pColumn->cpContent.cy
     1390             + pColumn->rclPadding.yBottom
     1391             + pColumn->rclPadding.yTop;
     1392
     1393        // now implement hacks for certain controls
     1394        switch ((ULONG)pcszClass)
     1395        {
     1396            case 0xffff0005L: // WC_STATIC:
     1397                // change the title if this is a static with SS_BITMAP;
     1398                // we have used a HBITMAP in there!
     1399                if (    (    ((flStyle & 0x0F) == SS_BITMAP)
     1400                          || ((flStyle & 0x0F) == SS_ICON)
     1401                        )
     1402                   )
     1403                {
     1404                    // change style flag to not use SS_BITMAP nor SS_ICON;
     1405                    // control creation fails otherwise (stupid, stupid PM)
     1406                    flOld = flStyle;
     1407                    flStyle = ((flStyle & ~0x0F) | SS_FGNDFRAME);
     1408                    pcszText = "";
     1409                    lHandleSet = (LHANDLE)pColumn->pcszText;
     1410                }
     1411            break;
     1412
     1413            case 0xffff0002L:   // combobox
     1414                if (flStyle & (CBS_DROPDOWN | CBS_DROPDOWNLIST))
     1415                {
     1416                    // while calculating the column height,
     1417                    // we have set pColumn->cpContent.cy
     1418                    // to the height of a single line to get
     1419                    // the position calculations right...
     1420                    LONG  cyDelta = pColumn->szlProposed.cy - pColumn->cpContent.cy;
     1421                    y  -= cyDelta;
     1422                    cy += cyDelta;
     1423                }
     1424            break;
     1425
     1426            case 0xffff0006L:   // entry field
     1427            case 0xffff000AL:   // MLE:
     1428                // the stupid entry field resizes itself if it has
     1429                // the ES_MARGIN style, so correlate that too... dammit
     1430                // V0.9.16 (2001-12-08) [umoeller]
     1431                if (flStyle & ES_MARGIN)
     1432                {
     1433                    LONG cxMargin = 3 * pDlgData->cxBorder;
     1434                    LONG cyMargin = 3 * pDlgData->cyBorder;
     1435
     1436                    x += cxMargin;
     1437                    y += cyMargin;
     1438                    cx -= 2 * cxMargin;
     1439                    cy -= 2 * cyMargin;
     1440                }
     1441
     1442                if ((ULONG)pcszClass == 0xffff0006L)
     1443                {
     1444                    // entry field:
     1445                    // defer setting the text because we should
     1446                    // first set the entry field limit
     1447                    // V0.9.21 (2002-08-18) [umoeller]
     1448                    pcszTextEF = pcszText;
     1449                    pcszText = "";          // for now
     1450                }
     1451            break;
     1452        } // end switch ((ULONG)pControlDef->pcszClass)
     1453
     1454        if (pColumn->hwndControl)
     1455        {
     1456            // control was already created by CalcAutoSize:
     1457            // resize it to what we really need
     1458            WinSetWindowPos(pColumn->hwndControl,
     1459                            HWND_BOTTOM,
     1460                            x,
     1461                            y,
     1462                            cx,
     1463                            cy,
     1464                            SWP_SIZE | SWP_MOVE | SWP_ZORDER);
     1465        }
     1466        else
     1467        {
     1468            TRY_QUIET(excpt1)
     1469            {
     1470                pColumn->hwndControl = WinCreateWindow(pDlgData->hwndDlg,   // parent
     1471                                                       (PSZ)pcszClass,      // window class, hacked
     1472                                                       (pcszText)           // control text, hacked
     1473                                                             ? (PSZ)pcszText
     1474                                                             : "",
     1475                                                       flStyle,             // window style, hacked
     1476                                                       x,
     1477                                                       y,
     1478                                                       cx,
     1479                                                       cy,
     1480                                                       pDlgData->hwndDlg,   // owner == parent
     1481                                                       HWND_BOTTOM,
     1482                                                       pColumn->usID,
     1483                                                       pColumn->pvCtlData,
     1484                                                       NULL);
     1485            }
     1486            CATCH(excpt1)
     1487            {
     1488                CHAR szClass2[100] = "Invalid mem",
     1489                     szText2[100] = "Invalid mem";
     1490                ULONG Size, Attr;
     1491                if (!(arc = DosQueryMem((PVOID)pcszClass, &Size, &Attr)))
     1492                    strhncpy0(szClass2, pcszClass, sizeof(szClass2));
     1493                if (!(arc = DosQueryMem((PVOID)pcszClass, &Size, &Attr)))
     1494                    strhncpy0(szText2, pcszText, sizeof(szText2));
     1495
     1496                _Pmpf(("Crash creating control of class 0x%lX (%s), title 0x%lX (%s)",
     1497                        szClass2,
     1498                        szText2));
     1499                arc = ERROR_PROTECTION_VIOLATION;
     1500            } END_CATCH();
     1501        }
     1502
     1503        if (pColumn->hwndControl)
     1504        {
     1505            // control created, or reused above:
     1506
     1507            if (lHandleSet)
     1508            {
     1509                // subclass the damn static
     1510                if ((flOld & 0x0F) == SS_ICON)
     1511                    // this was a static:
     1512                    ctlPrepareStaticIcon(pColumn->hwndControl,
     1513                                         1);
     1514                else
     1515                    // this was a bitmap:
     1516                    ctlPrepareStretchedBitmap(pColumn->hwndControl,
     1517                                              TRUE);
     1518
     1519                WinSendMsg(pColumn->hwndControl,
     1520                           SM_SETHANDLE,
     1521                           (MPARAM)lHandleSet,
     1522                           0);
     1523            }
     1524            else
     1525            {
     1526                if (pcszTextEF)
     1527                {
     1528                    // entry field:
     1529                    // set text limit to CCHMAXPATH per default,
     1530                    // and set the real text now
     1531                    // V0.9.21 (2002-08-18) [umoeller]
     1532                    winhSetEntryFieldLimit(pColumn->hwndControl, CCHMAXPATH);
     1533                    WinSetWindowText(pColumn->hwndControl, (PSZ)pcszTextEF);
     1534                }
     1535
     1536                if (pColumn->pcszFont)
     1537                    // we must set the font explicitly here...
     1538                    // doesn't always work with WinCreateWindow
     1539                    // presparams parameter, for some reason
     1540                    // V0.9.12 (2001-05-31) [umoeller]
     1541                    winhSetWindowFont(pColumn->hwndControl,
     1542                                      pColumn->pcszFont);
     1543            }
     1544
     1545#ifdef DEBUG_DIALOG_WINDOWS
     1546            // if (!pColumn->fIsNestedTable)
     1547            {
     1548                // debug: create a frame with the exact size
     1549                // of the box (not the content), so this
     1550                // includes spacing
     1551                CreateDebugFrame(pDlgData->hwndDlg,        // parent
     1552                                 pColumn->cpBox.x + pDlgData->ptlTotalOfs.x,
     1553                                 pColumn->cpBox.y + pDlgData->ptlTotalOfs.y,
     1554                                 pColumn->cpBox.cx,
     1555                                 pColumn->cpBox.cy,
     1556                                 RGBCOL_DARKGREEN,
     1557                                 LINETYPE_SOLID);
     1558
     1559                // and another one for the content (control size)
     1560                CreateDebugFrame(pDlgData->hwndDlg,        // parent
     1561                                 pColumn->cpContent.x + pDlgData->ptlTotalOfs.x,
     1562                                 pColumn->cpContent.y + pDlgData->ptlTotalOfs.y,
     1563                                 pColumn->cpContent.cx,
     1564                                 pColumn->cpContent.cy,
     1565                                 RGBCOL_RED,
     1566                                 LINETYPE_ALTERNATE);
     1567            }
     1568#endif
     1569
     1570            // append window that was created
     1571            // V0.9.18 (2002-03-03) [umoeller]
     1572            if (pDlgData->pllControls)
     1573                lstAppendItem(pDlgData->pllControls,
     1574                              (PVOID)pColumn->hwndControl);
     1575
     1576            // if this is the first control with WS_TABSTOP,
     1577            // we'll give it the focus later
     1578            if (    (flStyle & WS_TABSTOP)
     1579                 && (!pDlgData->hwndFirstFocus)
     1580               )
     1581                pDlgData->hwndFirstFocus = pColumn->hwndControl;
     1582
     1583            // if this is the first default push button,
     1584            // go store it too
     1585            // V0.9.14 (2001-08-21) [umoeller]
     1586            if (    (!pDlgData->hwndDefPushbutton)
     1587                 && ((ULONG)pColumn->pcszClass == 0xffff0003L)
     1588                 && (pColumn->flStyle & BS_DEFAULT)
     1589               )
     1590                pDlgData->hwndDefPushbutton = pColumn->hwndControl;
     1591        }
     1592        else
     1593            // V0.9.14 (2001-08-03) [umoeller]
     1594            arc = DLGERR_CANNOT_CREATE_CONTROL;
     1595    }
     1596
     1597    return arc;
     1598}
     1599
     1600/* ******************************************************************
     1601 *
     1602 *   Recursive workers for columns, rows, tables
     1603 *
     1604 ********************************************************************/
     1605
     1606/*
     1607 *@@ ProcessColumn:
     1608 *      processes a column, which per definition is either
     1609 *      a control or a nested subtable.
     1610 *
     1611 *      A column is part of a row, which in turn is part
     1612 *      of a table. There can be several columns in a row,
     1613 *      and several rows in a table.
     1614 *
     1615 *      Since tables may be specified as columns, it is
     1616 *      possible to produce complex dialog layouts by
     1617 *      nesting tables.
     1618 *
     1619 *      Preconditions:
     1620 *
     1621 *      -- PROCESS_6_CALC_POSITIONS: position of each column
     1622 *         is taken from *plX, which is increased by the
     1623 *         column width by this call.
     1624 *
     1625 *         Owning row must already have its y position properly
     1626 *         set, or we can't compute ours. Besides, plX must
     1627 *         point to the current X in the row and will be
     1628 *         incremented by the column's size here.
     1629 *
     1630 *@@changed V0.9.12 (2001-05-31) [umoeller]: added control data
     1631 *@@changed V0.9.12 (2001-05-31) [umoeller]: fixed font problems
     1632 *@@changed V0.9.20 (2002-08-08) [umoeller]: added support for aligning columns horizontally
     1633 *@@changed V0.9.21 (2002-08-16) [umoeller]: calc size rewritten for new algorithm
     1634 */
     1635
     1636static APIRET ProcessColumn(PCOLUMNDEF pColumn,
     1637                            PROWDEF pOwningRow,          // in: current row from ProcessRow
     1638                            enProcessMode ProcessMode,     // in: processing mode (see ProcessAll)
     1639                            PLONG plX,                   // in/out: PROCESS_6_CALC_POSITIONS only
     1640                            PDLGPRIVATE pDlgData)
     1641{
     1642    APIRET arc = NO_ERROR;
     1643
     1644    // pColumn->pOwningRow = pOwningRow;
     1645
     1646    switch (ProcessMode)
     1647    {
     1648        /*
     1649         * PROCESS_1_CALC_MIN_WIDTHS:
     1650         *
     1651         */
     1652
     1653        case PROCESS_1_CALC_MIN_WIDTHS:
     1654            // rewritten V0.9.21 (2002-08-16) [umoeller]
     1655
     1656            if (!pColumn->pNestedTable)
     1657            {
     1658                // control leaf node, not subtable:
     1659
     1660                // check if the control title is valid... we
     1661                // crash later otherwise
     1662                if ((ULONG)pColumn->pcszText > 0xFFFF0000)
     1663                    arc = DLGERR_INVALID_CONTROL_TITLE;
     1664                else
     1665                {
     1666                    if (pColumn->szlProposed.cx > 0)
     1667                    {
     1668                        // explicit size:
     1669                        pColumn->cxMinContent = pColumn->szlProposed.cx;
     1670                    }
     1671                    else if (pColumn->szlProposed.cx == SZL_AUTOSIZE)   // -1
     1672                    {
     1673                        // autosize width:
     1674                        // calc then
     1675                        arc = CalcAutoSize(pColumn,
     1676                                           1000,            // width, whatever...
     1677                                                            // that's what we want to know!
     1678                                           pDlgData);
     1679
     1680                        pColumn->cxMinContent = pColumn->szlAuto.cx;
     1681                    }
     1682                    // else: -100 < width < -1: percentage of parent table,
     1683                    // leave cxMinContent == 0 for now
     1684
     1685                    #ifdef DEBUG_DIALOG_WINDOWS
     1686                        if (pControlDef->pcszText)
     1687                        {
     1688                            CHAR szTemp[40];
     1689                            strhncpy0(szTemp, pControlDef->pcszText, sizeof(szTemp));
     1690                            strcpy(szTemp + 35, "...");
     1691                            _PmpfF(("PROCESS_1_CALC_MIN_WIDTHS [%s] cxMinContent %d",
     1692                                    szTemp,
     1693                                    pColumn->cxMinContent));
     1694                        }
     1695                    #endif
     1696                }
     1697            }
     1698            else
     1699            {
     1700                // column represents subtable:
     1701                // recurse!
     1702                if (!(arc = ProcessTable(pColumn->pNestedTable,
     1703                                         NULL,
     1704                                         ProcessMode,
     1705                                         pDlgData)))
     1706                {
     1707                    // ProcessTable has set pTableDef->cxMinBox,
     1708                    // that is the size of the entire table box...
     1709                    // use that for our cxMinContent
     1710                    pColumn->cxMinContent = pColumn->pNestedTable->cxMinBox;
     1711                }
     1712            }
     1713
     1714        break; // PROCESS_1_CALC_MIN_WIDTHS
     1715
     1716        /*
     1717         * PROCESS_2_CALC_RELATIVE_WIDTHS:
     1718         *
     1719         */
     1720
     1721        case PROCESS_2_CALC_RELATIVE_WIDTHS:
     1722            // rewritten V0.9.21 (2002-08-16) [umoeller]
     1723
     1724            if (!pColumn->pNestedTable)
     1725            {
     1726                // control leaf node, not subtable:
     1727                if (    (pColumn->szlProposed.cx == SZL_AUTOSIZE)   // -1
     1728                     || (pColumn->szlProposed.cx > 0)               // not SZL_REMAINDER
     1729                   )
     1730                {
     1731                    // explicit size or autosize:
     1732                    // that was computed with PROCESS_1_CALC_MIN_WIDTHS,
     1733                    // so copy from cxMinContent
     1734                    pColumn->cpContent.cx = pColumn->cxMinContent;
     1735                }
     1736                else if (pColumn->szlProposed.cx < 0)
     1737                {
     1738                    // control wants percentage of parent table width:
     1739                    PTABLEDEF   pOwningTable = pOwningRow->pOwningTable;
     1740                    PROWDEF     pWidestRow;
     1741
     1742                    #ifdef DEBUG_DIALOG_WINDOWS
     1743                        {
     1744                            CHAR szTemp[40];
     1745                            strhncpy0(szTemp,
     1746                                      (pControlDef->pcszText) ? pControlDef->pcszText : "NULL",
     1747                                      sizeof(szTemp));
     1748                            strcpy(szTemp + 35, "...");
     1749                            _PmpfF(("PROCESS_2_CALC_RELATIVE_WIDTHS [%s]"));
     1750                        }
     1751                    #endif
     1752
     1753                    if (pWidestRow = pOwningTable->pWidestRow)
     1754                    {
     1755                        PLISTNODE   pNode;
     1756                        PCOLUMNDEF  pSubColumn,
     1757                                    pTablesColumn;
     1758                        LONG        cxWidestRowsMinBox = pOwningTable->cxMinBox; // pWidestRow->cxMinBox;
     1759
     1760                        _Pmpf(("  pWidestRow->cxMinBox %d", pWidestRow->cxMinBox));
     1761                        _Pmpf(("  pOwningTable->cxMinBox %d", pOwningTable->cxMinBox));
     1762
     1763                        // now, since we're supposed to set our own CONTENT
     1764                        // rectangle, subtract our own padding and margin
     1765                        cxWidestRowsMinBox -=   pColumn->cxSpacingTotal;
     1766
     1767                        pColumn->cpContent.cx =   (double)cxWidestRowsMinBox
     1768                                                   * -pColumn->szlProposed.cx
     1769                                                   / 100;
     1770                    }
     1771
     1772                    #ifdef DEBUG_DIALOG_WINDOWS
     1773                        {
     1774                            _Pmpf(("   cpContent.cx %d",
     1775                                    pColumn->cpContent.cx));
     1776                            _Pmpf(("   pWidestRow was 0x%lX", pWidestRow));
     1777                        }
     1778                    #endif
     1779                } // end if (pControlDef->szlDlgUnits.cx < 0)
     1780                else if (pColumn->szlProposed.cx == SZL_REMAINDER) // 0
     1781                {
     1782                    // SZL_REMAINDER is calculated in PROCESS_4_REMAINDER_WIDTHS,
     1783                    // just count the remainders in the ROWDEF for now so
     1784                    // we can process them quickly later
     1785                    ++(pOwningRow->cWantRemainders);
     1786
     1787                    // set the flag so that Dlg2_CalcSizes knows we'll
     1788                    // need PROCESS_4_REMAINDER_WIDTHS
     1789                    pDlgData->flNeedsProcessing |= FL_REMAINDER_WIDTHS;
     1790                }
     1791            }
     1792            else
     1793            {
     1794                // column represents subtable:
     1795                // recurse!
     1796                if (!(arc = ProcessTable(pColumn->pNestedTable,
     1797                                         NULL,
     1798                                         ProcessMode,
     1799                                         pDlgData)))
     1800                {
     1801                    // ProcessTable has set pTableDef->cpTableBox.cx,
     1802                    // that is the size of the entire table box...
     1803                    // use that for our cpContent.cx
     1804                    pColumn->cpContent.cx = pColumn->pNestedTable->cpTableBox.cx;
     1805                }
     1806            }
     1807        break; // PROCESS_2_CALC_RELATIVE_WIDTHS
     1808
     1809        /*
     1810         * PROCESS_3_ALIGN_COLUMNS:
     1811         *
     1812         */
     1813
     1814        case PROCESS_3_ALIGN_COLUMNS:
     1815            // rewritten V0.9.21 (2002-08-16) [umoeller]
     1816
     1817            if (!pColumn->pNestedTable)
     1818            {
     1819                // control leaf node, not subtable:
     1820
     1821                LONG    cxWidest = 0;
     1822                PTABLEDEF pOwningTable;
     1823
     1824                // if our owning table has the TABLE_ALIGN_COLUMNS
     1825                // flag set, set this columns width to the width
     1826                // of the widest column in all rows of this table,
     1827                // but align this column ONLY if it does not want
     1828                // SZL_REMAINDER
     1829
     1830                if (    (pColumn->szlProposed.cx != SZL_REMAINDER)       // 0
     1831                     && (pOwningTable = pOwningRow->pOwningTable)
     1832                     && (pOwningTable->flTable & TABLE_ALIGN_COLUMNS)
     1833                   )
     1834                {
     1835                    // find the widest corresponding column in the
     1836                    // surrounding table; pColumn->ulColumnIndex
     1837                    // has our index, so we need to run through
     1838                    // the rows and compare the widths of all
     1839                    // columns with that index
     1840                    PLISTNODE pRowNode;
     1841
     1842                    FOR_ALL_NODES(&pOwningTable->llRows, pRowNode)
     1843                    {
     1844                        PROWDEF     pRowThis = (PROWDEF)pRowNode->pItemData;
     1845                        PCOLUMNDEF  pCorrespondingColumn;
     1846                        if (    (pCorrespondingColumn = (PCOLUMNDEF)lstItemFromIndex(&pRowThis->llColumns,
     1847                                                                                     pColumn->ulColumnIndex))
     1848                             && (pCorrespondingColumn->cxMinContent > cxWidest)
     1849                           )
     1850                        {
     1851                            #ifdef DEBUG_DIALOG_WINDOWS
     1852                            {
     1853                                const CONTROLDEF *pControlDef = (const CONTROLDEF *)pCorrespondingColumn->pvDefinition;
     1854                                if (pControlDef->pcszText)
     1855                                {
     1856                                    CHAR szTemp[40];
     1857                                    strhncpy0(szTemp, pControlDef->pcszText, sizeof(szTemp));
     1858                                    strcpy(szTemp + 35, "...");
     1859                                    _PmpfF(("   widest column is [%s] cxMinContent %d",
     1860                                            szTemp,
     1861                                            pCorrespondingColumn->cxMinContent));
     1862                                }
     1863                            }
     1864                            #endif
     1865
     1866                            cxWidest = pCorrespondingColumn->cxMinContent;
     1867                        }
     1868                    }
     1869
     1870                    pColumn->cpContent.cx = cxWidest;
     1871
     1872                    #ifdef DEBUG_DIALOG_WINDOWS
     1873                    {
     1874                        if (pControlDef->pcszText)
     1875                        {
     1876                            CHAR szTemp[40];
     1877                            strhncpy0(szTemp, pControlDef->pcszText, sizeof(szTemp));
     1878                            strcpy(szTemp + 35, "...");
     1879                            _PmpfF(("PROCESS_3_ALIGN_COLUMNS [%s] cpContent.cx %d",
     1880                                    szTemp,
     1881                                    pColumn->cpContent.cx));
     1882                        }
     1883                    }
     1884                    #endif
     1885                }
     1886            }
     1887            else
     1888            {
     1889                // column represents subtable:
     1890                // recurse!
     1891                arc = ProcessTable(pColumn->pNestedTable,
     1892                                   NULL,
     1893                                   ProcessMode,
     1894                                   pDlgData);
     1895
     1896                // the width of a table can NOT change from this
     1897                // processing, so no need to adjust
     1898                // (individual rows might have changed though)
     1899                // @@todo wrong, if the first column is made
     1900                // wider, the second column might now move over
     1901                // the table width, fix that
     1902            }
     1903
     1904            // in any case (control or subtable), count the
     1905            // widths of all columns that do not have SZL_REMAINDER
     1906            // set for PROCESS_4_REMAINDER_WIDTHS in the next loop
     1907
     1908            // NOTE: we add _all_ columns, including those that have
     1909            // SZL_REMAINDER set (for which cpContent.cx is null
     1910            // presently), because the "non remainder" space needs
     1911            // to include the spacing of _all_ columns (see the
     1912            // PROCESS_4_REMAINDER_WIDTHS processing below)
     1913            pOwningRow->cxNonRemainder +=   pColumn->cpContent.cx
     1914                                          + pColumn->cxSpacingTotal;
     1915
     1916        break; // PROCESS_3_ALIGN_COLUMNS
     1917
     1918        /*
     1919         * PROCESS_4_REMAINDER_WIDTHS:
     1920         *
     1921         */
     1922
     1923        case PROCESS_4_REMAINDER_WIDTHS:
     1924            if (!pColumn->pNestedTable)
     1925            {
     1926                // control leaf node, not subtable:
     1927                PTABLEDEF pOwningTable;
     1928
     1929                if (    (pColumn->szlProposed.cx == SZL_REMAINDER)       // 0
     1930                     && (pOwningTable = pOwningRow->pOwningTable)
     1931                   )
     1932                {
     1933                    LONG    cxRemaining = pOwningTable->cpTableBox.cx - pOwningRow->cxNonRemainder;
     1934                    // NOTE: pOwningRow->cxNonRemainder has
     1935                    // --   the sum of the column content rectangle widths that did not
     1936                    //      have SZL_REMAINDER set
     1937                    // --   the sum of _all_ column spacings, even if the column had
     1938                    //      SZL_REMAINDER set,
     1939                    // so this really has the leftover space now.
     1940                    // Divide that by the no. of columns in the row that have
     1941                    // SZL_REMAINDER set so that we evenly distribute the remaining
     1942                    // space among those columns.
     1943                    pColumn->cpContent.cx = (   cxRemaining
     1944                                              / pOwningRow->cWantRemainders
     1945                                                    // this cannot be 0 since we have
     1946                                                    // that flag and were thus counted
     1947                                            );
     1948
     1949                    #ifdef DEBUG_DIALOG_WINDOWS
     1950                    {
     1951                        CHAR szTemp[40] = "NULL";
     1952
     1953                        if (pControlDef->pcszText)
     1954                        {
     1955                            strhncpy0(szTemp, pControlDef->pcszText, sizeof(szTemp));
     1956                            strcpy(szTemp + 35, "...");
     1957                        }
     1958
     1959                        _PmpfF(("PROCESS_4_REMAINDER_WIDTHS [%s] pOwningTable->cpTableBox.cx %d",
     1960                                szTemp,
     1961                                pOwningTable->cpTableBox.cx));
     1962                        _PmpfF(("  pOwningRow->cxNonRemainder %d",
     1963                                pOwningRow->cxNonRemainder));
     1964                        _PmpfF(("  pOwningRow->cWantRemainders %d",
     1965                                pOwningRow->cWantRemainders));
     1966                        _PmpfF(("  cpContent.cx %d",
     1967                                pColumn->cpContent.cx));
     1968                    }
     1969                    #endif
     1970
     1971                }
     1972            }
     1973            else
     1974            {
     1975                // column represents subtable:
     1976                // recurse!
     1977                arc = ProcessTable(pColumn->pNestedTable,
     1978                                   NULL,
     1979                                   ProcessMode,
     1980                                   pDlgData);
     1981            }
     1982        break;
     1983
     1984        /*
     1985         * PROCESS_5_CALC_HEIGHTS:
     1986         *
     1987         */
     1988
     1989        case PROCESS_5_CALC_HEIGHTS:
     1990            if (!pColumn->pNestedTable)
     1991            {
     1992                // control leaf node, not subtable:
     1993                if (pColumn->szlProposed.cy > 0)
     1994                {
     1995                    // explicit size:
     1996                    pColumn->cpContent.cy = pColumn->szlProposed.cy;
     1997
     1998                    if ((ULONG)pColumn->pcszClass == 0xffff0002L)
     1999                    {
     2000                        // hack the stupid drop-down combobox where the
     2001                        // size of the drop-down is the full size of the
     2002                        // control: when creating the control, we _do_
     2003                        // specify the full size, but for the column,
     2004                        // we must rather use a single line with
     2005                        // the current font
     2006                        // V0.9.19 (2002-04-17) [umoeller]
     2007                        if (pColumn->flStyle & (CBS_DROPDOWN | CBS_DROPDOWNLIST))
     2008                        {
     2009                            SetDlgFont(pColumn->pcszFont, pDlgData);
     2010
     2011                            pColumn->cpContent.cy
     2012                                =   pDlgData->fmLast.lMaxBaselineExt
     2013                                  + pDlgData->fmLast.lExternalLeading
     2014                                  + 2 * 3 * pDlgData->cyBorder;
     2015                        }
     2016                    }
     2017                }
     2018                else if (pColumn->szlProposed.cy == SZL_AUTOSIZE)   // -1
     2019                {
     2020                    // autosize height:
     2021                    // we MIGHT have run autosize already above
     2022                    // (e.g. for the typical bitmap or icon statics),
     2023                    // so check if szlAuto.cy is already set
     2024                    if (!(pColumn->cpContent.cy = pColumn->szlAuto.cy))
     2025                    {
     2026                        // not yet determined:
     2027                        // calc then
     2028                        arc = CalcAutoSize(pColumn,
     2029                                           // width: now we know
     2030                                           pColumn->cpContent.cx,
     2031                                           pDlgData);
     2032                        pColumn->cpContent.cy = pColumn->szlAuto.cy;
     2033                    }
     2034                }
     2035                // else: -100 < width < -1: @@todo
     2036                // add another stage for using the percentage of
     2037                // the table height
     2038            }
     2039            else
     2040            {
     2041                // column represents subtable:
     2042                // recurse!
     2043                if (!(arc = ProcessTable(pColumn->pNestedTable,
     2044                                         NULL,
     2045                                         ProcessMode,
     2046                                         pDlgData)))
     2047                {
     2048                    // ProcessTable has set pTableDef->cpTableBox.cy,
     2049                    // that is the size of the entire table box...
     2050                    // use that for our cpContent.cy
     2051                    pColumn->cpContent.cy = pColumn->pNestedTable->cpTableBox.cy;
     2052                }
     2053            }
     2054
     2055            // we finally know the DEFINITE width and height
     2056            // of the content, so we can set the box width
     2057            // and height here now (ProcessRow relies on this
     2058            // to determine the row height)
     2059            pColumn->cpBox.cx =   pColumn->cpContent.cx
     2060                                + pColumn->cxSpacingTotal;
     2061            pColumn->cpBox.cy =   pColumn->cpContent.cy
     2062                                + pColumn->rclPadding.yBottom
     2063                                + pColumn->rclMargin.yBottom
     2064                                + pColumn->rclPadding.yTop
     2065                                + pColumn->rclMargin.yTop;
     2066        break;
     2067
     2068        /*
     2069         * PROCESS_6_CALC_POSITIONS:
     2070         *
     2071         */
     2072
     2073        case PROCESS_6_CALC_POSITIONS:
     2074            arc = ColumnCalcPositions(pColumn,
     2075                                      pOwningRow,
     2076                                      plX,
     2077                                      pDlgData);
     2078        break;
     2079
     2080        /*
     2081         * PROCESS_7_CREATE_CONTROLS:
     2082         *
     2083         */
     2084
     2085        case PROCESS_7_CREATE_CONTROLS:
     2086            arc = ColumnCreateControl(pColumn,
     2087                                      pDlgData);
     2088        break;
     2089    }
     2090
     2091    return arc;
     2092}
     2093
     2094/*
     2095 *@@ ProcessRow:
     2096 *      level-3 procedure (called from ProcessTable),
     2097 *      which in turn calls ProcessColumn for each column
     2098 *      in the row.
     2099 *
     2100 *@@changed V0.9.21 (2002-08-16) [umoeller]: adjusted for new algorithm
     2101 */
     2102
     2103static APIRET ProcessRow(PROWDEF pRowDef,
     2104                         PTABLEDEF pOwningTable,     // in: current table from ProcessTable
     2105                         enProcessMode ProcessMode,    // in: processing mode (see ProcessAll)
     2106                         PLONG plY,                  // in/out: current y position (decremented)
     2107                         PDLGPRIVATE pDlgData)
     2108{
     2109    APIRET  arc = NO_ERROR;
     2110    LONG    lXRowBox;
     2111    PLISTNODE pNode;
     2112
     2113    pRowDef->pOwningTable = pOwningTable;
     2114
     2115    switch (ProcessMode)
     2116    {
     2117        case PROCESS_3_ALIGN_COLUMNS:
     2118            // we've computed pRowDef->cpRowBox.cx in the
     2119            // previous run (PROCESS_2_CALC_RELATIVE_WIDTHS),
     2120            // but since we keep adding to it, we must
     2121            // reset it now... the row will probably become
     2122            // larger!
     2123            pRowDef->cpRowBox.cx = 0;
     2124        break;
     2125
     2126        case PROCESS_6_CALC_POSITIONS:
     2127            // set up x and y so that the columns can
     2128            // base on that
     2129            pRowDef->cpRowBox.x = pOwningTable->cpTableBox.x;
     2130            // decrease y by row height
     2131            *plY -= pRowDef->cpRowBox.cy;
     2132            // and use that for our bottom position
     2133            pRowDef->cpRowBox.y = *plY;
     2134
     2135            // set lX to left of row; used by column calls below
     2136            lXRowBox = pRowDef->cpRowBox.x;
     2137        break;
     2138    }
     2139
     2140    FOR_ALL_NODES(&pRowDef->llColumns, pNode)
     2141    {
     2142        PCOLUMNDEF  pColumnThis = (PCOLUMNDEF)pNode->pItemData;
     2143
     2144        if (!(arc = ProcessColumn(pColumnThis,
     2145                                  pRowDef,
     2146                                  ProcessMode,
     2147                                  &lXRowBox,
     2148                                  pDlgData)))
     2149        {
     2150            switch (ProcessMode)
     2151            {
     2152                case PROCESS_1_CALC_MIN_WIDTHS:
     2153                    // row width = sum of all columns
     2154                    pRowDef->cxMinBox +=   pColumnThis->cxMinContent
     2155                                         + pColumnThis->cxSpacingTotal;
     2156                break;
     2157
     2158                case PROCESS_2_CALC_RELATIVE_WIDTHS:
     2159                case PROCESS_3_ALIGN_COLUMNS:       // reapply, was reset above
     2160                    // row width = sum of all columns
     2161                    pRowDef->cpRowBox.cx +=   pColumnThis->cpContent.cx
     2162                                            + pColumnThis->cxSpacingTotal;
     2163                break;
     2164
     2165                case PROCESS_5_CALC_HEIGHTS:
     2166                    // row height = maximum height of a column
     2167                    if (pRowDef->cpRowBox.cy < pColumnThis->cpBox.cy)
     2168                        pRowDef->cpRowBox.cy = pColumnThis->cpBox.cy;
     2169            }
     2170        }
     2171        // we should stop on errors V0.9.20 (2002-08-10) [umoeller]
     2172        else
     2173            break;
     2174    }
     2175
     2176    return arc;
     2177}
     2178
     2179/*
     2180 *@@ ProcessTable:
     2181 *      level-2 procedure (called from ProcessAll),
     2182 *      which in turn calls ProcessRow for each row
     2183 *      in the table (which in turn calls ProcessColumn
     2184 *      for each column in the row).
     2185 *
     2186 *      See ProcessAll for the meaning of ProcessMode.
     2187 *
     2188 *      This routine is a bit sick because it can even be
     2189 *      called recursively from ProcessColumn (!) if a
     2190 *      nested table is found in a COLUMNDEF.
     2191 *
     2192 *      With PROCESS_6_CALC_POSITIONS, pptl must specify
     2193 *      the lower left corner of the table. For the
     2194 *      root call, this will be {0, 0}; for nested calls,
     2195 *      this must be the lower left corner of the column
     2196 *      to which the nested table belongs.
     2197 *
     2198 *@@changed V0.9.21 (2002-08-16) [umoeller]: adjusted for new algorithm
     2199 */
     2200
     2201static APIRET ProcessTable(PTABLEDEF pTableDef,
     2202                           const CONTROLPOS *pcpTableBox,   // in: table position with PROCESS_6_CALC_POSITIONS
     2203                           enProcessMode ProcessMode,         // in: processing mode (see ProcessAll)
     2204                           PDLGPRIVATE pDlgData)
     2205{
     2206    APIRET  arc = NO_ERROR;
     2207    LONG    lY;
     2208    PLISTNODE pNode;
     2209
     2210    switch (ProcessMode)
     2211    {
     2212        case PROCESS_2_CALC_RELATIVE_WIDTHS:
     2213            // before calculating relative widths for
     2214            // the table, inherit size from parent table
     2215            // if the TABLE_INHERIT_SIZE table flag is
     2216            // set; this was originally designed
     2217            // as a separate step (PROCESS_2_INHERIT_TABLE_SIZES),
     2218            // but we can save ourselves a loop here
     2219            // V0.9.21 (2002-08-16) [umoeller]
     2220            if (pTableDef->flTable & TABLE_INHERIT_SIZE)
     2221            {
     2222                PCOLUMNDEF  pOwningColumn;
     2223                PROWDEF     pOwningRow;
     2224                PTABLEDEF   pOwningTable;
     2225                if (    (!(pOwningColumn = pTableDef->pOwningColumn))
     2226                     || (!(pOwningRow = pOwningColumn->pOwningRow))
     2227                     || (!(pOwningTable = pOwningRow->pOwningTable))
     2228                   )
     2229                    arc = DLGERR_ROOT_TABLE_INHERIT_SIZE;
     2230                else
     2231                {
     2232                    PLISTNODE pRowNode;
     2233                    LONG cxMax = 0;
     2234                    FOR_ALL_NODES(&pOwningTable->llRows, pRowNode)
     2235                    {
     2236                        PROWDEF pRowThis = (PROWDEF)pRowNode->pItemData;
     2237                        if (pRowThis->cxMinBox > cxMax)
     2238                            cxMax = pRowThis->cxMinBox;
     2239                    }
     2240
     2241                    _Pmpf(("    cxMax found is %d", cxMax));
     2242
     2243                    pTableDef->cxMinBox =   cxMax
     2244                                          - pOwningColumn->cxSpacingTotal;
     2245                }
     2246            }
     2247        break;
     2248
     2249        case PROCESS_6_CALC_POSITIONS:
     2250            pTableDef->cpTableBox.x = pcpTableBox->x;
     2251            pTableDef->cpTableBox.y = pcpTableBox->y;
     2252
     2253            // start the rows on top
     2254            lY = pcpTableBox->y + pTableDef->cpTableBox.cy;
     2255        break;
     2256    }
     2257
     2258    if (!arc)
     2259    {
     2260        FOR_ALL_NODES(&pTableDef->llRows, pNode)
     2261        {
     2262            PROWDEF pRowDefThis = (PROWDEF)pNode->pItemData;
     2263
     2264            if (!(arc = ProcessRow(pRowDefThis, pTableDef, ProcessMode, &lY, pDlgData)))
     2265            {
     2266                switch (ProcessMode)
     2267                {
     2268                    case PROCESS_1_CALC_MIN_WIDTHS:
     2269                        // table width = maximum width of a row
     2270                        if (pTableDef->cxMinBox < pRowDefThis->cxMinBox)
     2271                        {
     2272                            pTableDef->cxMinBox = pRowDefThis->cxMinBox;
     2273
     2274                            // remember the widest row so that
     2275                            // PROCESS_2_CALC_RELATIVE_WIDTHS can calc relative
     2276                            // widths from it
     2277
     2278                            pTableDef->pWidestRow = pRowDefThis;
     2279                        }
     2280                    break;
     2281
     2282                    case PROCESS_2_CALC_RELATIVE_WIDTHS:
     2283                    case PROCESS_3_ALIGN_COLUMNS:
     2284                    {
     2285                        PCOLUMNDEF pOwningColumn;
     2286
     2287                        // table width = maximum width of a row
     2288                        if (pTableDef->cpTableBox.cx < pRowDefThis->cpRowBox.cx)
     2289                            pTableDef->cpTableBox.cx = pRowDefThis->cpRowBox.cx;
     2290
     2291                        // preserve the inherited width if it was larger
     2292                        if (pTableDef->cxMinBox > pTableDef->cpTableBox.cx)
     2293                            pTableDef->cpTableBox.cx = pTableDef->cxMinBox;
     2294
     2295                        // if the table has a group box with an explicit
     2296                        // size, use it if it's larger
     2297                        if (    (pOwningColumn = pTableDef->pOwningColumn)
     2298                             && (pOwningColumn->pcszClass)
     2299                             && (pOwningColumn->szlProposed.cx > 0)
     2300                             && (pOwningColumn->szlProposed.cx > pTableDef->cpTableBox.cx)
     2301                           )
     2302                            pTableDef->cpTableBox.cx = pOwningColumn->szlProposed.cx;
     2303                    }
     2304                    break;
     2305
     2306                    case PROCESS_5_CALC_HEIGHTS:
     2307                        // table height = sum of all rows
     2308                        pTableDef->cpTableBox.cy += pRowDefThis->cpRowBox.cy;
     2309                    break;
     2310                }
     2311            }
     2312            else
     2313                break;
     2314        }
     2315    }
     2316
     2317    return arc;
     2318}
     2319
     2320/*
     2321 *@@ ProcessAll:
     2322 *      level-1 procedure, which in turn calls ProcessTable
     2323 *      for each root-level table found (which in turn
     2324 *      calls ProcessRow for each row in the table, which
     2325 *      in turn calls ProcessColumn for each column in
     2326 *      the row).
     2327 */
     2328
     2329static APIRET ProcessAll(PDLGPRIVATE pDlgData,
     2330                         enProcessMode ProcessMode)
     2331{
     2332    APIRET arc = NO_ERROR;
     2333    PLISTNODE pNode;
     2334    CONTROLPOS cpTableBox;
     2335    ZERO(&cpTableBox);
     2336
     2337    switch (ProcessMode)
     2338    {
     2339        case PROCESS_1_CALC_MIN_WIDTHS:
     2340            pDlgData->szlClient.cx = 0;
     2341            pDlgData->szlClient.cy = 0;
     2342        break;
     2343
     2344        case PROCESS_6_CALC_POSITIONS:
     2345            // start with the table on top
     2346            cpTableBox.y = pDlgData->szlClient.cy;
     2347        break;
     2348    }
     2349
     2350    FOR_ALL_NODES(&pDlgData->llTables, pNode)
     2351    {
     2352        PTABLEDEF pTableDefThis = (PTABLEDEF)pNode->pItemData;
     2353
     2354        if (ProcessMode == PROCESS_6_CALC_POSITIONS)
     2355        {
     2356            cpTableBox.x = 0;
     2357            cpTableBox.y -= pTableDefThis->cpTableBox.cy;
     2358        }
     2359
     2360        if (!(arc = ProcessTable(pTableDefThis,
     2361                                 &cpTableBox,      // start pos
     2362                                 ProcessMode,
     2363                                 pDlgData)))
     2364        {
     2365            switch (ProcessMode)
     2366            {
     2367                case PROCESS_5_CALC_HEIGHTS:
     2368                {
     2369                    // all sizes have now been computed:
     2370                    pDlgData->szlClient.cx += pTableDefThis->cpTableBox.cx;
     2371                    pDlgData->szlClient.cy += pTableDefThis->cpTableBox.cy;
     2372                }
     2373            }
     2374        }
     2375        // we should stop on errors V0.9.20 (2002-08-10) [umoeller]
     2376        else
     2377            break;
     2378    }
     2379
     2380    return arc;
     2381}
     2382
     2383/* ******************************************************************
     2384 *
     2385 *   DLGHITEM parser
     2386 *
     2387 ********************************************************************/
     2388
     2389/*
     2390 *@@ CreateColumn:
     2391 *
     2392 *@@changed V0.9.21 (2002-08-18) [umoeller]: mostly rewritten for new algorithm
     2393 */
     2394
     2395static APIRET CreateColumn(PDLGPRIVATE pDlgData,
     2396                           PROWDEF pCurrentRow,
     2397                           PTABLEDEF pNestedTable,
     2398                           const CONTROLDEF *pControlDef,
     2399                           PCOLUMNDEF *ppColumn)    // out: new COLUMNDEF
     2400{
     2401    APIRET arc = NO_ERROR;
     2402
     2403    if (!pCurrentRow)
     2404        arc = DLGERR_CONTROL_BEFORE_ROW;
     2405    else
     2406    {
     2407        // create column and store ctl def
     2408        PCOLUMNDEF pColumn;
     2409        if (!(pColumn = NEW(COLUMNDEF)))
     2410            arc = ERROR_NOT_ENOUGH_MEMORY;
     2411        else
     2412        {
     2413            ZERO(pColumn);
     2414
     2415            pColumn->pOwningRow = pCurrentRow;
     2416
     2417            if (pColumn->pNestedTable = pNestedTable)
     2418            {
     2419                // should we create a PM control around the table?
     2420                if (pControlDef)
     2421                {
     2422                    // yes:
     2423                    pColumn->rclPadding.xLeft
     2424                    = pColumn->rclPadding.xRight
     2425                    = GROUP_INNER_SPACING_X * FACTOR_X;
     2426
     2427                    pColumn->rclPadding.yBottom = GROUP_INNER_SPACING_BOTTOM * FACTOR_Y;
     2428
     2429                    pColumn->rclPadding.yTop = GROUP_INNER_SPACING_TOP * FACTOR_Y;
     2430
     2431                    pColumn->rclMargin.xLeft = GROUP_OUTER_SPACING_X * FACTOR_X;
     2432                    pColumn->rclMargin.xRight = GROUP_OUTER_SPACING_X * FACTOR_X;
     2433                    pColumn->rclMargin.yBottom = GROUP_OUTER_SPACING_BOTTOM * FACTOR_Y;
     2434                    pColumn->rclMargin.yTop = GROUP_OUTER_SPACING_TOP * FACTOR_Y;
     2435                }
     2436            }
     2437            else
     2438                if (!pControlDef)
     2439                    arc = DLGERR_NULL_CONTROLDEF;
     2440
     2441            if (pControlDef)
     2442            {
     2443                // copy control fields
     2444                pColumn->pcszClass = pControlDef->pcszClass;
     2445                pColumn->pcszText = pControlDef->pcszText;
     2446                pColumn->flStyle = pControlDef->flStyle;
     2447                pColumn->usID = pControlDef->usID;
     2448
     2449                // resolve font
     2450                if (pControlDef->pcszFont == CTL_COMMON_FONT)
     2451                    pColumn->pcszFont = pDlgData->pcszControlsFont;
     2452                else
     2453                    pColumn->pcszFont = pControlDef->pcszFont;
     2454                                    // can be NULL
     2455
     2456                // copy and convert proposed size
     2457                if (pControlDef->szlDlgUnits.cx > 0)
     2458                    // not SZL_AUTOSIZE, not SZL_REMAINDER, not percentage:
     2459                    // convert from dlgunits to pixels
     2460                    pColumn->szlProposed.cx = pControlDef->szlDlgUnits.cx * FACTOR_X;
     2461                else
     2462                    pColumn->szlProposed.cx = pControlDef->szlDlgUnits.cx;
     2463
     2464                if (pControlDef->szlDlgUnits.cy > 0)
     2465                    // not SZL_AUTOSIZE, not SZL_REMAINDER, not percentage:
     2466                    // convert from dlgunits to pixels
     2467                    pColumn->szlProposed.cy = pControlDef->szlDlgUnits.cy * FACTOR_Y;
     2468                else
     2469                    pColumn->szlProposed.cy = pControlDef->szlDlgUnits.cy;
     2470
     2471                pColumn->pvCtlData = pControlDef->pvCtlData;
     2472
     2473                // note: we increase the margin here... it was null
     2474                // unless set above because we had a PM group control
     2475                // around a table
     2476                pColumn->rclMargin.xLeft += pControlDef->duSpacing * FACTOR_X;
     2477                pColumn->rclMargin.xRight += pControlDef->duSpacing * FACTOR_X;
     2478
     2479                pColumn->rclMargin.yBottom += pControlDef->duSpacing * FACTOR_Y;
     2480                pColumn->rclMargin.yTop += pControlDef->duSpacing * FACTOR_Y;
     2481            }
     2482
     2483            // calculate the column's total spacing width
     2484            // for speed
     2485            pColumn->cxSpacingTotal =   pColumn->rclPadding.xLeft
     2486                                      + pColumn->rclMargin.xLeft
     2487                                      + pColumn->rclPadding.xRight
     2488                                      + pColumn->rclMargin.xRight;
     2489
     2490            // set the column index V0.9.21 (2002-08-18) [umoeller]
     2491            pColumn->ulColumnIndex = (pCurrentRow->cColumns)++;
     2492
     2493            *ppColumn = pColumn;
     2494        }
     2495    }
     2496
     2497    return arc;
     2498}
     2499
     2500/*
     2501 *@@ FreeTable:
     2502 *      frees the specified table and recurses
     2503 *      into nested tables, if necessary.
     2504 *
     2505 *      This was added with V0.9.14 to fix the
     2506 *      bad memory leaks with nested tables.
     2507 *
     2508 *@@added V0.9.14 (2001-08-01) [umoeller]
     2509 */
     2510
     2511static VOID FreeTable(PTABLEDEF pTable)
     2512{
     2513    // for each table, clean up the rows
     2514    PLISTNODE pRowNode;
     2515    FOR_ALL_NODES(&pTable->llRows, pRowNode)
     2516    {
     2517        PROWDEF pRow = (PROWDEF)pRowNode->pItemData;
     2518
     2519        // for each row, clean up the columns
     2520        PLISTNODE pColumnNode;
     2521        FOR_ALL_NODES(&pRow->llColumns, pColumnNode)
     2522        {
     2523            PCOLUMNDEF pColumn = (PCOLUMNDEF)pColumnNode->pItemData;
     2524
     2525            if (pColumn->pNestedTable)
     2526                // nested table: recurse!
     2527                FreeTable(pColumn->pNestedTable);
     2528
     2529            free(pColumn);
     2530        }
     2531        lstClear(&pRow->llColumns);
     2532
     2533        free(pRow);
     2534    }
     2535    lstClear(&pTable->llRows);
     2536
     2537    free(pTable);
     2538}
     2539
     2540/*
     2541 *@@ STACKITEM:
     2542 *
     2543 */
     2544
     2545typedef struct _STACKITEM
     2546{
     2547    PTABLEDEF       pLastTable;
     2548    PROWDEF         pLastRow;
     2549
     2550} STACKITEM, *PSTACKITEM;
     2551
     2552/*
     2553 *@@ Dlg0_Init:
     2554 *
     2555 *@@added V0.9.15 (2001-08-26) [umoeller]
     2556 *@@changed V0.9.18 (2002-03-03) [umoeller]: added pllWindows
     2557 *@@changed V0.9.19 (2002-04-24) [umoeller]: added resolution correlation
     2558 */
     2559
     2560static APIRET Dlg0_Init(PDLGPRIVATE *ppDlgData,
     2561                        PCSZ pcszControlsFont,
     2562                        PLINKLIST pllControls)
     2563{
     2564    PDLGPRIVATE     pDlgData;
     2565    POINTL          ptl = {100, 100};
     2566
     2567    if (!(pDlgData = NEW(DLGPRIVATE)))
     2568        return (ERROR_NOT_ENOUGH_MEMORY);
     2569
     2570    ZERO(pDlgData);
     2571    lstInit(&pDlgData->llTables, FALSE);
     2572
     2573    if (pllControls)
     2574        pDlgData->pllControls = pllControls;
     2575
     2576    pDlgData->pcszControlsFont = pcszControlsFont;
     2577
     2578    // cache these now too V0.9.19 (2002-04-17) [umoeller]
     2579    pDlgData->cxBorder = WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
     2580    pDlgData->cyBorder = WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);
     2581
     2582    // check how many pixels we get out of the
     2583    // dlgunits (100/100) for mapping all sizes
     2584    // V0.9.19 (2002-04-24) [umoeller]
     2585    if (WinMapDlgPoints(NULLHANDLE,
     2586                        &ptl,
     2587                        1,
     2588                        TRUE))
     2589    {
     2590        // this worked:
     2591        // for 1024x768, I get 200/250 out of the above,
     2592        // so calculate a factor from that; we multiply
     2593        // szlDlgUnits with this factor when calculating
     2594        // the sizes
     2595        pDlgData->dFactorX = (double)ptl.x / (double)100;       // 2   on 1024x768
     2596        pDlgData->dFactorY = (double)ptl.y / (double)100;       // 2.5 on 1024x768
     2597    }
     2598    else
     2599    {
     2600        // didn't work:
     2601        pDlgData->dFactorX = 2;
     2602        pDlgData->dFactorY = 2.5;
     2603    }
     2604
     2605    *ppDlgData = pDlgData;
     2606
     2607    return NO_ERROR;
     2608}
     2609
     2610/*
     2611 *@@ Dlg1_ParseTables:
     2612 *
     2613 *@@added V0.9.15 (2001-08-26) [umoeller]
     2614 */
     2615
     2616static APIRET Dlg1_ParseTables(PDLGPRIVATE pDlgData,
     2617                               PCDLGHITEM paDlgItems,      // in: definition array
     2618                               ULONG cDlgItems)           // in: array item count (NOT array size)
     2619{
     2620    APIRET      arc = NO_ERROR;
     2621
     2622    LINKLIST    llStack;
     2623    ULONG       ul;
     2624    PTABLEDEF   pCurrentTable = NULL;
     2625    PROWDEF     pCurrentRow = NULL;
     2626
     2627    lstInit(&llStack, TRUE);      // this is our stack for nested table definitions
     2628
     2629    for (ul = 0;
     2630         ul < cDlgItems;
     2631         ul++)
     2632    {
     2633        PCDLGHITEM   pItemThis = &paDlgItems[ul];
     2634
     2635        switch (pItemThis->Type)
     2636        {
     2637            /*
     2638             * TYPE_START_NEW_TABLE:
     2639             *
     2640             */
     2641
     2642            case TYPE_START_NEW_TABLE:
     2643            {
     2644                // root table or nested?
     2645                BOOL fIsRoot = (pCurrentTable == NULL);
     2646
     2647                // push the current table on the stack
     2648                PSTACKITEM pStackItem;
     2649                if (!(pStackItem = NEW(STACKITEM)))
     2650                {
     2651                    arc = ERROR_NOT_ENOUGH_MEMORY;
     2652                    break;
     2653                }
     2654                else
     2655                {
     2656                    pStackItem->pLastTable = pCurrentTable;
     2657                    pStackItem->pLastRow = pCurrentRow;
     2658                    lstPush(&llStack, pStackItem);
     2659                }
     2660
     2661                // create new table
     2662                if (!(pCurrentTable = NEW(TABLEDEF)))
     2663                    arc = ERROR_NOT_ENOUGH_MEMORY;
     2664                else
     2665                {
     2666                    const CONTROLDEF *pControlDef;
     2667                    ZERO(pCurrentTable);
     2668
     2669                    lstInit(&pCurrentTable->llRows, FALSE);
     2670
     2671                    // if control specified: store it (this will become a PM group)
     2672                    // pCurrentTable->pCtlDef = (const CONTROLDEF *)pItemThis->ul1; // pItemThis->pCtlDef;
     2673                    pControlDef = (const CONTROLDEF *)pItemThis->ul1;
     2674                                // can be NULL for plain table
     2675
     2676                    pCurrentTable->flTable = pItemThis->ul2;         // V0.9.20 (2002-08-08) [umoeller]
     2677
     2678                    if (fIsRoot)
     2679                        // root table:
     2680                        // append to dialog data list
     2681                        lstAppendItem(&pDlgData->llTables, pCurrentTable);
     2682                    else
     2683                    {
     2684                        // nested table:
     2685                        // create "table" column for this in the current row
     2686                        PCOLUMNDEF pColumn;
     2687                        if (!(arc = CreateColumn(pDlgData,
     2688                                                 pCurrentRow,
     2689                                                 pCurrentTable,        // nested table
     2690                                                 pControlDef,
     2691                                                 &pColumn)))
     2692                        {
     2693                            pCurrentTable->pOwningColumn = pColumn;
     2694                            lstAppendItem(&pCurrentRow->llColumns,
     2695                                          pColumn);
     2696                        }
     2697                    }
     2698                }
     2699
     2700                // reset current row so we can detect
     2701                // wrong DLGHITEM ordering
     2702                pCurrentRow = NULL;
     2703            }
     2704            break;
     2705
     2706            /*
     2707             * TYPE_START_NEW_ROW:
     2708             *
     2709             */
     2710
     2711            case TYPE_START_NEW_ROW:
     2712                if (!pCurrentTable)
     2713                    arc = DLGERR_ROW_BEFORE_TABLE;
     2714                else
     2715                {
     2716                    // create new row
     2717                    if (!(pCurrentRow = NEW(ROWDEF)))
     2718                        arc = ERROR_NOT_ENOUGH_MEMORY;
     2719                    else
     2720                    {
     2721                        ZERO(pCurrentRow);
     2722
     2723                        pCurrentRow->pOwningTable = pCurrentTable;
     2724                        lstInit(&pCurrentRow->llColumns, FALSE);
     2725
     2726                        pCurrentRow->flRowFormat = pItemThis->ul2;
     2727
     2728                        lstAppendItem(&pCurrentTable->llRows, pCurrentRow);
     2729                    }
     2730                }
     2731            break;
     2732
     2733            /*
     2734             * TYPE_CONTROL_DEF:
     2735             *
     2736             */
     2737
     2738            case TYPE_CONTROL_DEF:
     2739            {
     2740                PCOLUMNDEF pColumn;
     2741                if (!(arc = CreateColumn(pDlgData,
     2742                                         pCurrentRow,
     2743                                         FALSE,        // no nested table
     2744                                         (PVOID)pItemThis->ul1, // pCtlDef, V0.9.21 (2002-08-18) [umoeller]
     2745                                         &pColumn)))
     2746                    lstAppendItem(&pCurrentRow->llColumns,
     2747                                  pColumn);
     2748            }
     2749            break;
     2750
     2751            /*
     2752             * TYPE_END_TABLE:
     2753             *
     2754             */
     2755
     2756            case TYPE_END_TABLE:
     2757            {
     2758                PLISTNODE pNode;
     2759                if (!(pNode = lstPop(&llStack)))
     2760                    // nothing on the stack:
     2761                    arc = DLGERR_TOO_MANY_TABLES_CLOSED;
     2762                else
     2763                {
     2764                    PSTACKITEM pStackItem = (PSTACKITEM)pNode->pItemData;
     2765                    pCurrentTable = pStackItem->pLastTable;
     2766                    pCurrentRow = pStackItem->pLastRow;
     2767
     2768                    lstRemoveNode(&llStack, pNode);
     2769                }
     2770            }
     2771            break;
     2772
     2773            default:
     2774                arc = DLGERR_INVALID_CODE;
     2775        }
     2776
     2777        if (arc)
     2778            break;
     2779    }
     2780
     2781    // all tables should be closed now
     2782    if (    (!arc)
     2783         && (lstCountItems(&llStack))
     2784       )
     2785        arc = DLGERR_TABLE_NOT_CLOSED;
     2786
     2787    lstClear(&llStack);
     2788
     2789    return arc;
     2790}
     2791
     2792/*
     2793 *@@ Dlg2_CalcSizes:
     2794 *      calls ProcessAll with the first four process modes
     2795 *      for calculating the final sizes (but not yet the
     2796 *      positions) of the controls.
     2797 *
     2798 *      See @dlg_algorithm for details.
     2799 *
     2800 *      After this, DLGPRIVATE.szlClient is valid.
     2801 *
     2802 *@@added V0.9.15 (2001-08-26) [umoeller]
     2803 *@@changed V0.9.21 (2002-08-16) [umoeller]: adjusted for new algorithm
     2804 */
     2805
     2806static APIRET Dlg2_CalcSizes(PDLGPRIVATE pDlgData)
     2807{
     2808    APIRET arc;
     2809
     2810    // call process mode with the first for "calc size"
     2811    // process modes
     2812    // changed V0.9.21 (2002-08-16) [umoeller]
     2813    if (!(arc = ProcessAll(pDlgData,
     2814                           PROCESS_1_CALC_MIN_WIDTHS)))
     2815        if (!(arc = ProcessAll(pDlgData,
     2816                               PROCESS_2_CALC_RELATIVE_WIDTHS)))
     2817            if (!(arc = ProcessAll(pDlgData,
     2818                                   PROCESS_3_ALIGN_COLUMNS)))
     2819                // skip PROCESS_4_REMAINDER_WIDTHS if the dlg doesn't need it
     2820                if (    (!(pDlgData->flNeedsProcessing & FL_REMAINDER_WIDTHS))
     2821                     || (!(arc = ProcessAll(pDlgData,
     2822                                            PROCESS_4_REMAINDER_WIDTHS)))
     2823                   )
     2824                    arc = ProcessAll(pDlgData,
     2825                                     PROCESS_5_CALC_HEIGHTS);
     2826
     2827    // free the cached font resources that
     2828    // might have been created here
     2829    if (pDlgData->hps)
     2830    {
     2831        if (pDlgData->lcidLast)
     2832        {
     2833            GpiSetCharSet(pDlgData->hps, LCID_DEFAULT);
     2834            GpiDeleteSetId(pDlgData->hps, pDlgData->lcidLast);
     2835        }
     2836
     2837        WinReleasePS(pDlgData->hps);
     2838    }
     2839
     2840    return arc;
     2841}
     2842
     2843/*
     2844 *@@ Dlg3_PositionAndCreate:
     2845 *
     2846 *@@added V0.9.15 (2001-08-26) [umoeller]
     2847 *@@changed V0.9.15 (2001-08-26) [umoeller]: BS_DEFAULT for other than first button was ignored, fixed
     2848 *@@changed V0.9.20 (2002-08-10) [umoeller]: return code checking was missing, fixed
     2849 */
     2850
     2851static APIRET Dlg3_PositionAndCreate(PDLGPRIVATE pDlgData,
     2852                                     HWND *phwndFocusItem)       // out: item to give focus to
     2853{
     2854    APIRET arc = NO_ERROR;
     2855
     2856    /*
     2857     *  5) compute _positions_ of all controls
     2858     *
     2859     */
     2860
     2861    // this was missing a return code, fixed V0.9.20 (2002-08-10) [umoeller]
     2862    if (!(arc = ProcessAll(pDlgData,
     2863                           PROCESS_6_CALC_POSITIONS)))
     2864    {
     2865        /*
     2866         *  6) create control windows, finally
     2867         *
     2868         */
     2869
     2870        pDlgData->ptlTotalOfs.x = DLG_OUTER_SPACING_X * FACTOR_X;
     2871        pDlgData->ptlTotalOfs.y = DLG_OUTER_SPACING_Y * FACTOR_Y;
     2872
     2873        // this was missing a return code, fixed V0.9.20 (2002-08-10) [umoeller]
     2874        if (!(arc = ProcessAll(pDlgData,
     2875                               PROCESS_7_CREATE_CONTROLS)))
     2876        {
     2877            if (pDlgData->hwndDefPushbutton)
     2878            {
     2879                // we had a default pushbutton:
     2880                // go set it V0.9.14 (2001-08-21) [umoeller]
     2881                WinSetWindowULong(pDlgData->hwndDlg,
     2882                                  QWL_DEFBUTTON,
     2883                                  pDlgData->hwndDefPushbutton);
     2884                *phwndFocusItem = pDlgData->hwndDefPushbutton;
     2885                        // V0.9.15 (2001-08-26) [umoeller]
     2886            }
     2887            else
     2888                *phwndFocusItem = (pDlgData->hwndFirstFocus)
     2889                                    ? pDlgData->hwndFirstFocus
     2890                                    : pDlgData->hwndDlg;
     2891        }
     2892    }
     2893
     2894    return arc;
     2895}
     2896
     2897/*
     2898 *@@ Dlg9_Cleanup:
     2899 *
     2900 *@@added V0.9.15 (2001-08-26) [umoeller]
     2901 */
     2902
     2903static VOID Dlg9_Cleanup(PDLGPRIVATE *ppDlgData)
     2904{
     2905    PDLGPRIVATE pDlgData;
     2906    if (    (ppDlgData)
     2907         && (pDlgData = *ppDlgData)
     2908       )
     2909    {
     2910        PLISTNODE pTableNode;
     2911
     2912        // clean up the tables
     2913        FOR_ALL_NODES(&pDlgData->llTables, pTableNode)
     2914        {
     2915            PTABLEDEF pTable = (PTABLEDEF)pTableNode->pItemData;
     2916
     2917            FreeTable(pTable);
     2918                    // this may recurse for nested tables
     2919        }
     2920
     2921        lstClear(&pDlgData->llTables);
     2922
     2923        free(pDlgData);
     2924        *ppDlgData = NULL;
     2925    }
     2926}
     2927
     2928/* ******************************************************************
     2929 *
     2930 *   Dialog formatter entry points
     2931 *
     2932 ********************************************************************/
     2933
     2934/*
     2935 *@@ dlghCreateDlg:
     2936 *      replacement for WinCreateDlg/WinLoadDlg for creating a
     2937 *      dialog from a settings array in memory, which is
     2938 *      formatted automatically.
     2939 *
     2940 *      This does NOT use regular dialog templates from
     2941 *      module resources. Instead, you pass in an array
     2942 *      of DLGHITEM structures, which define the controls
     2943 *      and how they are to be formatted.
     2944 *
     2945 *      The main advantage compared to dialog resources is
     2946 *      that with this function, you will never have to
     2947 *      define control _positions_. Instead, you only specify
     2948 *      the control _sizes_, and all positions are computed
     2949 *      automatically here. Even better, for many controls,
     2950 *      auto-sizing is supported according to the control's
     2951 *      text (e.g. for statics and checkboxes). This is
     2952 *      quite similar to HTML tables.
     2953 *
     2954 *      A regular standard dialog would use something like
     2955 *
     2956 +          FCF_TITLEBAR | FCF_SYSMENU | FCF_DLGBORDER | FCF_NOBYTEALIGN | FCF_CLOSEBUTTON
     2957 *
     2958 *      for flCreateFlags. To make the dlg sizeable, specify
     2959 *      FCF_SIZEBORDER instead of FCF_DLGBORDER.
     2960 *
     2961 *      dialog.h defines FCF_FIXED_DLG and FCF_SIZEABLE_DLG
     2962 *      to make this more handy.
     2963 *
     2964 *      <B>Usage:</B>
     2965 *
     2966 *      Like WinLoadDlg, this creates a standard WC_FRAME and
     2967 *      subclasses it with fnwpMyDlgProc. It then sends WM_INITDLG
     2968 *      to the dialog with pCreateParams in mp2.
     2969 *
     2970 *      If this func returns no error, you can then use
     2971 *      WinProcessDlg with the newly created dialog as usual. In
     2972 *      your dlg proc, use WinDefDlgProc as usual.
     2973 *
     2974 *      There is NO run-time overhead for either code or memory
     2975 *      after dialog creation; after this function returns, the
     2976 *      dialog is a standard dialog as if loaded from WinLoadDlg.
     2977 *      The array of DLGHITEM structures defines how the
     2978 *      dialog is set up. All this is ONLY used by this function
     2979 *      and NOT needed after the dialog has been created.
     2980 *
     2981 *      In DLGHITEM, the "Type" field determines what this
     2982 *      structure defines. A number of handy macros have been
     2983 *      defined to make this easier and to provide type-checking
     2984 *      at compile time. See dialog.h for the complete (and
     2985 *      ever-expanding) list of definitions.
     2986 *
     2987 *      See @dlg_using_macros for how to use these macros.
     2988 *
     2989 *      Essentially, such a dialog item operates similarly to
     2990 *      HTML tables. There are rows and columns in the table,
     2991 *      and each control which is specified must be a column
     2992 *      in some table. Tables may also nest (see below).
     2993 *
     2994 *      See @dlg_algorithm for the gory details of the new
     2995 *      algorithm used since V0.9.21.
     2996 *
     2997 *      See @dlg_boxmodel for information about how the
     2998 *      rectangles are defined.
    23592999 *
    23603000 *      <B>Example:</B>
     
    23693009 +                                        fnwpMyDlgProc,
    23703010 +                                        "My Dlg Title",
    2371  +                                        DlgTemplate,      // DLGHITEM array
    2372  +                                        ARRAYITEMCOUNT(DlgTemplate),
     3011 +                                        dlgTemplate,      // DLGHITEM array
     3012 +                                        ARRAYITEMCOUNT(dlgTemplate),
    23733013 +                                        NULL,             // mp2 for WM_INITDLG
    23743014 +                                        "9.WarpSans"))    // default font
     
    24293069
    24303070APIRET dlghCreateDlg(HWND *phwndDlg,            // out: new dialog
    2431                      HWND hwndOwner,
     3071                     HWND hwndOwner,            // in: owner for dialog
    24323072                     ULONG flCreateFlags,       // in: standard FCF_* frame flags
    2433                      PFNWP pfnwpDialogProc,
    2434                      PCSZ pcszDlgTitle,
    2435                      PCDLGHITEM paDlgItems,      // in: definition array
    2436                      ULONG cDlgItems,           // in: array item count (NOT array size)
    2437                      PVOID pCreateParams,       // in: for mp2 of WM_INITDLG
    2438                      PCSZ pcszControlsFont) // in: font for ctls with CTL_COMMON_FONT
     3073                     PFNWP pfnwpDialogProc,     // in: dialog winproc or WinDefDlgProc
     3074                     PCSZ pcszDlgTitle,         // in: title to set for dlg frame's titlebar
     3075                     PCDLGHITEM paDlgItems,     // in: definition array with tables, rows, and columns
     3076                     ULONG cDlgItems,           // in: ARRAYITEMCOUNT(paDlgItems)
     3077                     PVOID pCreateParams,       // in: create param for mp2 of WM_INITDLG
     3078                     PCSZ pcszControlsFont)     // in: font for ctls with CTL_COMMON_FONT
    24393079{
    24403080    APIRET      arc = NO_ERROR;
     
    25283168
    25293169                        // calculate the frame size from the client size
    2530                         rclClient.xLeft = 10;
    2531                         rclClient.yBottom = 10;
     3170                        rclClient.xLeft = DLG_OUTER_SPACING_X * FACTOR_X; // 10;
     3171                        rclClient.yBottom = DLG_OUTER_SPACING_Y * FACTOR_Y; // 10;
    25323172                        rclClient.xRight =   pDlgData->szlClient.cx
    2533                                            + 2 * (DLG_OUTER_SPACING_X * FACTOR_X);
     3173                                           + 2 * (DLG_OUTER_SPACING_X * FACTOR_X)
     3174                                           - 1;
    25343175                        rclClient.yTop   =   pDlgData->szlClient.cy
    2535                                            + 2 * (DLG_OUTER_SPACING_Y * FACTOR_Y);
     3176                                           + 2 * (DLG_OUTER_SPACING_Y * FACTOR_Y)
     3177                                           - 1;
    25363178                        WinCalcFrameRect(hwndDlg,
    25373179                                         &rclClient,
     
    28023444 +
    28033445 +      PDLGARRAY pArraySample = NULL;
     3446 +      // create array with sufficient size
    28043447 +      dlghCreateArray(   ARRAYITEMCOUNT(dlgSampleFront)
    28053448 +                       + ARRAYITEMCOUNT(dlgSampleSometimes)
     
    29133556
    29143557APIRET dlghAppendToArray(PDLGARRAY pArray,      // in: dialog array created by dlghCreateArray
    2915                          PCDLGHITEM paItems,     // in: subarray to be appended
     3558                         PCDLGHITEM paItems,    // in: subarray to be appended
    29163559                         ULONG cItems)          // in: subarray item count (NOT array size)
    29173560{
     
    29753618 *@@changed V0.9.20 (2002-07-12) [umoeller]: made icon spacing wider
    29763619 *@@changed V0.9.20 (2002-08-10) [umoeller]: fixed missing close button
     3620 *@@changed V0.9.21 (2002-08-16) [umoeller]: now using table alignment
    29773621 */
    29783622
     
    30053649    DLGHITEM MessageBoxFront[] =
    30063650                {
    3007                     START_TABLE,
     3651                    START_TABLE_ALIGN,
    30083652                        START_ROW(ROW_VALIGN_CENTER),
    30093653                            CONTROL_DEF(&Icon),
    3010                         START_TABLE,
    3011                             START_ROW(ROW_VALIGN_CENTER),
    3012                                 CONTROL_DEF(&Spacing),
    3013                             START_ROW(ROW_VALIGN_CENTER),
    3014                                 CONTROL_DEF(&InfoText),
    3015                             START_ROW(ROW_VALIGN_CENTER),
    3016                                 CONTROL_DEF(&Spacing),
    3017                             START_ROW(ROW_VALIGN_CENTER),
    3018                                 CONTROL_DEF(&Buttons[0]),
    3019                                 CONTROL_DEF(&Buttons[1]),
    3020                                 CONTROL_DEF(&Buttons[2]),
     3654                            START_TABLE,
     3655                                START_ROW(ROW_VALIGN_CENTER),
     3656                                    CONTROL_DEF(&Spacing),
     3657                                START_ROW(ROW_VALIGN_CENTER),
     3658                                    CONTROL_DEF(&InfoText),
     3659                                START_ROW(ROW_VALIGN_CENTER),
     3660                                    CONTROL_DEF(&Spacing),
     3661                            END_TABLE,
     3662                        START_ROW(ROW_VALIGN_CENTER),
     3663                            CONTROL_DEF(&Spacing),
     3664                            START_TABLE,
     3665                                START_ROW(ROW_VALIGN_CENTER),
     3666                                    CONTROL_DEF(&Buttons[0]),
     3667                                    CONTROL_DEF(&Buttons[1]),
     3668                                    CONTROL_DEF(&Buttons[2]),
    30213669                },
    30223670            MessageBoxHelp[] =
    30233671                {
    3024                                 CONTROL_DEF(&Buttons[3]),
     3672                                    CONTROL_DEF(&Buttons[3]),
    30253673                },
    30263674            MessageBoxTail[] =
    30273675                {
    3028                         END_TABLE,
     3676                            END_TABLE,
    30293677                    END_TABLE
    30303678                };
     
    32433891/*
    32443892 *@@ dlghMessageBox:
    3245  *      WinMessageBox replacement.
     3893 *      WinMessageBox replacement, which uses dlghCreateDlg
     3894 *      internally.
    32463895 *
    32473896 *      This has all the flags of the standard call,
     
    32903939                     const MSGBOXSTRINGS *pStrings) // in: strings array
    32913940{
    3292     HWND hwndDlg;
    3293     ULONG ulAlarmFlag;
    3294     APIRET arc = dlghCreateMessageBox(&hwndDlg,
    3295                                       hwndOwner,
    3296                                       hptrIcon,
    3297                                       pcszTitle,
    3298                                       pcszMessage,
    3299                                       pfnHelp,
    3300                                       flFlags,
    3301                                       pcszFont,
    3302                                       pStrings,
    3303                                       &ulAlarmFlag);
    3304 
    3305     if (!arc && hwndDlg)
     3941    HWND    hwndDlg;
     3942    ULONG   ulAlarmFlag;
     3943    APIRET  arc;
     3944    CHAR    szMsg[100];
     3945
     3946    if (    (!(arc = dlghCreateMessageBox(&hwndDlg,
     3947                                          hwndOwner,
     3948                                          hptrIcon,
     3949                                          pcszTitle,
     3950                                          pcszMessage,
     3951                                          pfnHelp,
     3952                                          flFlags,
     3953                                          pcszFont,
     3954                                          pStrings,
     3955                                          &ulAlarmFlag)))
     3956         && (hwndDlg)
     3957       )
    33063958    {
    33073959        // SHOW DIALOG
     
    33103962                                      flFlags));
    33113963    }
    3312     else
    3313     {
    3314         CHAR szMsg[100];
    3315         sprintf(szMsg, "dlghCreateMessageBox reported error %u.", arc);
    3316         WinMessageBox(HWND_DESKTOP,
    3317                       NULLHANDLE,
    3318                       "Error",
    3319                       szMsg,
    3320                       0,
    3321                       MB_CANCEL | MB_MOVEABLE);
    3322     }
     3964
     3965    sprintf(szMsg, "dlghCreateMessageBox reported error %u.", arc);
     3966    WinMessageBox(HWND_DESKTOP,
     3967                  NULLHANDLE,
     3968                  "Error",
     3969                  szMsg,
     3970                  0,
     3971                  MB_CANCEL | MB_MOVEABLE);
    33233972
    33243973    return (DID_CANCEL);
     
    33664015{
    33674016    CONTROLDEF
    3368                 Static = {
    3369                             WC_STATIC,
     4017        Static = CONTROLDEF_TEXT_WORDBREAK(
    33704018                            NULL,
    3371                             WS_VISIBLE | SS_TEXT | DT_LEFT | DT_WORDBREAK,
    33724019                            -1,
    3373                             CTL_COMMON_FONT,
    3374                             0,
    3375                             { 150, SZL_AUTOSIZE },     // size
    3376                             COMMON_SPACING,
    3377                          },
    3378                 Entry = {
    3379                             WC_ENTRYFIELD,
     4020                            150),
     4021        Entry = CONTROLDEF_ENTRYFIELD(
    33804022                            NULL,
    3381                             WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_MARGIN | ES_AUTOSCROLL,
    33824023                            999,
    3383                             CTL_COMMON_FONT,
    3384                             0,
    3385                             { 150, SZL_AUTOSIZE },     // size
    3386                             COMMON_SPACING,
    3387                          },
    3388                 OKButton = {
    3389                             WC_BUTTON,
     4024                            150,
     4025                            SZL_AUTOSIZE),
     4026        OKButton = CONTROLDEF_DEFPUSHBUTTON(
    33904027                            NULL,
    3391                             WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_DEFAULT,
    33924028                            DID_OK,
    3393                             CTL_COMMON_FONT,
    3394                             0,
    3395                             { STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT },    // size
    3396                             COMMON_SPACING,
    3397                          },
    3398                 CancelButton = {
    3399                             WC_BUTTON,
     4029                            STD_BUTTON_WIDTH,
     4030                            STD_BUTTON_HEIGHT),
     4031        CancelButton = CONTROLDEF_PUSHBUTTON(
    34004032                            NULL,
    3401                             WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
    34024033                            DID_CANCEL,
    3403                             CTL_COMMON_FONT,
    3404                             0,
    3405                             { STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT },    // size
    3406                             COMMON_SPACING,
    3407                          };
     4034                            STD_BUTTON_WIDTH,
     4035                            STD_BUTTON_HEIGHT);
     4036
    34084037    DLGHITEM DlgTemplate[] =
    34094038        {
  • trunk/src/helpers/encodings.c

    r192 r209  
    88 *
    99 *      See encCreateCodec for an introduction.
     10 *
     11 *      See http://www.ietf.org/rfc/rfc2279.txt for
     12 *      RFC 2279, which defines UTF-8.
    1013 *
    1114 *      Be warned, compilation of this file takes a long
  • trunk/src/helpers/exeh.c

    r176 r209  
    176176 *@@changed V0.9.16 (2001-12-08) [umoeller]: speed optimizations, changed some return codes
    177177 *@@changed V0.9.16 (2002-01-04) [umoeller]: added fixes for COM, BAT, CMD extensions
     178 *@@changed V0.9.21 (2002-08-18) [umoeller]: this was completely broken for files without extensions (os2krnl)
    178179 */
    179180
     
    193194
    194195    if (!ppExec)
    195         return (ERROR_INVALID_PARAMETER);
     196        return ERROR_INVALID_PARAMETER;
    196197
    197198    if (!(pExec = (PEXECUTABLE)malloc(sizeof(EXECUTABLE))))
    198         return (ERROR_NOT_ENOUGH_MEMORY);
     199        return ERROR_NOT_ENOUGH_MEMORY;
    199200
    200201    memset(pExec, 0, sizeof(EXECUTABLE));
     
    202203    // check some of the default extensions
    203204    // V0.9.16 (2002-01-04) [umoeller]
    204     if (pExt = doshGetExtension(pcszExecutable))
     205    if (!(pExt = doshGetExtension(pcszExecutable)))
    205206    {
     207        // has no extension: then open file!
     208        // fixed V0.9.21 (2002-08-18) [umoeller]
     209        fOpenFile = TRUE;
     210    }
     211    else
     212    {
     213        // has extension:
    206214        if (!stricmp(pExt, "COM"))
    207215        {
     
    508516/*
    509517 *@@ ParseBldLevel:
    510  *      called from exehQueryBldLevel to parse
    511  *      the BLDLEVEL string.
    512  *
    513  *      On entry, caller has copied the string into
    514  *      pExec->pszDescription. The string is
    515  *      null-terminated.
    516  *
    517  *      The BLDLEVEL string comes in two flavors.
     518 *      called from exehQueryBldLevel to parse the BLDLEVEL string.
     519 *
     520 *      On entry, caller has copied the string into pExec->pszDescription.
     521 *      The string is null-terminated.
     522 *
     523 *      The BLDLEVEL string comes in at least two basic flavors.
    518524 *
    519525 *      --  The standard format is:
     
    524530 *          need to have them.
    525531 *
    526  *      --  However, there is an extended version
    527  *          in that the DESCRIPTION field is split
    528  *          up even more. The marker for this seems
    529  *          to be that the description starts out
    530  *          with "##1##".
     532 *      --  However, there is an extended version in that the DESCRIPTION field
     533 *          is split up even more.
     534 *
     535 *          I have seen two subformats for this.
     536 *
     537 *          --  DANIS506.ADD and some IBM programs have a marker that seems
     538 *              to be that the description starts out with "##1##".
    531539 *
    532540 +              ##1## DATETIME BUILDMACHINE:ASD:LANG:CTRY:REVISION:UNKNOWN:FIXPAK@@DESCRIPTION
    533541 *
    534  *          The problem is that the DATETIME field comes
    535  *          in several flavors. IBM uses things like
    536  *
    537  +              "Thu Nov 30 15:30:37 2000 BWBLD228"
    538  *
    539  *          while DANIS506.ADD has
    540  *
    541  +              "15.12.2000 18:22:57      Nachtigall"
    542  *
    543  *          Looks like the date/time string is standardized
    544  *          to have 24 characters then.
     542 *              The problem is that the DATETIME field comes
     543 *              in several flavors. IBM uses things like
     544 *
     545 +                  "Thu Nov 30 15:30:37 2000 BWBLD228"
     546 *
     547 *              while DANIS506.ADD has
     548 *
     549 +                  "15.12.2000 18:22:57      Nachtigall"
     550 *
     551 *              Looks like the date/time string is standardized to have 24 characters then.
     552 *
     553 *          --  IBM TCP/IP executables (try INETD.EXE) have something yet different on.
     554 *              We now try to parse that format as well, even though bldlevel.exe can't
     555 *              handle it. (Isn't that utility from IBM too?)
     556 *
     557 *              Here's what I get for inetd.exe:
     558 *
     559 +              ##built 09:16:27 Mon Sep 17 2001 -- On AURORA43;0.1@@ TCP/IP for OS/2: INETD
    545560 *
    546561 *@@added V0.9.12 (2001-05-18) [umoeller]
    547562 *@@changed V0.9.12 (2001-05-19) [umoeller]: added extended BLDLEVEL support
     563 *@@changed V0.9.21 (2002-08-18) [umoeller]: added support for IBM TCP/IP format
     564 *@@changed V0.9.21 (2002-08-18) [umoeller]: fixed DANIS506 format when an extended field had only one character
    548565 */
    549566
     
    555572
    556573    // @#VENDOR:VERSION#@ DESCRIPTION
    557     // but skip the first byte, which has the string length
    558574    if (    (pStartOfVendor = strstr(pExec->pszDescription, "@#"))
    559575         && (pStartOfInfo = strstr(pStartOfVendor + 2, "#@"))
     
    569585
    570586        // now check if we have extended DESCRIPTION V0.9.12 (2001-05-19) [umoeller]
    571         if (    (strlen(pStartOfInfo) > 6)
    572              && (!memcmp(pStartOfInfo, "##1##", 5))
    573            )
     587        if (strlen(pStartOfInfo) > 6)
    574588        {
    575             // yes: parse that beast
    576             const char *p = pStartOfInfo + 5;
    577 
    578             // get build date/time
    579             if (strlen(p) > 24)
     589            if (!memcmp(pStartOfInfo, "##1##", 5))
    580590            {
    581                 // date/time seems to be fixed 24 chars in length
    582                 if (pExec->pszBuildDateTime = (PSZ)malloc(25))
    583                 {
    584                     memcpy(pExec->pszBuildDateTime,
     591                // DANIS506.ADD format:
     592                // "##1## 2.7.2002 19:32:34        Nachtigall::::6::@@..."
     593
     594                // parse that beast
     595                PCSZ p = pStartOfInfo + 5;
     596
     597                // get build date/time
     598                if (strlen(p) > 24)
     599                {
     600                    // skip leading and trailing spaces
     601                    // V0.9.21 (2002-08-18) [umoeller]
     602                    PCSZ pStartOfDT = p,
     603                         pEndOfDT = p + 24;
     604                                // date/time seems to be fixed 24 chars in length
     605
     606                    while (*pStartOfDT == ' ')
     607                        ++pStartOfDT;
     608
     609                    while (    (*pEndOfDT == ' ')
     610                            && (pEndOfDT > pStartOfDT)
     611                          )
     612                        --pEndOfDT;
     613
     614                    pExec->pszBuildDateTime = strhSubstr(pStartOfDT, pEndOfDT + 1);
     615
     616                    /* memcpy(pExec->pszBuildDateTime,
    585617                           p,
    586618                           24);
    587619                    pExec->pszBuildDateTime[24] = '\0';
    588 
     620                    */
     621
     622                    // date/time seems to be fixed 24 chars in length
    589623                    p += 24;
    590624
     
    613647                             ul++)
    614648                        {
    615                             BOOL fStop = FALSE;
    616                             const char *pNextColon = strchr(p, ':'),
    617                                        *pDoubleAt = strstr(p, "@@");
     649                            BOOL    fStop = FALSE;
     650                            PCSZ    pNextColon = strchr(p, ':'),
     651                                    pDoubleAt = strstr(p, "@@");
    618652                            if (!pNextColon)
    619653                            {
     
    635669                               )
    636670                            {
    637                                 if (pNextColon > p + 1)
     671                                // if (pNextColon > p + 1)
     672                                        // fixed V0.9.21 (2002-08-18) [umoeller]
     673                                        // this failed on fields like "revision"
     674                                        // which only had one character
     675                                if (pNextColon > p)
    638676                                    *(papsz[ul]) = strhSubstr(p, pNextColon);
    639677                            }
     
    648686                    }
    649687                }
     688
     689                if (pStartOfInfo = strstr(p,
     690                                          "@@"))
     691                    pStartOfInfo += 2;
     692            } // end if (!memcmp(pStartOfInfo, "##1##", 5))
     693            else if (!memcmp(pStartOfInfo, "##built", 7))
     694            {
     695                // IBM TCP/IP format:
     696                // V0.9.21 (2002-08-18) [umoeller]
     697
     698                // ##built 09:16:27 Mon Sep 17 2001 -- On AURORA43;0.1@@ TCP/IP for OS/2: INETD
     699
     700                PCSZ    p = pStartOfInfo + 7,
     701                        p2,
     702                        p3;
     703
     704                if (p3 = strchr(p, ';'))
     705                {
     706                    while (*p == ' ')
     707                        ++p;
     708
     709                    // ##built 09:16:27 Mon Sep 17 2001 -- On AURORA43;0.1@@ TCP/IP for OS/2: INETD
     710                    //         ^ p                                    ^ p3
     711                    //                                 ^ p2
     712
     713                    if (    (p2 = strstr(p, " -- On "))
     714                         && (p2 < p3)
     715                       )
     716                    {
     717                        pExec->pszBuildMachine = strhSubstr(p2 + 7, p3);
     718                        pExec->pszBuildDateTime = strhSubstr(p, p2);
     719                    }
     720                    else
     721                        pExec->pszBuildDateTime = strhSubstr(p, p3);
     722
     723                    p = p3 + 1;
     724                }
     725
     726                if (pStartOfInfo = strstr(p,
     727                                          "@@"))
     728                {
     729                    if (pStartOfInfo > p3)
     730                    {
     731                        // p3 points to this "0.1" string; I assume this is
     732                        // a "revision.fixpak" format since inetver reports
     733                        // four digits with this revision
     734                        PCSZ p4;
     735                        if (    (p4 = strchr(p3, '.'))
     736                             && (p4 < pStartOfInfo)
     737                           )
     738                        {
     739                            pExec->pszRevision = strhSubstr(p3 + 1, p4);
     740                            pExec->pszFixpak = strhSubstr(p4 + 1, pStartOfInfo);
     741                        }
     742                        else
     743                            pExec->pszRevision = strhSubstr(p3 + 1, pStartOfInfo);
     744                    }
     745
     746                    pStartOfInfo += 2;
     747                }
    650748            }
    651 
    652             pStartOfInfo = strstr(p,
    653                                   "@@");
    654             if (pStartOfInfo)
    655                 pStartOfInfo += 2;
    656749        }
    657750
     
    666759            // skip leading spaces in info string
    667760            while (*pStartOfInfo == ' ')
    668                 pStartOfInfo++;
     761                ++pStartOfInfo;
     762
    669763            if (*pStartOfInfo)  // V0.9.9 (2001-04-04) [umoeller]
    670764                // and copy until end of string
     
    21422236static APIRET ExpandIterdata1(char *pabTarget,         // out: page data (pagesize as in lx spec)
    21432237                              int cbTarget,            // in: sizeof *pabTarget (pagesize as in lx spec)
    2144                               const char *pabSource,   // in: compressed source data in EXEPACK:1 format
     2238                              PCSZ pabSource,   // in: compressed source data in EXEPACK:1 format
    21452239                              int cbSource)            // in: sizeof *pabSource
    21462240{
     
    22052299 */
    22062300
    2207 static void memcpyw(char *pch1, const char *pch2, size_t cch)
     2301static void memcpyw(char *pch1, PCSZ pch2, size_t cch)
    22082302{
    22092303    /*
     
    22392333 */
    22402334
    2241 static void memcpyb(char *pch1, const char *pch2, size_t cch)
     2335static void memcpyb(char *pch1, PCSZ pch2, size_t cch)
    22422336{
    22432337    /*
     
    22762370static APIRET ExpandIterdata2(char *pachPage,              // out: page data (pagesize as in lx spec)
    22772371                              int cchPage,                 // in: sizeof *pachPage (pagesize as in lx spec)
    2278                               const char *pachSrcPage,     // in: compressed source data in EXEPACK:1 format
     2372                              PCSZ pachSrcPage,     // in: compressed source data in EXEPACK:1 format
    22792373                              int cchSrcPage)              // in: size of source buf
    22802374{
     
    31823276}
    31833277
     3278
  • trunk/src/helpers/makefile

    r201 r209  
    142142    @echo ----- Leaving $(MAKEDIR)
    143143
     144# Define the main dependency between the output HELPERS.LIB and
     145# all the object files.
     146# $? represents the names of all dependent files that are
     147# out-of-date with respect to the target file.
     148# The exclamation point ( ! ) preceding the LIB command causes NMAKE
     149# to execute the LIB command once for each dependent file in the list.
     150
     151$(OUTPUTDIR)\helpers.lib: $(OBJS)
     152!ifdef EMX
     153    !emxomfar cr $* $?
     154!else
     155    !ilib /nol /nob $* -+$?;
     156!endif
     157
     158# same thing for cp.lib
     159$(OUTPUTDIR)\cp.lib: $(CPOBJS)
     160!ifdef EMX
     161    !emxomfar cr $* $?
     162!else
     163    !ilib /nol /nob $* -+$?;
     164!endif
     165
     166# same thing for plainc.lib
     167$(OUTPUTDIR)\plainc.lib: $(PLAINCOBJS)
     168!ifdef EMX
     169    !emxomfar cr $* $?
     170!else
     171    !ilib /nol /nob $* -+$?;
     172!endif
     173
     174!include helpers_post.in
     175
     176###################################################
     177#
    144178# "test" target: for test cases
     179#
     180###################################################
     181
    145182TESTCASE_DIR = testcase
    146183
    147 TESTCASE_CC = icc /c /ti+ /w2 /ss /se /i$(HELPERS_BASE)\include /Fo$(TESTCASE_DIR)\$(@B).obj $(@B).c
     184DEBUGDIALOG =
     185!ifdef DBGDLG
     186DEBUGDIALOG = /DDEBUG_DIALOG_WINDOWS=1
     187!endif
     188
     189TESTCASE_CC = icc /c /ti+ /w2 /ss /se /D__DEBUG__=1 $(DEBUGDIALOG) /i$(HELPERS_BASE)\include /Fo$(TESTCASE_DIR)\$(@B).obj $(@B).c
    148190
    149191.c.{$(TESTCASE_DIR)}.obj:
    150192    @echo $(MAKEDIR)\makefile: Compiling $(@B).c
     193    @echo INCLUDE is $(INCLUDE)
    151194    $(TESTCASE_CC)
    152195
     
    155198    dosh.exe \
    156199    dialog.exe \
    157     vcard.exe \
     200    exeh.exe \
    158201    fdlg.exe \
    159 
    160 # dosh.exe
    161 DOSH_TEST_OBJS = \
    162     $(TESTCASE_DIR)\dosh.obj \
    163     $(TESTCASE_DIR)\_test_dosh.obj
    164 
    165 dosh.exe: $(DOSH_TEST_OBJS)
    166     ilink /debug /optfunc /pmtype:vio $(DOSH_TEST_OBJS) /o:$@
    167 
    168 $(TESTCASE_DIR)\dialog.obj: ..\..\include\helpers\dialog.h
    169 $(TESTCASE_DIR)\_test_dialog.obj: ..\..\include\helpers\dialog.h
     202    vcard.exe
    170203
    171204# dialog.exe
     
    190223    $(TESTCASE_DIR)\gpih.obj
    191224
     225$(TESTCASE_DIR)\dialog.obj: ..\..\include\helpers\dialog.h
     226$(TESTCASE_DIR)\_test_dialog.obj: ..\..\include\helpers\dialog.h
     227
    192228dialog.exe: $(DIALOG_TEST_OBJS)
    193     ilink /debug /optfunc /pmtype:pm $(DIALOG_TEST_OBJS) /o:$@
     229    ilink /debug /optfunc /pmtype:pm $(DIALOG_TEST_OBJS) pmprintf.lib /o:$@
     230
     231# dosh.exe
     232DOSH_TEST_OBJS = \
     233    $(TESTCASE_DIR)\dosh.obj \
     234    $(TESTCASE_DIR)\_test_dosh.obj
     235
     236dosh.exe: $(DOSH_TEST_OBJS)
     237    ilink /debug /optfunc /pmtype:vio $(DOSH_TEST_OBJS) pmprintf.lib /o:$@
     238
     239# exeh.exe
     240EXEH_TEST_OBJS = \
     241    $(TESTCASE_DIR)\dosh.obj \
     242    $(TESTCASE_DIR)\exeh.obj \
     243    $(TESTCASE_DIR)\stringh.obj \
     244    $(TESTCASE_DIR)\xstring.obj \
     245    $(TESTCASE_DIR)\_test_exeh.obj
     246
     247exeh.exe: $(EXEH_TEST_OBJS)
     248    ilink /debug /optfunc /pmtype:vio $(EXEH_TEST_OBJS) pmprintf.lib /o:$@
     249
     250# fdlg.exe
     251FDLG_TEST_OBJS = \
     252    $(TESTCASE_DIR)\_call_filedlg.obj
     253
     254fdlg.exe: $(FDLG_TEST_OBJS)
     255    ilink /debug /pmtype:pm $(FDLG_TEST_OBJS) /o:$@
    194256
    195257# vcard.exe
     
    210272    ilink /debug /pmtype:vio $(VCARD_TEST_OBJS) /o:$@
    211273
    212 # vcard.exe
    213 VCARD_TEST_OBJS = \
    214     $(TESTCASE_DIR)\_call_filedlg.obj
    215 
    216 fdlg.exe: $(VCARD_TEST_OBJS)
    217     ilink /debug /pmtype:pm $(VCARD_TEST_OBJS) /o:$@
    218 
    219274test: $(TESTCASE_TARGETS)
    220275
    221 # Define the main dependency between the output HELPERS.LIB and
    222 # all the object files.
    223 # $? represents the names of all dependent files that are
    224 # out-of-date with respect to the target file.
    225 # The exclamation point ( ! ) preceding the LIB command causes NMAKE
    226 # to execute the LIB command once for each dependent file in the list.
    227 
    228 $(OUTPUTDIR)\helpers.lib: $(OBJS)
    229 !ifdef EMX
    230     !emxomfar cr $* $?
    231 !else
    232     !ilib /nol /nob $* -+$?;
    233 !endif
    234 
    235 # same thing for cp.lib
    236 $(OUTPUTDIR)\cp.lib: $(CPOBJS)
    237 !ifdef EMX
    238     !emxomfar cr $* $?
    239 !else
    240     !ilib /nol /nob $* -+$?;
    241 !endif
    242 
    243 # same thing for plainc.lib
    244 $(OUTPUTDIR)\plainc.lib: $(PLAINCOBJS)
    245 !ifdef EMX
    246     !emxomfar cr $* $?
    247 !else
    248     !ilib /nol /nob $* -+$?;
    249 !endif
    250 
    251 !include helpers_post.in
    252 
    253 
     276
Note: See TracChangeset for help on using the changeset viewer.