| 1 |
|
|---|
| 2 | /*
|
|---|
| 3 | *@@sourcefile dialog.c:
|
|---|
| 4 | * contains PM helper functions to create and
|
|---|
| 5 | * auto-format dialogs from control arrays in memory.
|
|---|
| 6 | *
|
|---|
| 7 | * See dlghCreateDlg for details.
|
|---|
| 8 | *
|
|---|
| 9 | * In addition, this has dlghMessageBox (a WinMessageBox
|
|---|
| 10 | * replacement) and some helper functions for simulating
|
|---|
| 11 | * dialog behavior in regular window procs (see
|
|---|
| 12 | * dlghSetPrevFocus and others).
|
|---|
| 13 | *
|
|---|
| 14 | * Usage: All PM programs.
|
|---|
| 15 | *
|
|---|
| 16 | * Function prefixes (new with V0.81):
|
|---|
| 17 | * -- dlg* Dialog functions
|
|---|
| 18 | *
|
|---|
| 19 | * Note: Version numbering in this file relates to XWorkplace version
|
|---|
| 20 | * numbering.
|
|---|
| 21 | *
|
|---|
| 22 | *@@added V0.9.9 (2001-04-01) [umoeller]
|
|---|
| 23 | *@@header "helpers\dialog.h"
|
|---|
| 24 | */
|
|---|
| 25 |
|
|---|
| 26 | /*
|
|---|
| 27 | * Copyright (C) 2001 Ulrich Mller.
|
|---|
| 28 | * This file is part of the "XWorkplace helpers" source package.
|
|---|
| 29 | * This is free software; you can redistribute it and/or modify
|
|---|
| 30 | * it under the terms of the GNU General Public License as published
|
|---|
| 31 | * by the Free Software Foundation, in version 2 as it comes in the
|
|---|
| 32 | * "COPYING" file of the XWorkplace main distribution.
|
|---|
| 33 | * This program is distributed in the hope that it will be useful,
|
|---|
| 34 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 35 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 36 | * GNU General Public License for more details.
|
|---|
| 37 | */
|
|---|
| 38 |
|
|---|
| 39 | #define OS2EMX_PLAIN_CHAR
|
|---|
| 40 | // this is needed for "os2emx.h"; if this is defined,
|
|---|
| 41 | // emx will define PSZ as _signed_ char, otherwise
|
|---|
| 42 | // as unsigned char
|
|---|
| 43 |
|
|---|
| 44 | #define INCL_DOSERRORS
|
|---|
| 45 |
|
|---|
| 46 | #define INCL_WINWINDOWMGR
|
|---|
| 47 | #define INCL_WINFRAMEMGR
|
|---|
| 48 | #define INCL_WINDIALOGS
|
|---|
| 49 | #define INCL_WININPUT
|
|---|
| 50 | #define INCL_WINBUTTONS
|
|---|
| 51 | #define INCL_WINSTATICS
|
|---|
| 52 | #define INCL_WINSYS
|
|---|
| 53 |
|
|---|
| 54 | #define INCL_GPIPRIMITIVES
|
|---|
| 55 | #define INCL_GPIBITMAPS
|
|---|
| 56 | #define INCL_GPILCIDS
|
|---|
| 57 | #include <os2.h>
|
|---|
| 58 |
|
|---|
| 59 | #include <stdlib.h>
|
|---|
| 60 | #include <string.h>
|
|---|
| 61 | #include <stdio.h>
|
|---|
| 62 |
|
|---|
| 63 | #include "setup.h" // code generation and debugging options
|
|---|
| 64 |
|
|---|
| 65 | #include "helpers\comctl.h"
|
|---|
| 66 | #include "helpers\dialog.h"
|
|---|
| 67 | #include "helpers\gpih.h"
|
|---|
| 68 | #include "helpers\linklist.h"
|
|---|
| 69 | #include "helpers\standards.h"
|
|---|
| 70 | #include "helpers\stringh.h"
|
|---|
| 71 | #include "helpers\winh.h"
|
|---|
| 72 |
|
|---|
| 73 | /*
|
|---|
| 74 | *@@category: Helpers\PM helpers\Dialog templates
|
|---|
| 75 | */
|
|---|
| 76 |
|
|---|
| 77 | /* ******************************************************************
|
|---|
| 78 | *
|
|---|
| 79 | * Private declarations
|
|---|
| 80 | *
|
|---|
| 81 | ********************************************************************/
|
|---|
| 82 |
|
|---|
| 83 | /*
|
|---|
| 84 | *@@ DLGPRIVATE:
|
|---|
| 85 | * private data to the dlg manager, allocated
|
|---|
| 86 | * by dlghCreateDlg. This is what is really
|
|---|
| 87 | * used, even though the prototype only
|
|---|
| 88 | * declares DIALOGDATA.
|
|---|
| 89 | *
|
|---|
| 90 | * This only exists while the dialog is being
|
|---|
| 91 | * created and is not stored with the new dialog.
|
|---|
| 92 | */
|
|---|
| 93 |
|
|---|
| 94 | typedef struct _DLGPRIVATE
|
|---|
| 95 | {
|
|---|
| 96 | // public data
|
|---|
| 97 | HWND hwndDlg;
|
|---|
| 98 |
|
|---|
| 99 | // definition data (private)
|
|---|
| 100 | LINKLIST llTables;
|
|---|
| 101 |
|
|---|
| 102 | HWND hwndFirstFocus,
|
|---|
| 103 | hwndDefPushbutton; // V0.9.14 (2001-08-21) [umoeller]
|
|---|
| 104 |
|
|---|
| 105 | POINTL ptlTotalOfs;
|
|---|
| 106 |
|
|---|
| 107 | LINKLIST llControls; // linked list of all PCOLUMNDEF structs,
|
|---|
| 108 | // in the order in which windows were
|
|---|
| 109 | // created
|
|---|
| 110 |
|
|---|
| 111 | const char *pcszControlsFont; // from dlghCreateDlg
|
|---|
| 112 |
|
|---|
| 113 | // V0.9.14 (2001-08-01) [umoeller]
|
|---|
| 114 | HPS hps;
|
|---|
| 115 | const char *pcszFontLast;
|
|---|
| 116 | LONG lcidLast;
|
|---|
| 117 | FONTMETRICS fmLast;
|
|---|
| 118 |
|
|---|
| 119 | } DLGPRIVATE, *PDLGPRIVATE;
|
|---|
| 120 |
|
|---|
| 121 | typedef struct _COLUMNDEF *PCOLUMNDEF;
|
|---|
| 122 | typedef struct _ROWDEF *PROWDEF;
|
|---|
| 123 | typedef struct _TABLEDEF *PTABLEDEF;
|
|---|
| 124 |
|
|---|
| 125 | /*
|
|---|
| 126 | *@@ CONTROLPOS:
|
|---|
| 127 | * control position. We don't want to use SWP.
|
|---|
| 128 | */
|
|---|
| 129 |
|
|---|
| 130 | typedef struct _CONTROLPOS
|
|---|
| 131 | {
|
|---|
| 132 | LONG x,
|
|---|
| 133 | y,
|
|---|
| 134 | cx,
|
|---|
| 135 | cy;
|
|---|
| 136 | } CONTROLPOS, *PCONTROLPOS;
|
|---|
| 137 |
|
|---|
| 138 | /*
|
|---|
| 139 | *@@ COLUMNDEF:
|
|---|
| 140 | * representation of a table column.
|
|---|
| 141 | * This is stored in a linked list in ROWDEF.
|
|---|
| 142 | *
|
|---|
| 143 | * A table column represents either a PM control
|
|---|
| 144 | * window or another table, which may therefore
|
|---|
| 145 | * be nested.
|
|---|
| 146 | */
|
|---|
| 147 |
|
|---|
| 148 | typedef struct _COLUMNDEF
|
|---|
| 149 | {
|
|---|
| 150 | PROWDEF pOwningRow; // row whose linked list this column belongs to
|
|---|
| 151 |
|
|---|
| 152 | BOOL fIsNestedTable; // if TRUE, pvDefinition points to a nested TABLEDEF;
|
|---|
| 153 | // if FALSE, pvDefinition points to a CONTROLDEF as
|
|---|
| 154 | // specified by the caller
|
|---|
| 155 |
|
|---|
| 156 | PVOID pvDefinition; // either a PTABLEDEF or a PCONTROLDEF
|
|---|
| 157 |
|
|---|
| 158 | CONTROLPOS cpControl, // real pos and size of control
|
|---|
| 159 | cpColumn; // pos and size of column; can be wider, spacings applied
|
|---|
| 160 |
|
|---|
| 161 | HWND hwndControl; // created control; NULLHANDLE for tables always
|
|---|
| 162 |
|
|---|
| 163 | } COLUMNDEF;
|
|---|
| 164 |
|
|---|
| 165 | /*
|
|---|
| 166 | *@@ ROWDEF:
|
|---|
| 167 | *
|
|---|
| 168 | */
|
|---|
| 169 |
|
|---|
| 170 | typedef struct _ROWDEF
|
|---|
| 171 | {
|
|---|
| 172 | PTABLEDEF pOwningTable; // table whose linked list this row belongs to
|
|---|
| 173 |
|
|---|
| 174 | LINKLIST llColumns; // contains COLUMNDEF structs, no auto-free
|
|---|
| 175 |
|
|---|
| 176 | ULONG flRowFormat; // one of:
|
|---|
| 177 | // -- ROW_VALIGN_BOTTOM 0x0000
|
|---|
| 178 | // -- ROW_VALIGN_CENTER 0x0001
|
|---|
| 179 | // -- ROW_VALIGN_TOP 0x0002
|
|---|
| 180 |
|
|---|
| 181 | CONTROLPOS cpRow;
|
|---|
| 182 |
|
|---|
| 183 | } ROWDEF;
|
|---|
| 184 |
|
|---|
| 185 | /*
|
|---|
| 186 | *@@ TABLEDEF:
|
|---|
| 187 | *
|
|---|
| 188 | */
|
|---|
| 189 |
|
|---|
| 190 | typedef struct _TABLEDEF
|
|---|
| 191 | {
|
|---|
| 192 | LINKLIST llRows; // contains ROWDEF structs, no auto-free
|
|---|
| 193 |
|
|---|
| 194 | PCONTROLDEF pCtlDef; // if != NULL, we create a PM control around the table
|
|---|
| 195 |
|
|---|
| 196 | CONTROLPOS cpTable;
|
|---|
| 197 |
|
|---|
| 198 | } TABLEDEF;
|
|---|
| 199 |
|
|---|
| 200 | /*
|
|---|
| 201 | *@@ PROCESSMODE:
|
|---|
| 202 | *
|
|---|
| 203 | */
|
|---|
| 204 |
|
|---|
| 205 | typedef enum _PROCESSMODE
|
|---|
| 206 | {
|
|---|
| 207 | PROCESS_CALC_SIZES, // step 1
|
|---|
| 208 | PROCESS_CALC_POSITIONS, // step 3
|
|---|
| 209 | PROCESS_CREATE_CONTROLS // step 4
|
|---|
| 210 | } PROCESSMODE;
|
|---|
| 211 |
|
|---|
| 212 | /* ******************************************************************
|
|---|
| 213 | *
|
|---|
| 214 | * Worker routines
|
|---|
| 215 | *
|
|---|
| 216 | ********************************************************************/
|
|---|
| 217 |
|
|---|
| 218 | #define PM_GROUP_SPACING_X 10
|
|---|
| 219 | #define PM_GROUP_SPACING_TOP 20
|
|---|
| 220 |
|
|---|
| 221 | APIRET ProcessTable(PTABLEDEF pTableDef,
|
|---|
| 222 | const CONTROLPOS *pcpTable,
|
|---|
| 223 | PROCESSMODE ProcessMode,
|
|---|
| 224 | PDLGPRIVATE pDlgData);
|
|---|
| 225 |
|
|---|
| 226 | /*
|
|---|
| 227 | *@@ CalcAutoSizeText:
|
|---|
| 228 | *
|
|---|
| 229 | *@@changed V0.9.12 (2001-05-31) [umoeller]: fixed various things with statics
|
|---|
| 230 | *@@changed V0.9.12 (2001-05-31) [umoeller]: fixed broken fonts
|
|---|
| 231 | *@@changed V0.9.14 (2001-08-01) [umoeller]: now caching fonts, which is significantly faster
|
|---|
| 232 | */
|
|---|
| 233 |
|
|---|
| 234 | VOID CalcAutoSizeText(PCONTROLDEF pControlDef,
|
|---|
| 235 | BOOL fMultiLine, // in: if TRUE, multiple lines
|
|---|
| 236 | PSIZEL pszlAuto, // out: computed size
|
|---|
| 237 | PDLGPRIVATE pDlgData)
|
|---|
| 238 | {
|
|---|
| 239 | const char *pcszFontThis = pControlDef->pcszFont;
|
|---|
| 240 | // can be NULL,
|
|---|
| 241 | // or CTL_COMMON_FONT
|
|---|
| 242 |
|
|---|
| 243 | if (pcszFontThis == CTL_COMMON_FONT)
|
|---|
| 244 | pcszFontThis = pDlgData->pcszControlsFont;
|
|---|
| 245 |
|
|---|
| 246 | if (!pDlgData->hps)
|
|---|
| 247 | pDlgData->hps = WinGetPS(pDlgData->hwndDlg);
|
|---|
| 248 |
|
|---|
| 249 | if (pcszFontThis)
|
|---|
| 250 | {
|
|---|
| 251 | LONG lPointSize = 0;
|
|---|
| 252 |
|
|---|
| 253 | // check if we can reuse font data from last time
|
|---|
| 254 | // V0.9.14 (2001-08-01) [umoeller]
|
|---|
| 255 | if (strhcmp(pcszFontThis,
|
|---|
| 256 | pDlgData->pcszFontLast))
|
|---|
| 257 | {
|
|---|
| 258 | // different font than last time:
|
|---|
| 259 |
|
|---|
| 260 | // delete old font?
|
|---|
| 261 | if (pDlgData->lcidLast)
|
|---|
| 262 | {
|
|---|
| 263 | GpiSetCharSet(pDlgData->hps, LCID_DEFAULT);
|
|---|
| 264 | GpiDeleteSetId(pDlgData->hps, pDlgData->lcidLast);
|
|---|
| 265 | }
|
|---|
| 266 |
|
|---|
| 267 | // create new font
|
|---|
| 268 | pDlgData->lcidLast = gpihFindPresFont(NULLHANDLE, // no window yet
|
|---|
| 269 | FALSE,
|
|---|
| 270 | pDlgData->hps,
|
|---|
| 271 | pcszFontThis,
|
|---|
| 272 | &pDlgData->fmLast,
|
|---|
| 273 | &lPointSize);
|
|---|
| 274 |
|
|---|
| 275 | GpiSetCharSet(pDlgData->hps, pDlgData->lcidLast);
|
|---|
| 276 | if (pDlgData->fmLast.fsDefn & FM_DEFN_OUTLINE)
|
|---|
| 277 | gpihSetPointSize(pDlgData->hps, lPointSize);
|
|---|
| 278 |
|
|---|
| 279 | pDlgData->pcszFontLast = pcszFontThis;
|
|---|
| 280 | }
|
|---|
| 281 |
|
|---|
| 282 | pszlAuto->cy = pDlgData->fmLast.lMaxBaselineExt
|
|---|
| 283 | + pDlgData->fmLast.lExternalLeading;
|
|---|
| 284 | }
|
|---|
| 285 |
|
|---|
| 286 | // ok, we FINALLY have a font now...
|
|---|
| 287 | // get the control string and see how much space it needs
|
|---|
| 288 | if (pControlDef->pcszText)
|
|---|
| 289 | {
|
|---|
| 290 | // do we have multiple lines?
|
|---|
| 291 | if (fMultiLine)
|
|---|
| 292 | {
|
|---|
| 293 | RECTL rcl = {0, 0, 0, 0};
|
|---|
| 294 | if (pControlDef->szlControlProposed.cx != -1)
|
|---|
| 295 | rcl.xRight = pControlDef->szlControlProposed.cx; // V0.9.12 (2001-05-31) [umoeller]
|
|---|
| 296 | else
|
|---|
| 297 | rcl.xRight = winhQueryScreenCX() * 2 / 3;
|
|---|
| 298 | if (pControlDef->szlControlProposed.cy != -1)
|
|---|
| 299 | rcl.yTop = pControlDef->szlControlProposed.cy; // V0.9.12 (2001-05-31) [umoeller]
|
|---|
| 300 | else
|
|---|
| 301 | rcl.yTop = winhQueryScreenCY() * 2 / 3;
|
|---|
| 302 |
|
|---|
| 303 | winhDrawFormattedText(pDlgData->hps,
|
|---|
| 304 | &rcl,
|
|---|
| 305 | pControlDef->pcszText,
|
|---|
| 306 | DT_LEFT | DT_TOP | DT_WORDBREAK | DT_QUERYEXTENT);
|
|---|
| 307 | pszlAuto->cx = rcl.xRight - rcl.xLeft;
|
|---|
| 308 | pszlAuto->cy = rcl.yTop - rcl.yBottom;
|
|---|
| 309 | }
|
|---|
| 310 | else
|
|---|
| 311 | {
|
|---|
| 312 | POINTL aptl[TXTBOX_COUNT];
|
|---|
| 313 | GpiQueryTextBox(pDlgData->hps,
|
|---|
| 314 | strlen(pControlDef->pcszText),
|
|---|
| 315 | (PCH)pControlDef->pcszText,
|
|---|
| 316 | TXTBOX_COUNT,
|
|---|
| 317 | aptl);
|
|---|
| 318 | pszlAuto->cx = aptl[TXTBOX_TOPRIGHT].x - aptl[TXTBOX_BOTTOMLEFT].x;
|
|---|
| 319 | }
|
|---|
| 320 | }
|
|---|
| 321 | }
|
|---|
| 322 |
|
|---|
| 323 | /*
|
|---|
| 324 | *@@ CalcAutoSize:
|
|---|
| 325 | *
|
|---|
| 326 | *@@changed V0.9.12 (2001-05-31) [umoeller]: fixed various things with statics
|
|---|
| 327 | */
|
|---|
| 328 |
|
|---|
| 329 | VOID CalcAutoSize(PCONTROLDEF pControlDef,
|
|---|
| 330 | PSIZEL pszlAuto, // out: computed size
|
|---|
| 331 | PDLGPRIVATE pDlgData)
|
|---|
| 332 | {
|
|---|
| 333 | // dumb defaults
|
|---|
| 334 | pszlAuto->cx = 100;
|
|---|
| 335 | pszlAuto->cy = 30;
|
|---|
| 336 |
|
|---|
| 337 | switch ((ULONG)pControlDef->pcszClass)
|
|---|
| 338 | {
|
|---|
| 339 | case 0xffff0003L: // WC_BUTTON:
|
|---|
| 340 | CalcAutoSizeText(pControlDef,
|
|---|
| 341 | FALSE, // no multiline
|
|---|
| 342 | pszlAuto,
|
|---|
| 343 | pDlgData);
|
|---|
| 344 | if (pControlDef->flStyle & ( BS_AUTOCHECKBOX
|
|---|
| 345 | | BS_AUTORADIOBUTTON
|
|---|
| 346 | | BS_AUTO3STATE
|
|---|
| 347 | | BS_3STATE
|
|---|
| 348 | | BS_CHECKBOX
|
|---|
| 349 | | BS_RADIOBUTTON))
|
|---|
| 350 | {
|
|---|
| 351 | // give a little extra width for the box bitmap
|
|---|
| 352 | pszlAuto->cx += 20; // @@todo
|
|---|
| 353 | // and height
|
|---|
| 354 | pszlAuto->cy += 2;
|
|---|
| 355 | }
|
|---|
| 356 | else if (pControlDef->flStyle & BS_BITMAP)
|
|---|
| 357 | ;
|
|---|
| 358 | else if (pControlDef->flStyle & (BS_ICON | BS_MINIICON))
|
|---|
| 359 | ;
|
|---|
| 360 | // we can't test for BS_PUSHBUTTON because that's 0x0000
|
|---|
| 361 | else if (!(pControlDef->flStyle & BS_USERBUTTON))
|
|---|
| 362 | {
|
|---|
| 363 | pszlAuto->cx += (2 * WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER) + 15);
|
|---|
| 364 | pszlAuto->cy += (2 * WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER) + 15);
|
|---|
| 365 | }
|
|---|
| 366 | break;
|
|---|
| 367 |
|
|---|
| 368 | case 0xffff0005L: // WC_STATIC:
|
|---|
| 369 | if ((pControlDef->flStyle & 0x0F) == SS_TEXT)
|
|---|
| 370 | CalcAutoSizeText(pControlDef,
|
|---|
| 371 | ((pControlDef->flStyle & DT_WORDBREAK) != 0),
|
|---|
| 372 | pszlAuto,
|
|---|
| 373 | pDlgData);
|
|---|
| 374 | else if ((pControlDef->flStyle & 0x0F) == SS_BITMAP)
|
|---|
| 375 | {
|
|---|
| 376 | HBITMAP hbm = (HBITMAP)pControlDef->pcszText;
|
|---|
| 377 | if (hbm)
|
|---|
| 378 | {
|
|---|
| 379 | BITMAPINFOHEADER2 bmih2;
|
|---|
| 380 | ZERO(&bmih2);
|
|---|
| 381 | bmih2.cbFix = sizeof(bmih2);
|
|---|
| 382 | if (GpiQueryBitmapInfoHeader(hbm,
|
|---|
| 383 | &bmih2))
|
|---|
| 384 | {
|
|---|
| 385 | pszlAuto->cx = bmih2.cx;
|
|---|
| 386 | pszlAuto->cy = bmih2.cy;
|
|---|
| 387 | }
|
|---|
| 388 | }
|
|---|
| 389 | }
|
|---|
| 390 | else if ((pControlDef->flStyle & 0x0F) == SS_ICON)
|
|---|
| 391 | {
|
|---|
| 392 | pszlAuto->cx = WinQuerySysValue(HWND_DESKTOP, SV_CXICON);
|
|---|
| 393 | pszlAuto->cy = WinQuerySysValue(HWND_DESKTOP, SV_CYICON);
|
|---|
| 394 | }
|
|---|
| 395 | break;
|
|---|
| 396 | }
|
|---|
| 397 | }
|
|---|
| 398 |
|
|---|
| 399 | /*
|
|---|
| 400 | *@@ ProcessColumn:
|
|---|
| 401 | * processes a column, which per definition is either
|
|---|
| 402 | * a control or a nested subtable.
|
|---|
| 403 | *
|
|---|
| 404 | * A column is part of a row, which in turn is part
|
|---|
| 405 | * of a table. There can be several columns in a row,
|
|---|
| 406 | * and several rows in a table.
|
|---|
| 407 | *
|
|---|
| 408 | * Since tables may be specified as columns, it is
|
|---|
| 409 | * possible to produce complex dialog layouts by
|
|---|
| 410 | * nesting tables.
|
|---|
| 411 | *
|
|---|
| 412 | * This does the following:
|
|---|
| 413 | *
|
|---|
| 414 | * -- PROCESS_CALC_SIZES: size is taken from control def,
|
|---|
| 415 | * or for tables, this produces a recursive ProcessTable
|
|---|
| 416 | * call.
|
|---|
| 417 | * Preconditions: none.
|
|---|
| 418 | *
|
|---|
| 419 | * -- PROCESS_CALC_POSITIONS: position of each column
|
|---|
| 420 | * is taken from *plX, which is increased by the
|
|---|
| 421 | * column width by this call.
|
|---|
| 422 | *
|
|---|
| 423 | * Preconditions: Owning row must already have its
|
|---|
| 424 | * y position properly set, or we can't compute
|
|---|
| 425 | * ours. Besides, plX must point to the current X
|
|---|
| 426 | * in the row and will be incremented by the columns
|
|---|
| 427 | * size here.
|
|---|
| 428 | *
|
|---|
| 429 | * -- PROCESS_CREATE_CONTROLS: well, creates the controls.
|
|---|
| 430 | *
|
|---|
| 431 | * For tables, this recurses again. If the table has
|
|---|
| 432 | * a string assigned, this also produces a group box
|
|---|
| 433 | * after the recursion.
|
|---|
| 434 | *
|
|---|
| 435 | *@@changed V0.9.12 (2001-05-31) [umoeller]: added control data
|
|---|
| 436 | *@@changed V0.9.12 (2001-05-31) [umoeller]: fixed font problems
|
|---|
| 437 | */
|
|---|
| 438 |
|
|---|
| 439 | APIRET ProcessColumn(PCOLUMNDEF pColumnDef,
|
|---|
| 440 | PROWDEF pOwningRow, // in: current row from ProcessRow
|
|---|
| 441 | PROCESSMODE ProcessMode, // in: processing mode (see ProcessAll)
|
|---|
| 442 | PLONG plX, // in/out: PROCESS_CALC_POSITIONS only
|
|---|
| 443 | PDLGPRIVATE pDlgData)
|
|---|
| 444 | {
|
|---|
| 445 | APIRET arc = NO_ERROR;
|
|---|
| 446 |
|
|---|
| 447 | pColumnDef->pOwningRow = pOwningRow;
|
|---|
| 448 |
|
|---|
| 449 | switch (ProcessMode)
|
|---|
| 450 | {
|
|---|
| 451 | /*
|
|---|
| 452 | * PROCESS_CALC_SIZES:
|
|---|
| 453 | * step 1.
|
|---|
| 454 | */
|
|---|
| 455 |
|
|---|
| 456 | case PROCESS_CALC_SIZES:
|
|---|
| 457 | {
|
|---|
| 458 | ULONG ulXSpacing = 0,
|
|---|
| 459 | ulYSpacing = 0;
|
|---|
| 460 | if (pColumnDef->fIsNestedTable)
|
|---|
| 461 | {
|
|---|
| 462 | // nested table: recurse!!
|
|---|
| 463 | PTABLEDEF pTableDef = (PTABLEDEF)pColumnDef->pvDefinition;
|
|---|
| 464 | ProcessTable(pTableDef,
|
|---|
| 465 | NULL,
|
|---|
| 466 | ProcessMode,
|
|---|
| 467 | pDlgData);
|
|---|
| 468 |
|
|---|
| 469 | // store the size of the sub-table
|
|---|
| 470 | pColumnDef->cpControl.cx = pTableDef->cpTable.cx;
|
|---|
| 471 | pColumnDef->cpControl.cy = pTableDef->cpTable.cy;
|
|---|
| 472 |
|
|---|
| 473 | // should we create a PM control around the table?
|
|---|
| 474 | if (pTableDef->pCtlDef)
|
|---|
| 475 | {
|
|---|
| 476 | // yes: make this wider
|
|---|
| 477 | ulXSpacing = (2 * PM_GROUP_SPACING_X);
|
|---|
| 478 | ulYSpacing = (PM_GROUP_SPACING_X + PM_GROUP_SPACING_TOP);
|
|---|
| 479 | }
|
|---|
| 480 | }
|
|---|
| 481 | else
|
|---|
| 482 | {
|
|---|
| 483 | // no nested table, but control:
|
|---|
| 484 | PCONTROLDEF pControlDef = (PCONTROLDEF)pColumnDef->pvDefinition;
|
|---|
| 485 | PSIZEL pszl = &pControlDef->szlControlProposed;
|
|---|
| 486 | SIZEL szlAuto;
|
|---|
| 487 |
|
|---|
| 488 | if ( (pszl->cx == -1)
|
|---|
| 489 | || (pszl->cy == -1)
|
|---|
| 490 | )
|
|---|
| 491 | {
|
|---|
| 492 | CalcAutoSize(pControlDef,
|
|---|
| 493 | &szlAuto,
|
|---|
| 494 | pDlgData);
|
|---|
| 495 | }
|
|---|
| 496 |
|
|---|
| 497 | if (pszl->cx == -1)
|
|---|
| 498 | pColumnDef->cpControl.cx = szlAuto.cx;
|
|---|
| 499 | else
|
|---|
| 500 | pColumnDef->cpControl.cx = pszl->cx;
|
|---|
| 501 |
|
|---|
| 502 | if (pszl->cy == -1)
|
|---|
| 503 | pColumnDef->cpControl.cy = szlAuto.cy;
|
|---|
| 504 | else
|
|---|
| 505 | pColumnDef->cpControl.cy = pszl->cy;
|
|---|
| 506 |
|
|---|
| 507 | // @@todo hack sizes
|
|---|
| 508 |
|
|---|
| 509 | ulXSpacing = ulYSpacing = (2 * pControlDef->ulSpacing);
|
|---|
| 510 | }
|
|---|
| 511 |
|
|---|
| 512 | pColumnDef->cpColumn.cx = pColumnDef->cpControl.cx
|
|---|
| 513 | + ulXSpacing;
|
|---|
| 514 | pColumnDef->cpColumn.cy = pColumnDef->cpControl.cy
|
|---|
| 515 | + ulYSpacing;
|
|---|
| 516 | break; }
|
|---|
| 517 |
|
|---|
| 518 | /*
|
|---|
| 519 | * PROCESS_CALC_POSITIONS:
|
|---|
| 520 | * step 2.
|
|---|
| 521 | */
|
|---|
| 522 |
|
|---|
| 523 | case PROCESS_CALC_POSITIONS:
|
|---|
| 524 | {
|
|---|
| 525 | // calculate column position: this includes spacing
|
|---|
| 526 | ULONG ulSpacing = 0;
|
|---|
| 527 |
|
|---|
| 528 | // column position = *plX on ProcessRow stack
|
|---|
| 529 | pColumnDef->cpColumn.x = *plX;
|
|---|
| 530 | pColumnDef->cpColumn.y = pOwningRow->cpRow.y;
|
|---|
| 531 |
|
|---|
| 532 | // check vertical alignment of row;
|
|---|
| 533 | // we might need to increase column y
|
|---|
| 534 | switch (pOwningRow->flRowFormat & ROW_VALIGN_MASK)
|
|---|
| 535 | {
|
|---|
| 536 | // case ROW_VALIGN_BOTTOM: // do nothing
|
|---|
| 537 |
|
|---|
| 538 | case ROW_VALIGN_CENTER:
|
|---|
| 539 | if (pColumnDef->cpColumn.cy < pOwningRow->cpRow.cy)
|
|---|
| 540 | pColumnDef->cpColumn.y
|
|---|
| 541 | += ( (pOwningRow->cpRow.cy - pColumnDef->cpColumn.cy)
|
|---|
| 542 | / 2);
|
|---|
| 543 | break;
|
|---|
| 544 |
|
|---|
| 545 | case ROW_VALIGN_TOP:
|
|---|
| 546 | if (pColumnDef->cpColumn.cy < pOwningRow->cpRow.cy)
|
|---|
| 547 | pColumnDef->cpColumn.y
|
|---|
| 548 | += (pOwningRow->cpRow.cy - pColumnDef->cpColumn.cy);
|
|---|
| 549 | break;
|
|---|
| 550 | }
|
|---|
| 551 |
|
|---|
| 552 | if (pColumnDef->fIsNestedTable)
|
|---|
| 553 | {
|
|---|
| 554 | PTABLEDEF pTableDef = (PTABLEDEF)pColumnDef->pvDefinition;
|
|---|
| 555 | // should we create a PM control around the table?
|
|---|
| 556 | if (pTableDef->pCtlDef)
|
|---|
| 557 | // yes:
|
|---|
| 558 | ulSpacing = PM_GROUP_SPACING_X;
|
|---|
| 559 | }
|
|---|
| 560 | else
|
|---|
| 561 | {
|
|---|
| 562 | // no nested table, but control:
|
|---|
| 563 | PCONTROLDEF pControlDef = (PCONTROLDEF)pColumnDef->pvDefinition;
|
|---|
| 564 | ulSpacing = pControlDef->ulSpacing;
|
|---|
| 565 | }
|
|---|
| 566 |
|
|---|
| 567 | // increase plX by column width
|
|---|
| 568 | *plX += pColumnDef->cpColumn.cx;
|
|---|
| 569 |
|
|---|
| 570 | // calculate CONTROL pos from COLUMN pos by applying spacing
|
|---|
| 571 | pColumnDef->cpControl.x = pColumnDef->cpColumn.x
|
|---|
| 572 | + ulSpacing;
|
|---|
| 573 | pColumnDef->cpControl.y = pColumnDef->cpColumn.y
|
|---|
| 574 | + ulSpacing;
|
|---|
| 575 |
|
|---|
| 576 | if (pColumnDef->fIsNestedTable)
|
|---|
| 577 | {
|
|---|
| 578 | // nested table:
|
|---|
| 579 | PTABLEDEF pTableDef = (PTABLEDEF)pColumnDef->pvDefinition;
|
|---|
| 580 |
|
|---|
| 581 | // recurse!! to create windows for the sub-table
|
|---|
| 582 | ProcessTable(pTableDef,
|
|---|
| 583 | &pColumnDef->cpControl, // start pos for new table
|
|---|
| 584 | ProcessMode,
|
|---|
| 585 | pDlgData);
|
|---|
| 586 | }
|
|---|
| 587 | break; }
|
|---|
| 588 |
|
|---|
| 589 | /*
|
|---|
| 590 | * PROCESS_CREATE_CONTROLS:
|
|---|
| 591 | * step 3.
|
|---|
| 592 | */
|
|---|
| 593 |
|
|---|
| 594 | case PROCESS_CREATE_CONTROLS:
|
|---|
| 595 | {
|
|---|
| 596 | PCONTROLPOS pcp = NULL;
|
|---|
| 597 | PCONTROLDEF pControlDef = NULL;
|
|---|
| 598 | const char *pcszTitle = NULL;
|
|---|
| 599 | ULONG flStyle = 0;
|
|---|
| 600 | LHANDLE lHandleSet = NULLHANDLE;
|
|---|
| 601 | ULONG flOld = 0;
|
|---|
| 602 |
|
|---|
| 603 | if (pColumnDef->fIsNestedTable)
|
|---|
| 604 | {
|
|---|
| 605 | // nested table:
|
|---|
| 606 | PTABLEDEF pTableDef = (PTABLEDEF)pColumnDef->pvDefinition;
|
|---|
| 607 |
|
|---|
| 608 | // recurse!!
|
|---|
| 609 | if (!(arc = ProcessTable(pTableDef,
|
|---|
| 610 | NULL,
|
|---|
| 611 | ProcessMode,
|
|---|
| 612 | pDlgData)))
|
|---|
| 613 | {
|
|---|
| 614 | // should we create a PM control around the table?
|
|---|
| 615 | // (do this AFTER the other controls from recursing,
|
|---|
| 616 | // otherwise the stupid container doesn't show up)
|
|---|
| 617 | if (pTableDef->pCtlDef)
|
|---|
| 618 | {
|
|---|
| 619 | // yes:
|
|---|
| 620 | pcp = &pColumnDef->cpColumn; // !! not control
|
|---|
| 621 | pControlDef = pTableDef->pCtlDef;
|
|---|
| 622 | pcszTitle = pControlDef->pcszText;
|
|---|
| 623 | flStyle = pControlDef->flStyle;
|
|---|
| 624 | }
|
|---|
| 625 | }
|
|---|
| 626 | else
|
|---|
| 627 | break;
|
|---|
| 628 | }
|
|---|
| 629 | else
|
|---|
| 630 | {
|
|---|
| 631 | // no nested table, but control:
|
|---|
| 632 | pControlDef = (PCONTROLDEF)pColumnDef->pvDefinition;
|
|---|
| 633 | pcp = &pColumnDef->cpControl;
|
|---|
| 634 | pcszTitle = pControlDef->pcszText;
|
|---|
| 635 | flStyle = pControlDef->flStyle;
|
|---|
| 636 |
|
|---|
| 637 | // change the title if this is a static with SS_BITMAP;
|
|---|
| 638 | // we have used a HBITMAP in there!
|
|---|
| 639 | if ( ((ULONG)pControlDef->pcszClass == 0xffff0005L) // WC_STATIC:
|
|---|
| 640 | && ( ((flStyle & 0x0F) == SS_BITMAP)
|
|---|
| 641 | || ((flStyle & 0x0F) == SS_ICON)
|
|---|
| 642 | )
|
|---|
| 643 | )
|
|---|
| 644 | {
|
|---|
| 645 | // change style flag to not use SS_BITMAP nor SS_ICON;
|
|---|
| 646 | // control creation fails otherwise (stupid, stupid PM)
|
|---|
| 647 | flOld = flStyle;
|
|---|
| 648 | flStyle = ((flStyle & ~0x0F) | SS_FGNDFRAME);
|
|---|
| 649 | pcszTitle = "";
|
|---|
| 650 | lHandleSet = (LHANDLE)pControlDef->pcszText;
|
|---|
| 651 | }
|
|---|
| 652 | }
|
|---|
| 653 |
|
|---|
| 654 | if (pcp && pControlDef)
|
|---|
| 655 | {
|
|---|
| 656 | // create something:
|
|---|
| 657 | // PPRESPARAMS ppp = NULL;
|
|---|
| 658 |
|
|---|
| 659 | const char *pcszFont = pControlDef->pcszFont;
|
|---|
| 660 | // can be NULL, or CTL_COMMON_FONT
|
|---|
| 661 | if (pcszFont == CTL_COMMON_FONT)
|
|---|
| 662 | pcszFont = pDlgData->pcszControlsFont;
|
|---|
| 663 |
|
|---|
| 664 | /* if (pcszFont)
|
|---|
| 665 | winhStorePresParam(&ppp,
|
|---|
| 666 | PP_FONTNAMESIZE,
|
|---|
| 667 | strlen(pcszFont),
|
|---|
| 668 | (PVOID)pcszFont); */
|
|---|
| 669 |
|
|---|
| 670 | if (pColumnDef->hwndControl
|
|---|
| 671 | = WinCreateWindow(pDlgData->hwndDlg, // parent
|
|---|
| 672 | (PSZ)pControlDef->pcszClass,
|
|---|
| 673 | (pcszTitle) // hacked
|
|---|
| 674 | ? (PSZ)pcszTitle
|
|---|
| 675 | : "",
|
|---|
| 676 | flStyle, // hacked
|
|---|
| 677 | pcp->x + pDlgData->ptlTotalOfs.x,
|
|---|
| 678 | pcp->y + pDlgData->ptlTotalOfs.y,
|
|---|
| 679 | pcp->cx,
|
|---|
| 680 | pcp->cy,
|
|---|
| 681 | pDlgData->hwndDlg, // owner
|
|---|
| 682 | HWND_BOTTOM,
|
|---|
| 683 | pControlDef->usID,
|
|---|
| 684 | pControlDef->pvCtlData,
|
|---|
| 685 | NULL))
|
|---|
| 686 | {
|
|---|
| 687 | if (lHandleSet)
|
|---|
| 688 | {
|
|---|
| 689 | // subclass the damn static
|
|---|
| 690 | if ((flOld & 0x0F) == SS_ICON)
|
|---|
| 691 | // this was a static:
|
|---|
| 692 | ctlPrepareStaticIcon(pColumnDef->hwndControl,
|
|---|
| 693 | 1);
|
|---|
| 694 | else
|
|---|
| 695 | // this was a bitmap:
|
|---|
| 696 | ctlPrepareStretchedBitmap(pColumnDef->hwndControl,
|
|---|
| 697 | TRUE);
|
|---|
| 698 |
|
|---|
| 699 | WinSendMsg(pColumnDef->hwndControl,
|
|---|
| 700 | SM_SETHANDLE,
|
|---|
| 701 | (MPARAM)lHandleSet,
|
|---|
| 702 | 0);
|
|---|
| 703 | }
|
|---|
| 704 | else
|
|---|
| 705 | if (pcszFont)
|
|---|
| 706 | // we must set the font explicitly here...
|
|---|
| 707 | // doesn't always work with WinCreateWindow
|
|---|
| 708 | // presparams parameter, for some reason
|
|---|
| 709 | // V0.9.12 (2001-05-31) [umoeller]
|
|---|
| 710 | winhSetWindowFont(pColumnDef->hwndControl,
|
|---|
| 711 | pcszFont);
|
|---|
| 712 |
|
|---|
| 713 | lstAppendItem(&pDlgData->llControls,
|
|---|
| 714 | pColumnDef);
|
|---|
| 715 |
|
|---|
| 716 | // if this is the first control with WS_TABSTOP,
|
|---|
| 717 | // we give it the focus later
|
|---|
| 718 | if ( (flStyle & WS_TABSTOP)
|
|---|
| 719 | && (!pDlgData->hwndFirstFocus)
|
|---|
| 720 | )
|
|---|
| 721 | pDlgData->hwndFirstFocus = pColumnDef->hwndControl;
|
|---|
| 722 |
|
|---|
| 723 | // if this is the first default push button,
|
|---|
| 724 | // go store it too
|
|---|
| 725 | // V0.9.14 (2001-08-21) [umoeller]
|
|---|
| 726 | if ( (!pDlgData->hwndDefPushbutton)
|
|---|
| 727 | && ((ULONG)pControlDef->pcszClass == 0xffff0003L)
|
|---|
| 728 | && (pControlDef->flStyle & BS_DEFAULT)
|
|---|
| 729 | )
|
|---|
| 730 | pDlgData->hwndDefPushbutton = pColumnDef->hwndControl;
|
|---|
| 731 | }
|
|---|
| 732 | else
|
|---|
| 733 | // V0.9.14 (2001-08-03) [umoeller]
|
|---|
| 734 | arc = DLGERR_CANNOT_CREATE_CONTROL;
|
|---|
| 735 | }
|
|---|
| 736 | break; }
|
|---|
| 737 | }
|
|---|
| 738 |
|
|---|
| 739 | return (arc);
|
|---|
| 740 | }
|
|---|
| 741 |
|
|---|
| 742 | /*
|
|---|
| 743 | *@@ ProcessRow:
|
|---|
| 744 | * level-3 procedure (called from ProcessTable),
|
|---|
| 745 | * which in turn calls ProcessColumn for each column
|
|---|
| 746 | * in the row.
|
|---|
| 747 | *
|
|---|
| 748 | * See ProcessAll for the meaning of ProcessMode.
|
|---|
| 749 | */
|
|---|
| 750 |
|
|---|
| 751 | APIRET ProcessRow(PROWDEF pRowDef,
|
|---|
| 752 | PTABLEDEF pOwningTable, // in: current table from ProcessTable
|
|---|
| 753 | PROCESSMODE ProcessMode, // in: processing mode (see ProcessAll)
|
|---|
| 754 | PLONG plY, // in/out: current y position (decremented)
|
|---|
| 755 | PDLGPRIVATE pDlgData)
|
|---|
| 756 | {
|
|---|
| 757 | APIRET arc = NO_ERROR;
|
|---|
| 758 | LONG lX;
|
|---|
| 759 | PLISTNODE pNode;
|
|---|
| 760 |
|
|---|
| 761 | pRowDef->pOwningTable = pOwningTable;
|
|---|
| 762 |
|
|---|
| 763 | if (ProcessMode == PROCESS_CALC_SIZES)
|
|---|
| 764 | {
|
|---|
| 765 | pRowDef->cpRow.cx = 0;
|
|---|
| 766 | pRowDef->cpRow.cy = 0;
|
|---|
| 767 | }
|
|---|
| 768 | else if (ProcessMode == PROCESS_CALC_POSITIONS)
|
|---|
| 769 | {
|
|---|
| 770 | // set up x and y so that the columns can
|
|---|
| 771 | // base on that
|
|---|
| 772 | pRowDef->cpRow.x = pOwningTable->cpTable.x;
|
|---|
| 773 | // decrease y by row height
|
|---|
| 774 | *plY -= pRowDef->cpRow.cy;
|
|---|
| 775 | // and use that for our bottom position
|
|---|
| 776 | pRowDef->cpRow.y = *plY;
|
|---|
| 777 |
|
|---|
| 778 | // set lX to left of row; used by column calls below
|
|---|
| 779 | lX = pRowDef->cpRow.x;
|
|---|
| 780 | }
|
|---|
| 781 |
|
|---|
| 782 | FOR_ALL_NODES(&pRowDef->llColumns, pNode)
|
|---|
| 783 | {
|
|---|
| 784 | PCOLUMNDEF pColumnDefThis = (PCOLUMNDEF)pNode->pItemData;
|
|---|
| 785 |
|
|---|
| 786 | if (!(arc = ProcessColumn(pColumnDefThis, pRowDef, ProcessMode, &lX, pDlgData)))
|
|---|
| 787 | {
|
|---|
| 788 | if (ProcessMode == PROCESS_CALC_SIZES)
|
|---|
| 789 | {
|
|---|
| 790 | // row width = sum of all columns
|
|---|
| 791 | pRowDef->cpRow.cx += pColumnDefThis->cpColumn.cx;
|
|---|
| 792 |
|
|---|
| 793 | // row height = maximum height of a column
|
|---|
| 794 | if (pRowDef->cpRow.cy < pColumnDefThis->cpColumn.cy)
|
|---|
| 795 | pRowDef->cpRow.cy = pColumnDefThis->cpColumn.cy;
|
|---|
| 796 | }
|
|---|
| 797 | }
|
|---|
| 798 | }
|
|---|
| 799 |
|
|---|
| 800 | return (arc);
|
|---|
| 801 | }
|
|---|
| 802 |
|
|---|
| 803 | /*
|
|---|
| 804 | *@@ ProcessTable:
|
|---|
| 805 | * level-2 procedure (called from ProcessAll),
|
|---|
| 806 | * which in turn calls ProcessRow for each row
|
|---|
| 807 | * in the table (which in turn calls ProcessColumn
|
|---|
| 808 | * for each column in the row).
|
|---|
| 809 | *
|
|---|
| 810 | * See ProcessAll for the meaning of ProcessMode.
|
|---|
| 811 | *
|
|---|
| 812 | * This routine is a bit sick because it can even be
|
|---|
| 813 | * called recursively from ProcessColumn (!) if a
|
|---|
| 814 | * nested table is found in a COLUMNDEF.
|
|---|
| 815 | *
|
|---|
| 816 | * With PROCESS_CALC_POSITIONS, pptl must specify
|
|---|
| 817 | * the lower left corner of the table. For the
|
|---|
| 818 | * root call, this will be {0, 0}; for nested calls,
|
|---|
| 819 | * this must be the lower left corner of the column
|
|---|
| 820 | * to which the nested table belongs.
|
|---|
| 821 | *
|
|---|
| 822 | */
|
|---|
| 823 |
|
|---|
| 824 | APIRET ProcessTable(PTABLEDEF pTableDef,
|
|---|
| 825 | const CONTROLPOS *pcpTable, // in: table position with PROCESS_CALC_POSITIONS
|
|---|
| 826 | PROCESSMODE ProcessMode, // in: processing mode (see ProcessAll)
|
|---|
| 827 | PDLGPRIVATE pDlgData)
|
|---|
| 828 | {
|
|---|
| 829 | APIRET arc = NO_ERROR;
|
|---|
| 830 | LONG lY;
|
|---|
| 831 | PLISTNODE pNode;
|
|---|
| 832 |
|
|---|
| 833 | if (ProcessMode == PROCESS_CALC_SIZES)
|
|---|
| 834 | {
|
|---|
| 835 | pTableDef->cpTable.cx = 0;
|
|---|
| 836 | pTableDef->cpTable.cy = 0;
|
|---|
| 837 | }
|
|---|
| 838 | else if (ProcessMode == PROCESS_CALC_POSITIONS)
|
|---|
| 839 | {
|
|---|
| 840 | pTableDef->cpTable.x = pcpTable->x;
|
|---|
| 841 | pTableDef->cpTable.y = pcpTable->y;
|
|---|
| 842 |
|
|---|
| 843 | // start the rows on top
|
|---|
| 844 | lY = pcpTable->y + pTableDef->cpTable.cy;
|
|---|
| 845 | }
|
|---|
| 846 |
|
|---|
| 847 | FOR_ALL_NODES(&pTableDef->llRows, pNode)
|
|---|
| 848 | {
|
|---|
| 849 | PROWDEF pRowDefThis = (PROWDEF)pNode->pItemData;
|
|---|
| 850 |
|
|---|
| 851 | if (!(arc = ProcessRow(pRowDefThis, pTableDef, ProcessMode, &lY, pDlgData)))
|
|---|
| 852 | {
|
|---|
| 853 | if (ProcessMode == PROCESS_CALC_SIZES)
|
|---|
| 854 | {
|
|---|
| 855 | // table width = maximum width of a row
|
|---|
| 856 | if (pTableDef->cpTable.cx < pRowDefThis->cpRow.cx)
|
|---|
| 857 | pTableDef->cpTable.cx = pRowDefThis->cpRow.cx;
|
|---|
| 858 |
|
|---|
| 859 | // table height = sum of all rows
|
|---|
| 860 | pTableDef->cpTable.cy += pRowDefThis->cpRow.cy;
|
|---|
| 861 | }
|
|---|
| 862 | }
|
|---|
| 863 | else
|
|---|
| 864 | break;
|
|---|
| 865 | }
|
|---|
| 866 |
|
|---|
| 867 | return (arc);
|
|---|
| 868 | }
|
|---|
| 869 |
|
|---|
| 870 | /*
|
|---|
| 871 | *@@ ProcessAll:
|
|---|
| 872 | * level-1 procedure, which in turn calls ProcessTable
|
|---|
| 873 | * for each root-level table found (which in turn
|
|---|
| 874 | * calls ProcessRow for each row in the table, which
|
|---|
| 875 | * in turn calls ProcessColumn for each column in
|
|---|
| 876 | * the row).
|
|---|
| 877 | *
|
|---|
| 878 | * The first trick to formatting is that ProcessAll will
|
|---|
| 879 | * get three times, thus going down the entire tree three
|
|---|
| 880 | * times, with ProcessMode being set to one of the
|
|---|
| 881 | * following for each call (in this order):
|
|---|
| 882 | *
|
|---|
| 883 | * -- PROCESS_CALC_SIZES: calculates the sizes
|
|---|
| 884 | * of all tables, rows, columns, and controls.
|
|---|
| 885 | *
|
|---|
| 886 | * After this first call, we know all the sizes
|
|---|
| 887 | * only and then then calculate the positions.
|
|---|
| 888 | *
|
|---|
| 889 | * -- PROCESS_CALC_POSITIONS: calculates the positions
|
|---|
| 890 | * based on the sizes calculated before.
|
|---|
| 891 | *
|
|---|
| 892 | * -- PROCESS_CREATE_CONTROLS: creates the controls with the
|
|---|
| 893 | * positions and sizes calculated before.
|
|---|
| 894 | *
|
|---|
| 895 | * The second trick is the precondition that tables may
|
|---|
| 896 | * nest by allowing a table definition instead of a
|
|---|
| 897 | * control definition in a column. This way we can
|
|---|
| 898 | * recurse from columns back into tables and thus
|
|---|
| 899 | * know the size and position of a nested table column
|
|---|
| 900 | * just as if it were a regular control.
|
|---|
| 901 | */
|
|---|
| 902 |
|
|---|
| 903 | APIRET ProcessAll(PDLGPRIVATE pDlgData,
|
|---|
| 904 | PSIZEL pszlClient,
|
|---|
| 905 | PROCESSMODE ProcessMode)
|
|---|
| 906 | {
|
|---|
| 907 | APIRET arc = NO_ERROR;
|
|---|
| 908 | PLISTNODE pNode;
|
|---|
| 909 | CONTROLPOS cpTable;
|
|---|
| 910 | ZERO(&cpTable);
|
|---|
| 911 |
|
|---|
| 912 | switch (ProcessMode)
|
|---|
| 913 | {
|
|---|
| 914 | case PROCESS_CALC_SIZES:
|
|---|
| 915 | pszlClient->cx = 0;
|
|---|
| 916 | pszlClient->cy = 0;
|
|---|
| 917 | break;
|
|---|
| 918 |
|
|---|
| 919 | case PROCESS_CALC_POSITIONS:
|
|---|
| 920 | // start with the table on top
|
|---|
| 921 | cpTable.y = pszlClient->cy;
|
|---|
| 922 | break;
|
|---|
| 923 | }
|
|---|
| 924 |
|
|---|
| 925 | FOR_ALL_NODES(&pDlgData->llTables, pNode)
|
|---|
| 926 | {
|
|---|
| 927 | PTABLEDEF pTableDefThis = (PTABLEDEF)pNode->pItemData;
|
|---|
| 928 |
|
|---|
| 929 | if (ProcessMode == PROCESS_CALC_POSITIONS)
|
|---|
| 930 | {
|
|---|
| 931 | cpTable.x = 0;
|
|---|
| 932 | cpTable.y -= pTableDefThis->cpTable.cy;
|
|---|
| 933 | }
|
|---|
| 934 |
|
|---|
| 935 | if (!(arc = ProcessTable(pTableDefThis,
|
|---|
| 936 | &cpTable, // start pos
|
|---|
| 937 | ProcessMode,
|
|---|
| 938 | pDlgData)))
|
|---|
| 939 | {
|
|---|
| 940 | if (ProcessMode == PROCESS_CALC_SIZES)
|
|---|
| 941 | {
|
|---|
| 942 | pszlClient->cx += pTableDefThis->cpTable.cx;
|
|---|
| 943 | pszlClient->cy += pTableDefThis->cpTable.cy;
|
|---|
| 944 | }
|
|---|
| 945 | }
|
|---|
| 946 | }
|
|---|
| 947 |
|
|---|
| 948 | return (arc);
|
|---|
| 949 | }
|
|---|
| 950 |
|
|---|
| 951 | /*
|
|---|
| 952 | *@@ CreateColumn:
|
|---|
| 953 | *
|
|---|
| 954 | */
|
|---|
| 955 |
|
|---|
| 956 | APIRET CreateColumn(PROWDEF pCurrentRow,
|
|---|
| 957 | BOOL fIsNestedTable,
|
|---|
| 958 | PVOID pvDefinition, // in: either PTABLEDEF or PCONTROLDEF
|
|---|
| 959 | PCOLUMNDEF *ppColumnDef) // out: new COLUMNDEF
|
|---|
| 960 | {
|
|---|
| 961 | APIRET arc = NO_ERROR;
|
|---|
| 962 |
|
|---|
| 963 | if (!pCurrentRow)
|
|---|
| 964 | arc = DLGERR_CONTROL_BEFORE_ROW;
|
|---|
| 965 | else
|
|---|
| 966 | {
|
|---|
| 967 | // append the control def
|
|---|
| 968 | if (!pvDefinition)
|
|---|
| 969 | arc = DLGERR_NULL_CTL_DEF;
|
|---|
| 970 | else
|
|---|
| 971 | {
|
|---|
| 972 | // create column and store ctl def
|
|---|
| 973 | PCOLUMNDEF pColumnDef = NEW(COLUMNDEF);
|
|---|
| 974 | if (!pColumnDef)
|
|---|
| 975 | arc = ERROR_NOT_ENOUGH_MEMORY;
|
|---|
| 976 | else
|
|---|
| 977 | {
|
|---|
| 978 | memset(pColumnDef, 0, sizeof(COLUMNDEF));
|
|---|
| 979 | pColumnDef->pOwningRow = pCurrentRow;
|
|---|
| 980 | pColumnDef->fIsNestedTable = fIsNestedTable;
|
|---|
| 981 | pColumnDef->pvDefinition = pvDefinition;
|
|---|
| 982 |
|
|---|
| 983 | *ppColumnDef = pColumnDef;
|
|---|
| 984 | }
|
|---|
| 985 | }
|
|---|
| 986 | }
|
|---|
| 987 |
|
|---|
| 988 | return (arc);
|
|---|
| 989 | }
|
|---|
| 990 |
|
|---|
| 991 | /*
|
|---|
| 992 | *@@ FreeTable:
|
|---|
| 993 | * frees the specified table and recurses
|
|---|
| 994 | * into nested tables, if necessary.
|
|---|
| 995 | *
|
|---|
| 996 | * This was added with V0.9.14 to fix the
|
|---|
| 997 | * bad memory leaks with nested tables.
|
|---|
| 998 | *
|
|---|
| 999 | *@@added V0.9.14 (2001-08-01) [umoeller]
|
|---|
| 1000 | */
|
|---|
| 1001 |
|
|---|
| 1002 | VOID FreeTable(PTABLEDEF pTable)
|
|---|
| 1003 | {
|
|---|
| 1004 | // for each table, clean up the rows
|
|---|
| 1005 | PLISTNODE pRowNode;
|
|---|
| 1006 | FOR_ALL_NODES(&pTable->llRows, pRowNode)
|
|---|
| 1007 | {
|
|---|
| 1008 | PROWDEF pRow = (PROWDEF)pRowNode->pItemData;
|
|---|
| 1009 |
|
|---|
| 1010 | // for each row, clean up the columns
|
|---|
| 1011 | PLISTNODE pColumnNode;
|
|---|
| 1012 | FOR_ALL_NODES(&pRow->llColumns, pColumnNode)
|
|---|
| 1013 | {
|
|---|
| 1014 | PCOLUMNDEF pColumn = (PCOLUMNDEF)pColumnNode->pItemData;
|
|---|
| 1015 |
|
|---|
| 1016 | if (pColumn->fIsNestedTable)
|
|---|
| 1017 | {
|
|---|
| 1018 | // nested table: recurse!
|
|---|
| 1019 | PTABLEDEF pNestedTable = (PTABLEDEF)pColumn->pvDefinition;
|
|---|
| 1020 | FreeTable(pNestedTable);
|
|---|
| 1021 | }
|
|---|
| 1022 |
|
|---|
| 1023 | free(pColumn);
|
|---|
| 1024 | }
|
|---|
| 1025 | lstClear(&pRow->llColumns);
|
|---|
| 1026 |
|
|---|
| 1027 | free(pRow);
|
|---|
| 1028 | }
|
|---|
| 1029 | lstClear(&pTable->llRows);
|
|---|
| 1030 |
|
|---|
| 1031 | free(pTable);
|
|---|
| 1032 | }
|
|---|
| 1033 |
|
|---|
| 1034 | /* ******************************************************************
|
|---|
| 1035 | *
|
|---|
| 1036 | * Public APIs
|
|---|
| 1037 | *
|
|---|
| 1038 | ********************************************************************/
|
|---|
| 1039 |
|
|---|
| 1040 | /*
|
|---|
| 1041 | *@@ STACKITEM:
|
|---|
| 1042 | *
|
|---|
| 1043 | */
|
|---|
| 1044 |
|
|---|
| 1045 | typedef struct _STACKITEM
|
|---|
| 1046 | {
|
|---|
| 1047 | PTABLEDEF pLastTable;
|
|---|
| 1048 | PROWDEF pLastRow;
|
|---|
| 1049 |
|
|---|
| 1050 | } STACKITEM, *PSTACKITEM;
|
|---|
| 1051 |
|
|---|
| 1052 | /*
|
|---|
| 1053 | *@@ dlghCreateDlg:
|
|---|
| 1054 | * replacement for WinCreateDlg/WinLoadDlg for creating a
|
|---|
| 1055 | * dialog from a settings array in memory, which is
|
|---|
| 1056 | * formatted automatically.
|
|---|
| 1057 | *
|
|---|
| 1058 | * This does NOT use regular dialog templates from
|
|---|
| 1059 | * module resources. Instead, you pass in an array
|
|---|
| 1060 | * of DLGHITEM structures, which define the controls
|
|---|
| 1061 | * and how they are to be formatted.
|
|---|
| 1062 | *
|
|---|
| 1063 | * The main advantage compared to dialog resources is
|
|---|
| 1064 | * that with this function, you will never have to
|
|---|
| 1065 | * define control _positions_. Instead, you only specify
|
|---|
| 1066 | * the control _sizes_, and all positions are computed
|
|---|
| 1067 | * automatically here. Even better, for many controls,
|
|---|
| 1068 | * auto-sizing is supported according to the control's
|
|---|
| 1069 | * text (e.g. for statics and checkboxes).
|
|---|
| 1070 | *
|
|---|
| 1071 | * A regular standard dialog would use something like
|
|---|
| 1072 | *
|
|---|
| 1073 | + FCF_TITLEBAR | FCF_SYSMENU | FCF_DLGBORDER | FCF_NOBYTEALIGN
|
|---|
| 1074 | *
|
|---|
| 1075 | * for flCreateFlags. To make the dlg sizeable, specify
|
|---|
| 1076 | * FCF_SIZEBORDER instead of FCF_DLGBORDER.
|
|---|
| 1077 | *
|
|---|
| 1078 | * <B>Usage:</B>
|
|---|
| 1079 | *
|
|---|
| 1080 | * Like WinLoadDlg, this creates a standard WC_FRAME and
|
|---|
| 1081 | * subclasses it with fnwpMyDlgProc. It then sends WM_INITDLG
|
|---|
| 1082 | * to the dialog with pCreateParams in mp2.
|
|---|
| 1083 | *
|
|---|
| 1084 | * If this func returns no error, you can then use
|
|---|
| 1085 | * WinProcessDlg with the newly created dialog as usual. In
|
|---|
| 1086 | * your dlg proc, use WinDefDlgProc as usual.
|
|---|
| 1087 | *
|
|---|
| 1088 | * There is NO run-time overhead for either code or memory
|
|---|
| 1089 | * after dialog creation; after this function returns, the
|
|---|
| 1090 | * dialog is a standard dialog as if loaded from WinLoadDlg.
|
|---|
| 1091 | * The array of DLGHITEM structures defines how the
|
|---|
| 1092 | * dialog is set up. All this is ONLY used by this function
|
|---|
| 1093 | * and NOT needed after the dialog has been created.
|
|---|
| 1094 | *
|
|---|
| 1095 | * In DLGHITEM, the "Type" field determines what this
|
|---|
| 1096 | * structure defines. A number of handy macros have been
|
|---|
| 1097 | * defined to make this easier and to provide type-checking
|
|---|
| 1098 | * at compile time. See dialog.h for more.
|
|---|
| 1099 | *
|
|---|
| 1100 | * Essentially, such a dialog item operates similarly to
|
|---|
| 1101 | * HTML tables. There are rows and columns in the table,
|
|---|
| 1102 | * and each control which is specified must be a column
|
|---|
| 1103 | * in some table. Tables may also nest (see below).
|
|---|
| 1104 | *
|
|---|
| 1105 | * The macros are:
|
|---|
| 1106 | *
|
|---|
| 1107 | * -- START_TABLE starts a new table. The tables may nest,
|
|---|
| 1108 | * but must each be properly terminated with END_TABLE.
|
|---|
| 1109 | *
|
|---|
| 1110 | * -- START_GROUP_TABLE(pDef) starts a group. This
|
|---|
| 1111 | * behaves exacly like START_TABLE, but in addition,
|
|---|
| 1112 | * it produces a static group control around the table.
|
|---|
| 1113 | * Useful for group boxes. pDef must point to a
|
|---|
| 1114 | * _CONTROLDEF describing the control to be used for
|
|---|
| 1115 | * the group (usually a WC_STATIC with SS_GROUP style),
|
|---|
| 1116 | * whose size parameter is ignored.
|
|---|
| 1117 | *
|
|---|
| 1118 | * As with START_TABLE, START_GROUP_TABLE must be
|
|---|
| 1119 | * terminated with END_TABLE.
|
|---|
| 1120 | *
|
|---|
| 1121 | * -- START_ROW(fl) starts a new row in a table (regular
|
|---|
| 1122 | * or group). This must also be the first item after
|
|---|
| 1123 | * the (group) table tag.
|
|---|
| 1124 | *
|
|---|
| 1125 | * fl specifies formatting flags for the row. This
|
|---|
| 1126 | * can be one of ROW_VALIGN_BOTTOM, ROW_VALIGN_CENTER,
|
|---|
| 1127 | * ROW_VALIGN_TOP and affects all items in the control.
|
|---|
| 1128 | *
|
|---|
| 1129 | * -- CONTROL_DEF(pDef) defines a control in a table row.
|
|---|
| 1130 | * pDef must point to a CONTROLDEF structure.
|
|---|
| 1131 | *
|
|---|
| 1132 | * Again, there is is NO information in
|
|---|
| 1133 | * CONTROLDEF about a control's _position_.
|
|---|
| 1134 | * Instead, the structure only contains the _size_
|
|---|
| 1135 | * of the control. All positions are computed by
|
|---|
| 1136 | * this function, depending on the sizes of the
|
|---|
| 1137 | * controls and their nesting within the various tables.
|
|---|
| 1138 | *
|
|---|
| 1139 | * If you specify SZL_AUTOSIZE, the size of the
|
|---|
| 1140 | * control is even computed automatically. Presently,
|
|---|
| 1141 | * this only works for statics with SS_TEXT, SS_ICON,
|
|---|
| 1142 | * and SS_BITMAP.
|
|---|
| 1143 | *
|
|---|
| 1144 | * Unless separated with START_ROW items, subsequent
|
|---|
| 1145 | * control items will be considered to be in the same
|
|---|
| 1146 | * row (== positioned next to each other).
|
|---|
| 1147 | *
|
|---|
| 1148 | * There are a few rules, whose violation will produce
|
|---|
| 1149 | * an error:
|
|---|
| 1150 | *
|
|---|
| 1151 | * -- The entire array must be enclosed in a table
|
|---|
| 1152 | * (the "root" table).
|
|---|
| 1153 | *
|
|---|
| 1154 | * -- After START_TABLE or START_GROUP_TABLE, there must
|
|---|
| 1155 | * always be a START_ROW first.
|
|---|
| 1156 | *
|
|---|
| 1157 | * To create a dialog, set up arrays like the following:
|
|---|
| 1158 | *
|
|---|
| 1159 | + // control definitions referenced by DlgTemplate:
|
|---|
| 1160 | + CONTROLDEF
|
|---|
| 1161 | + (1) GroupDef = {
|
|---|
| 1162 | + WC_STATIC, "", ....,
|
|---|
| 1163 | + { 0, 0 }, // size, ignored for groups
|
|---|
| 1164 | + 5 // spacing
|
|---|
| 1165 | + },
|
|---|
| 1166 | + (2) CnrDef = {
|
|---|
| 1167 | + WC_CONTAINER, "", ....,
|
|---|
| 1168 | + { 50, 50 }, // size
|
|---|
| 1169 | + 5 // spacing
|
|---|
| 1170 | + },
|
|---|
| 1171 | + (3) Static = {
|
|---|
| 1172 | + WC_STATIC, "Static below cnr", ...,
|
|---|
| 1173 | + { SZL_AUTOSIZE, SZL_AUTOSIZE }, // size
|
|---|
| 1174 | + 5 // spacing
|
|---|
| 1175 | + },
|
|---|
| 1176 | + (4) OKButton = {
|
|---|
| 1177 | + WC_STATIC, "~OK", ...,
|
|---|
| 1178 | + { 100, 30 }, // size
|
|---|
| 1179 | + 5 // spacing
|
|---|
| 1180 | + },
|
|---|
| 1181 | + (5) CancelButton = {
|
|---|
| 1182 | + WC_STATIC, "~Cancel", ...,
|
|---|
| 1183 | + { 100, 30 }, // size
|
|---|
| 1184 | + 5 // spacing
|
|---|
| 1185 | + };
|
|---|
| 1186 | +
|
|---|
| 1187 | + DLGHITEM DlgTemplate[] =
|
|---|
| 1188 | + {
|
|---|
| 1189 | + START_TABLE, // root table, required
|
|---|
| 1190 | + START_ROW(0), // row 1 in the root table, required
|
|---|
| 1191 | + // create group on top
|
|---|
| 1192 | + (1) START_GROUP_TABLE(&Group),
|
|---|
| 1193 | + START_ROW(0),
|
|---|
| 1194 | + (2) CONTROL_DEF(&CnrDef),
|
|---|
| 1195 | + START_ROW(0),
|
|---|
| 1196 | + (3) CONTROL_DEF(&Static),
|
|---|
| 1197 | + END_TABLE, // end of group
|
|---|
| 1198 | + START_ROW(0), // row 2 in the root table
|
|---|
| 1199 | + // two buttons next to each other
|
|---|
| 1200 | + (4) CONTROL_DEF(&OKButton),
|
|---|
| 1201 | + (5) CONTROL_DEF(&CancelButton),
|
|---|
| 1202 | + END_TABLE
|
|---|
| 1203 | + }
|
|---|
| 1204 | *
|
|---|
| 1205 | * This will produce a dlg like this:
|
|---|
| 1206 | *
|
|---|
| 1207 | + ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
|
|---|
| 1208 | + º º
|
|---|
| 1209 | + º ÚÄ Group (1) ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ º
|
|---|
| 1210 | + º ³ ³ º
|
|---|
| 1211 | + º ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ º
|
|---|
| 1212 | + º ³ ³ ³ ³ º
|
|---|
| 1213 | + º ³ ³ Cnr inside group (2) ³ ³ º
|
|---|
| 1214 | + º ³ ³ ³ ³ º
|
|---|
| 1215 | + º ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ º
|
|---|
| 1216 | + º ³ Static below cnr (3) ³ º
|
|---|
| 1217 | + º ³ ³ º
|
|---|
| 1218 | + º ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ º
|
|---|
| 1219 | + º ÚÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ º
|
|---|
| 1220 | + º ³ OK (4) ³ ³ Cancel (5) ³ º
|
|---|
| 1221 | + º ÀÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ º
|
|---|
| 1222 | + º º
|
|---|
| 1223 | + ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ
|
|---|
| 1224 | *
|
|---|
| 1225 | * <B>Errors:</B>
|
|---|
| 1226 | *
|
|---|
| 1227 | * This does not return a HWND, but an APIRET. This will be
|
|---|
| 1228 | * one of the following:
|
|---|
| 1229 | *
|
|---|
| 1230 | * -- NO_ERROR: only in that case, the phwndDlg ptr
|
|---|
| 1231 | * receives the HWND of the new dialog, which can
|
|---|
| 1232 | * then be given to WinProcessDlg. Don't forget
|
|---|
| 1233 | * WinDestroyWindow.
|
|---|
| 1234 | *
|
|---|
| 1235 | * -- ERROR_NOT_ENOUGH_MEMORY
|
|---|
| 1236 | *
|
|---|
| 1237 | * -- DLGERR_ROW_BEFORE_TABLE: a row definition appeared
|
|---|
| 1238 | * outside a table definition.
|
|---|
| 1239 | *
|
|---|
| 1240 | * -- DLGERR_CONTROL_BEFORE_ROW: a control definition
|
|---|
| 1241 | * appeared right after a table definition. You must
|
|---|
| 1242 | * specify a row first.
|
|---|
| 1243 | *
|
|---|
| 1244 | * -- DLGERR_NULL_CTL_DEF: TYPE_END_TABLE was specified,
|
|---|
| 1245 | * but the CONTROLDEF ptr was NULL.
|
|---|
| 1246 | *
|
|---|
| 1247 | * -- DLGERR_CANNOT_CREATE_FRAME: unable to create the
|
|---|
| 1248 | * WC_FRAME window. Maybe an invalid owner was specified.
|
|---|
| 1249 | *
|
|---|
| 1250 | * -- DLGERR_INVALID_CODE: invalid "Type" field in
|
|---|
| 1251 | * DLGHITEM.
|
|---|
| 1252 | *
|
|---|
| 1253 | * -- DLGERR_TABLE_NOT_CLOSED, DLGERR_TOO_MANY_TABLES_CLOSED:
|
|---|
| 1254 | * improper nesting of TYPE_START_NEW_TABLE and
|
|---|
| 1255 | * TYPE_END_TABLE fields.
|
|---|
| 1256 | *
|
|---|
| 1257 | * <B>Example:</B>
|
|---|
| 1258 | *
|
|---|
| 1259 | * The typical calling sequence would be:
|
|---|
| 1260 | *
|
|---|
| 1261 | + HWND hwndDlg = NULLHANDLE;
|
|---|
| 1262 | + if (NO_ERROR == dlghCreateDlg(&hwndDlg,
|
|---|
| 1263 | + hwndOwner,
|
|---|
| 1264 | + FCF_DLGBORDER | FCF_NOBYTEALIGN,
|
|---|
| 1265 | + fnwpMyDlgProc,
|
|---|
| 1266 | + "My Dlg Title",
|
|---|
| 1267 | + DlgTemplate, // DLGHITEM array
|
|---|
| 1268 | + ARRAYITEMCOUNT(DlgTemplate),
|
|---|
| 1269 | + NULL, // mp2 for WM_INITDLG
|
|---|
| 1270 | + "9.WarpSans")) // default font
|
|---|
| 1271 | + {
|
|---|
| 1272 | + ULONG idReturn = WinProcessDlg(hwndDlg);
|
|---|
| 1273 | + WinDestroyWindow(hwndDlg);
|
|---|
| 1274 | + }
|
|---|
| 1275 | *
|
|---|
| 1276 | *@@changed V0.9.14 (2001-07-07) [umoeller]: fixed disabled mouse with hwndOwner == HWND_DESKTOP
|
|---|
| 1277 | *@@changed V0.9.14 (2001-08-01) [umoeller]: fixed major memory leaks with nested tables
|
|---|
| 1278 | *@@changed V0.9.14 (2001-08-21) [umoeller]: fixed default push button problems
|
|---|
| 1279 | */
|
|---|
| 1280 |
|
|---|
| 1281 | APIRET dlghCreateDlg(HWND *phwndDlg, // out: new dialog
|
|---|
| 1282 | HWND hwndOwner,
|
|---|
| 1283 | ULONG flCreateFlags, // in: standard FCF_* frame flags
|
|---|
| 1284 | PFNWP pfnwpDialogProc,
|
|---|
| 1285 | const char *pcszDlgTitle,
|
|---|
| 1286 | PDLGHITEM paDlgItems, // in: definition array
|
|---|
| 1287 | ULONG cDlgItems, // in: array item count (NOT array size)
|
|---|
| 1288 | PVOID pCreateParams, // in: for mp2 of WM_INITDLG
|
|---|
| 1289 | const char *pcszControlsFont) // in: font for ctls with CTL_COMMON_FONT
|
|---|
| 1290 | {
|
|---|
| 1291 | APIRET arc = NO_ERROR;
|
|---|
| 1292 |
|
|---|
| 1293 | #define SPACING 10
|
|---|
| 1294 |
|
|---|
| 1295 | PTABLEDEF pCurrentTable = NULL;
|
|---|
| 1296 | PROWDEF pCurrentRow = NULL;
|
|---|
| 1297 | ULONG ul;
|
|---|
| 1298 | LINKLIST llStack;
|
|---|
| 1299 |
|
|---|
| 1300 | PDLGPRIVATE pDlgData = NEW(DLGPRIVATE);
|
|---|
| 1301 |
|
|---|
| 1302 | if (!pDlgData)
|
|---|
| 1303 | return (ERROR_NOT_ENOUGH_MEMORY);
|
|---|
| 1304 |
|
|---|
| 1305 | ZERO(pDlgData);
|
|---|
| 1306 | lstInit(&pDlgData->llTables, FALSE);
|
|---|
| 1307 | lstInit(&pDlgData->llControls, FALSE);
|
|---|
| 1308 |
|
|---|
| 1309 | pDlgData->pcszControlsFont = pcszControlsFont;
|
|---|
| 1310 |
|
|---|
| 1311 | /*
|
|---|
| 1312 | * 1) parse the table and create structures from it
|
|---|
| 1313 | *
|
|---|
| 1314 | */
|
|---|
| 1315 |
|
|---|
| 1316 | lstInit(&llStack, TRUE); // this is our stack for nested table definitions
|
|---|
| 1317 |
|
|---|
| 1318 | for (ul = 0;
|
|---|
| 1319 | ul < cDlgItems;
|
|---|
| 1320 | ul++)
|
|---|
| 1321 | {
|
|---|
| 1322 | PDLGHITEM pItemThis = &paDlgItems[ul];
|
|---|
| 1323 |
|
|---|
| 1324 | switch (pItemThis->Type)
|
|---|
| 1325 | {
|
|---|
| 1326 | /*
|
|---|
| 1327 | * TYPE_START_NEW_TABLE:
|
|---|
| 1328 | *
|
|---|
| 1329 | */
|
|---|
| 1330 |
|
|---|
| 1331 | case TYPE_START_NEW_TABLE:
|
|---|
| 1332 | {
|
|---|
| 1333 | // root table or nested?
|
|---|
| 1334 | BOOL fIsRoot = (pCurrentTable == NULL);
|
|---|
| 1335 |
|
|---|
| 1336 | // push the current table on the stack
|
|---|
| 1337 | PSTACKITEM pStackItem;
|
|---|
| 1338 | if (!(pStackItem = NEW(STACKITEM)))
|
|---|
| 1339 | {
|
|---|
| 1340 | arc = ERROR_NOT_ENOUGH_MEMORY;
|
|---|
| 1341 | break;
|
|---|
| 1342 | }
|
|---|
| 1343 | else
|
|---|
| 1344 | {
|
|---|
| 1345 | pStackItem->pLastTable = pCurrentTable;
|
|---|
| 1346 | pStackItem->pLastRow = pCurrentRow;
|
|---|
| 1347 | lstPush(&llStack, pStackItem);
|
|---|
| 1348 | }
|
|---|
| 1349 |
|
|---|
| 1350 | // create new table
|
|---|
| 1351 | if (!(pCurrentTable = NEW(TABLEDEF)))
|
|---|
| 1352 | arc = ERROR_NOT_ENOUGH_MEMORY;
|
|---|
| 1353 | else
|
|---|
| 1354 | {
|
|---|
| 1355 | ZERO(pCurrentTable);
|
|---|
| 1356 |
|
|---|
| 1357 | lstInit(&pCurrentTable->llRows, FALSE);
|
|---|
| 1358 |
|
|---|
| 1359 | if (pItemThis->ulData)
|
|---|
| 1360 | // control specified: store it (this will become a PM group)
|
|---|
| 1361 | pCurrentTable->pCtlDef = (PCONTROLDEF)pItemThis->ulData;
|
|---|
| 1362 |
|
|---|
| 1363 | if (fIsRoot)
|
|---|
| 1364 | // root table:
|
|---|
| 1365 | // append to dialog data list
|
|---|
| 1366 | lstAppendItem(&pDlgData->llTables, pCurrentTable);
|
|---|
| 1367 | else
|
|---|
| 1368 | {
|
|---|
| 1369 | // nested table:
|
|---|
| 1370 | // create "table" column for this
|
|---|
| 1371 | PCOLUMNDEF pColumnDef;
|
|---|
| 1372 | if (!(arc = CreateColumn(pCurrentRow,
|
|---|
| 1373 | TRUE, // nested table
|
|---|
| 1374 | pCurrentTable,
|
|---|
| 1375 | &pColumnDef)))
|
|---|
| 1376 | lstAppendItem(&pCurrentRow->llColumns,
|
|---|
| 1377 | pColumnDef);
|
|---|
| 1378 | }
|
|---|
| 1379 | }
|
|---|
| 1380 |
|
|---|
| 1381 | pCurrentRow = NULL;
|
|---|
| 1382 | break; }
|
|---|
| 1383 |
|
|---|
| 1384 | /*
|
|---|
| 1385 | * TYPE_START_NEW_ROW:
|
|---|
| 1386 | *
|
|---|
| 1387 | */
|
|---|
| 1388 |
|
|---|
| 1389 | case TYPE_START_NEW_ROW:
|
|---|
| 1390 | {
|
|---|
| 1391 | if (!pCurrentTable)
|
|---|
| 1392 | arc = DLGERR_ROW_BEFORE_TABLE;
|
|---|
| 1393 | else
|
|---|
| 1394 | {
|
|---|
| 1395 | // create new row
|
|---|
| 1396 | if (!(pCurrentRow = NEW(ROWDEF)))
|
|---|
| 1397 | arc = ERROR_NOT_ENOUGH_MEMORY;
|
|---|
| 1398 | else
|
|---|
| 1399 | {
|
|---|
| 1400 | ZERO(pCurrentRow);
|
|---|
| 1401 |
|
|---|
| 1402 | pCurrentRow->pOwningTable = pCurrentTable;
|
|---|
| 1403 | lstInit(&pCurrentRow->llColumns, FALSE);
|
|---|
| 1404 |
|
|---|
| 1405 | pCurrentRow->flRowFormat = pItemThis->ulData;
|
|---|
| 1406 |
|
|---|
| 1407 | lstAppendItem(&pCurrentTable->llRows, pCurrentRow);
|
|---|
| 1408 | }
|
|---|
| 1409 | }
|
|---|
| 1410 | break; }
|
|---|
| 1411 |
|
|---|
| 1412 | /*
|
|---|
| 1413 | * TYPE_CONTROL_DEF:
|
|---|
| 1414 | *
|
|---|
| 1415 | */
|
|---|
| 1416 |
|
|---|
| 1417 | case TYPE_CONTROL_DEF:
|
|---|
| 1418 | {
|
|---|
| 1419 | PCOLUMNDEF pColumnDef;
|
|---|
| 1420 | if (!(arc = CreateColumn(pCurrentRow,
|
|---|
| 1421 | FALSE, // no nested table
|
|---|
| 1422 | (PVOID)pItemThis->ulData,
|
|---|
| 1423 | &pColumnDef)))
|
|---|
| 1424 | lstAppendItem(&pCurrentRow->llColumns,
|
|---|
| 1425 | pColumnDef);
|
|---|
| 1426 | break; }
|
|---|
| 1427 |
|
|---|
| 1428 | /*
|
|---|
| 1429 | * TYPE_END_TABLE:
|
|---|
| 1430 | *
|
|---|
| 1431 | */
|
|---|
| 1432 |
|
|---|
| 1433 | case TYPE_END_TABLE:
|
|---|
| 1434 | {
|
|---|
| 1435 | PLISTNODE pNode = lstPop(&llStack);
|
|---|
| 1436 | if (!pNode)
|
|---|
| 1437 | // nothing on the stack:
|
|---|
| 1438 | arc = DLGERR_TOO_MANY_TABLES_CLOSED;
|
|---|
| 1439 | else
|
|---|
| 1440 | {
|
|---|
| 1441 | PSTACKITEM pStackItem = (PSTACKITEM)pNode->pItemData;
|
|---|
| 1442 | pCurrentTable = pStackItem->pLastTable;
|
|---|
| 1443 | pCurrentRow = pStackItem->pLastRow;
|
|---|
| 1444 |
|
|---|
| 1445 | lstRemoveNode(&llStack, pNode);
|
|---|
| 1446 | }
|
|---|
| 1447 | break; }
|
|---|
| 1448 |
|
|---|
| 1449 | default:
|
|---|
| 1450 | arc = DLGERR_INVALID_CODE;
|
|---|
| 1451 | }
|
|---|
| 1452 |
|
|---|
| 1453 | if (arc)
|
|---|
| 1454 | break;
|
|---|
| 1455 | }
|
|---|
| 1456 |
|
|---|
| 1457 | if (arc == NO_ERROR)
|
|---|
| 1458 | if (lstCountItems(&llStack))
|
|---|
| 1459 | arc = DLGERR_TABLE_NOT_CLOSED;
|
|---|
| 1460 |
|
|---|
| 1461 | lstClear(&llStack);
|
|---|
| 1462 |
|
|---|
| 1463 | if (arc == NO_ERROR)
|
|---|
| 1464 | {
|
|---|
| 1465 | /*
|
|---|
| 1466 | * 2) create empty dialog frame
|
|---|
| 1467 | *
|
|---|
| 1468 | */
|
|---|
| 1469 |
|
|---|
| 1470 | FRAMECDATA fcData = {0};
|
|---|
| 1471 | ULONG flStyle = 0;
|
|---|
| 1472 |
|
|---|
| 1473 | fcData.cb = sizeof(FRAMECDATA);
|
|---|
| 1474 | fcData.flCreateFlags = flCreateFlags | 0x40000000L;
|
|---|
| 1475 |
|
|---|
| 1476 | if (flCreateFlags & FCF_SIZEBORDER)
|
|---|
| 1477 | // dialog has size border:
|
|---|
| 1478 | // add "clip siblings" style
|
|---|
| 1479 | flStyle |= WS_CLIPSIBLINGS;
|
|---|
| 1480 |
|
|---|
| 1481 | if (hwndOwner == HWND_DESKTOP)
|
|---|
| 1482 | // there's some dumb XWorkplace code left
|
|---|
| 1483 | // which uses this, and this disables the
|
|---|
| 1484 | // mouse for some reason
|
|---|
| 1485 | // V0.9.14 (2001-07-07) [umoeller]
|
|---|
| 1486 | hwndOwner = NULLHANDLE;
|
|---|
| 1487 |
|
|---|
| 1488 | if (!(pDlgData->hwndDlg = WinCreateWindow(HWND_DESKTOP,
|
|---|
| 1489 | WC_FRAME,
|
|---|
| 1490 | (PSZ)pcszDlgTitle,
|
|---|
| 1491 | flStyle, // style; invisible for now
|
|---|
| 1492 | 0, 0, 0, 0,
|
|---|
| 1493 | hwndOwner,
|
|---|
| 1494 | HWND_TOP,
|
|---|
| 1495 | 0, // ID
|
|---|
| 1496 | &fcData,
|
|---|
| 1497 | NULL))) // presparams
|
|---|
| 1498 | arc = DLGERR_CANNOT_CREATE_FRAME;
|
|---|
| 1499 | else
|
|---|
| 1500 | {
|
|---|
| 1501 | HWND hwndDlg = pDlgData->hwndDlg;
|
|---|
| 1502 | SIZEL szlClient = {0};
|
|---|
| 1503 | RECTL rclClient;
|
|---|
| 1504 | HWND hwndFocusItem = NULLHANDLE;
|
|---|
| 1505 |
|
|---|
| 1506 | /*
|
|---|
| 1507 | * 3) compute size of all controls
|
|---|
| 1508 | *
|
|---|
| 1509 | */
|
|---|
| 1510 |
|
|---|
| 1511 | ProcessAll(pDlgData,
|
|---|
| 1512 | &szlClient,
|
|---|
| 1513 | PROCESS_CALC_SIZES);
|
|---|
| 1514 | // this goes into major recursions...
|
|---|
| 1515 |
|
|---|
| 1516 | // free the cached font resources that
|
|---|
| 1517 | // might have been created here
|
|---|
| 1518 | if (pDlgData->lcidLast)
|
|---|
| 1519 | {
|
|---|
| 1520 | GpiSetCharSet(pDlgData->hps, LCID_DEFAULT);
|
|---|
| 1521 | GpiDeleteSetId(pDlgData->hps, pDlgData->lcidLast);
|
|---|
| 1522 | }
|
|---|
| 1523 | if (pDlgData->hps)
|
|---|
| 1524 | WinReleasePS(pDlgData->hps);
|
|---|
| 1525 |
|
|---|
| 1526 | WinSubclassWindow(hwndDlg, pfnwpDialogProc);
|
|---|
| 1527 |
|
|---|
| 1528 | /*
|
|---|
| 1529 | * 4) compute size of dialog client from total
|
|---|
| 1530 | * size of all controls
|
|---|
| 1531 | */
|
|---|
| 1532 |
|
|---|
| 1533 | // calculate the frame size from the client size
|
|---|
| 1534 | rclClient.xLeft = 10;
|
|---|
| 1535 | rclClient.yBottom = 10;
|
|---|
| 1536 | rclClient.xRight = szlClient.cx + 2 * SPACING;
|
|---|
| 1537 | rclClient.yTop = szlClient.cy + 2 * SPACING;
|
|---|
| 1538 | WinCalcFrameRect(hwndDlg,
|
|---|
| 1539 | &rclClient,
|
|---|
| 1540 | FALSE); // frame from client
|
|---|
| 1541 |
|
|---|
| 1542 | WinSetWindowPos(hwndDlg,
|
|---|
| 1543 | 0,
|
|---|
| 1544 | 10,
|
|---|
| 1545 | 10,
|
|---|
| 1546 | rclClient.xRight,
|
|---|
| 1547 | rclClient.yTop,
|
|---|
| 1548 | SWP_MOVE | SWP_SIZE | SWP_NOADJUST);
|
|---|
| 1549 |
|
|---|
| 1550 | /*
|
|---|
| 1551 | * 5) compute _positions_ of all controls
|
|---|
| 1552 | *
|
|---|
| 1553 | */
|
|---|
| 1554 |
|
|---|
| 1555 | ProcessAll(pDlgData,
|
|---|
| 1556 | &szlClient,
|
|---|
| 1557 | PROCESS_CALC_POSITIONS);
|
|---|
| 1558 |
|
|---|
| 1559 | /*
|
|---|
| 1560 | * 6) create control windows, finally
|
|---|
| 1561 | *
|
|---|
| 1562 | */
|
|---|
| 1563 |
|
|---|
| 1564 | pDlgData->ptlTotalOfs.x = SPACING;
|
|---|
| 1565 | pDlgData->ptlTotalOfs.y = SPACING;
|
|---|
| 1566 |
|
|---|
| 1567 | ProcessAll(pDlgData,
|
|---|
| 1568 | &szlClient,
|
|---|
| 1569 | PROCESS_CREATE_CONTROLS);
|
|---|
| 1570 |
|
|---|
| 1571 | if (pDlgData->hwndDefPushbutton)
|
|---|
| 1572 | // we had a default pushbutton:
|
|---|
| 1573 | // go set it V0.9.14 (2001-08-21) [umoeller]
|
|---|
| 1574 | WinSetWindowULong(pDlgData->hwndDlg,
|
|---|
| 1575 | QWL_DEFBUTTON,
|
|---|
| 1576 | pDlgData->hwndDefPushbutton);
|
|---|
| 1577 |
|
|---|
| 1578 | /*
|
|---|
| 1579 | * 7) WM_INITDLG, set focus
|
|---|
| 1580 | *
|
|---|
| 1581 | */
|
|---|
| 1582 |
|
|---|
| 1583 | hwndFocusItem = (pDlgData->hwndFirstFocus)
|
|---|
| 1584 | ? pDlgData->hwndFirstFocus
|
|---|
| 1585 | : hwndDlg;
|
|---|
| 1586 | if (!WinSendMsg(hwndDlg,
|
|---|
| 1587 | WM_INITDLG,
|
|---|
| 1588 | (MPARAM)hwndFocusItem,
|
|---|
| 1589 | (MPARAM)pCreateParams))
|
|---|
| 1590 | {
|
|---|
| 1591 | // if WM_INITDLG returns FALSE, this means
|
|---|
| 1592 | // the dlg proc has not changed the focus;
|
|---|
| 1593 | // we must then set the focus here
|
|---|
| 1594 | WinSetFocus(HWND_DESKTOP, hwndFocusItem);
|
|---|
| 1595 | }
|
|---|
| 1596 | }
|
|---|
| 1597 | }
|
|---|
| 1598 |
|
|---|
| 1599 | if (pDlgData)
|
|---|
| 1600 | {
|
|---|
| 1601 | PLISTNODE pTableNode;
|
|---|
| 1602 |
|
|---|
| 1603 | if (arc)
|
|---|
| 1604 | {
|
|---|
| 1605 | // error: clean up
|
|---|
| 1606 | if (pDlgData->hwndDlg)
|
|---|
| 1607 | WinDestroyWindow(pDlgData->hwndDlg);
|
|---|
| 1608 | }
|
|---|
| 1609 | else
|
|---|
| 1610 | // no error: output dialog
|
|---|
| 1611 | *phwndDlg = pDlgData->hwndDlg;
|
|---|
| 1612 |
|
|---|
| 1613 | // in any case, clean up our mess:
|
|---|
| 1614 |
|
|---|
| 1615 | // clean up the tables
|
|---|
| 1616 | FOR_ALL_NODES(&pDlgData->llTables, pTableNode)
|
|---|
| 1617 | {
|
|---|
| 1618 | PTABLEDEF pTable = (PTABLEDEF)pTableNode->pItemData;
|
|---|
| 1619 |
|
|---|
| 1620 | FreeTable(pTable);
|
|---|
| 1621 | // this may recurse for nested tables
|
|---|
| 1622 | }
|
|---|
| 1623 |
|
|---|
| 1624 | lstClear(&pDlgData->llTables);
|
|---|
| 1625 | lstClear(&pDlgData->llControls);
|
|---|
| 1626 |
|
|---|
| 1627 | free(pDlgData);
|
|---|
| 1628 | }
|
|---|
| 1629 |
|
|---|
| 1630 | if (arc)
|
|---|
| 1631 | {
|
|---|
| 1632 | CHAR szErr[300];
|
|---|
| 1633 | sprintf(szErr, "Error %d occured in dlghCreateDlg.", arc);
|
|---|
| 1634 | winhDebugBox(hwndOwner,
|
|---|
| 1635 | "Error in Dialog Manager",
|
|---|
| 1636 | szErr);
|
|---|
| 1637 | }
|
|---|
| 1638 |
|
|---|
| 1639 | return (arc);
|
|---|
| 1640 | }
|
|---|
| 1641 |
|
|---|
| 1642 | /*
|
|---|
| 1643 | *@@ dlghCreateMessageBox:
|
|---|
| 1644 | *
|
|---|
| 1645 | *@@added V0.9.13 (2001-06-21) [umoeller]
|
|---|
| 1646 | *@@changed V0.9.14 (2001-07-26) [umoeller]: fixed missing focus on buttons
|
|---|
| 1647 | */
|
|---|
| 1648 |
|
|---|
| 1649 | APIRET dlghCreateMessageBox(HWND *phwndDlg,
|
|---|
| 1650 | HWND hwndOwner,
|
|---|
| 1651 | HPOINTER hptrIcon,
|
|---|
| 1652 | const char *pcszTitle,
|
|---|
| 1653 | const char *pcszMessage,
|
|---|
| 1654 | ULONG flFlags,
|
|---|
| 1655 | const char *pcszFont,
|
|---|
| 1656 | const MSGBOXSTRINGS *pStrings,
|
|---|
| 1657 | PULONG pulAlarmFlag) // out: alarm sound to be played
|
|---|
| 1658 | {
|
|---|
| 1659 | CONTROLDEF
|
|---|
| 1660 | Icon = {
|
|---|
| 1661 | WC_STATIC,
|
|---|
| 1662 | NULL, // text, set below
|
|---|
| 1663 | WS_VISIBLE | SS_ICON,
|
|---|
| 1664 | 0, // ID
|
|---|
| 1665 | NULL, // no font
|
|---|
| 1666 | 0,
|
|---|
| 1667 | { SZL_AUTOSIZE, SZL_AUTOSIZE },
|
|---|
| 1668 | 5
|
|---|
| 1669 | },
|
|---|
| 1670 | InfoText =
|
|---|
| 1671 | {
|
|---|
| 1672 | WC_STATIC,
|
|---|
| 1673 | NULL, // text, set below
|
|---|
| 1674 | WS_VISIBLE | SS_TEXT | DT_WORDBREAK | DT_LEFT | DT_TOP,
|
|---|
| 1675 | 10, // ID
|
|---|
| 1676 | CTL_COMMON_FONT,
|
|---|
| 1677 | 0,
|
|---|
| 1678 | { 400, SZL_AUTOSIZE },
|
|---|
| 1679 | 5
|
|---|
| 1680 | },
|
|---|
| 1681 | Buttons[] = {
|
|---|
| 1682 | {
|
|---|
| 1683 | WC_BUTTON,
|
|---|
| 1684 | NULL, // text, set below
|
|---|
| 1685 | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
|
|---|
| 1686 | 1, // ID
|
|---|
| 1687 | CTL_COMMON_FONT, // no font
|
|---|
| 1688 | 0,
|
|---|
| 1689 | { 100, 30 },
|
|---|
| 1690 | 5
|
|---|
| 1691 | },
|
|---|
| 1692 | {
|
|---|
| 1693 | WC_BUTTON,
|
|---|
| 1694 | NULL, // text, set below
|
|---|
| 1695 | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
|
|---|
| 1696 | 2, // ID
|
|---|
| 1697 | CTL_COMMON_FONT, // no font
|
|---|
| 1698 | 0,
|
|---|
| 1699 | { 100, 30 },
|
|---|
| 1700 | 5
|
|---|
| 1701 | },
|
|---|
| 1702 | {
|
|---|
| 1703 | WC_BUTTON,
|
|---|
| 1704 | NULL, // text, set below
|
|---|
| 1705 | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
|
|---|
| 1706 | 3, // ID
|
|---|
| 1707 | CTL_COMMON_FONT, // no font
|
|---|
| 1708 | 0,
|
|---|
| 1709 | { 100, 30 },
|
|---|
| 1710 | 5
|
|---|
| 1711 | }
|
|---|
| 1712 | };
|
|---|
| 1713 |
|
|---|
| 1714 | DLGHITEM MessageBox[] =
|
|---|
| 1715 | {
|
|---|
| 1716 | START_TABLE,
|
|---|
| 1717 | START_ROW(ROW_VALIGN_CENTER),
|
|---|
| 1718 | CONTROL_DEF(&Icon),
|
|---|
| 1719 | START_TABLE,
|
|---|
| 1720 | START_ROW(ROW_VALIGN_CENTER),
|
|---|
| 1721 | CONTROL_DEF(&InfoText),
|
|---|
| 1722 | START_ROW(ROW_VALIGN_CENTER),
|
|---|
| 1723 | CONTROL_DEF(&Buttons[0]),
|
|---|
| 1724 | CONTROL_DEF(&Buttons[1]),
|
|---|
| 1725 | CONTROL_DEF(&Buttons[2]),
|
|---|
| 1726 | END_TABLE,
|
|---|
| 1727 | END_TABLE
|
|---|
| 1728 | };
|
|---|
| 1729 |
|
|---|
| 1730 | ULONG flButtons = flFlags & 0xF; // low nibble contains MB_YESNO etc.
|
|---|
| 1731 |
|
|---|
| 1732 | const char *p0 = "Error",
|
|---|
| 1733 | *p1 = NULL,
|
|---|
| 1734 | *p2 = NULL;
|
|---|
| 1735 |
|
|---|
| 1736 | Icon.pcszText = (const char *)hptrIcon;
|
|---|
| 1737 | InfoText.pcszText = pcszMessage;
|
|---|
| 1738 |
|
|---|
| 1739 | // now work on the three buttons of the dlg template:
|
|---|
| 1740 | // give them proper titles or hide them
|
|---|
| 1741 | if (flButtons == MB_OK)
|
|---|
| 1742 | {
|
|---|
| 1743 | p0 = pStrings->pcszOK;
|
|---|
| 1744 | }
|
|---|
| 1745 | else if (flButtons == MB_OKCANCEL)
|
|---|
| 1746 | {
|
|---|
| 1747 | p0 = pStrings->pcszOK;
|
|---|
| 1748 | p1 = pStrings->pcszCancel;
|
|---|
| 1749 | }
|
|---|
| 1750 | else if (flButtons == MB_RETRYCANCEL)
|
|---|
| 1751 | {
|
|---|
| 1752 | p0 = pStrings->pcszRetry;
|
|---|
| 1753 | p1 = pStrings->pcszCancel;
|
|---|
| 1754 | }
|
|---|
| 1755 | else if (flButtons == MB_ABORTRETRYIGNORE)
|
|---|
| 1756 | {
|
|---|
| 1757 | p0 = pStrings->pcszAbort;
|
|---|
| 1758 | p1 = pStrings->pcszRetry;
|
|---|
| 1759 | p2 = pStrings->pcszIgnore;
|
|---|
| 1760 | }
|
|---|
| 1761 | else if (flButtons == MB_YESNO)
|
|---|
| 1762 | {
|
|---|
| 1763 | p0 = pStrings->pcszYes;
|
|---|
| 1764 | p1 = pStrings->pcszNo;
|
|---|
| 1765 | }
|
|---|
| 1766 | else if (flButtons == MB_YESNOCANCEL)
|
|---|
| 1767 | {
|
|---|
| 1768 | p0 = pStrings->pcszYes;
|
|---|
| 1769 | p1 = pStrings->pcszNo;
|
|---|
| 1770 | p2 = pStrings->pcszCancel;
|
|---|
| 1771 | }
|
|---|
| 1772 | else if (flButtons == MB_CANCEL)
|
|---|
| 1773 | {
|
|---|
| 1774 | p0 = pStrings->pcszCancel;
|
|---|
| 1775 | }
|
|---|
| 1776 | else if (flButtons == MB_ENTER)
|
|---|
| 1777 | {
|
|---|
| 1778 | p0 = pStrings->pcszEnter;
|
|---|
| 1779 | }
|
|---|
| 1780 | else if (flButtons == MB_ENTERCANCEL)
|
|---|
| 1781 | {
|
|---|
| 1782 | p0 = pStrings->pcszEnter;
|
|---|
| 1783 | p1 = pStrings->pcszCancel;
|
|---|
| 1784 | }
|
|---|
| 1785 | else if (flButtons == MB_YES_YES2ALL_NO)
|
|---|
| 1786 | {
|
|---|
| 1787 | p0 = pStrings->pcszYes;
|
|---|
| 1788 | p1 = pStrings->pcszYesToAll;
|
|---|
| 1789 | p2 = pStrings->pcszNo;
|
|---|
| 1790 | }
|
|---|
| 1791 |
|
|---|
| 1792 | // now set strings and hide empty buttons
|
|---|
| 1793 | Buttons[0].pcszText = p0;
|
|---|
| 1794 |
|
|---|
| 1795 | if (p1)
|
|---|
| 1796 | Buttons[1].pcszText = p1;
|
|---|
| 1797 | else
|
|---|
| 1798 | Buttons[1].flStyle &= ~WS_VISIBLE;
|
|---|
| 1799 |
|
|---|
| 1800 | if (p2)
|
|---|
| 1801 | Buttons[2].pcszText = p2;
|
|---|
| 1802 | else
|
|---|
| 1803 | Buttons[2].flStyle &= ~WS_VISIBLE;
|
|---|
| 1804 |
|
|---|
| 1805 | // query default button IDs
|
|---|
| 1806 | if (flFlags & MB_DEFBUTTON2)
|
|---|
| 1807 | Buttons[1].flStyle |= BS_DEFAULT;
|
|---|
| 1808 | else if (flFlags & MB_DEFBUTTON3)
|
|---|
| 1809 | Buttons[2].flStyle |= BS_DEFAULT;
|
|---|
| 1810 | else
|
|---|
| 1811 | Buttons[0].flStyle |= BS_DEFAULT;
|
|---|
| 1812 |
|
|---|
| 1813 | *pulAlarmFlag = WA_NOTE;
|
|---|
| 1814 | if (flFlags & (MB_ICONHAND | MB_ERROR))
|
|---|
| 1815 | *pulAlarmFlag = WA_ERROR;
|
|---|
| 1816 | else if (flFlags & (MB_ICONEXCLAMATION | MB_WARNING))
|
|---|
| 1817 | *pulAlarmFlag = WA_WARNING;
|
|---|
| 1818 |
|
|---|
| 1819 | return (dlghCreateDlg(phwndDlg,
|
|---|
| 1820 | hwndOwner,
|
|---|
| 1821 | FCF_TITLEBAR | FCF_SYSMENU | FCF_DLGBORDER | FCF_NOBYTEALIGN,
|
|---|
| 1822 | WinDefDlgProc,
|
|---|
| 1823 | pcszTitle,
|
|---|
| 1824 | MessageBox,
|
|---|
| 1825 | ARRAYITEMCOUNT(MessageBox),
|
|---|
| 1826 | NULL,
|
|---|
| 1827 | pcszFont));
|
|---|
| 1828 | }
|
|---|
| 1829 |
|
|---|
| 1830 | /*
|
|---|
| 1831 | *@@ dlghProcessMessageBox:
|
|---|
| 1832 | *
|
|---|
| 1833 | *@@added V0.9.13 (2001-06-21) [umoeller]
|
|---|
| 1834 | */
|
|---|
| 1835 |
|
|---|
| 1836 | ULONG dlghProcessMessageBox(HWND hwndDlg,
|
|---|
| 1837 | ULONG ulAlarmFlag,
|
|---|
| 1838 | ULONG flFlags)
|
|---|
| 1839 | {
|
|---|
| 1840 | ULONG ulrcDlg;
|
|---|
| 1841 | ULONG flButtons = flFlags & 0xF; // low nibble contains MB_YESNO etc.
|
|---|
| 1842 |
|
|---|
| 1843 | winhCenterWindow(hwndDlg);
|
|---|
| 1844 |
|
|---|
| 1845 | if (flFlags & MB_SYSTEMMODAL)
|
|---|
| 1846 | WinSetSysModalWindow(HWND_DESKTOP, hwndDlg);
|
|---|
| 1847 |
|
|---|
| 1848 | if (ulAlarmFlag)
|
|---|
| 1849 | WinAlarm(HWND_DESKTOP, ulAlarmFlag);
|
|---|
| 1850 |
|
|---|
| 1851 | ulrcDlg = WinProcessDlg(hwndDlg);
|
|---|
| 1852 |
|
|---|
| 1853 | WinDestroyWindow(hwndDlg);
|
|---|
| 1854 |
|
|---|
| 1855 | if (flButtons == MB_OK)
|
|---|
| 1856 | return MBID_OK;
|
|---|
| 1857 | else if (flButtons == MB_OKCANCEL)
|
|---|
| 1858 | switch (ulrcDlg)
|
|---|
| 1859 | {
|
|---|
| 1860 | case 1: return MBID_OK;
|
|---|
| 1861 | default: return MBID_CANCEL;
|
|---|
| 1862 | }
|
|---|
| 1863 | else if (flButtons == MB_RETRYCANCEL)
|
|---|
| 1864 | switch (ulrcDlg)
|
|---|
| 1865 | {
|
|---|
| 1866 | case 1: return MBID_RETRY;
|
|---|
| 1867 | default: return MBID_CANCEL;
|
|---|
| 1868 | }
|
|---|
| 1869 | else if (flButtons == MB_ABORTRETRYIGNORE)
|
|---|
| 1870 | switch (ulrcDlg)
|
|---|
| 1871 | {
|
|---|
| 1872 | case 2: return MBID_RETRY;
|
|---|
| 1873 | case 3: return MBID_IGNORE;
|
|---|
| 1874 | default: return MBID_ABORT;
|
|---|
| 1875 | }
|
|---|
| 1876 | else if (flButtons == MB_YESNO)
|
|---|
| 1877 | switch (ulrcDlg)
|
|---|
| 1878 | {
|
|---|
| 1879 | case 1: return MBID_YES;
|
|---|
| 1880 | default: return MBID_NO;
|
|---|
| 1881 | }
|
|---|
| 1882 | else if (flButtons == MB_YESNOCANCEL)
|
|---|
| 1883 | switch (ulrcDlg)
|
|---|
| 1884 | {
|
|---|
| 1885 | case 1: return MBID_YES;
|
|---|
| 1886 | case 2: return MBID_NO;
|
|---|
| 1887 | default: return MBID_CANCEL;
|
|---|
| 1888 | }
|
|---|
| 1889 | else if (flButtons == MB_CANCEL)
|
|---|
| 1890 | return MBID_CANCEL;
|
|---|
| 1891 | else if (flButtons == MB_ENTER)
|
|---|
| 1892 | return MBID_ENTER;
|
|---|
| 1893 | else if (flButtons == MB_ENTERCANCEL)
|
|---|
| 1894 | switch (ulrcDlg)
|
|---|
| 1895 | {
|
|---|
| 1896 | case 1: return MBID_ENTER;
|
|---|
| 1897 | default: return MBID_CANCEL;
|
|---|
| 1898 | }
|
|---|
| 1899 | else if (flButtons == MB_YES_YES2ALL_NO)
|
|---|
| 1900 | switch (ulrcDlg)
|
|---|
| 1901 | {
|
|---|
| 1902 | case 1: return MBID_YES;
|
|---|
| 1903 | case 2: return MBID_YES2ALL;
|
|---|
| 1904 | default: return MBID_NO;
|
|---|
| 1905 | }
|
|---|
| 1906 |
|
|---|
| 1907 | return (MBID_CANCEL);
|
|---|
| 1908 | }
|
|---|
| 1909 |
|
|---|
| 1910 | /*
|
|---|
| 1911 | *@@ dlghMessageBox:
|
|---|
| 1912 | * WinMessageBox replacement.
|
|---|
| 1913 | *
|
|---|
| 1914 | * This has all the flags of the standard call,
|
|---|
| 1915 | * but looks much prettier. Besides, it allows
|
|---|
| 1916 | * you to specify any icon to be displayed.
|
|---|
| 1917 | *
|
|---|
| 1918 | * Currently the following flStyle's are supported:
|
|---|
| 1919 | *
|
|---|
| 1920 | * -- MB_OK 0x0000
|
|---|
| 1921 | * -- MB_OKCANCEL 0x0001
|
|---|
| 1922 | * -- MB_RETRYCANCEL 0x0002
|
|---|
| 1923 | * -- MB_ABORTRETRYIGNORE 0x0003
|
|---|
| 1924 | * -- MB_YESNO 0x0004
|
|---|
| 1925 | * -- MB_YESNOCANCEL 0x0005
|
|---|
| 1926 | * -- MB_CANCEL 0x0006
|
|---|
| 1927 | * -- MB_ENTER 0x0007 (not implemented yet)
|
|---|
| 1928 | * -- MB_ENTERCANCEL 0x0008 (not implemented yet)
|
|---|
| 1929 | *
|
|---|
| 1930 | * -- MB_YES_YES2ALL_NO 0x0009
|
|---|
| 1931 | * This is new: this has three buttons called "Yes"
|
|---|
| 1932 | * (MBID_YES), "Yes to all" (MBID_YES2ALL), "No" (MBID_NO).
|
|---|
| 1933 | *
|
|---|
| 1934 | * -- MB_DEFBUTTON2 (for two-button styles)
|
|---|
| 1935 | * -- MB_DEFBUTTON3 (for three-button styles)
|
|---|
| 1936 | *
|
|---|
| 1937 | * -- MB_ICONHAND
|
|---|
| 1938 | * -- MB_ICONEXCLAMATION
|
|---|
| 1939 | *
|
|---|
| 1940 | * Returns MBID_* codes like WinMessageBox.
|
|---|
| 1941 | *
|
|---|
| 1942 | *@@added V0.9.13 (2001-06-21) [umoeller]
|
|---|
| 1943 | */
|
|---|
| 1944 |
|
|---|
| 1945 | ULONG dlghMessageBox(HWND hwndOwner, // in: owner for msg box
|
|---|
| 1946 | HPOINTER hptrIcon, // in: icon to display
|
|---|
| 1947 | const char *pcszTitle, // in: title
|
|---|
| 1948 | const char *pcszMessage, // in: message
|
|---|
| 1949 | ULONG flFlags, // in: standard message box flags
|
|---|
| 1950 | const char *pcszFont, // in: font (e.g. "9.WarpSans")
|
|---|
| 1951 | const MSGBOXSTRINGS *pStrings) // in: strings array
|
|---|
| 1952 | {
|
|---|
| 1953 | HWND hwndDlg;
|
|---|
| 1954 | ULONG ulAlarmFlag;
|
|---|
| 1955 | APIRET arc = dlghCreateMessageBox(&hwndDlg,
|
|---|
| 1956 | hwndOwner,
|
|---|
| 1957 | hptrIcon,
|
|---|
| 1958 | pcszTitle,
|
|---|
| 1959 | pcszMessage,
|
|---|
| 1960 | flFlags,
|
|---|
| 1961 | pcszFont,
|
|---|
| 1962 | pStrings,
|
|---|
| 1963 | &ulAlarmFlag);
|
|---|
| 1964 |
|
|---|
| 1965 | if (!arc && hwndDlg)
|
|---|
| 1966 | {
|
|---|
| 1967 | // SHOW DIALOG
|
|---|
| 1968 | return (dlghProcessMessageBox(hwndDlg,
|
|---|
| 1969 | ulAlarmFlag,
|
|---|
| 1970 | flFlags));
|
|---|
| 1971 | }
|
|---|
| 1972 | else
|
|---|
| 1973 | {
|
|---|
| 1974 | CHAR szMsg[100];
|
|---|
| 1975 | sprintf(szMsg, "dlghCreateMessageBox reported error %u.", arc);
|
|---|
| 1976 | WinMessageBox(HWND_DESKTOP,
|
|---|
| 1977 | NULLHANDLE,
|
|---|
| 1978 | "Error",
|
|---|
| 1979 | szMsg,
|
|---|
| 1980 | 0,
|
|---|
| 1981 | MB_CANCEL | MB_MOVEABLE);
|
|---|
| 1982 | }
|
|---|
| 1983 |
|
|---|
| 1984 | return (DID_CANCEL);
|
|---|
| 1985 | }
|
|---|
| 1986 |
|
|---|
| 1987 | /*
|
|---|
| 1988 | *@@ dlghSetPrevFocus:
|
|---|
| 1989 | * "backward" function for rotating the focus
|
|---|
| 1990 | * in a dialog when the "shift+tab" keys get
|
|---|
| 1991 | * pressed.
|
|---|
| 1992 | *
|
|---|
| 1993 | * pllWindows must be a linked list with the
|
|---|
| 1994 | * plain HWND window handles of the focussable
|
|---|
| 1995 | * controls in the dialog.
|
|---|
| 1996 | */
|
|---|
| 1997 |
|
|---|
| 1998 | VOID dlghSetPrevFocus(PVOID pvllWindows)
|
|---|
| 1999 | {
|
|---|
| 2000 | PLINKLIST pllWindows = (PLINKLIST)pvllWindows;
|
|---|
| 2001 |
|
|---|
| 2002 | // check current focus
|
|---|
| 2003 | HWND hwndFocus = WinQueryFocus(HWND_DESKTOP);
|
|---|
| 2004 |
|
|---|
| 2005 | PLISTNODE pNode = lstNodeFromItem(pllWindows, (PVOID)hwndFocus);
|
|---|
| 2006 |
|
|---|
| 2007 | BOOL fRestart = FALSE;
|
|---|
| 2008 |
|
|---|
| 2009 | while (pNode)
|
|---|
| 2010 | {
|
|---|
| 2011 | CHAR szClass[100];
|
|---|
| 2012 |
|
|---|
| 2013 | // previos node
|
|---|
| 2014 | pNode = pNode->pPrevious;
|
|---|
| 2015 |
|
|---|
| 2016 | if ( (!pNode) // no next, or not found:
|
|---|
| 2017 | && (!fRestart) // avoid infinite looping if bad list
|
|---|
| 2018 | )
|
|---|
| 2019 | {
|
|---|
| 2020 | pNode = lstQueryLastNode(pllWindows);
|
|---|
| 2021 | fRestart = TRUE;
|
|---|
| 2022 | }
|
|---|
| 2023 |
|
|---|
| 2024 | if (pNode)
|
|---|
| 2025 | {
|
|---|
| 2026 | // check if this is a focusable control
|
|---|
| 2027 | if (WinQueryClassName((HWND)pNode->pItemData,
|
|---|
| 2028 | sizeof(szClass),
|
|---|
| 2029 | szClass))
|
|---|
| 2030 | {
|
|---|
| 2031 | if ( (strcmp(szClass, "#5")) // not static
|
|---|
| 2032 | )
|
|---|
| 2033 | break;
|
|---|
| 2034 | // else: go for next then
|
|---|
| 2035 | }
|
|---|
| 2036 | }
|
|---|
| 2037 | }
|
|---|
| 2038 |
|
|---|
| 2039 | if (pNode)
|
|---|
| 2040 | {
|
|---|
| 2041 | WinSetFocus(HWND_DESKTOP,
|
|---|
| 2042 | (HWND)pNode->pItemData);
|
|---|
| 2043 | }
|
|---|
| 2044 | }
|
|---|
| 2045 |
|
|---|
| 2046 | /*
|
|---|
| 2047 | *@@ dlghSetNextFocus:
|
|---|
| 2048 | * "forward" function for rotating the focus
|
|---|
| 2049 | * in a dialog when the "ab" key gets pressed.
|
|---|
| 2050 | *
|
|---|
| 2051 | * pllWindows must be a linked list with the
|
|---|
| 2052 | * plain HWND window handles of the focussable
|
|---|
| 2053 | * controls in the dialog.
|
|---|
| 2054 | */
|
|---|
| 2055 |
|
|---|
| 2056 | VOID dlghSetNextFocus(PVOID pvllWindows)
|
|---|
| 2057 | {
|
|---|
| 2058 | PLINKLIST pllWindows = (PLINKLIST)pvllWindows;
|
|---|
| 2059 |
|
|---|
| 2060 | // check current focus
|
|---|
| 2061 | HWND hwndFocus = WinQueryFocus(HWND_DESKTOP);
|
|---|
| 2062 |
|
|---|
| 2063 | PLISTNODE pNode = lstNodeFromItem(pllWindows, (PVOID)hwndFocus);
|
|---|
| 2064 |
|
|---|
| 2065 | BOOL fRestart = FALSE;
|
|---|
| 2066 |
|
|---|
| 2067 | while (pNode)
|
|---|
| 2068 | {
|
|---|
| 2069 | CHAR szClass[100];
|
|---|
| 2070 |
|
|---|
| 2071 | // next focus in node
|
|---|
| 2072 | pNode = pNode->pNext;
|
|---|
| 2073 |
|
|---|
| 2074 | if ( (!pNode) // no next, or not found:
|
|---|
| 2075 | && (!fRestart) // avoid infinite looping if bad list
|
|---|
| 2076 | )
|
|---|
| 2077 | {
|
|---|
| 2078 | pNode = lstQueryFirstNode(pllWindows);
|
|---|
| 2079 | fRestart = TRUE;
|
|---|
| 2080 | }
|
|---|
| 2081 |
|
|---|
| 2082 | if (pNode)
|
|---|
| 2083 | {
|
|---|
| 2084 | // check if this is a focusable control
|
|---|
| 2085 | if (WinQueryClassName((HWND)pNode->pItemData,
|
|---|
| 2086 | sizeof(szClass),
|
|---|
| 2087 | szClass))
|
|---|
| 2088 | {
|
|---|
| 2089 | if ( (strcmp(szClass, "#5")) // not static
|
|---|
| 2090 | )
|
|---|
| 2091 | break;
|
|---|
| 2092 | // else: go for next then
|
|---|
| 2093 | }
|
|---|
| 2094 | }
|
|---|
| 2095 | }
|
|---|
| 2096 |
|
|---|
| 2097 | if (pNode)
|
|---|
| 2098 | {
|
|---|
| 2099 | WinSetFocus(HWND_DESKTOP,
|
|---|
| 2100 | (HWND)pNode->pItemData);
|
|---|
| 2101 | }
|
|---|
| 2102 | }
|
|---|
| 2103 |
|
|---|
| 2104 | /*
|
|---|
| 2105 | *@@ MatchMnemonic:
|
|---|
| 2106 | * returns TRUE if the specified control matches
|
|---|
| 2107 | *
|
|---|
| 2108 | *
|
|---|
| 2109 | *@@added V0.9.9 (2001-03-17) [umoeller]
|
|---|
| 2110 | */
|
|---|
| 2111 |
|
|---|
| 2112 | /*
|
|---|
| 2113 | *@@ dlghProcessMnemonic:
|
|---|
| 2114 | * finds the control which matches usch
|
|---|
| 2115 | * and gives it the focus. If this is a
|
|---|
| 2116 | * static control, the next control in the
|
|---|
| 2117 | * list is given focus instead. (Standard
|
|---|
| 2118 | * dialog behavior.)
|
|---|
| 2119 | *
|
|---|
| 2120 | * Pass in usch from WM_CHAR. It is assumed
|
|---|
| 2121 | * that the caller has already tested for
|
|---|
| 2122 | * the "alt" key to be depressed.
|
|---|
| 2123 | *
|
|---|
| 2124 | *@@added V0.9.9 (2001-03-17) [umoeller]
|
|---|
| 2125 | */
|
|---|
| 2126 |
|
|---|
| 2127 | HWND dlghProcessMnemonic(PVOID pvllWindows,
|
|---|
| 2128 | USHORT usch)
|
|---|
| 2129 | {
|
|---|
| 2130 | PLINKLIST pllWindows = (PLINKLIST)pvllWindows;
|
|---|
| 2131 |
|
|---|
| 2132 | HWND hwndFound = NULLHANDLE;
|
|---|
| 2133 | PLISTNODE pNode = lstQueryFirstNode(pllWindows);
|
|---|
| 2134 | CHAR szClass[100];
|
|---|
| 2135 |
|
|---|
| 2136 | while (pNode)
|
|---|
| 2137 | {
|
|---|
| 2138 | HWND hwnd = (HWND)pNode->pItemData;
|
|---|
| 2139 |
|
|---|
| 2140 | if (WinSendMsg(hwnd,
|
|---|
| 2141 | WM_MATCHMNEMONIC,
|
|---|
| 2142 | (MPARAM)usch,
|
|---|
| 2143 | 0))
|
|---|
| 2144 | {
|
|---|
| 2145 | // according to the docs, only buttons and static
|
|---|
| 2146 | // return TRUE to that msg;
|
|---|
| 2147 | // if this is a static, give focus to the next
|
|---|
| 2148 | // control
|
|---|
| 2149 |
|
|---|
| 2150 | // _Pmpf((__FUNCTION__ ": hwnd 0x%lX", hwnd));
|
|---|
| 2151 |
|
|---|
| 2152 | // check if this is a focusable control
|
|---|
| 2153 | if (WinQueryClassName(hwnd,
|
|---|
| 2154 | sizeof(szClass),
|
|---|
| 2155 | szClass))
|
|---|
| 2156 | {
|
|---|
| 2157 | if (!strcmp(szClass, "#3"))
|
|---|
| 2158 | // it's a button: click it
|
|---|
| 2159 | WinSendMsg(hwnd, BM_CLICK, (MPARAM)TRUE, 0);
|
|---|
| 2160 | else if (!strcmp(szClass, "#5"))
|
|---|
| 2161 | {
|
|---|
| 2162 | // it's a static: give focus to following control
|
|---|
| 2163 | pNode = pNode->pNext;
|
|---|
| 2164 | if (pNode)
|
|---|
| 2165 | WinSetFocus(HWND_DESKTOP, (HWND)pNode->pItemData);
|
|---|
| 2166 | }
|
|---|
| 2167 | }
|
|---|
| 2168 | else
|
|---|
| 2169 | // any other control (are there any?): give them focus
|
|---|
| 2170 | WinSetFocus(HWND_DESKTOP, hwnd);
|
|---|
| 2171 |
|
|---|
| 2172 | // in any case, stop
|
|---|
| 2173 | hwndFound = hwnd;
|
|---|
| 2174 | break;
|
|---|
| 2175 | }
|
|---|
| 2176 |
|
|---|
| 2177 | pNode = pNode->pNext;
|
|---|
| 2178 | }
|
|---|
| 2179 |
|
|---|
| 2180 | return (hwndFound);
|
|---|
| 2181 | }
|
|---|
| 2182 |
|
|---|
| 2183 | /*
|
|---|
| 2184 | *@@ dlghEnter:
|
|---|
| 2185 | * presses the first button with BS_DEFAULT.
|
|---|
| 2186 | */
|
|---|
| 2187 |
|
|---|
| 2188 | BOOL dlghEnter(PVOID pvllWindows)
|
|---|
| 2189 | {
|
|---|
| 2190 | PLINKLIST pllWindows = (PLINKLIST)pvllWindows;
|
|---|
| 2191 |
|
|---|
| 2192 | PLISTNODE pNode = lstQueryFirstNode(pllWindows);
|
|---|
| 2193 | CHAR szClass[100];
|
|---|
| 2194 | while (pNode)
|
|---|
| 2195 | {
|
|---|
| 2196 | HWND hwnd = (HWND)pNode->pItemData;
|
|---|
| 2197 | if (WinQueryClassName(hwnd,
|
|---|
| 2198 | sizeof(szClass),
|
|---|
| 2199 | szClass))
|
|---|
| 2200 | {
|
|---|
| 2201 | if (!strcmp(szClass, "#3")) // button
|
|---|
| 2202 | {
|
|---|
| 2203 | // _Pmpf((__FUNCTION__ ": found button"));
|
|---|
| 2204 | if ( (WinQueryWindowULong(hwnd, QWL_STYLE) & (BS_PUSHBUTTON | BS_DEFAULT))
|
|---|
| 2205 | == (BS_PUSHBUTTON | BS_DEFAULT)
|
|---|
| 2206 | )
|
|---|
| 2207 | {
|
|---|
| 2208 | // _Pmpf((" is default!"));
|
|---|
| 2209 | WinPostMsg(hwnd,
|
|---|
| 2210 | BM_CLICK,
|
|---|
| 2211 | (MPARAM)TRUE, // upclick
|
|---|
| 2212 | 0);
|
|---|
| 2213 | return (TRUE);
|
|---|
| 2214 | }
|
|---|
| 2215 | }
|
|---|
| 2216 | }
|
|---|
| 2217 |
|
|---|
| 2218 | pNode = pNode->pNext;
|
|---|
| 2219 | }
|
|---|
| 2220 |
|
|---|
| 2221 | return (FALSE);
|
|---|
| 2222 | }
|
|---|
| 2223 |
|
|---|
| 2224 |
|
|---|