[232] | 1 |
|
---|
| 2 | /*
|
---|
| 3 | *@@sourcefile cctl_toolbar.c:
|
---|
| 4 | * implementation for the "tool bar" common control.
|
---|
| 5 | * See ctlCreateToolBar and ctl_fnwpToolbar.
|
---|
| 6 | *
|
---|
| 7 | * See comctl.c for an overview of the common controls.
|
---|
| 8 | *
|
---|
| 9 | * This file implements two window classes: a tool bar
|
---|
| 10 | * control (which is most conveniently used with
|
---|
| 11 | * ctlCreateStdWindow) and a tool button control as
|
---|
| 12 | * a replacement for the dull OS/2 pushbutton controls.
|
---|
| 13 | *
|
---|
| 14 | * This is new with V1.0.1 (2002-11-30) [umoeller].
|
---|
| 15 | *
|
---|
| 16 | * Note: Version numbering in this file relates to XWorkplace version
|
---|
| 17 | * numbering.
|
---|
| 18 | *
|
---|
| 19 | *@@header "helpers\comctl.h"
|
---|
| 20 | *@@added V1.0.1 (2002-11-30) [umoeller]
|
---|
| 21 | */
|
---|
| 22 |
|
---|
| 23 | /*
|
---|
| 24 | * Copyright (C) 1997-2002 Ulrich Mller.
|
---|
| 25 | * This file is part of the "XWorkplace helpers" source package.
|
---|
| 26 | * This is free software; you can redistribute it and/or modify
|
---|
| 27 | * it under the terms of the GNU General Public License as published
|
---|
| 28 | * by the Free Software Foundation, in version 2 as it comes in the
|
---|
| 29 | * "COPYING" file of the XWorkplace main distribution.
|
---|
| 30 | * This program is distributed in the hope that it will be useful,
|
---|
| 31 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 32 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 33 | * GNU General Public License for more details.
|
---|
| 34 | */
|
---|
| 35 |
|
---|
| 36 | #define OS2EMX_PLAIN_CHAR
|
---|
| 37 | // this is needed for "os2emx.h"; if this is defined,
|
---|
| 38 | // emx will define PSZ as _signed_ char, otherwise
|
---|
| 39 | // as unsigned char
|
---|
| 40 |
|
---|
| 41 | #define INCL_WINWINDOWMGR
|
---|
| 42 | #define INCL_WINFRAMEMGR
|
---|
| 43 | #define INCL_WINSYS
|
---|
| 44 | #define INCL_WINPOINTERS
|
---|
| 45 | #define INCL_WININPUT
|
---|
| 46 | #define INCL_WINBUTTONS
|
---|
| 47 |
|
---|
| 48 | #define INCL_GPIPRIMITIVES
|
---|
| 49 | #define INCL_GPILOGCOLORTABLE
|
---|
| 50 | #define INCL_GPIBITMAPS
|
---|
| 51 | #define INCL_GPIPATHS
|
---|
| 52 | #define INCL_GPIREGIONS
|
---|
| 53 | #define INCL_GPIBITMAPS
|
---|
| 54 | #include <os2.h>
|
---|
| 55 |
|
---|
| 56 | #include <stdlib.h>
|
---|
| 57 | #include <stdio.h>
|
---|
| 58 | #include <string.h>
|
---|
| 59 | #include <setjmp.h> // needed for except.h
|
---|
| 60 | #include <assert.h> // needed for except.h
|
---|
| 61 |
|
---|
| 62 | #include "setup.h" // code generation and debugging options
|
---|
| 63 |
|
---|
| 64 | #include "helpers\gpih.h"
|
---|
| 65 | #include "helpers\linklist.h"
|
---|
| 66 | #include "helpers\standards.h"
|
---|
[233] | 67 | #include "helpers\stringh.h"
|
---|
[232] | 68 | #include "helpers\winh.h"
|
---|
[233] | 69 | #include "helpers\xstring.h"
|
---|
[232] | 70 |
|
---|
| 71 | #include "helpers\comctl.h"
|
---|
| 72 |
|
---|
| 73 | #pragma hdrstop
|
---|
| 74 |
|
---|
| 75 | /*
|
---|
| 76 | *@@category: Helpers\PM helpers\Window classes\Toolbars
|
---|
| 77 | * See cctl_toolbar.c.
|
---|
| 78 | */
|
---|
| 79 |
|
---|
| 80 | /* ******************************************************************
|
---|
| 81 | *
|
---|
| 82 | * Private definitions
|
---|
| 83 | *
|
---|
| 84 | ********************************************************************/
|
---|
| 85 |
|
---|
| 86 | /*
|
---|
| 87 | *@@ TBBUTTONDATA:
|
---|
| 88 | *
|
---|
| 89 | */
|
---|
| 90 |
|
---|
| 91 | typedef struct _TBBUTTONDATA
|
---|
| 92 | {
|
---|
| 93 | XBUTTONDATA bd;
|
---|
| 94 | XBUTTONSTATE bs;
|
---|
| 95 | } TBBUTTONDATA, *PTBBUTTONDATA;
|
---|
| 96 |
|
---|
| 97 | /*
|
---|
| 98 | *@@ TOOLBARDATA:
|
---|
| 99 | *
|
---|
| 100 | */
|
---|
| 101 |
|
---|
| 102 | typedef struct _TOOLBARDATA
|
---|
| 103 | {
|
---|
| 104 | DEFWINDATA dwd;
|
---|
| 105 |
|
---|
[233] | 106 | HWND hwndControlsOwner,
|
---|
| 107 | hwndToolTip; // != NULLHANDLE if TBS_TOOLTIPS is set
|
---|
[232] | 108 |
|
---|
| 109 | LONG lSpacing,
|
---|
| 110 | lMaxControlCY;
|
---|
| 111 |
|
---|
| 112 | LINKLIST llControls; // linked list of HWNDs for controls in toolbar
|
---|
| 113 |
|
---|
| 114 | ULONG flReformat;
|
---|
| 115 | #define RFFL_HEIGHT 0x0001 // height changed, needs complete resize
|
---|
| 116 |
|
---|
[233] | 117 | XSTRING strToolTipBuf;
|
---|
| 118 |
|
---|
[232] | 119 | } TOOLBARDATA, *PTOOLBARDATA;
|
---|
| 120 |
|
---|
| 121 | #define TB_LEFT_SPACING 5
|
---|
| 122 | #define TB_BOTTOM_SPACING 5
|
---|
| 123 |
|
---|
| 124 | #define TBB_BORDER 2
|
---|
| 125 |
|
---|
| 126 | #define TBB_TEXTSPACING 2
|
---|
| 127 |
|
---|
| 128 | /* ******************************************************************
|
---|
| 129 | *
|
---|
| 130 | * "Toolbar button" control
|
---|
| 131 | *
|
---|
| 132 | ********************************************************************/
|
---|
| 133 |
|
---|
| 134 | /*
|
---|
| 135 | *@@ ctlInitXButtonData:
|
---|
| 136 | *
|
---|
| 137 | */
|
---|
| 138 |
|
---|
| 139 | VOID ctlInitXButtonData(PXBUTTONDATA pbd, // in: button data
|
---|
| 140 | ULONG fl) // in: TBBS_* style flags
|
---|
| 141 | {
|
---|
| 142 | if (fl & TBBS_BIGICON)
|
---|
| 143 | {
|
---|
| 144 | pbd->szlIconOrBitmap.cx = G_cxIcon;
|
---|
| 145 | pbd->szlIconOrBitmap.cy = G_cyIcon;
|
---|
| 146 | }
|
---|
| 147 | else if (fl & TBBS_MINIICON)
|
---|
| 148 | {
|
---|
| 149 | pbd->szlIconOrBitmap.cx = G_cxIcon / 2;
|
---|
| 150 | pbd->szlIconOrBitmap.cy = G_cyIcon / 2;
|
---|
| 151 | }
|
---|
| 152 | else if ( (fl & TBBS_BITMAP)
|
---|
| 153 | && (pbd->hptr)
|
---|
| 154 | )
|
---|
| 155 | {
|
---|
| 156 | BITMAPINFOHEADER2 bmih2;
|
---|
| 157 | bmih2.cbFix = sizeof(BITMAPINFOHEADER2);
|
---|
| 158 | GpiQueryBitmapInfoHeader(pbd->hptr,
|
---|
| 159 | &bmih2);
|
---|
| 160 | pbd->szlIconOrBitmap.cx = bmih2.cx;
|
---|
| 161 | pbd->szlIconOrBitmap.cy = bmih2.cy;
|
---|
| 162 | }
|
---|
| 163 | }
|
---|
| 164 |
|
---|
| 165 | /*
|
---|
| 166 | *@@ ctlPaintTBButton:
|
---|
| 167 | * paints a tool bar button control. Can be called externally
|
---|
| 168 | * for just painting a button even if this is not really
|
---|
| 169 | * a window.
|
---|
| 170 | *
|
---|
| 171 | *@@added V0.9.13 (2001-06-21) [umoeller]
|
---|
| 172 | *@@changed V0.9.16 (2001-10-24) [umoeller]: fixed wrong hatch color and paint offset
|
---|
| 173 | *@@changed V0.9.16 (2001-10-28) [umoeller]: added bitmap support, fixed bad clip rectangle
|
---|
| 174 | *@@changed V0.9.20 (2002-08-04) [umoeller]: fixed button offset, depressed color
|
---|
| 175 | *@@changed V1.0.1 (2002-11-30) [umoeller]: moved this here from comctl.c, renamed
|
---|
[233] | 176 | *@@changed V1.0.1 (2002-12-08) [umoeller]: added support for WS_DISABLED
|
---|
[232] | 177 | */
|
---|
| 178 |
|
---|
| 179 | VOID ctlPaintTBButton(HPS hps, // in: presentation space (RGB mode)
|
---|
| 180 | ULONG fl, // in: TBBS_* flags
|
---|
| 181 | PXBUTTONDATA pbd, // in: button data
|
---|
| 182 | PXBUTTONSTATE pbs) // in: button state
|
---|
| 183 | {
|
---|
| 184 | LONG lBorder = 0,
|
---|
| 185 | lOfs = 0;
|
---|
| 186 | LONG lLeft,
|
---|
| 187 | lRight,
|
---|
[243] | 188 | lColorMiddle = ctlQueryColor(&pbd->dwd, CTLCOL_BGND); // pbd->dwd.lcolBackground;
|
---|
[232] | 189 | RECTL rclWin,
|
---|
| 190 | rclTemp;
|
---|
| 191 | POINTL ptl;
|
---|
| 192 |
|
---|
| 193 | rclWin.xLeft = 0;
|
---|
| 194 | rclWin.yBottom = 0;
|
---|
| 195 | rclWin.xRight = pbd->dwd.szlWin.cx;
|
---|
| 196 | rclWin.yTop = pbd->dwd.szlWin.cy;
|
---|
| 197 | // make backup for later
|
---|
| 198 | memcpy(&rclTemp, &rclWin, sizeof(RECTL));
|
---|
| 199 |
|
---|
| 200 | if (!(fl & TBBS_FLAT))
|
---|
| 201 | lBorder = TBB_BORDER;
|
---|
| 202 |
|
---|
| 203 | gpihSwitchToRGB(hps);
|
---|
| 204 |
|
---|
| 205 | if (pbs->fPaintButtonSunk)
|
---|
| 206 | {
|
---|
| 207 | // paint button "down":
|
---|
| 208 | lLeft = G_lcol3DDark;
|
---|
| 209 | lRight = G_lcol3DLight;
|
---|
| 210 | // add offset for icon painting at the bottom
|
---|
| 211 | lOfs += 1;
|
---|
| 212 | if (!lBorder)
|
---|
| 213 | lBorder = 1;
|
---|
| 214 | }
|
---|
| 215 | else
|
---|
| 216 | {
|
---|
| 217 | lLeft = G_lcol3DLight;
|
---|
| 218 | lRight = G_lcol3DDark;
|
---|
| 219 |
|
---|
[233] | 220 | if ( (!lBorder)
|
---|
| 221 | && (pbs->fMouseOver)
|
---|
| 222 | && (fl & TBBS_HILITE)
|
---|
| 223 | )
|
---|
| 224 | lBorder = 1;
|
---|
[232] | 225 | }
|
---|
| 226 |
|
---|
| 227 | if (lBorder)
|
---|
| 228 | {
|
---|
| 229 | // paint button border
|
---|
| 230 | // make rcl inclusive
|
---|
| 231 | rclWin.xRight--;
|
---|
| 232 | rclWin.yTop--;
|
---|
| 233 | gpihDraw3DFrame2(hps,
|
---|
| 234 | &rclWin, // inclusive
|
---|
| 235 | lBorder,
|
---|
| 236 | lLeft,
|
---|
| 237 | lRight);
|
---|
| 238 | rclWin.xRight++;
|
---|
| 239 | rclWin.yTop++;
|
---|
| 240 | }
|
---|
| 241 |
|
---|
| 242 | if (fl & TBBS_BACKGROUND)
|
---|
| 243 | {
|
---|
| 244 | // now paint button middle
|
---|
| 245 | if (pbs->fPaintButtonSunk)
|
---|
| 246 | // make the depressed color darker
|
---|
| 247 | gpihManipulateRGB(&lColorMiddle,
|
---|
| 248 | .95);
|
---|
| 249 | else if ((fl & TBBS_HILITE) && (pbs->fMouseOver))
|
---|
| 250 | // make the mouse over color lighter
|
---|
| 251 | gpihManipulateRGB(&lColorMiddle,
|
---|
| 252 | 1.05);
|
---|
| 253 |
|
---|
| 254 | WinFillRect(hps,
|
---|
| 255 | &rclWin, // exclusive
|
---|
| 256 | lColorMiddle);
|
---|
| 257 | }
|
---|
| 258 |
|
---|
| 259 | // calc x and y so that icon is centered in rectangle
|
---|
| 260 | ptl.x = ((pbd->dwd.szlWin.cx - pbd->szlIconOrBitmap.cx) / 2);
|
---|
| 261 | // center vertically only if we have no text
|
---|
| 262 | if (fl & TBBS_TEXT)
|
---|
| 263 | ptl.y = pbd->dwd.szlWin.cy - pbd->szlIconOrBitmap.cy - 2;
|
---|
| 264 | else
|
---|
| 265 | ptl.y = ((pbd->dwd.szlWin.cy - pbd->szlIconOrBitmap.cy) / 2);
|
---|
| 266 |
|
---|
| 267 | if (fl & TBBS_INUSE)
|
---|
| 268 | {
|
---|
| 269 | // caller wants in-use (hatched) emphasis:
|
---|
| 270 | // draw a box then
|
---|
| 271 | POINTL ptl2;
|
---|
| 272 | ptl2.x = ptl.x - 2;
|
---|
| 273 | ptl2.y = ptl.y - 2;
|
---|
| 274 | GpiMove(hps,
|
---|
| 275 | &ptl2); // &ptl
|
---|
| 276 | // duh, typo V0.9.16 (2001-10-24) [umoeller]
|
---|
| 277 | GpiSetPattern(hps, PATSYM_DIAG1);
|
---|
| 278 | GpiSetColor(hps, RGBCOL_BLACK); // V0.9.16 (2001-10-24) [umoeller]
|
---|
| 279 | ptl2.x = ptl.x + pbd->szlIconOrBitmap.cx + 1; // inclusive!
|
---|
| 280 | ptl2.y = ptl.y + pbd->szlIconOrBitmap.cy + 1; // inclusive!
|
---|
| 281 | GpiBox(hps,
|
---|
| 282 | DRO_FILL,
|
---|
| 283 | &ptl2,
|
---|
| 284 | 0,
|
---|
| 285 | 0);
|
---|
| 286 | }
|
---|
| 287 |
|
---|
| 288 | // make rcl inclusive
|
---|
| 289 | rclWin.xRight--;
|
---|
| 290 | rclWin.yTop--;
|
---|
| 291 | GpiIntersectClipRectangle(hps,
|
---|
| 292 | &rclWin); // inclusive!
|
---|
| 293 |
|
---|
| 294 | if ( (pbd->hptr)
|
---|
| 295 | && (fl & (TBBS_BIGICON | TBBS_MINIICON | TBBS_BITMAP))
|
---|
| 296 | )
|
---|
| 297 | {
|
---|
| 298 | // RECTL rcl3;
|
---|
| 299 |
|
---|
| 300 | // now paint icon
|
---|
| 301 | ptl.x += lOfs;
|
---|
| 302 | ptl.y -= lOfs;
|
---|
| 303 |
|
---|
| 304 | /*
|
---|
| 305 | rcl3.xLeft = ptl.x;
|
---|
| 306 | rcl3.yBottom = ptl.y;
|
---|
| 307 | rcl3.xRight = ptl.x + pbd->szlIconOrBitmap.cx;
|
---|
| 308 | rcl3.yTop = ptl.y + pbd->szlIconOrBitmap.cy;
|
---|
| 309 | WinFillRect(hps, &rcl3, RGBCOL_GREEN);
|
---|
| 310 | */
|
---|
| 311 |
|
---|
| 312 | if (fl & TBBS_BITMAP)
|
---|
| 313 | // V0.9.16 (2001-10-28) [umoeller]
|
---|
| 314 | WinDrawBitmap(hps,
|
---|
| 315 | pbd->hptr, // a bitmap really
|
---|
| 316 | NULL, // entire bitmap
|
---|
| 317 | &ptl,
|
---|
| 318 | 0,
|
---|
| 319 | 0,
|
---|
[233] | 320 | (fl & WS_DISABLED)
|
---|
| 321 | ? DBM_HALFTONE
|
---|
| 322 | : DBM_NORMAL);
|
---|
[232] | 323 | else
|
---|
[233] | 324 | {
|
---|
| 325 | ULONG fl2 = DP_NORMAL; // 0x0000
|
---|
| 326 |
|
---|
| 327 | if (!(fl & TBBS_BIGICON))
|
---|
| 328 | fl2 = DP_MINI;
|
---|
| 329 | if (fl & WS_DISABLED) // V1.0.1 (2002-12-08) [umoeller]
|
---|
| 330 | fl2 |= DP_HALFTONED; // I love this... DBM_HALFTONE, but DP_HALFTONED!
|
---|
| 331 | // PM is just so half-toned itself...
|
---|
[232] | 332 | WinDrawPointer(hps,
|
---|
| 333 | ptl.x,
|
---|
| 334 | ptl.y,
|
---|
| 335 | pbd->hptr,
|
---|
[233] | 336 | fl2);
|
---|
| 337 | }
|
---|
[232] | 338 |
|
---|
| 339 | rclTemp.yTop -= pbd->szlIconOrBitmap.cy;
|
---|
| 340 | }
|
---|
| 341 |
|
---|
| 342 | if ( (pbd->dwd.pszText)
|
---|
| 343 | && (fl & TBBS_TEXT)
|
---|
| 344 | )
|
---|
| 345 | {
|
---|
[243] | 346 | GpiSetColor(hps,
|
---|
| 347 | ctlQueryColor(&pbd->dwd, CTLCOL_FGND)); // pbd->dwd.lcolForeground);
|
---|
[232] | 348 | rclTemp.yTop -= 2 * TBB_TEXTSPACING + lOfs;
|
---|
| 349 | rclTemp.xRight += 2 * lOfs; // twice the offset because we center horizontally
|
---|
| 350 | winhDrawFormattedText(hps,
|
---|
| 351 | &rclTemp,
|
---|
| 352 | pbd->dwd.pszText,
|
---|
| 353 | DT_CENTER | DT_TOP | DT_MNEMONIC | DT_WORDBREAK);
|
---|
| 354 | }
|
---|
| 355 | }
|
---|
| 356 |
|
---|
[243] | 357 | /* static const SYSCOLORSET G_scsToolbarButton =
|
---|
[232] | 358 | {
|
---|
| 359 | TRUE, // inherit presparams
|
---|
[242] | 360 |
|
---|
[232] | 361 | SYSCLR_BUTTONMIDDLE,
|
---|
| 362 | SYSCLR_MENUTEXT
|
---|
| 363 | };
|
---|
[243] | 364 | */
|
---|
[232] | 365 |
|
---|
[243] | 366 | static const CCTLCOLOR G_scsToolbarButton[] =
|
---|
| 367 | {
|
---|
| 368 | TRUE, PP_BACKGROUNDCOLOR, SYSCLR_BUTTONMIDDLE,
|
---|
| 369 | TRUE, PP_FOREGROUNDCOLOR, SYSCLR_MENUTEXT,
|
---|
| 370 | };
|
---|
| 371 |
|
---|
[232] | 372 | /*
|
---|
| 373 | *@@ BtnAutoSize:
|
---|
| 374 | *
|
---|
| 375 | */
|
---|
| 376 |
|
---|
| 377 | STATIC VOID BtnAutoSize(ULONG flStyle,
|
---|
| 378 | PTBBUTTONDATA pData)
|
---|
| 379 | {
|
---|
| 380 | if (flStyle & TBBS_AUTORESIZE)
|
---|
| 381 | {
|
---|
| 382 | HPS hps;
|
---|
| 383 | if (hps = WinGetPS(pData->bd.dwd.hwnd))
|
---|
| 384 | {
|
---|
| 385 | ULONG ulBorder = 2;
|
---|
| 386 | if (!(flStyle & TBBS_FLAT))
|
---|
| 387 | ulBorder += TBB_BORDER;
|
---|
| 388 |
|
---|
| 389 | pData->bd.dwd.szlWin.cx
|
---|
| 390 | = pData->bd.dwd.szlWin.cy
|
---|
| 391 | = 2 * ulBorder;
|
---|
| 392 |
|
---|
| 393 | if (flStyle & (TBBS_BIGICON | TBBS_MINIICON | TBBS_BITMAP))
|
---|
| 394 | {
|
---|
| 395 | pData->bd.dwd.szlWin.cx += pData->bd.szlIconOrBitmap.cx;
|
---|
| 396 | pData->bd.dwd.szlWin.cy += pData->bd.szlIconOrBitmap.cy;
|
---|
| 397 |
|
---|
| 398 | if (flStyle & TBBS_TEXT)
|
---|
| 399 | pData->bd.dwd.szlWin.cx += 2 * TBB_TEXTSPACING;
|
---|
| 400 | }
|
---|
| 401 |
|
---|
| 402 | if (flStyle & TBBS_TEXT)
|
---|
| 403 | {
|
---|
| 404 | RECTL rcl = { 0, 0, 100, 100 };
|
---|
| 405 | LONG lMinX;
|
---|
| 406 | winhDrawFormattedText(hps,
|
---|
| 407 | &rcl,
|
---|
| 408 | pData->bd.dwd.pszText,
|
---|
| 409 | DT_TOP | DT_LEFT | DT_QUERYEXTENT);
|
---|
| 410 |
|
---|
| 411 | lMinX = (rcl.xRight - rcl.xLeft) + 2 * TBB_TEXTSPACING;
|
---|
| 412 | STOREIFMAX(lMinX, pData->bd.dwd.szlWin.cx);
|
---|
| 413 | // pData->bd.dwd.rcl.xRight += (rcl.xRight - rcl.xLeft) + 2 * TBB_TEXTSPACING;
|
---|
| 414 | pData->bd.dwd.szlWin.cy += (rcl.yTop - rcl.yBottom) + 2 * TBB_TEXTSPACING;
|
---|
| 415 | }
|
---|
| 416 |
|
---|
| 417 | WinSetWindowPos(pData->bd.dwd.hwnd,
|
---|
| 418 | 0,
|
---|
| 419 | 0,
|
---|
| 420 | 0,
|
---|
| 421 | pData->bd.dwd.szlWin.cx,
|
---|
| 422 | pData->bd.dwd.szlWin.cy,
|
---|
| 423 | SWP_SIZE | SWP_NOADJUST);
|
---|
| 424 |
|
---|
| 425 | WinReleasePS(hps);
|
---|
| 426 | }
|
---|
| 427 | }
|
---|
| 428 | }
|
---|
| 429 |
|
---|
| 430 | /*
|
---|
| 431 | *@@ BtnCreate:
|
---|
| 432 | * implementation for WM_CREATE in ctl_fnwpToolbarButton.
|
---|
| 433 | */
|
---|
| 434 |
|
---|
| 435 | STATIC MRESULT BtnCreate(HWND hwndButton, MPARAM mp1, MPARAM mp2)
|
---|
| 436 | {
|
---|
| 437 | PTBBUTTONDATA pData;
|
---|
| 438 | MRESULT mrc = 0;
|
---|
| 439 |
|
---|
| 440 | if (!(pData = NEW(TBBUTTONDATA)))
|
---|
| 441 | mrc = (MRESULT)TRUE; // stop window creation
|
---|
| 442 | else
|
---|
| 443 | {
|
---|
| 444 | PCSZ pcszText = ((PCREATESTRUCT)mp2)->pszText;
|
---|
| 445 | PSZ p;
|
---|
| 446 |
|
---|
| 447 | WinSetWindowPtr(hwndButton, QWL_USER + 1, pData);
|
---|
| 448 | ZERO(pData);
|
---|
| 449 |
|
---|
| 450 | // initialize DEFWINDOWDATA
|
---|
| 451 | ctlInitDWD(hwndButton,
|
---|
| 452 | mp2,
|
---|
| 453 | &pData->bd.dwd,
|
---|
| 454 | WinDefWindowProc,
|
---|
[243] | 455 | 0,
|
---|
| 456 | G_scsToolbarButton,
|
---|
| 457 | ARRAYITEMCOUNT(G_scsToolbarButton));
|
---|
[232] | 458 |
|
---|
| 459 | if ( (pcszText)
|
---|
| 460 | && (*pcszText == '#')
|
---|
| 461 | )
|
---|
| 462 | {
|
---|
| 463 | pData->bd.hptr = atoi(pcszText + 1);
|
---|
| 464 | if (p = strchr(pcszText + 1, '#'))
|
---|
| 465 | pcszText = p + 1;
|
---|
| 466 | else
|
---|
| 467 | pcszText = NULL;
|
---|
| 468 | }
|
---|
| 469 |
|
---|
| 470 | ctlInitXButtonData(&pData->bd,
|
---|
| 471 | ((PCREATESTRUCT)mp2)->flStyle);
|
---|
| 472 |
|
---|
| 473 | if (pcszText)
|
---|
| 474 | {
|
---|
| 475 | pData->bd.dwd.pszText = strdup(pcszText);
|
---|
| 476 | if ( (((PCREATESTRUCT)mp2)->flStyle & TBBS_DROPMNEMONIC)
|
---|
| 477 | && (p = strchr(pData->bd.dwd.pszText, '~'))
|
---|
| 478 | )
|
---|
| 479 | memmove(p, p + 1, strlen(p));
|
---|
| 480 | }
|
---|
| 481 |
|
---|
| 482 | BtnAutoSize(((PCREATESTRUCT)mp2)->flStyle,
|
---|
| 483 | pData);
|
---|
| 484 |
|
---|
| 485 | if ( (((PCREATESTRUCT)mp2)->flStyle & TBBS_CHECKINITIAL)
|
---|
| 486 | && (((PCREATESTRUCT)mp2)->flStyle & (TBBS_CHECK | TBBS_RADIO))
|
---|
| 487 | )
|
---|
| 488 | pData->bs.fPaintButtonSunk = TRUE;
|
---|
| 489 | }
|
---|
| 490 |
|
---|
| 491 | return mrc;
|
---|
| 492 | }
|
---|
| 493 |
|
---|
| 494 | /*
|
---|
| 495 | *@@ BtnButton1Down:
|
---|
| 496 | * implementation for WM_BUTTON1DOWN in ctl_fnwpToolbarButton.
|
---|
| 497 | */
|
---|
| 498 |
|
---|
| 499 | STATIC MRESULT BtnButton1Down(HWND hwndButton)
|
---|
| 500 | {
|
---|
| 501 | PTBBUTTONDATA pData;
|
---|
| 502 | if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
|
---|
| 503 | {
|
---|
| 504 | ULONG flStyle = winhQueryWindowStyle(hwndButton);
|
---|
| 505 |
|
---|
| 506 | if (flStyle & WS_DISABLED)
|
---|
| 507 | WinAlarm(HWND_DESKTOP, WA_WARNING);
|
---|
| 508 | else
|
---|
| 509 | {
|
---|
| 510 | WinSetFocus(HWND_DESKTOP, hwndButton);
|
---|
| 511 |
|
---|
| 512 | if (!pData->bs.fMouseCaptured)
|
---|
| 513 | {
|
---|
| 514 | // capture mouse events while the
|
---|
| 515 | // mouse button is down
|
---|
| 516 | WinSetCapture(HWND_DESKTOP, hwndButton);
|
---|
| 517 | pData->bs.fMouseCaptured = TRUE;
|
---|
| 518 | }
|
---|
| 519 |
|
---|
| 520 | if (!pData->bs.fPaintButtonSunk)
|
---|
| 521 | {
|
---|
| 522 | // toggle state is still UP (i.e. button pressed
|
---|
| 523 | // for the first time): create menu
|
---|
| 524 | pData->bs.fPaintButtonSunk = TRUE;
|
---|
| 525 | WinInvalidateRect(hwndButton, NULL, FALSE);
|
---|
| 526 |
|
---|
| 527 | if (flStyle & TBBS_CHECK)
|
---|
| 528 | // ignore the next button 1 up
|
---|
| 529 | pData->bs.fIgnoreMB1Up = TRUE;
|
---|
| 530 |
|
---|
| 531 | } // end if (!pData->fButtonSunk)
|
---|
| 532 | }
|
---|
| 533 | }
|
---|
| 534 |
|
---|
| 535 | return (MRESULT)TRUE; // processed
|
---|
| 536 | }
|
---|
| 537 |
|
---|
| 538 | /*
|
---|
| 539 | *@@ ClickNotifyOwner:
|
---|
| 540 | *
|
---|
| 541 | */
|
---|
| 542 |
|
---|
| 543 | STATIC VOID ClickNotifyOwner(HWND hwndButton)
|
---|
| 544 | {
|
---|
| 545 | HWND hwndOwner;
|
---|
| 546 |
|
---|
| 547 | if (hwndOwner = WinQueryWindow(hwndButton, QW_OWNER))
|
---|
| 548 | {
|
---|
| 549 | ULONG flStyle = winhQueryWindowStyle(hwndButton);
|
---|
| 550 |
|
---|
| 551 | if (flStyle & (TBBS_COMMAND | TBBS_SYSCOMMAND))
|
---|
| 552 | WinPostMsg(hwndOwner,
|
---|
| 553 | (flStyle & TBBS_SYSCOMMAND)
|
---|
| 554 | ? WM_SYSCOMMAND
|
---|
| 555 | : WM_COMMAND,
|
---|
| 556 | (MPARAM)WinQueryWindowUShort(hwndButton, QWS_ID),
|
---|
| 557 | MPFROM2SHORT(CMDSRC_PUSHBUTTON,
|
---|
| 558 | TRUE)); // pointer, not keyboard
|
---|
| 559 | else
|
---|
| 560 | ctlSendWmControl(hwndButton,
|
---|
| 561 | BN_CLICKED,
|
---|
| 562 | (MPARAM)hwndButton);
|
---|
| 563 | }
|
---|
| 564 | }
|
---|
| 565 |
|
---|
| 566 | /*
|
---|
| 567 | *@@ BtnButton1Up:
|
---|
| 568 | * implementation for WM_BUTTON1UP in ctl_fnwpToolbarButton.
|
---|
| 569 | */
|
---|
| 570 |
|
---|
| 571 | STATIC MRESULT BtnButton1Up(HWND hwndButton)
|
---|
| 572 | {
|
---|
| 573 | PTBBUTTONDATA pData;
|
---|
| 574 | if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
|
---|
| 575 | {
|
---|
| 576 | ULONG flStyle = winhQueryWindowStyle(hwndButton);
|
---|
| 577 |
|
---|
| 578 | if (pData->bs.fMouseCaptured)
|
---|
| 579 | {
|
---|
| 580 | WinSetCapture(HWND_DESKTOP, NULLHANDLE);
|
---|
| 581 | pData->bs.fMouseCaptured = FALSE;
|
---|
| 582 | }
|
---|
| 583 |
|
---|
| 584 | if (!(flStyle & WS_DISABLED))
|
---|
| 585 | {
|
---|
| 586 | pData->bs.fMB1Pressed = FALSE;
|
---|
| 587 |
|
---|
| 588 | if (flStyle & TBBS_CHECK)
|
---|
| 589 | {
|
---|
| 590 | if (pData->bs.fIgnoreMB1Up)
|
---|
| 591 | pData->bs.fIgnoreMB1Up = FALSE;
|
---|
| 592 | else
|
---|
| 593 | pData->bs.fPaintButtonSunk = FALSE;
|
---|
| 594 |
|
---|
| 595 | WinInvalidateRect(hwndButton, NULL, FALSE);
|
---|
| 596 |
|
---|
| 597 | ClickNotifyOwner(hwndButton);
|
---|
| 598 | }
|
---|
| 599 | else if (flStyle & TBBS_RADIO)
|
---|
| 600 | {
|
---|
| 601 | WinSendMsg(hwndButton,
|
---|
| 602 | TBBM_CHECK,
|
---|
| 603 | (MPARAM)1,
|
---|
| 604 | 0);
|
---|
| 605 |
|
---|
| 606 | ClickNotifyOwner(hwndButton);
|
---|
| 607 | }
|
---|
| 608 | else
|
---|
| 609 | {
|
---|
| 610 | pData->bs.fPaintButtonSunk = FALSE;
|
---|
| 611 |
|
---|
| 612 | ClickNotifyOwner(hwndButton);
|
---|
| 613 |
|
---|
| 614 | WinInvalidateRect(hwndButton, NULL, FALSE);
|
---|
| 615 | }
|
---|
| 616 | }
|
---|
| 617 | }
|
---|
| 618 |
|
---|
| 619 | return (MRESULT)TRUE; // processed
|
---|
| 620 | }
|
---|
| 621 |
|
---|
| 622 | #define IGNORE_CHECK_MAGIC 0x87678a1d
|
---|
| 623 |
|
---|
| 624 | /*
|
---|
| 625 | *@@ UncheckOthers:
|
---|
| 626 | * gets called twice from BtnCheck for radio buttons
|
---|
| 627 | * to uncheck the others in the group.
|
---|
| 628 | */
|
---|
| 629 |
|
---|
| 630 | STATIC VOID BtnUncheckOthers(HWND hwndButton,
|
---|
| 631 | ULONG ulQW) // in: QW_PREV or QW_NEXT
|
---|
| 632 | {
|
---|
| 633 | HWND hwnd = hwndButton;
|
---|
| 634 | CHAR szClass[50];
|
---|
| 635 |
|
---|
| 636 | while (hwnd = WinQueryWindow(hwnd, ulQW))
|
---|
| 637 | {
|
---|
| 638 | if ( (!WinQueryClassName(hwnd, sizeof(szClass), szClass)
|
---|
| 639 | || (strcmp(szClass, WC_CCTL_TBBUTTON))
|
---|
| 640 | || (!(winhQueryWindowStyle(hwnd) & TBBS_RADIO)))
|
---|
| 641 | )
|
---|
| 642 | break;
|
---|
| 643 |
|
---|
| 644 | WinSendMsg(hwnd,
|
---|
| 645 | TBBM_CHECK,
|
---|
| 646 | (MPARAM)FALSE,
|
---|
| 647 | (MPARAM)IGNORE_CHECK_MAGIC); // force uncheck without resending
|
---|
| 648 | }
|
---|
| 649 | }
|
---|
| 650 |
|
---|
| 651 | /*
|
---|
| 652 | *@@ BtnCheck:
|
---|
| 653 | * implementation for TBBM_CHECK in ctl_fnwpToolbarButton.
|
---|
| 654 | */
|
---|
| 655 |
|
---|
| 656 | STATIC VOID BtnCheck(HWND hwndButton,
|
---|
| 657 | BOOL fCheck,
|
---|
| 658 | ULONG ulMagic)
|
---|
| 659 | {
|
---|
| 660 | PTBBUTTONDATA pData;
|
---|
| 661 |
|
---|
| 662 | if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
|
---|
| 663 | {
|
---|
| 664 | ULONG flStyle = winhQueryWindowStyle(hwndButton);
|
---|
| 665 |
|
---|
| 666 | if ( (flStyle & TBBS_CHECK)
|
---|
| 667 | || (ulMagic == IGNORE_CHECK_MAGIC)
|
---|
| 668 | // magic code sent to radio tool bar buttons to
|
---|
| 669 | // force an uncheck without resending
|
---|
| 670 | )
|
---|
| 671 | {
|
---|
| 672 | pData->bs.fPaintButtonSunk = fCheck;
|
---|
| 673 | }
|
---|
| 674 | else if (flStyle & TBBS_RADIO)
|
---|
| 675 | {
|
---|
| 676 | BtnUncheckOthers(hwndButton, QW_PREV);
|
---|
| 677 | BtnUncheckOthers(hwndButton, QW_NEXT);
|
---|
| 678 |
|
---|
| 679 | pData->bs.fPaintButtonSunk = TRUE;
|
---|
| 680 | }
|
---|
| 681 |
|
---|
| 682 | WinInvalidateRect(hwndButton, NULL, FALSE);
|
---|
| 683 | }
|
---|
| 684 | }
|
---|
| 685 |
|
---|
| 686 | /*
|
---|
| 687 | *@@ ctl_fnwpToolbarButton:
|
---|
| 688 | * window proc for the tool bar button control.
|
---|
| 689 | *
|
---|
| 690 | * This control is not at all based on the ugly OS/2 button
|
---|
| 691 | * control, but a complete rewrite. This supports a large
|
---|
| 692 | * variety of TBBS_* style flags which are useful in the
|
---|
| 693 | * context of a tool bar.
|
---|
| 694 | *
|
---|
| 695 | * The following styles are supported:
|
---|
| 696 | *
|
---|
| 697 | * -- WS_DISABLED @@todo halftone the display
|
---|
| 698 | *
|
---|
| 699 | * -- optionally one of TBBS_BIGICON, TBBS_MINIICON, or
|
---|
| 700 | * TBBS_BITMAP to paint a picture in the control
|
---|
| 701 | *
|
---|
| 702 | * -- optionally TBBS_TEXT; you can use this alone or
|
---|
| 703 | * together with one of the picture styles
|
---|
| 704 | *
|
---|
| 705 | * -- TBBS_CHECK: if set, button toggles between pressed
|
---|
| 706 | * and released on every click ("checkbox" style,
|
---|
| 707 | * even though it still looks as a button).
|
---|
| 708 | *
|
---|
| 709 | * -- TBBS_RADIO: if set, the button assumes it is part of
|
---|
| 710 | * a group and behaves like a radio button, that is, it
|
---|
| 711 | * automatically unchecks its sibling buttons which have
|
---|
| 712 | * this style too.
|
---|
| 713 | *
|
---|
| 714 | * -- TBBS_AUTORESIZE: if set, the button automatically
|
---|
| 715 | * resizes itself to the space it needs when its style
|
---|
| 716 | * or text changes.
|
---|
| 717 | *
|
---|
| 718 | * -- TBBS_HILITE: if set, the button hilites when mouse
|
---|
| 719 | * moves over it.
|
---|
| 720 | *
|
---|
| 721 | * -- TBBS_FLAT: if set, the button paints a border only
|
---|
| 722 | * if the mouse is moving over it; if not set, it
|
---|
| 723 | * always has a (thicker) border.
|
---|
| 724 | *
|
---|
| 725 | * -- TBBS_COMMAND, TBBS_SYSCOMMAND: if none of these are
|
---|
| 726 | * set, the button _sends_ WM_CONTROL with the standard
|
---|
| 727 | * button code BN_CLICKED to its owner when it is
|
---|
| 728 | * pressed. If TBBS_COMMAND is set, the button _posts_
|
---|
| 729 | * WM_COMMAND instead; if TBBS_SYSCOMMAND is set, the
|
---|
| 730 | * button posts WM_SYSCOMMAND instead.
|
---|
| 731 | *
|
---|
| 732 | * Note that this is different from the standard button
|
---|
| 733 | * behavior: even a tool bar button that does not have
|
---|
| 734 | * the TBBS_CHECK or TBBS_RADIO styles will only post
|
---|
| 735 | * WM_COMMAND if the TBBS_COMMAND style is set.
|
---|
| 736 | *
|
---|
| 737 | * There are two ways to set the icon or bitmap to be
|
---|
| 738 | * displayed with the control:
|
---|
| 739 | *
|
---|
| 740 | * -- Pass it with the window title on tool bar creation in
|
---|
| 741 | * the form "#handle#text", where "handle" is the decimal
|
---|
| 742 | * HPOINTER or HBITMAP and "text" is the actual button
|
---|
| 743 | * text. Note that this only works on creation, not with
|
---|
| 744 | * WinSetWindowText after creation.
|
---|
| 745 | *
|
---|
| 746 | * -- Send a XBBM_SETHANDLE message after button creation.
|
---|
| 747 | */
|
---|
| 748 |
|
---|
| 749 | MRESULT EXPENTRY ctl_fnwpToolbarButton(HWND hwndButton, ULONG msg, MPARAM mp1, MPARAM mp2)
|
---|
| 750 | {
|
---|
| 751 | MRESULT mrc = 0;
|
---|
| 752 | PTBBUTTONDATA pData;
|
---|
| 753 |
|
---|
| 754 | switch (msg)
|
---|
| 755 | {
|
---|
| 756 | case WM_CREATE:
|
---|
| 757 | mrc = BtnCreate(hwndButton, mp1, mp2);
|
---|
| 758 | break;
|
---|
| 759 |
|
---|
| 760 | case WM_BUTTON1DOWN:
|
---|
| 761 | mrc = BtnButton1Down(hwndButton);
|
---|
| 762 | break;
|
---|
| 763 |
|
---|
| 764 | case WM_BUTTON1UP:
|
---|
| 765 | mrc = BtnButton1Up(hwndButton);
|
---|
| 766 | break;
|
---|
| 767 |
|
---|
| 768 | case WM_MOUSEENTER:
|
---|
| 769 | case WM_MOUSELEAVE:
|
---|
| 770 | if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
|
---|
| 771 | {
|
---|
| 772 | BOOL fMouseOver = (msg == WM_MOUSEENTER);
|
---|
| 773 | if (fMouseOver != pData->bs.fMouseOver)
|
---|
| 774 | {
|
---|
| 775 | pData->bs.fMouseOver = fMouseOver;
|
---|
[233] | 776 |
|
---|
| 777 | if (winhQueryWindowStyle(hwndButton) & TBBS_HILITE)
|
---|
| 778 | WinInvalidateRect(hwndButton, NULL, FALSE);
|
---|
[232] | 779 | }
|
---|
| 780 | }
|
---|
| 781 | break;
|
---|
| 782 |
|
---|
| 783 | case WM_PAINT:
|
---|
| 784 | {
|
---|
| 785 | HPS hps;
|
---|
| 786 | RECTL rcl;
|
---|
| 787 | POINTL ptl;
|
---|
| 788 | if (hps = WinBeginPaint(hwndButton, NULLHANDLE, &rcl))
|
---|
| 789 | {
|
---|
| 790 | if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
|
---|
| 791 | {
|
---|
| 792 | gpihSwitchToRGB(hps);
|
---|
| 793 | ctlPaintTBButton(hps,
|
---|
[233] | 794 | winhQueryWindowStyle(hwndButton)
|
---|
| 795 | | TBBS_BACKGROUND,
|
---|
[232] | 796 | &pData->bd,
|
---|
| 797 | &pData->bs);
|
---|
| 798 | }
|
---|
| 799 |
|
---|
| 800 | WinEndPaint(hps);
|
---|
| 801 | }
|
---|
| 802 | }
|
---|
| 803 | break;
|
---|
| 804 |
|
---|
| 805 | /*
|
---|
| 806 | *@@ TBBM_CHECK:
|
---|
| 807 | * checks the given button. Effect depends on the
|
---|
| 808 | * button style:
|
---|
| 809 | *
|
---|
| 810 | * -- With TBBS_CHECK, this sets the button check
|
---|
| 811 | * state to (BOOL)mp1.
|
---|
| 812 | *
|
---|
| 813 | * -- With TBBS_CHECKGROUP, this sets the current
|
---|
| 814 | * button check state and unchecks neighboring
|
---|
| 815 | * buttons (siblings) that have the same style.
|
---|
| 816 | * mp1 is ignored.
|
---|
| 817 | *
|
---|
| 818 | * As opposed to a check in response to a mouse
|
---|
| 819 | * event, this does _not_ send out the BN_CLICKED
|
---|
| 820 | * notification.
|
---|
| 821 | */
|
---|
| 822 |
|
---|
| 823 | case TBBM_CHECK:
|
---|
| 824 | BtnCheck(hwndButton, (BOOL)mp1, (ULONG)mp2);
|
---|
| 825 | break;
|
---|
| 826 |
|
---|
| 827 | /*
|
---|
| 828 | *@@ TBBM_QUERYCHECK:
|
---|
| 829 | * returns the current check status of a button
|
---|
| 830 | * with TBBS_CHECK or TBBS_CHECKGROUP style
|
---|
| 831 | * as TRUE or FALSE.
|
---|
| 832 | *
|
---|
| 833 | * No parameters.
|
---|
| 834 | */
|
---|
| 835 |
|
---|
| 836 | case TBBM_QUERYCHECK:
|
---|
| 837 | if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
|
---|
| 838 | mrc = (MRESULT)pData->bs.fPaintButtonSunk;
|
---|
| 839 | break;
|
---|
| 840 |
|
---|
| 841 | case WM_DESTROY:
|
---|
| 842 | if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
|
---|
| 843 | {
|
---|
| 844 | FREE(pData->bd.dwd.pszText);
|
---|
| 845 | free(pData);
|
---|
| 846 | }
|
---|
| 847 | break;
|
---|
| 848 |
|
---|
| 849 | default:
|
---|
| 850 | if (pData = (PTBBUTTONDATA)WinQueryWindowPtr(hwndButton, QWL_USER + 1))
|
---|
| 851 | mrc = ctlDefWindowProc(&pData->bd.dwd, msg, mp1, mp2);
|
---|
| 852 | }
|
---|
| 853 |
|
---|
| 854 | return mrc;
|
---|
| 855 | }
|
---|
| 856 |
|
---|
| 857 | /* ******************************************************************
|
---|
| 858 | *
|
---|
| 859 | * "Toolbar" control
|
---|
| 860 | *
|
---|
| 861 | ********************************************************************/
|
---|
| 862 |
|
---|
[243] | 863 | static const CCTLCOLOR G_scsToolbar[] =
|
---|
[232] | 864 | {
|
---|
[243] | 865 | TRUE, PP_BACKGROUNDCOLOR, SYSCLR_MENU,
|
---|
| 866 | TRUE, PP_FOREGROUNDCOLOR, SYSCLR_MENUTEXT
|
---|
[232] | 867 | };
|
---|
| 868 |
|
---|
| 869 | /*
|
---|
| 870 | *@@ CreateToolbarControl:
|
---|
| 871 | *
|
---|
| 872 | */
|
---|
| 873 |
|
---|
| 874 | STATIC HWND CreateToolbarControl(PTOOLBARDATA pData,
|
---|
| 875 | PTOOLBARCONTROL pControl,
|
---|
| 876 | PLONG px,
|
---|
| 877 | PPRESPARAMS ppp)
|
---|
| 878 | {
|
---|
| 879 | HWND hwndControl;
|
---|
| 880 |
|
---|
| 881 | if (hwndControl = WinCreateWindow(pData->dwd.hwnd,
|
---|
| 882 | (PSZ)pControl->pcszClass,
|
---|
| 883 | (PSZ)pControl->pcszTitle,
|
---|
| 884 | pControl->flStyle,
|
---|
| 885 | *px,
|
---|
| 886 | TB_BOTTOM_SPACING,
|
---|
| 887 | pControl->cx,
|
---|
| 888 | pControl->cy,
|
---|
| 889 | pData->hwndControlsOwner,
|
---|
| 890 | HWND_TOP,
|
---|
| 891 | pControl->id,
|
---|
| 892 | NULL,
|
---|
| 893 | ppp))
|
---|
| 894 | {
|
---|
| 895 | *px += pControl->cx + pData->lSpacing;
|
---|
[233] | 896 |
|
---|
| 897 | if (pData->hwndToolTip)
|
---|
| 898 | {
|
---|
| 899 | TOOLINFO ti = {0};
|
---|
| 900 | ti.ulFlags = TTF_CENTER_X_ON_TOOL | TTF_POS_Y_BELOW_TOOL | TTF_SUBCLASS;
|
---|
| 901 | ti.hwndToolOwner = pData->dwd.hwnd;
|
---|
| 902 | ti.pszText = PSZ_TEXTCALLBACK;
|
---|
| 903 | ti.hwndTool = hwndControl;
|
---|
| 904 | WinSendMsg(pData->hwndToolTip,
|
---|
| 905 | TTM_ADDTOOL,
|
---|
| 906 | (MPARAM)0,
|
---|
| 907 | &ti);
|
---|
| 908 | }
|
---|
[232] | 909 | }
|
---|
| 910 |
|
---|
| 911 | return hwndControl;
|
---|
| 912 | }
|
---|
| 913 |
|
---|
| 914 | /*
|
---|
| 915 | *@@ ReformatControls:
|
---|
| 916 | *
|
---|
| 917 | */
|
---|
| 918 |
|
---|
| 919 | STATIC VOID ReformatControls(HWND hwndToolBar)
|
---|
| 920 | {
|
---|
| 921 | PTOOLBARDATA pData;
|
---|
| 922 | if (pData = (PTOOLBARDATA)WinQueryWindowPtr(hwndToolBar, QWL_USER + 1))
|
---|
| 923 | {
|
---|
| 924 | LONG x = TB_LEFT_SPACING;
|
---|
| 925 | PLISTNODE pNode;
|
---|
| 926 | LONG cControls;
|
---|
| 927 | PSWP paswp,
|
---|
| 928 | pswpThis;
|
---|
| 929 |
|
---|
| 930 | if ( (cControls = lstCountItems(&pData->llControls))
|
---|
| 931 | && (paswp = (PSWP)malloc(sizeof(SWP) * cControls))
|
---|
| 932 | )
|
---|
| 933 | {
|
---|
| 934 | BOOL rc;
|
---|
| 935 |
|
---|
| 936 | pswpThis = paswp;
|
---|
| 937 |
|
---|
| 938 | FOR_ALL_NODES(&pData->llControls, pNode)
|
---|
| 939 | {
|
---|
| 940 | HWND hwnd = (HWND)pNode->pItemData;
|
---|
| 941 | SWP swp;
|
---|
| 942 | CHAR szClass[50];
|
---|
| 943 |
|
---|
| 944 | WinQueryWindowPos(hwnd, &swp);
|
---|
| 945 |
|
---|
| 946 | if ( (WinQueryClassName(hwnd, sizeof(szClass), szClass))
|
---|
| 947 | && (!strcmp(szClass, WC_CCTL_SEPARATOR))
|
---|
| 948 | )
|
---|
| 949 | {
|
---|
| 950 | pswpThis->cy = pData->lMaxControlCY;
|
---|
| 951 | pswpThis->fl = SWP_MOVE | SWP_SIZE;
|
---|
| 952 | }
|
---|
| 953 | else
|
---|
| 954 | {
|
---|
| 955 | pswpThis->cy = swp.cy;
|
---|
| 956 | pswpThis->fl = SWP_MOVE;
|
---|
| 957 | }
|
---|
| 958 |
|
---|
| 959 | pswpThis->cx = swp.cx;
|
---|
| 960 | pswpThis->y = TB_BOTTOM_SPACING;
|
---|
| 961 | pswpThis->x = x;
|
---|
| 962 | pswpThis->hwndInsertBehind = HWND_BOTTOM;
|
---|
| 963 | pswpThis->hwnd = hwnd;
|
---|
| 964 |
|
---|
| 965 | x += swp.cx + pData->lSpacing;
|
---|
| 966 |
|
---|
| 967 | if (swp.cy > pData->lMaxControlCY)
|
---|
| 968 | {
|
---|
| 969 | pData->lMaxControlCY = swp.cy;
|
---|
| 970 | pData->flReformat = RFFL_HEIGHT;
|
---|
| 971 | }
|
---|
| 972 |
|
---|
| 973 | pswpThis++;
|
---|
| 974 | }
|
---|
| 975 |
|
---|
| 976 | rc = WinSetMultWindowPos(pData->dwd.hab,
|
---|
| 977 | paswp,
|
---|
| 978 | cControls);
|
---|
| 979 |
|
---|
| 980 | free(paswp);
|
---|
| 981 | }
|
---|
| 982 | }
|
---|
| 983 | }
|
---|
| 984 |
|
---|
| 985 | /*
|
---|
| 986 | *@@ TbAddControls:
|
---|
| 987 | *
|
---|
| 988 | */
|
---|
| 989 |
|
---|
| 990 | STATIC ULONG TbAddControls(PTOOLBARDATA pData,
|
---|
| 991 | ULONG cControls,
|
---|
| 992 | PTOOLBARCONTROL paControls,
|
---|
| 993 | LONG lIndex) // in: index before which to add entries; -1 means rightmost
|
---|
| 994 | {
|
---|
| 995 | ULONG ul,
|
---|
| 996 | cCreated = 0;
|
---|
| 997 |
|
---|
| 998 | LONG x = 0;
|
---|
| 999 | HWND hwndBefore;
|
---|
| 1000 | SWP swp;
|
---|
| 1001 |
|
---|
| 1002 | if (!lIndex)
|
---|
| 1003 | x = TB_LEFT_SPACING;
|
---|
| 1004 | else
|
---|
| 1005 | {
|
---|
| 1006 | if ( (lIndex > 0)
|
---|
| 1007 | && (hwndBefore = (HWND)lstItemFromIndex(&pData->llControls,
|
---|
| 1008 | lIndex))
|
---|
| 1009 | && (WinQueryWindowPos(hwndBefore, &swp))
|
---|
| 1010 | )
|
---|
| 1011 | {
|
---|
| 1012 | x = swp.x + swp.cx + pData->lSpacing;
|
---|
| 1013 | }
|
---|
| 1014 | }
|
---|
| 1015 |
|
---|
| 1016 | if (x)
|
---|
| 1017 | {
|
---|
| 1018 | PPRESPARAMS ppp = NULL;
|
---|
| 1019 |
|
---|
| 1020 | PCSZ pcszFont = winhQueryDefaultFont();
|
---|
| 1021 | LONG lColor;
|
---|
| 1022 |
|
---|
| 1023 | winhStorePresParam(&ppp,
|
---|
| 1024 | PP_FONTNAMESIZE,
|
---|
| 1025 | strlen(pcszFont) + 1,
|
---|
| 1026 | (PVOID)pcszFont);
|
---|
| 1027 |
|
---|
[243] | 1028 | lColor = ctlQueryColor(&pData->dwd, CTLCOL_BGND);
|
---|
[232] | 1029 | winhStorePresParam(&ppp,
|
---|
| 1030 | PP_BACKGROUNDCOLOR,
|
---|
| 1031 | sizeof(lColor),
|
---|
| 1032 | &lColor);
|
---|
| 1033 |
|
---|
[243] | 1034 | lColor = ctlQueryColor(&pData->dwd, CTLCOL_FGND);
|
---|
[232] | 1035 | winhStorePresParam(&ppp,
|
---|
| 1036 | PP_FOREGROUNDCOLOR,
|
---|
| 1037 | sizeof(lColor),
|
---|
| 1038 | &lColor);
|
---|
| 1039 |
|
---|
| 1040 | // create controls
|
---|
| 1041 | for (ul = 0;
|
---|
| 1042 | ul < cControls;
|
---|
| 1043 | ++ul)
|
---|
| 1044 | {
|
---|
| 1045 | HWND hwndControl;
|
---|
| 1046 |
|
---|
| 1047 | if (hwndControl = CreateToolbarControl(pData,
|
---|
| 1048 | &paControls[ul],
|
---|
| 1049 | &x,
|
---|
| 1050 | ppp))
|
---|
| 1051 | {
|
---|
| 1052 | lstInsertItemBefore(&pData->llControls,
|
---|
| 1053 | (PVOID)hwndControl,
|
---|
| 1054 | lIndex++);
|
---|
| 1055 | ++cCreated;
|
---|
| 1056 | }
|
---|
| 1057 | else
|
---|
| 1058 | break;
|
---|
| 1059 | }
|
---|
| 1060 |
|
---|
| 1061 | if (ppp)
|
---|
| 1062 | free(ppp);
|
---|
| 1063 | }
|
---|
| 1064 |
|
---|
| 1065 | pData->lMaxControlCY = 0;
|
---|
| 1066 | ReformatControls(pData->dwd.hwnd);
|
---|
| 1067 |
|
---|
| 1068 | if (pData->flReformat & RFFL_HEIGHT)
|
---|
| 1069 | {
|
---|
| 1070 | if (WinQueryWindowULong(pData->dwd.hwnd, QWL_STYLE) & TBS_AUTORESIZE)
|
---|
| 1071 | {
|
---|
| 1072 | WinQueryWindowPos(pData->dwd.hwnd, &swp);
|
---|
| 1073 | WinSetWindowPos(pData->dwd.hwnd,
|
---|
| 1074 | 0,
|
---|
| 1075 | 0,
|
---|
| 1076 | 0,
|
---|
| 1077 | swp.cx,
|
---|
| 1078 | pData->lMaxControlCY + 2 * TB_BOTTOM_SPACING,
|
---|
| 1079 | SWP_SIZE);
|
---|
| 1080 |
|
---|
| 1081 | ReformatControls(pData->dwd.hwnd);
|
---|
| 1082 |
|
---|
| 1083 | ctlPostWmControl(pData->dwd.hwnd,
|
---|
| 1084 | TBN_RESIZED,
|
---|
| 1085 | 0);
|
---|
| 1086 |
|
---|
| 1087 | pData->flReformat &= ~RFFL_HEIGHT;
|
---|
| 1088 | }
|
---|
| 1089 | }
|
---|
| 1090 |
|
---|
| 1091 | return cCreated;
|
---|
| 1092 | }
|
---|
| 1093 |
|
---|
| 1094 | /*
|
---|
| 1095 | *@@ TbCreate:
|
---|
| 1096 | *
|
---|
| 1097 | */
|
---|
| 1098 |
|
---|
| 1099 | STATIC MRESULT TbCreate(HWND hwndToolBar, MPARAM mp1, MPARAM mp2)
|
---|
| 1100 | {
|
---|
| 1101 | PTOOLBARDATA pData;
|
---|
| 1102 | PTOOLBARCDATA ptbcd = (PTOOLBARCDATA)mp1;
|
---|
| 1103 |
|
---|
| 1104 | if (!(pData = NEW(TOOLBARDATA)))
|
---|
| 1105 | return (MRESULT)TRUE; // stop window creation
|
---|
| 1106 |
|
---|
| 1107 | WinSetWindowPtr(hwndToolBar, QWL_USER + 1, pData);
|
---|
| 1108 | ZERO(pData);
|
---|
| 1109 |
|
---|
| 1110 | // initialize DEFWINDOWDATA
|
---|
| 1111 | ctlInitDWD(hwndToolBar,
|
---|
| 1112 | mp2,
|
---|
| 1113 | &pData->dwd,
|
---|
| 1114 | WinDefWindowProc,
|
---|
[243] | 1115 | 0,
|
---|
| 1116 | G_scsToolbar,
|
---|
| 1117 | ARRAYITEMCOUNT(G_scsToolbar));
|
---|
[232] | 1118 |
|
---|
| 1119 | pData->hwndControlsOwner = ptbcd->hwndControlsOwner;
|
---|
| 1120 | pData->lSpacing = 5;
|
---|
| 1121 | lstInit(&pData->llControls, FALSE);
|
---|
| 1122 |
|
---|
[233] | 1123 | xstrInit(&pData->strToolTipBuf, 0);
|
---|
| 1124 |
|
---|
| 1125 | if (((PCREATESTRUCT)mp2)->flStyle & TBS_TOOLTIPS)
|
---|
| 1126 | {
|
---|
| 1127 | pData->hwndToolTip = WinCreateWindow(HWND_DESKTOP,
|
---|
| 1128 | WC_CCTL_TOOLTIP,
|
---|
| 1129 | NULL,
|
---|
| 1130 | TTS_ALWAYSTIP,
|
---|
| 1131 | 0, 0, 0, 0, // window pos and size, ignored
|
---|
| 1132 | hwndToolBar,
|
---|
| 1133 | NULLHANDLE, // hwndInsertBehind, ignored
|
---|
| 1134 | 0,
|
---|
| 1135 | NULL, // control data
|
---|
| 1136 | NULL); // presparams
|
---|
| 1137 | }
|
---|
| 1138 |
|
---|
[232] | 1139 | if ( (ptbcd->cControls)
|
---|
| 1140 | && (ptbcd->patbc)
|
---|
| 1141 | )
|
---|
| 1142 | {
|
---|
| 1143 | TbAddControls(pData,
|
---|
| 1144 | ptbcd->cControls,
|
---|
| 1145 | ptbcd->patbc,
|
---|
| 1146 | 0);
|
---|
| 1147 | }
|
---|
| 1148 |
|
---|
| 1149 | return (MRESULT)FALSE;
|
---|
| 1150 | }
|
---|
| 1151 |
|
---|
| 1152 | /*
|
---|
| 1153 | *@@ TbDestroy:
|
---|
| 1154 | *
|
---|
| 1155 | */
|
---|
| 1156 |
|
---|
| 1157 | STATIC VOID TbDestroy(HWND hwndToolBar)
|
---|
| 1158 | {
|
---|
| 1159 | PTOOLBARDATA pData;
|
---|
| 1160 | if (pData = (PTOOLBARDATA)WinQueryWindowPtr(hwndToolBar, QWL_USER + 1))
|
---|
| 1161 | {
|
---|
| 1162 | PLISTNODE pNode;
|
---|
[233] | 1163 |
|
---|
| 1164 | if (pData->hwndToolTip)
|
---|
| 1165 | WinDestroyWindow(pData->hwndToolTip);
|
---|
| 1166 |
|
---|
[232] | 1167 | FOR_ALL_NODES(&pData->llControls, pNode)
|
---|
| 1168 | {
|
---|
| 1169 | WinDestroyWindow((HWND)pNode->pItemData);
|
---|
| 1170 | }
|
---|
| 1171 | lstClear(&pData->llControls);
|
---|
[233] | 1172 |
|
---|
| 1173 | xstrClear(&pData->strToolTipBuf);
|
---|
| 1174 |
|
---|
[232] | 1175 | free(pData);
|
---|
| 1176 | }
|
---|
| 1177 | }
|
---|
| 1178 |
|
---|
| 1179 | /*
|
---|
| 1180 | *@@ ctl_fnwpToolbar:
|
---|
| 1181 | * window proc for the tool bar class.
|
---|
| 1182 | *
|
---|
| 1183 | * The tool bar understands the following messages:
|
---|
| 1184 | *
|
---|
| 1185 | * -- TBM_ADDCONTROLS
|
---|
| 1186 | */
|
---|
| 1187 |
|
---|
| 1188 | MRESULT EXPENTRY ctl_fnwpToolbar(HWND hwndToolBar, ULONG msg, MPARAM mp1, MPARAM mp2)
|
---|
| 1189 | {
|
---|
| 1190 | MRESULT mrc = 0;
|
---|
| 1191 | PTOOLBARDATA pData;
|
---|
| 1192 |
|
---|
| 1193 | switch (msg)
|
---|
| 1194 | {
|
---|
| 1195 | case WM_CREATE:
|
---|
| 1196 | TbCreate(hwndToolBar, mp1, mp2);
|
---|
| 1197 | break;
|
---|
| 1198 |
|
---|
| 1199 | /*
|
---|
| 1200 | *@@ TBM_ADDCONTROLS:
|
---|
| 1201 | * adds new controls to the tool bar.
|
---|
| 1202 | *
|
---|
| 1203 | * Parameters:
|
---|
| 1204 | *
|
---|
| 1205 | * -- PTOOLBARCONTROL mp1: array of TOOLBARCONTROL structs
|
---|
| 1206 | * which specify the windows to add to the tool bar.
|
---|
| 1207 | *
|
---|
| 1208 | * -- SHORT1FROMMP(mp2): number of items in that array
|
---|
| 1209 | * (not array size).
|
---|
| 1210 | *
|
---|
| 1211 | * -- SHORT2FROMMP(mp2): index where to add the new controls.
|
---|
| 1212 | * 0 means leftmost, 1 before the second item, and so on.
|
---|
| 1213 | * -1 means add rightmost.
|
---|
| 1214 | *
|
---|
| 1215 | * The tool bar will automatically repaint itself. If it
|
---|
| 1216 | * also has the TBS_AUTORESIZE window style, it will even
|
---|
| 1217 | * automatically resize itself and post its owner a
|
---|
| 1218 | * WM_CONTROL with TBN_RESIZED message so it can adjust
|
---|
| 1219 | * itself.
|
---|
| 1220 | */
|
---|
| 1221 |
|
---|
| 1222 | case TBM_ADDCONTROLS:
|
---|
| 1223 | if (pData = (PTOOLBARDATA)WinQueryWindowPtr(hwndToolBar, QWL_USER + 1))
|
---|
| 1224 | {
|
---|
| 1225 | TbAddControls(pData,
|
---|
| 1226 | SHORT1FROMMP(mp2),
|
---|
| 1227 | (PTOOLBARCONTROL)mp1,
|
---|
| 1228 | SHORT2FROMMP(mp2));
|
---|
| 1229 | }
|
---|
| 1230 | break;
|
---|
| 1231 |
|
---|
[233] | 1232 | case WM_CONTROL:
|
---|
| 1233 | if ( (pData = (PTOOLBARDATA)WinQueryWindowPtr(hwndToolBar, QWL_USER + 1))
|
---|
| 1234 | && (pData->hwndToolTip)
|
---|
| 1235 | && (SHORT2FROMMP(mp1) == TTN_NEEDTEXT)
|
---|
| 1236 | )
|
---|
| 1237 | {
|
---|
| 1238 | PTOOLTIPTEXT pttt = (PTOOLTIPTEXT)mp2;
|
---|
| 1239 | PSZ psz;
|
---|
| 1240 | xstrClear(&pData->strToolTipBuf);
|
---|
| 1241 |
|
---|
| 1242 | if (psz = winhQueryWindowText(pttt->hwndTool))
|
---|
| 1243 | xstrset(&pData->strToolTipBuf, psz);
|
---|
| 1244 |
|
---|
| 1245 | pttt->ulFormat = TTFMT_PSZ;
|
---|
| 1246 | pttt->pszText = pData->strToolTipBuf.psz;
|
---|
| 1247 | }
|
---|
| 1248 | break;
|
---|
| 1249 |
|
---|
[232] | 1250 | case WM_PAINT:
|
---|
| 1251 | {
|
---|
| 1252 | HPS hps;
|
---|
| 1253 | RECTL rcl;
|
---|
| 1254 | POINTL ptl;
|
---|
| 1255 | if (hps = WinBeginPaint(hwndToolBar, NULLHANDLE, &rcl))
|
---|
| 1256 | {
|
---|
| 1257 | gpihSwitchToRGB(hps);
|
---|
| 1258 | rcl.yBottom += 2;
|
---|
| 1259 | WinFillRect(hps,
|
---|
| 1260 | &rcl,
|
---|
| 1261 | winhQueryPresColor2(hwndToolBar,
|
---|
| 1262 | PP_BACKGROUNDCOLOR,
|
---|
| 1263 | PP_BACKGROUNDCOLORINDEX,
|
---|
| 1264 | FALSE,
|
---|
| 1265 | SYSCLR_MENU));
|
---|
| 1266 | ptl.x = 0;
|
---|
| 1267 | ptl.y = 0;
|
---|
| 1268 | GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONLIGHT, 0));
|
---|
| 1269 | GpiMove(hps, &ptl);
|
---|
| 1270 | ptl.x = rcl.xRight;
|
---|
| 1271 | GpiLine(hps, &ptl);
|
---|
| 1272 | ptl.x = 0;
|
---|
| 1273 | ptl.y = 1;
|
---|
| 1274 | GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONDARK, 0));
|
---|
| 1275 | GpiMove(hps, &ptl);
|
---|
| 1276 | ptl.x = rcl.xRight;
|
---|
| 1277 | GpiLine(hps, &ptl);
|
---|
| 1278 |
|
---|
| 1279 | WinEndPaint(hps);
|
---|
| 1280 | }
|
---|
| 1281 | }
|
---|
| 1282 | break;
|
---|
| 1283 |
|
---|
| 1284 | case WM_DESTROY:
|
---|
| 1285 | TbDestroy(hwndToolBar);
|
---|
| 1286 | break;
|
---|
| 1287 |
|
---|
| 1288 | default:
|
---|
| 1289 | if (pData = (PTOOLBARDATA)WinQueryWindowPtr(hwndToolBar, QWL_USER + 1))
|
---|
| 1290 | mrc = ctlDefWindowProc(&pData->dwd, msg, mp1, mp2);
|
---|
| 1291 | }
|
---|
| 1292 |
|
---|
| 1293 | return mrc;
|
---|
| 1294 | }
|
---|
| 1295 |
|
---|
| 1296 | /*
|
---|
| 1297 | *@@ ctlRegisterToolbar:
|
---|
| 1298 | * this registers the tool bar window class (ctl_fnwpToolbar)
|
---|
| 1299 | * _and_ the tool bar button control (ctl_fnwpToolbarButton)
|
---|
| 1300 | * for an application. This is required before the tool bar
|
---|
| 1301 | * control can be used.
|
---|
| 1302 | */
|
---|
| 1303 |
|
---|
| 1304 | BOOL ctlRegisterToolbar(HAB hab)
|
---|
| 1305 | {
|
---|
| 1306 | return ( WinRegisterClass(hab,
|
---|
| 1307 | WC_CCTL_TOOLBAR,
|
---|
| 1308 | ctl_fnwpToolbar,
|
---|
| 1309 | CS_SYNCPAINT | /* CS_CLIPSIBLINGS | */ CS_CLIPCHILDREN,
|
---|
| 1310 | sizeof(PVOID) * 2) // addt'l bytes to reserve:
|
---|
| 1311 | // one pointer for QWL_USER,
|
---|
| 1312 | // one more for instance data
|
---|
| 1313 | && WinRegisterClass(hab,
|
---|
| 1314 | WC_CCTL_TBBUTTON,
|
---|
| 1315 | ctl_fnwpToolbarButton,
|
---|
| 1316 | CS_SYNCPAINT | CS_CLIPSIBLINGS | CS_CLIPCHILDREN,
|
---|
| 1317 | sizeof(PVOID) * 2) // addt'l bytes to reserve:
|
---|
| 1318 | // one pointer for QWL_USER,
|
---|
| 1319 | // one more for instance data
|
---|
| 1320 | );
|
---|
| 1321 | }
|
---|
| 1322 |
|
---|
| 1323 | /*
|
---|
| 1324 | *@@ ctlCreateToolBar:
|
---|
| 1325 | * type-safe wrapper around WinCreateWindow to create a tool bar.
|
---|
| 1326 | *
|
---|
| 1327 | * The easiest way to create a tool bar completely with the tools
|
---|
| 1328 | * is to pass them as an array of TOOLBARCONTROL structs here,
|
---|
| 1329 | * which simply specify the window classes to create. In most
|
---|
| 1330 | * cases, you will want to add tools of the WC_CCTL_TBBUTTON
|
---|
| 1331 | * and WC_SEPARATORLINE classes.
|
---|
| 1332 | *
|
---|
| 1333 | * Keep in mind to call ctlRegisterToolbar and ctlRegisterSeparatorLine
|
---|
| 1334 | * first, or window creation will fail.
|
---|
| 1335 | */
|
---|
| 1336 |
|
---|
| 1337 | HWND ctlCreateToolBar(HWND hwndParent, // in: parent of tool bar (e.g. frame)
|
---|
| 1338 | HWND hwndOwner, // in: owner of tool bar itself (e.g. frame)
|
---|
| 1339 | ULONG flStyle, // in: window style (WS_VISIBLE | TBS_* flags)
|
---|
| 1340 | HWND hwndControlsOwner, // in: owner for tool bar controls (e.g. frame client)
|
---|
| 1341 | ULONG cControls,
|
---|
| 1342 | PTOOLBARCONTROL patbc)
|
---|
| 1343 | {
|
---|
| 1344 | TOOLBARCDATA tbcd;
|
---|
| 1345 | memset(&tbcd, 0, sizeof(tbcd));
|
---|
| 1346 | tbcd.cb = sizeof(tbcd);
|
---|
| 1347 | tbcd.hwndControlsOwner = hwndControlsOwner;
|
---|
| 1348 | tbcd.cControls = cControls;
|
---|
| 1349 | tbcd.patbc = patbc;
|
---|
| 1350 |
|
---|
| 1351 | return WinCreateWindow(hwndParent,
|
---|
| 1352 | WC_CCTL_TOOLBAR,
|
---|
| 1353 | NULL,
|
---|
| 1354 | flStyle,
|
---|
| 1355 | 0,
|
---|
| 1356 | 0,
|
---|
| 1357 | 0,
|
---|
| 1358 | 0,
|
---|
| 1359 | hwndOwner,
|
---|
| 1360 | HWND_BOTTOM,
|
---|
| 1361 | FID_TOOLBAR,
|
---|
| 1362 | &tbcd,
|
---|
| 1363 | NULL);
|
---|
| 1364 | }
|
---|
[233] | 1365 |
|
---|