Changeset 209
- Timestamp:
- Aug 19, 2002, 11:23:17 PM (23 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/helpers/apps.h
r201 r209 55 55 56 56 APIRET appParseEnvironment(const char *pcszEnv, 57 57 PDOSENVIRONMENT pEnv); 58 58 59 59 APIRET appGetEnvironment(PDOSENVIRONMENT pEnv); 60 60 61 61 PSZ* appFindEnvironmentVar(PDOSENVIRONMENT pEnv, 62 62 PSZ pszVarName); 63 63 64 64 APIRET appSetEnvironmentVar(PDOSENVIRONMENT pEnv, 65 66 65 PSZ pszNewEnv, 66 BOOL fAddFirst); 67 67 68 68 APIRET appConvertEnvironment(PDOSENVIRONMENT pEnv, 69 70 69 PSZ *ppszEnv, 70 PULONG pulSize); 71 71 72 72 APIRET appFreeEnvironment(PDOSENVIRONMENT pEnv); … … 81 81 82 82 APIRET appQueryAppType(const char *pcszExecutable, 83 84 83 PULONG pulDosAppType, 84 PULONG pulWinAppType); 85 85 86 86 PCSZ appDescribeAppType(PROGCATEGORY progc); … … 116 116 PULONG pulExitCode); 117 117 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); 123 124 124 BOOL appOpenURL(PCSZ pcszURL); 125 APIRET appOpenURL(PCSZ pcszURL, 126 PSZ pszAppStarted, 127 ULONG cbAppStarted); 125 128 126 129 #endif -
trunk/include/helpers/comctl.h
r189 r209 36 36 #ifndef COMCTL_HEADER_INCLUDED 37 37 #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); 38 48 39 49 /* ****************************************************************** -
trunk/include/helpers/dialog.h
r201 r209 46 46 #define DLGERR_ROW_BEFORE_TABLE (ERROR_DLG_FIRST) 47 47 #define DLGERR_CONTROL_BEFORE_ROW (ERROR_DLG_FIRST + 1) 48 #define DLGERR_NULL_C TL_DEF(ERROR_DLG_FIRST + 2)48 #define DLGERR_NULL_CONTROLDEF (ERROR_DLG_FIRST + 2) 49 49 #define DLGERR_CANNOT_CREATE_FRAME (ERROR_DLG_FIRST + 3) 50 50 #define DLGERR_INVALID_CODE (ERROR_DLG_FIRST + 4) … … 55 55 #define DLGERR_INVALID_CONTROL_TITLE (ERROR_DLG_FIRST + 9) 56 56 #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) 60 65 61 66 /* ****************************************************************** … … 66 71 67 72 #define SZL_AUTOSIZE (-1) 73 #define SZL_REMAINDER (0) 68 74 69 75 #define CTL_COMMON_FONT ((PCSZ)-1) … … 97 103 // font specified on input to dlghCreateDlg 98 104 99 USHORT usAdjustPosition;105 // USHORT usAdjustPosition; 100 106 // flags for winhAdjustControls; any combination of 101 107 // XAC_MOVEX, XAC_MOVEY, XAC_SIZEX, XAC_SIZEY 102 // @@todo not implemented yet108 // removed V0.9.21 (2002-08-18) [umoeller] 103 109 104 110 SIZEL szlDlgUnits; 105 // proposed size for the control . Note that starting106 // with V0.9.19, these are now dialog units to107 // finally fix the bad alignment problems with108 // lower resolutions. The dialog formatter applies109 // a n internal factor to these things based on111 // 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 110 116 // 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 // 111 122 // A number of special flags are available per 112 123 // cx and cy field: 124 // 113 125 // -- 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 // 116 137 // -- Any other _negative_ value is considered a 117 138 // percentage of the largest row width in the … … 119 140 // the largest row in the table. This is valid 120 141 // 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 // 121 149 // If the CONTROLDEF appears with a START_NEW_TABLE 122 150 // type in _DLGHITEM (to specify a group table) … … 177 205 // TYPE_END_TABLE // end of table 178 206 179 const CONTROLDEF *pCtlDef;207 ULONG ul1; // const CONTROLDEF *pCtlDef; 180 208 // -- with TYPE_START_NEW_TABLE: if NULL, this starts 181 209 // an invisible table (for formatting only). … … 186 214 // the table. 187 215 188 ULONG fl;216 ULONG ul2; 189 217 // -- with TYPE_START_NEW_TABLE. TABLE_* formatting flags. 190 218 #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 191 230 192 231 // -- with TYPE_START_NEW_ROW: ROW_* formatting flags. … … 202 241 // a few handy macros for defining templates 203 242 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 } 219 262 220 263 /* ****************************************************************** … … 248 291 #define DLG_OUTER_SPACING_Y 3 249 292 250 #define COMMON_SPACING 1 293 #ifdef DEBUG_DIALOG_WINDOWS 294 #define COMMON_SPACING 5 295 #else 296 #define COMMON_SPACING 1 297 #endif 251 298 252 299 #define GROUP_INNER_SPACING_X 3 253 #define GROUP_OUTER_SPACING_BOTTOM 1254 300 #define GROUP_INNER_SPACING_BOTTOM 3 255 301 #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 257 305 258 306 #define STD_BUTTON_WIDTH 50 … … 274 322 #define CONTROLDEF_GROUP(pcsz, id, cx, cy) { WC_STATIC, pcsz, \ 275 323 WS_VISIBLE | SS_GROUPBOX | DT_MNEMONIC, \ 276 id, CTL_COMMON_FONT, 0, { cx, cy }, COMMON_SPACING}324 id, CTL_COMMON_FONT, { cx, cy }, 0 } 277 325 278 326 #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 } 279 331 280 332 #define CONTROLDEF_TEXT(pcsz, id, cx, cy) { WC_STATIC, pcsz, \ 281 333 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 } 283 335 284 336 #define LOADDEF_TEXT(id) CONTROLDEF_TEXT(LOAD_STRING, id, SZL_AUTOSIZE, SZL_AUTOSIZE) … … 286 338 #define CONTROLDEF_TEXT_CENTER(pcsz, id, cx, cy) { WC_STATIC, pcsz, \ 287 339 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 } 289 341 290 342 #define CONTROLDEF_TEXT_RIGHT(pcsz, id, cx, cy) { WC_STATIC, pcsz, \ 291 343 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 } 293 345 294 346 #define LOADDEF_TEXT_RIGHT(id) CONTROLDEF_TEXT_RIGHT(LOAD_STRING, id, SZL_AUTOSIZE, SZL_AUTOSIZE) … … 296 348 #define CONTROLDEF_TEXT_WORDBREAK(pcsz, id, cx) { WC_STATIC, pcsz, \ 297 349 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 } 299 351 300 352 #define CONTROLDEF_TEXT_WORDBREAK_CY(pcsz, id, cx, cy) { WC_STATIC, pcsz, \ 301 353 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 } 303 355 304 356 #define LOADDEF_TEXT_WORDBREAK(id, cx) CONTROLDEF_TEXT_WORDBREAK(LOAD_STRING, id, cx) … … 306 358 #define CONTROLDEF_TEXT_WORDBREAK_MNEMONIC(pcsz, id, cx) { WC_STATIC, pcsz, \ 307 359 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 } 309 361 310 362 #define LOADDEF_TEXT_WORDBREAK_MNEMONIC(id, cx) CONTROLDEF_TEXT_WORDBREAK_MNEMONIC(LOAD_STRING, id, cx) … … 312 364 #define CONTROLDEF_ICON(hptr, id) { WC_STATIC, (PCSZ)(hptr), \ 313 365 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 } 315 367 316 368 #define CONTROLDEF_ICON_WIDER(hptr, id) { WC_STATIC, (PCSZ)(hptr), \ 317 369 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 } 319 371 320 372 #define CONTROLDEF_BITMAP(hbm, id) { WC_STATIC, (PCSZ)(hbm), \ 321 373 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 } 323 375 324 376 // the following require INCL_WINBUTTONS … … 326 378 #define CONTROLDEF_DEFPUSHBUTTON(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \ 327 379 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 } 329 381 330 382 #define LOADDEF_DEFPUSHBUTTON(id) CONTROLDEF_DEFPUSHBUTTON(LOAD_STRING, id, STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT) … … 332 384 #define CONTROLDEF_PUSHBUTTON(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \ 333 385 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 } 335 387 336 388 #define LOADDEF_PUSHBUTTON(id) CONTROLDEF_PUSHBUTTON(LOAD_STRING, id, STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT) … … 338 390 #define CONTROLDEF_DEFNOFOCUSBUTTON(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \ 339 391 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 } 341 393 342 394 #define CONTROLDEF_NOFOCUSBUTTON(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \ 343 395 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 } 345 397 346 398 #define LOADDEF_NOFOCUSBUTTON(id) CONTROLDEF_NOFOCUSBUTTON(LOAD_STRING, id, STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT) … … 348 400 #define CONTROLDEF_HELPPUSHBUTTON(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \ 349 401 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 } 351 403 352 404 #define LOADDEF_HELPPUSHBUTTON(id) CONTROLDEF_HELPPUSHBUTTON(LOAD_STRING, id, STD_BUTTON_WIDTH, STD_BUTTON_HEIGHT) … … 354 406 #define CONTROLDEF_AUTOCHECKBOX(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \ 355 407 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 } 357 409 358 410 #define LOADDEF_AUTOCHECKBOX(id) CONTROLDEF_AUTOCHECKBOX(LOAD_STRING, id, SZL_AUTOSIZE, SZL_AUTOSIZE) … … 360 412 #define CONTROLDEF_FIRST_AUTORADIO(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \ 361 413 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) 365 418 366 419 #define CONTROLDEF_NEXT_AUTORADIO(pcsz, id, cx, cy) { WC_BUTTON, pcsz, \ 367 420 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 } 369 422 370 423 #define LOADDEF_NEXT_AUTORADIO(id) CONTROLDEF_NEXT_AUTORADIO(LOAD_STRING, id, SZL_AUTOSIZE, SZL_AUTOSIZE) … … 374 427 #define CONTROLDEF_ENTRYFIELD(pcsz, id, cx, cy) { WC_ENTRYFIELD, pcsz, \ 375 428 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 } 377 430 378 431 #define CONTROLDEF_ENTRYFIELD_RO(pcsz, id, cx, cy) { WC_ENTRYFIELD, pcsz, \ 379 432 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 } 381 434 382 435 // the following require INCL_WINMLE … … 384 437 #define CONTROLDEF_MLE(pcsz, id, cx, cy) { WC_MLE, pcsz, \ 385 438 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 } 387 440 388 441 // the following require INCL_WINLISTBOXES … … 390 443 #define CONTROLDEF_LISTBOX(id, cx, cy) { WC_LISTBOX, NULL, \ 391 444 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 } 393 446 394 447 // the following require INCL_WINLISTBOXES and INCL_WINENTRYFIELDS … … 396 449 #define CONTROLDEF_DROPDOWN(id, cx, cy) { WC_COMBOBOX, NULL, \ 397 450 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 } 399 452 400 453 #define CONTROLDEF_DROPDOWNLIST(id, cx, cy) { WC_COMBOBOX, NULL, \ 401 454 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 } 403 456 404 457 // the following require INCL_WINSTDSPIN … … 406 459 #define CONTROLDEF_SPINBUTTON(id, cx, cy) { WC_SPINBUTTON, NULL, \ 407 460 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 } 409 462 410 463 // the following require INCL_WINSTDCNR … … 412 465 #define CONTROLDEF_CONTAINER(id, cx, cy) { WC_CONTAINER, NULL, \ 413 466 WS_VISIBLE | WS_TABSTOP | 0, \ 414 id, CTL_COMMON_FONT, 0,{cx, cy}, COMMON_SPACING }467 id, CTL_COMMON_FONT, {cx, cy}, COMMON_SPACING } 415 468 416 469 #define CONTROLDEF_CONTAINER_EXTSEL(id, cx, cy) { WC_CONTAINER, NULL, \ 417 470 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 } 419 472 420 473 // the following require INCL_WINSTDSLIDER … … 423 476 WS_VISIBLE | WS_TABSTOP | WS_GROUP | SLS_HORIZONTAL | SLS_PRIMARYSCALE1 \ 424 477 | 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 } 426 480 427 481 #define CONTROLDEF_VSLIDER(id, cx, cy, pctldata) { WC_SLIDER, NULL, \ 428 482 WS_VISIBLE | WS_TABSTOP | WS_GROUP | SLS_VERTICAL | SLS_PRIMARYSCALE1 \ 429 483 | 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 } 431 490 432 491 // the following require #include helpers\textview.h … … 434 493 #define CONTROLDEF_XTEXTVIEW(text, id, cx, pctldata) { WC_XTEXTVIEW, text, \ 435 494 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 } 437 496 438 497 #define CONTROLDEF_XTEXTVIEW_HTML(text, id, cx, pctldata) { WC_XTEXTVIEW, text, \ 439 498 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 } 441 500 442 501 /* ****************************************************************** -
trunk/src/helpers/apps.c
r208 r209 879 879 // if the path has spaces, or other invalid characters, 880 880 // include it in quotes V0.9.21 (2002-08-12) [umoeller] 881 if (fQuotes = !!strpbrk(pProgDetails->pszExecutable, " +&| "))881 if (fQuotes = !!strpbrk(pProgDetails->pszExecutable, " +&|=")) 882 882 xstrcatc(pstrParams, '"'); 883 // @@bugbug "=" still doesn't work 883 884 884 885 #ifdef DEBUG_PROGRAMSTART … … 1165 1166 *@@changed V0.9.20 (2002-07-03) [umoeller]: fixed Win-OS/2 full screen breakage 1166 1167 *@@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 1167 1169 */ 1168 1170 … … 1347 1349 arc = ERROR_PATH_NOT_FOUND; 1348 1350 } 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 1349 1362 1350 1363 // we frequently get here for BAT and CMD files … … 1399 1412 break; 1400 1413 } // end switch (Details.progt.progc) 1414 #endif // ENABLEBATCHHACKS 1401 1415 } 1402 1416 } … … 2045 2059 *@@changed V0.9.20 (2002-08-10) [umoeller]: fixed missing destroy window, made wait optional 2046 2060 *@@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 2064 APIRET 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 2054 2070 { 2071 APIRET arc = NO_ERROR; 2055 2072 PROGDETAILS pd = {0}; 2056 HAPP happ, 2057 happReturn = NULLHANDLE; 2073 HAPP happReturn = NULLHANDLE; 2058 2074 CHAR szDir[CCHMAXPATH] = ""; 2059 2075 PCSZ p; … … 2077 2093 2078 2094 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))) 2085 2101 ) 2086 2102 { 2087 2103 if (pulExitCode) 2088 2104 appWaitForApp(hwndObject, 2089 happ,2105 *phapp, 2090 2106 pulExitCode); 2091 2107 2092 happReturn = happ;2093 2094 2108 WinDestroyWindow(hwndObject); // was missing V0.9.20 (2002-08-10) [umoeller] 2095 2109 } 2096 2110 2097 return happReturn;2111 return arc; 2098 2112 } 2099 2113 … … 2103 2117 * URL. 2104 2118 * 2119 * We return TRUE if appQuickStartApp succeeded with 2120 * that URL. 2121 * 2105 2122 *@@added V0.9.20 (2002-08-10) [umoeller] 2106 2123 */ 2107 2124 2108 BOOL appOpenURL(PCSZ pcszURL) 2125 APIRET appOpenURL(PCSZ pcszURL, // in: URL to open 2126 PSZ pszAppStarted, // out: application that was started 2127 ULONG cbAppStarted) // in: size of that buffer 2109 2128 { 2110 BOOL brc = FALSE;2129 APIRET arc = NO_ERROR; 2111 2130 2112 2131 CHAR szBrowser[CCHMAXPATH], … … 2123 2142 sizeof(szBrowser))) 2124 2143 { 2125 PSZ pszDefParams; 2144 PSZ pszDefParams; 2145 HAPP happ; 2126 2146 2127 2147 if (pszDefParams = prfhQueryProfileData(HINI_USER, … … 2145 2165 2146 2166 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); 2152 2178 } 2153 2179 2154 2180 xstrClear(&strParameters); 2155 2181 2156 return brc;2182 return arc; 2157 2183 } -
trunk/src/helpers/comctl.c
r196 r209 116 116 117 117 #pragma hdrstop 118 119 /* ****************************************************************** 120 * 121 * "Separator line" control 122 * 123 ********************************************************************/ 124 125 PFNWP 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 135 static 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 187 BOOL 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 } 118 206 119 207 /* ****************************************************************** -
trunk/src/helpers/dialog.c
r202 r209 6 6 * 7 7 * 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. 8 14 * 9 15 * In addition, this has dlghMessageBox (a WinMessageBox … … 41 47 */ 42 48 49 // #define DEBUG_DIALOG_WINDOWS 1 50 // blue frame is table 51 // green frame is column 52 // red frame is control 53 43 54 #define OS2EMX_PLAIN_CHAR 44 55 // this is needed for "os2emx.h"; if this is defined, … … 86 97 #pragma hdrstop 87 98 88 // #define DEBUG_DIALOG_WINDOWS 189 90 99 /* 91 100 *@@category: Helpers\PM helpers\Dialog templates … … 94 103 /* ****************************************************************** 95 104 * 96 * Private declarations105 * Glossary entries 97 106 * 98 107 ********************************************************************/ 99 108 100 109 /* 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 2223 111 * 2224 112 * The DLGHITEM macros are: … … 2357 245 + º º 2358 246 + ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ 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 463 typedef 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 510 typedef struct _COLUMNDEF *PCOLUMNDEF; 511 typedef struct _ROWDEF *PROWDEF; 512 typedef 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 522 typedef 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 549 typedef 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 582 typedef 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 669 typedef 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 721 typedef 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 753 static 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 769 static 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 829 HWND 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 870 static 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 888 static 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 951 static 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 986 static 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 1032 static 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 1108 static 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 1226 static 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 1293 static 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 1636 static 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 2103 static 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 2201 static 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 2329 static 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 2395 static 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 2511 static 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 2545 typedef 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 2560 static 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 2616 static 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 2806 static 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 2851 static 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 2903 static 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. 2359 2999 * 2360 3000 * <B>Example:</B> … … 2369 3009 + fnwpMyDlgProc, 2370 3010 + "My Dlg Title", 2371 + DlgTemplate, // DLGHITEM array2372 + ARRAYITEMCOUNT( DlgTemplate),3011 + dlgTemplate, // DLGHITEM array 3012 + ARRAYITEMCOUNT(dlgTemplate), 2373 3013 + NULL, // mp2 for WM_INITDLG 2374 3014 + "9.WarpSans")) // default font … … 2429 3069 2430 3070 APIRET dlghCreateDlg(HWND *phwndDlg, // out: new dialog 2431 HWND hwndOwner, 3071 HWND hwndOwner, // in: owner for dialog 2432 3072 ULONG flCreateFlags, // in: standard FCF_* frame flags 2433 PFNWP pfnwpDialogProc, 2434 PCSZ pcszDlgTitle, 2435 PCDLGHITEM paDlgItems, // in: definition array2436 ULONG cDlgItems, // in: array item count (NOT array size)2437 PVOID pCreateParams, // in: for mp2 of WM_INITDLG2438 PCSZ pcszControlsFont) // in: font for ctls with CTL_COMMON_FONT3073 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 2439 3079 { 2440 3080 APIRET arc = NO_ERROR; … … 2528 3168 2529 3169 // 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; 2532 3172 rclClient.xRight = pDlgData->szlClient.cx 2533 + 2 * (DLG_OUTER_SPACING_X * FACTOR_X); 3173 + 2 * (DLG_OUTER_SPACING_X * FACTOR_X) 3174 - 1; 2534 3175 rclClient.yTop = pDlgData->szlClient.cy 2535 + 2 * (DLG_OUTER_SPACING_Y * FACTOR_Y); 3176 + 2 * (DLG_OUTER_SPACING_Y * FACTOR_Y) 3177 - 1; 2536 3178 WinCalcFrameRect(hwndDlg, 2537 3179 &rclClient, … … 2802 3444 + 2803 3445 + PDLGARRAY pArraySample = NULL; 3446 + // create array with sufficient size 2804 3447 + dlghCreateArray( ARRAYITEMCOUNT(dlgSampleFront) 2805 3448 + + ARRAYITEMCOUNT(dlgSampleSometimes) … … 2913 3556 2914 3557 APIRET dlghAppendToArray(PDLGARRAY pArray, // in: dialog array created by dlghCreateArray 2915 PCDLGHITEM paItems, 3558 PCDLGHITEM paItems, // in: subarray to be appended 2916 3559 ULONG cItems) // in: subarray item count (NOT array size) 2917 3560 { … … 2975 3618 *@@changed V0.9.20 (2002-07-12) [umoeller]: made icon spacing wider 2976 3619 *@@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 2977 3621 */ 2978 3622 … … 3005 3649 DLGHITEM MessageBoxFront[] = 3006 3650 { 3007 START_TABLE ,3651 START_TABLE_ALIGN, 3008 3652 START_ROW(ROW_VALIGN_CENTER), 3009 3653 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]), 3021 3669 }, 3022 3670 MessageBoxHelp[] = 3023 3671 { 3024 CONTROL_DEF(&Buttons[3]),3672 CONTROL_DEF(&Buttons[3]), 3025 3673 }, 3026 3674 MessageBoxTail[] = 3027 3675 { 3028 END_TABLE,3676 END_TABLE, 3029 3677 END_TABLE 3030 3678 }; … … 3243 3891 /* 3244 3892 *@@ dlghMessageBox: 3245 * WinMessageBox replacement. 3893 * WinMessageBox replacement, which uses dlghCreateDlg 3894 * internally. 3246 3895 * 3247 3896 * This has all the flags of the standard call, … … 3290 3939 const MSGBOXSTRINGS *pStrings) // in: strings array 3291 3940 { 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 ) 3306 3958 { 3307 3959 // SHOW DIALOG … … 3310 3962 flFlags)); 3311 3963 } 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); 3323 3972 3324 3973 return (DID_CANCEL); … … 3366 4015 { 3367 4016 CONTROLDEF 3368 Static = { 3369 WC_STATIC, 4017 Static = CONTROLDEF_TEXT_WORDBREAK( 3370 4018 NULL, 3371 WS_VISIBLE | SS_TEXT | DT_LEFT | DT_WORDBREAK,3372 4019 -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( 3380 4022 NULL, 3381 WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_MARGIN | ES_AUTOSCROLL,3382 4023 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( 3390 4027 NULL, 3391 WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_DEFAULT,3392 4028 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( 3400 4032 NULL, 3401 WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,3402 4033 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 3408 4037 DLGHITEM DlgTemplate[] = 3409 4038 { -
trunk/src/helpers/encodings.c
r192 r209 8 8 * 9 9 * See encCreateCodec for an introduction. 10 * 11 * See http://www.ietf.org/rfc/rfc2279.txt for 12 * RFC 2279, which defines UTF-8. 10 13 * 11 14 * Be warned, compilation of this file takes a long -
trunk/src/helpers/exeh.c
r176 r209 176 176 *@@changed V0.9.16 (2001-12-08) [umoeller]: speed optimizations, changed some return codes 177 177 *@@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) 178 179 */ 179 180 … … 193 194 194 195 if (!ppExec) 195 return (ERROR_INVALID_PARAMETER);196 return ERROR_INVALID_PARAMETER; 196 197 197 198 if (!(pExec = (PEXECUTABLE)malloc(sizeof(EXECUTABLE)))) 198 return (ERROR_NOT_ENOUGH_MEMORY);199 return ERROR_NOT_ENOUGH_MEMORY; 199 200 200 201 memset(pExec, 0, sizeof(EXECUTABLE)); … … 202 203 // check some of the default extensions 203 204 // V0.9.16 (2002-01-04) [umoeller] 204 if ( pExt = doshGetExtension(pcszExecutable))205 if (!(pExt = doshGetExtension(pcszExecutable))) 205 206 { 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: 206 214 if (!stricmp(pExt, "COM")) 207 215 { … … 508 516 /* 509 517 *@@ 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. 518 524 * 519 525 * -- The standard format is: … … 524 530 * need to have them. 525 531 * 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##". 531 539 * 532 540 + ##1## DATETIME BUILDMACHINE:ASD:LANG:CTRY:REVISION:UNKNOWN:FIXPAK@@DESCRIPTION 533 541 * 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 545 560 * 546 561 *@@added V0.9.12 (2001-05-18) [umoeller] 547 562 *@@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 548 565 */ 549 566 … … 555 572 556 573 // @#VENDOR:VERSION#@ DESCRIPTION 557 // but skip the first byte, which has the string length558 574 if ( (pStartOfVendor = strstr(pExec->pszDescription, "@#")) 559 575 && (pStartOfInfo = strstr(pStartOfVendor + 2, "#@")) … … 569 585 570 586 // 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) 574 588 { 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)) 580 590 { 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, 585 617 p, 586 618 24); 587 619 pExec->pszBuildDateTime[24] = '\0'; 588 620 */ 621 622 // date/time seems to be fixed 24 chars in length 589 623 p += 24; 590 624 … … 613 647 ul++) 614 648 { 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, "@@"); 618 652 if (!pNextColon) 619 653 { … … 635 669 ) 636 670 { 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) 638 676 *(papsz[ul]) = strhSubstr(p, pNextColon); 639 677 } … … 648 686 } 649 687 } 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 } 650 748 } 651 652 pStartOfInfo = strstr(p,653 "@@");654 if (pStartOfInfo)655 pStartOfInfo += 2;656 749 } 657 750 … … 666 759 // skip leading spaces in info string 667 760 while (*pStartOfInfo == ' ') 668 pStartOfInfo++; 761 ++pStartOfInfo; 762 669 763 if (*pStartOfInfo) // V0.9.9 (2001-04-04) [umoeller] 670 764 // and copy until end of string … … 2142 2236 static APIRET ExpandIterdata1(char *pabTarget, // out: page data (pagesize as in lx spec) 2143 2237 int cbTarget, // in: sizeof *pabTarget (pagesize as in lx spec) 2144 const char *pabSource, // in: compressed source data in EXEPACK:1 format2238 PCSZ pabSource, // in: compressed source data in EXEPACK:1 format 2145 2239 int cbSource) // in: sizeof *pabSource 2146 2240 { … … 2205 2299 */ 2206 2300 2207 static void memcpyw(char *pch1, const char *pch2, size_t cch)2301 static void memcpyw(char *pch1, PCSZ pch2, size_t cch) 2208 2302 { 2209 2303 /* … … 2239 2333 */ 2240 2334 2241 static void memcpyb(char *pch1, const char *pch2, size_t cch)2335 static void memcpyb(char *pch1, PCSZ pch2, size_t cch) 2242 2336 { 2243 2337 /* … … 2276 2370 static APIRET ExpandIterdata2(char *pachPage, // out: page data (pagesize as in lx spec) 2277 2371 int cchPage, // in: sizeof *pachPage (pagesize as in lx spec) 2278 const char *pachSrcPage, // in: compressed source data in EXEPACK:1 format2372 PCSZ pachSrcPage, // in: compressed source data in EXEPACK:1 format 2279 2373 int cchSrcPage) // in: size of source buf 2280 2374 { … … 3182 3276 } 3183 3277 3278 -
trunk/src/helpers/makefile
r201 r209 142 142 @echo ----- Leaving $(MAKEDIR) 143 143 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 # 144 178 # "test" target: for test cases 179 # 180 ################################################### 181 145 182 TESTCASE_DIR = testcase 146 183 147 TESTCASE_CC = icc /c /ti+ /w2 /ss /se /i$(HELPERS_BASE)\include /Fo$(TESTCASE_DIR)\$(@B).obj $(@B).c 184 DEBUGDIALOG = 185 !ifdef DBGDLG 186 DEBUGDIALOG = /DDEBUG_DIALOG_WINDOWS=1 187 !endif 188 189 TESTCASE_CC = icc /c /ti+ /w2 /ss /se /D__DEBUG__=1 $(DEBUGDIALOG) /i$(HELPERS_BASE)\include /Fo$(TESTCASE_DIR)\$(@B).obj $(@B).c 148 190 149 191 .c.{$(TESTCASE_DIR)}.obj: 150 192 @echo $(MAKEDIR)\makefile: Compiling $(@B).c 193 @echo INCLUDE is $(INCLUDE) 151 194 $(TESTCASE_CC) 152 195 … … 155 198 dosh.exe \ 156 199 dialog.exe \ 157 vcard.exe \200 exeh.exe \ 158 201 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 170 203 171 204 # dialog.exe … … 190 223 $(TESTCASE_DIR)\gpih.obj 191 224 225 $(TESTCASE_DIR)\dialog.obj: ..\..\include\helpers\dialog.h 226 $(TESTCASE_DIR)\_test_dialog.obj: ..\..\include\helpers\dialog.h 227 192 228 dialog.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 232 DOSH_TEST_OBJS = \ 233 $(TESTCASE_DIR)\dosh.obj \ 234 $(TESTCASE_DIR)\_test_dosh.obj 235 236 dosh.exe: $(DOSH_TEST_OBJS) 237 ilink /debug /optfunc /pmtype:vio $(DOSH_TEST_OBJS) pmprintf.lib /o:$@ 238 239 # exeh.exe 240 EXEH_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 247 exeh.exe: $(EXEH_TEST_OBJS) 248 ilink /debug /optfunc /pmtype:vio $(EXEH_TEST_OBJS) pmprintf.lib /o:$@ 249 250 # fdlg.exe 251 FDLG_TEST_OBJS = \ 252 $(TESTCASE_DIR)\_call_filedlg.obj 253 254 fdlg.exe: $(FDLG_TEST_OBJS) 255 ilink /debug /pmtype:pm $(FDLG_TEST_OBJS) /o:$@ 194 256 195 257 # vcard.exe … … 210 272 ilink /debug /pmtype:vio $(VCARD_TEST_OBJS) /o:$@ 211 273 212 # vcard.exe213 VCARD_TEST_OBJS = \214 $(TESTCASE_DIR)\_call_filedlg.obj215 216 fdlg.exe: $(VCARD_TEST_OBJS)217 ilink /debug /pmtype:pm $(VCARD_TEST_OBJS) /o:$@218 219 274 test: $(TESTCASE_TARGETS) 220 275 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.