| 1 |  | 
|---|
| 2 | /* | 
|---|
| 3 | *@@sourcefile comctl.c: | 
|---|
| 4 | *      contains various window procedures for implementing | 
|---|
| 5 | *      common controls. The source file name has nothing to do | 
|---|
| 6 | *      with the Windoze DLL of the same name. | 
|---|
| 7 | * | 
|---|
| 8 | *      Usage: All PM programs. | 
|---|
| 9 | * | 
|---|
| 10 | *      Function prefixes (new with V0.81): | 
|---|
| 11 | *      --  ctl*   common control helper functions | 
|---|
| 12 | * | 
|---|
| 13 | *      The functionality of this code is accessed with the use | 
|---|
| 14 | *      of a special helper function. Sometimes that function | 
|---|
| 15 | *      registers a new window class, sometimes a static control | 
|---|
| 16 | *      needs to be subclassed. See the respective functions for | 
|---|
| 17 | *      details. | 
|---|
| 18 | * | 
|---|
| 19 | *      In detail, we have: | 
|---|
| 20 | * | 
|---|
| 21 | *      --  a "menu button" control, which displays a menu when | 
|---|
| 22 | *          pressed (see ctlMakeMenuButton for details); | 
|---|
| 23 | * | 
|---|
| 24 | *      --  progress bar support (see ctlProgressBarFromStatic for | 
|---|
| 25 | *          details); | 
|---|
| 26 | * | 
|---|
| 27 | *      --  a "chart" control for displaying pie charts (all new | 
|---|
| 28 | *          with V0.9.0; see ctlChartFromStatic for details); | 
|---|
| 29 | * | 
|---|
| 30 | *      --  split windows support (all new with V0.9.0; see | 
|---|
| 31 | *          ctlCreateSplitWindow for details); | 
|---|
| 32 | * | 
|---|
| 33 | *      --  a subclassed static control for enhanced bitmap and | 
|---|
| 34 | *          and icon display (see ctl_fnwpBitmapStatic for details). | 
|---|
| 35 | *          This used to be in animate.c and has been enhanced | 
|---|
| 36 | *          with V0.9.0; | 
|---|
| 37 | * | 
|---|
| 38 | *      --  a "tooltip" control, which shows fly-over ("bubble") | 
|---|
| 39 | *          help over any window, including controls. This is | 
|---|
| 40 | *          largely API-compatible with the Win95 tooltip control. | 
|---|
| 41 | *          See ctl_fnwpTooltip for details; | 
|---|
| 42 | * | 
|---|
| 43 | *      --  a "checkbox container" control, which is a subclassed | 
|---|
| 44 | *          container which uses checkboxes as record icons. | 
|---|
| 45 | *          See ctlMakeCheckboxContainer for details. | 
|---|
| 46 | * | 
|---|
| 47 | *      Note: Version numbering in this file relates to XWorkplace version | 
|---|
| 48 | *            numbering. | 
|---|
| 49 | * | 
|---|
| 50 | *@@header "helpers\comctl.h" | 
|---|
| 51 | */ | 
|---|
| 52 |  | 
|---|
| 53 | /* | 
|---|
| 54 | *      Copyright (C) 1997-2002 Ulrich Mller. | 
|---|
| 55 | *      This file is part of the "XWorkplace helpers" source package. | 
|---|
| 56 | *      This is free software; you can redistribute it and/or modify | 
|---|
| 57 | *      it under the terms of the GNU General Public License as published | 
|---|
| 58 | *      by the Free Software Foundation, in version 2 as it comes in the | 
|---|
| 59 | *      "COPYING" file of the XWorkplace main distribution. | 
|---|
| 60 | *      This program is distributed in the hope that it will be useful, | 
|---|
| 61 | *      but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 62 | *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
| 63 | *      GNU General Public License for more details. | 
|---|
| 64 | */ | 
|---|
| 65 |  | 
|---|
| 66 | #define OS2EMX_PLAIN_CHAR | 
|---|
| 67 | // this is needed for "os2emx.h"; if this is defined, | 
|---|
| 68 | // emx will define PSZ as _signed_ char, otherwise | 
|---|
| 69 | // as unsigned char | 
|---|
| 70 |  | 
|---|
| 71 | #define INCL_DOSEXCEPTIONS | 
|---|
| 72 | #define INCL_DOSPROCESS | 
|---|
| 73 | #define INCL_DOSSEMAPHORES | 
|---|
| 74 | #define INCL_DOSERRORS | 
|---|
| 75 |  | 
|---|
| 76 | #define INCL_WINWINDOWMGR | 
|---|
| 77 | #define INCL_WINFRAMEMGR | 
|---|
| 78 | #define INCL_WINMESSAGEMGR | 
|---|
| 79 | #define INCL_WININPUT | 
|---|
| 80 | #define INCL_WINPOINTERS | 
|---|
| 81 | #define INCL_WINTRACKRECT | 
|---|
| 82 | #define INCL_WINTIMER | 
|---|
| 83 | #define INCL_WINSYS | 
|---|
| 84 |  | 
|---|
| 85 | #define INCL_WINRECTANGLES      /// xxx temporary | 
|---|
| 86 |  | 
|---|
| 87 | #define INCL_WINMENUS | 
|---|
| 88 | #define INCL_WINSTATICS | 
|---|
| 89 | #define INCL_WINBUTTONS | 
|---|
| 90 | #define INCL_WINSTDCNR | 
|---|
| 91 | #define INCL_WINENTRYFIELDS | 
|---|
| 92 |  | 
|---|
| 93 | #define INCL_GPIPRIMITIVES | 
|---|
| 94 | #define INCL_GPILOGCOLORTABLE | 
|---|
| 95 | #define INCL_GPILCIDS | 
|---|
| 96 | #define INCL_GPIPATHS | 
|---|
| 97 | #define INCL_GPIREGIONS | 
|---|
| 98 | #define INCL_GPIBITMAPS             // added V0.9.1 (2000-01-04) [umoeller]: needed for EMX headers | 
|---|
| 99 | #include <os2.h> | 
|---|
| 100 |  | 
|---|
| 101 | #include <stdlib.h> | 
|---|
| 102 | #include <stdio.h> | 
|---|
| 103 | #include <string.h> | 
|---|
| 104 | #include <setjmp.h>             // needed for except.h | 
|---|
| 105 | #include <assert.h>             // needed for except.h | 
|---|
| 106 |  | 
|---|
| 107 | #include "setup.h"                      // code generation and debugging options | 
|---|
| 108 |  | 
|---|
| 109 | #include "helpers\cnrh.h" | 
|---|
| 110 | #include "helpers\except.h"             // exception handling | 
|---|
| 111 | #include "helpers\gpih.h" | 
|---|
| 112 | #include "helpers\linklist.h" | 
|---|
| 113 | #include "helpers\winh.h" | 
|---|
| 114 |  | 
|---|
| 115 | #include "helpers\comctl.h" | 
|---|
| 116 |  | 
|---|
| 117 | #pragma hdrstop | 
|---|
| 118 |  | 
|---|
| 119 | /* ****************************************************************** | 
|---|
| 120 | * | 
|---|
| 121 | *   "Separator line" control | 
|---|
| 122 | * | 
|---|
| 123 | ********************************************************************/ | 
|---|
| 124 |  | 
|---|
| 125 | PFNWP   G_pfnwpSepStatic = NULL; | 
|---|
| 126 |  | 
|---|
| 127 | /* | 
|---|
| 128 | *@@ fnwpSeparatorLine: | 
|---|
| 129 | *      window proc for the subclassed static control that makes | 
|---|
| 130 | *      the "separator line" control. | 
|---|
| 131 | * | 
|---|
| 132 | *@@added V0.9.20 (2002-08-10) [umoeller] | 
|---|
| 133 | */ | 
|---|
| 134 |  | 
|---|
| 135 | STATIC MRESULT EXPENTRY fnwpSeparatorLine(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) | 
|---|
| 136 | { | 
|---|
| 137 | MRESULT mrc = 0; | 
|---|
| 138 |  | 
|---|
| 139 | switch (msg) | 
|---|
| 140 | { | 
|---|
| 141 | case WM_PAINT: | 
|---|
| 142 | { | 
|---|
| 143 | RECTL rcl; | 
|---|
| 144 | HPS hps; | 
|---|
| 145 | WinQueryWindowRect(hwnd, &rcl); | 
|---|
| 146 | if (hps = WinBeginPaint(hwnd, NULLHANDLE, NULL)) | 
|---|
| 147 | { | 
|---|
| 148 | POINTL ptl; | 
|---|
| 149 |  | 
|---|
| 150 | gpihSwitchToRGB(hps); | 
|---|
| 151 |  | 
|---|
| 152 | GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONLIGHT, 0)); | 
|---|
| 153 |  | 
|---|
| 154 | ptl.x = rcl.xLeft; | 
|---|
| 155 | ptl.y = (rcl.yTop - rcl.yBottom) / 2 - 1; | 
|---|
| 156 | GpiMove(hps, &ptl); | 
|---|
| 157 | ptl.x = rcl.xRight; | 
|---|
| 158 | GpiLine(hps, &ptl); | 
|---|
| 159 |  | 
|---|
| 160 | GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONDARK, 0)); | 
|---|
| 161 |  | 
|---|
| 162 | ptl.x = rcl.xLeft; | 
|---|
| 163 | ++ptl.y; | 
|---|
| 164 | GpiMove(hps, &ptl); | 
|---|
| 165 | ptl.x = rcl.xRight; | 
|---|
| 166 | GpiLine(hps, &ptl); | 
|---|
| 167 |  | 
|---|
| 168 | WinEndPaint(hps); | 
|---|
| 169 | } | 
|---|
| 170 | } | 
|---|
| 171 | break; | 
|---|
| 172 |  | 
|---|
| 173 | default: | 
|---|
| 174 | mrc = G_pfnwpSepStatic(hwnd, msg, mp1, mp2); | 
|---|
| 175 | } | 
|---|
| 176 |  | 
|---|
| 177 | return mrc; | 
|---|
| 178 | } | 
|---|
| 179 |  | 
|---|
| 180 | /* | 
|---|
| 181 | *@@ ctlMakeSeparatorLine: | 
|---|
| 182 | *      turns the given static control into a 3D separator line. | 
|---|
| 183 | * | 
|---|
| 184 | *@@added V1.0.0 (2002-08-12) [umoeller] | 
|---|
| 185 | */ | 
|---|
| 186 |  | 
|---|
| 187 | BOOL ctlRegisterSeparatorLine(HAB hab) | 
|---|
| 188 | { | 
|---|
| 189 | CLASSINFO ciStatic; | 
|---|
| 190 | if (WinQueryClassInfo(hab, | 
|---|
| 191 | WC_STATIC, | 
|---|
| 192 | &ciStatic)) | 
|---|
| 193 | { | 
|---|
| 194 | G_pfnwpSepStatic = ciStatic.pfnWindowProc; | 
|---|
| 195 |  | 
|---|
| 196 | return WinRegisterClass(hab, | 
|---|
| 197 | WC_SEPARATORLINE, | 
|---|
| 198 | fnwpSeparatorLine, | 
|---|
| 199 | (ciStatic.flClassStyle & ~CS_PUBLIC), | 
|---|
| 200 | ciStatic.cbWindowData); | 
|---|
| 201 |  | 
|---|
| 202 | } | 
|---|
| 203 |  | 
|---|
| 204 | return FALSE; | 
|---|
| 205 | } | 
|---|
| 206 |  | 
|---|
| 207 | /* ****************************************************************** | 
|---|
| 208 | * | 
|---|
| 209 | *   "XButton" control | 
|---|
| 210 | * | 
|---|
| 211 | ********************************************************************/ | 
|---|
| 212 |  | 
|---|
| 213 | /* | 
|---|
| 214 | *@@ ctlPaintXButton: | 
|---|
| 215 | *      paints an X-button control. Can be called externally | 
|---|
| 216 | *      for just painting a button even if this is not really | 
|---|
| 217 | *      a window. | 
|---|
| 218 | * | 
|---|
| 219 | *      WARNING: this is work in progress and will change into | 
|---|
| 220 | *      the future. Eventually this will turn into a full | 
|---|
| 221 | *      button control replacement. | 
|---|
| 222 | * | 
|---|
| 223 | *@@added V0.9.13 (2001-06-21) [umoeller] | 
|---|
| 224 | *@@changed V0.9.16 (2001-10-24) [umoeller]: fixed wrong hatch color and paint offset | 
|---|
| 225 | *@@changed V0.9.16 (2001-10-28) [umoeller]: added bitmap support, fixed bad clip rectangle | 
|---|
| 226 | *@@changed V0.9.20 (2002-08-04) [umoeller]: fixed button offset, depressed color | 
|---|
| 227 | */ | 
|---|
| 228 |  | 
|---|
| 229 | VOID ctlPaintXButton(HPS hps,               // in: presentation space (RGB mode) | 
|---|
| 230 | ULONG fl,              // in: XBF_* flags | 
|---|
| 231 | PXBUTTONDATA pxbd)     // in: button data | 
|---|
| 232 | { | 
|---|
| 233 | ULONG   ulBorder = 0, | 
|---|
| 234 | cx, | 
|---|
| 235 | cy, | 
|---|
| 236 | ulOfs = 0; | 
|---|
| 237 | LONG    lLeft, | 
|---|
| 238 | lRight, | 
|---|
| 239 | lColorMiddle = pxbd->lMiddle; | 
|---|
| 240 | RECTL   rclWin; | 
|---|
| 241 |  | 
|---|
| 242 | memcpy(&rclWin, &pxbd->rcl, sizeof(RECTL)); | 
|---|
| 243 |  | 
|---|
| 244 | if (0 == (fl & XBF_FLAT)) | 
|---|
| 245 | ulBorder = 2; | 
|---|
| 246 |  | 
|---|
| 247 | gpihSwitchToRGB(hps); | 
|---|
| 248 |  | 
|---|
| 249 | if (fl & XBF_PRESSED) | 
|---|
| 250 | { | 
|---|
| 251 | // paint button "down": | 
|---|
| 252 | lLeft = pxbd->lcol3DDark; | 
|---|
| 253 | lRight = pxbd->lcol3DLight; | 
|---|
| 254 | // add offset for icon painting at the bottom | 
|---|
| 255 | ulOfs += 1; | 
|---|
| 256 | if (ulBorder == 0) | 
|---|
| 257 | ulBorder = 1; | 
|---|
| 258 |  | 
|---|
| 259 | // make the depressed color darker | 
|---|
| 260 | // V0.9.20 (2002-07-31) [umoeller] | 
|---|
| 261 | gpihManipulateRGB(&lColorMiddle, | 
|---|
| 262 | .95); | 
|---|
| 263 | } | 
|---|
| 264 | else | 
|---|
| 265 | { | 
|---|
| 266 | lLeft = pxbd->lcol3DLight; | 
|---|
| 267 | lRight = pxbd->lcol3DDark; | 
|---|
| 268 | } | 
|---|
| 269 |  | 
|---|
| 270 | if (ulBorder) | 
|---|
| 271 | { | 
|---|
| 272 | // button border: | 
|---|
| 273 | // now paint button frame | 
|---|
| 274 |  | 
|---|
| 275 | // make rcl inclusive | 
|---|
| 276 | rclWin.xRight--; | 
|---|
| 277 | rclWin.yTop--; | 
|---|
| 278 | gpihDraw3DFrame(hps, | 
|---|
| 279 | &rclWin,        // inclusive | 
|---|
| 280 | ulBorder, | 
|---|
| 281 | lLeft, | 
|---|
| 282 | lRight); | 
|---|
| 283 |  | 
|---|
| 284 | // now paint button middle | 
|---|
| 285 | rclWin.xLeft += ulBorder; | 
|---|
| 286 | rclWin.yBottom += ulBorder; | 
|---|
| 287 | rclWin.xRight -= ulBorder - 1;  // make exclusive again | 
|---|
| 288 | rclWin.yTop -= ulBorder - 1;    // make exclusive again | 
|---|
| 289 | } | 
|---|
| 290 |  | 
|---|
| 291 | if (fl & XBF_BACKGROUND) | 
|---|
| 292 | WinFillRect(hps, | 
|---|
| 293 | &rclWin,        // exclusive | 
|---|
| 294 | lColorMiddle); | 
|---|
| 295 |  | 
|---|
| 296 | // get icon | 
|---|
| 297 | if (pxbd->hptr) | 
|---|
| 298 | { | 
|---|
| 299 | // calculate x and y to be centered in rectangle | 
|---|
| 300 | POINTL  ptl; | 
|---|
| 301 |  | 
|---|
| 302 | cx = rclWin.xRight - rclWin.xLeft; | 
|---|
| 303 | cy = rclWin.yTop - rclWin.yBottom; | 
|---|
| 304 |  | 
|---|
| 305 | ptl.x = rclWin.xLeft + ((cx - pxbd->cxIconOrBitmap) / 2); | 
|---|
| 306 | ptl.y = rclWin.yBottom + ((cy - pxbd->cyIconOrBitmap) / 2); | 
|---|
| 307 |  | 
|---|
| 308 | if (fl & XBF_INUSE) | 
|---|
| 309 | { | 
|---|
| 310 | // caller wants in-use (hatched) emphasis: | 
|---|
| 311 | // draw a box then | 
|---|
| 312 | POINTL ptl2; | 
|---|
| 313 | ptl2.x = ptl.x - 2; | 
|---|
| 314 | ptl2.y = ptl.y - 2; | 
|---|
| 315 | GpiMove(hps, | 
|---|
| 316 | &ptl2);     // &ptl | 
|---|
| 317 | // duh, typo V0.9.16 (2001-10-24) [umoeller] | 
|---|
| 318 | GpiSetPattern(hps, PATSYM_DIAG1); | 
|---|
| 319 | GpiSetColor(hps, RGBCOL_BLACK);     // V0.9.16 (2001-10-24) [umoeller] | 
|---|
| 320 | ptl2.x = ptl.x + pxbd->cxIconOrBitmap + 1; // inclusive! | 
|---|
| 321 | ptl2.y = ptl.y + pxbd->cyIconOrBitmap + 1; // inclusive! | 
|---|
| 322 | GpiBox(hps, | 
|---|
| 323 | DRO_FILL, | 
|---|
| 324 | &ptl2, | 
|---|
| 325 | 0, | 
|---|
| 326 | 0); | 
|---|
| 327 | } | 
|---|
| 328 |  | 
|---|
| 329 | // now paint icon | 
|---|
| 330 |  | 
|---|
| 331 | // make rcl inclusive           // V0.9.16 (2001-10-28) [umoeller] | 
|---|
| 332 | rclWin.xRight--; | 
|---|
| 333 | rclWin.yTop--; | 
|---|
| 334 | GpiIntersectClipRectangle(hps, | 
|---|
| 335 | &rclWin);    // inclusive! | 
|---|
| 336 |  | 
|---|
| 337 | // center this in remaining rectl | 
|---|
| 338 | ptl.x += ulOfs; | 
|---|
| 339 | ptl.y -= ulOfs; | 
|---|
| 340 | if (fl & XBF_BITMAP) | 
|---|
| 341 | // V0.9.16 (2001-10-28) [umoeller] | 
|---|
| 342 | WinDrawBitmap(hps, | 
|---|
| 343 | pxbd->hptr,           // a bitmap really | 
|---|
| 344 | NULL,                 // entire bitmap | 
|---|
| 345 | &ptl, | 
|---|
| 346 | 0, | 
|---|
| 347 | 0, | 
|---|
| 348 | DBM_NORMAL); | 
|---|
| 349 | else | 
|---|
| 350 | WinDrawPointer(hps, | 
|---|
| 351 | // center this in remaining rectl | 
|---|
| 352 | ptl.x, //  + ulOfs, | 
|---|
| 353 | ptl.y, //  - ulOfs, | 
|---|
| 354 | pxbd->hptr, | 
|---|
| 355 | DP_MINI); | 
|---|
| 356 | } | 
|---|
| 357 | } | 
|---|
| 358 |  | 
|---|
| 359 | /* | 
|---|
| 360 | *@@category: Helpers\PM helpers\Window classes\Menu buttons | 
|---|
| 361 | *      See comctl.c and ctlMakeMenuButton. | 
|---|
| 362 | */ | 
|---|
| 363 |  | 
|---|
| 364 | /* ****************************************************************** | 
|---|
| 365 | * | 
|---|
| 366 | *   "Menu button" control | 
|---|
| 367 | * | 
|---|
| 368 | ********************************************************************/ | 
|---|
| 369 |  | 
|---|
| 370 | /* | 
|---|
| 371 | *@@ MENUBUTTONDATA: | 
|---|
| 372 | *      internal data for "menu button" | 
|---|
| 373 | * | 
|---|
| 374 | *@@added V0.9.0 [umoeller] | 
|---|
| 375 | */ | 
|---|
| 376 |  | 
|---|
| 377 | typedef struct _MENUBUTTONDATA | 
|---|
| 378 | { | 
|---|
| 379 | PFNWP       pfnwpButtonOriginal; | 
|---|
| 380 | HMODULE     hmodMenu; | 
|---|
| 381 | ULONG       idMenu; | 
|---|
| 382 | BOOL        fMouseCaptured,         // TRUE if WinSetCapture | 
|---|
| 383 | fMouseButton1Down,      // TRUE in between WM_BUTTON1DOWN and WM_BUTTON1UP | 
|---|
| 384 | fButtonSunk;            // toggle state of the button | 
|---|
| 385 | HWND        hwndMenu; | 
|---|
| 386 | } MENUBUTTONDATA, *PMENUBUTTONDATA; | 
|---|
| 387 |  | 
|---|
| 388 | /* | 
|---|
| 389 | *@@ ctlDisplayButtonMenu: | 
|---|
| 390 | *      displays the specified menu above the button. | 
|---|
| 391 | * | 
|---|
| 392 | *@@added V0.9.7 (2000-11-29) [umoeller] | 
|---|
| 393 | */ | 
|---|
| 394 |  | 
|---|
| 395 | VOID ctlDisplayButtonMenu(HWND hwndButton, | 
|---|
| 396 | HWND hwndMenu) | 
|---|
| 397 | { | 
|---|
| 398 | SWP     swpButton; | 
|---|
| 399 | POINTL  ptlMenu; | 
|---|
| 400 | WinQueryWindowPos(hwndButton, &swpButton); | 
|---|
| 401 | ptlMenu.x = swpButton.x; | 
|---|
| 402 | ptlMenu.y = swpButton.y; | 
|---|
| 403 |  | 
|---|
| 404 | // ptlMenu now has button coordinates | 
|---|
| 405 | // relative to the button's parent; | 
|---|
| 406 | // convert this to screen coordinates: | 
|---|
| 407 | WinMapWindowPoints(WinQueryWindow(hwndButton, QW_PARENT), | 
|---|
| 408 | HWND_DESKTOP, | 
|---|
| 409 | &ptlMenu, | 
|---|
| 410 | 1); | 
|---|
| 411 |  | 
|---|
| 412 | // now show the menu on top of the button | 
|---|
| 413 | WinPopupMenu(HWND_DESKTOP,               // menu parent | 
|---|
| 414 | hwndButton,                 // owner | 
|---|
| 415 | hwndMenu, | 
|---|
| 416 | (SHORT)(ptlMenu.x), | 
|---|
| 417 | (SHORT)(ptlMenu.y + swpButton.cy - 1), | 
|---|
| 418 | 0,                          // ID | 
|---|
| 419 | PU_NONE | 
|---|
| 420 | | PU_MOUSEBUTTON1 | 
|---|
| 421 | | PU_KEYBOARD | 
|---|
| 422 | | PU_HCONSTRAIN | 
|---|
| 423 | | PU_VCONSTRAIN); | 
|---|
| 424 | } | 
|---|
| 425 |  | 
|---|
| 426 | /* | 
|---|
| 427 | *@@ ctl_fnwpSubclassedMenuButton: | 
|---|
| 428 | *      subclassed window proc for "menu button". | 
|---|
| 429 | *      See ctlMakeMenuButton for details. | 
|---|
| 430 | * | 
|---|
| 431 | *@@added V0.9.0 [umoeller] | 
|---|
| 432 | *@@changed V0.9.2 (2000-02-28) [umoeller]: menu was displayed even if button was disabled; fixed | 
|---|
| 433 | *@@changed V0.9.14 (2001-07-31) [umoeller]: fixed WM_MENUEND submenu quirk | 
|---|
| 434 | */ | 
|---|
| 435 |  | 
|---|
| 436 | MRESULT EXPENTRY ctl_fnwpSubclassedMenuButton(HWND hwndButton, ULONG msg, MPARAM mp1, MPARAM mp2) | 
|---|
| 437 | { | 
|---|
| 438 | MRESULT mrc = 0; | 
|---|
| 439 | PMENUBUTTONDATA pmbd = (PMENUBUTTONDATA)WinQueryWindowULong(hwndButton, QWL_USER); | 
|---|
| 440 |  | 
|---|
| 441 | switch (msg) | 
|---|
| 442 | { | 
|---|
| 443 | /* | 
|---|
| 444 | * WM_BUTTON1DOWN: | 
|---|
| 445 | * WM_BUTTON1UP: | 
|---|
| 446 | *      these show/hide the menu. | 
|---|
| 447 | * | 
|---|
| 448 | *      Showing the menu follows these steps: | 
|---|
| 449 | *          a)  first WM_BUTTON1DOWN hilites the button; | 
|---|
| 450 | *          b)  first WM_BUTTON1UP shows the menu. | 
|---|
| 451 | * | 
|---|
| 452 | *      When the button is pressed again, the open | 
|---|
| 453 | *      menu loses focus, which results in WM_MENUEND | 
|---|
| 454 | *      and destroys the window automatically. | 
|---|
| 455 | */ | 
|---|
| 456 |  | 
|---|
| 457 | case WM_BUTTON1DOWN: | 
|---|
| 458 | case WM_BUTTON1DBLCLK: | 
|---|
| 459 | // only do this if the button is enabled | 
|---|
| 460 | // V0.9.2 (2000-02-28) [umoeller] | 
|---|
| 461 | if (WinIsWindowEnabled(hwndButton)) | 
|---|
| 462 | { | 
|---|
| 463 | // _Pmpf(("WM_BUTTON1DOWN")); | 
|---|
| 464 | // since we're not passing the message | 
|---|
| 465 | // to WinDefWndProc, we need to give | 
|---|
| 466 | // ourselves the focus | 
|---|
| 467 | WinSetFocus(HWND_DESKTOP, hwndButton); | 
|---|
| 468 |  | 
|---|
| 469 | if (!pmbd->fMouseCaptured) | 
|---|
| 470 | { | 
|---|
| 471 | // capture mouse events while the | 
|---|
| 472 | // mouse button is down | 
|---|
| 473 | WinSetCapture(HWND_DESKTOP, hwndButton); | 
|---|
| 474 | pmbd->fMouseCaptured = TRUE; | 
|---|
| 475 | } | 
|---|
| 476 |  | 
|---|
| 477 | pmbd->fMouseButton1Down = TRUE; | 
|---|
| 478 |  | 
|---|
| 479 | if (!pmbd->fButtonSunk) | 
|---|
| 480 | { | 
|---|
| 481 | // button not hilited yet (first click): | 
|---|
| 482 | // do it now | 
|---|
| 483 | // _Pmpf(("  Sinking menu WM_BUTTON1DOWN ")); | 
|---|
| 484 | pmbd->fButtonSunk = TRUE; | 
|---|
| 485 | WinSendMsg(hwndButton, | 
|---|
| 486 | BM_SETHILITE, | 
|---|
| 487 | (MPARAM)TRUE, | 
|---|
| 488 | (MPARAM)0); | 
|---|
| 489 | } | 
|---|
| 490 |  | 
|---|
| 491 | // else: the menu has just been destroyed | 
|---|
| 492 | // (WM_MENUEND below) | 
|---|
| 493 | } | 
|---|
| 494 |  | 
|---|
| 495 | mrc = (MPARAM)TRUE;     // message processed | 
|---|
| 496 | break; | 
|---|
| 497 |  | 
|---|
| 498 | /* | 
|---|
| 499 | * WM_BUTTON1UP: | 
|---|
| 500 | * | 
|---|
| 501 | */ | 
|---|
| 502 |  | 
|---|
| 503 | case WM_BUTTON1UP: | 
|---|
| 504 | // only do this if the button is enabled | 
|---|
| 505 | // V0.9.2 (2000-02-28) [umoeller] | 
|---|
| 506 | if (WinIsWindowEnabled(hwndButton)) | 
|---|
| 507 | { | 
|---|
| 508 | // _Pmpf(("WM_BUTTON1UP sunk %d hwndMenu 0x%lX", pmbd->fButtonSunk, pmbd->hwndMenu)); | 
|---|
| 509 |  | 
|---|
| 510 | // un-capture the mouse first | 
|---|
| 511 | if (pmbd->fMouseCaptured) | 
|---|
| 512 | { | 
|---|
| 513 | WinSetCapture(HWND_DESKTOP, NULLHANDLE); | 
|---|
| 514 | pmbd->fMouseCaptured = FALSE; | 
|---|
| 515 | } | 
|---|
| 516 |  | 
|---|
| 517 | pmbd->fMouseButton1Down = FALSE; | 
|---|
| 518 |  | 
|---|
| 519 | if (    (pmbd->fButtonSunk)      // set by WM_BUTTON1DOWN above | 
|---|
| 520 | && (pmbd->hwndMenu)         // menu currently showing | 
|---|
| 521 | ) | 
|---|
| 522 | { | 
|---|
| 523 | // button currently depressed: | 
|---|
| 524 | // un-hilite button | 
|---|
| 525 | // _Pmpf(("  Unsinking menu WM_BUTTON1UP 1")); | 
|---|
| 526 | pmbd->fButtonSunk = FALSE; | 
|---|
| 527 | WinSendMsg(hwndButton, | 
|---|
| 528 | BM_SETHILITE, | 
|---|
| 529 | (MPARAM)FALSE, | 
|---|
| 530 | (MPARAM)0); | 
|---|
| 531 | } | 
|---|
| 532 | else | 
|---|
| 533 | { | 
|---|
| 534 | // first button up: | 
|---|
| 535 | // show menu | 
|---|
| 536 |  | 
|---|
| 537 | if (pmbd->idMenu) | 
|---|
| 538 | { | 
|---|
| 539 | // _Pmpf(("  Loading menu hmod %lX id %lX", pmbd->hmodMenu, pmbd->idMenu)); | 
|---|
| 540 | // menu specified: load from | 
|---|
| 541 | // specified resources | 
|---|
| 542 | pmbd->hwndMenu = WinLoadMenu(hwndButton, | 
|---|
| 543 | pmbd->hmodMenu, | 
|---|
| 544 | pmbd->idMenu); | 
|---|
| 545 | } | 
|---|
| 546 | else | 
|---|
| 547 | { | 
|---|
| 548 | HWND    hwndOwner = WinQueryWindow(hwndButton, QW_OWNER); | 
|---|
| 549 | // _Pmpf(("  Querying menu WM_COMMAND from owner 0x%lX", hwndOwner)); | 
|---|
| 550 | // send WM_COMMAND to owner | 
|---|
| 551 | pmbd->hwndMenu | 
|---|
| 552 | = (HWND)WinSendMsg(hwndOwner, | 
|---|
| 553 | WM_COMMAND, | 
|---|
| 554 | (MPARAM)(ULONG)WinQueryWindowUShort(hwndButton, | 
|---|
| 555 | QWS_ID), | 
|---|
| 556 | (MPARAM)0); | 
|---|
| 557 | } | 
|---|
| 558 |  | 
|---|
| 559 | // _Pmpf(("  Loaded menu, hwnd: 0x%lX", pmbd->hwndMenu)); | 
|---|
| 560 |  | 
|---|
| 561 | if (pmbd->hwndMenu) | 
|---|
| 562 | { | 
|---|
| 563 | // menu successfully loaded: | 
|---|
| 564 | // find out where to put it | 
|---|
| 565 | ctlDisplayButtonMenu(hwndButton, | 
|---|
| 566 | pmbd->hwndMenu); | 
|---|
| 567 | } // end if (pmbd->hwndMenu) | 
|---|
| 568 | else | 
|---|
| 569 | { | 
|---|
| 570 | // menu not loaded: | 
|---|
| 571 | // _Pmpf(("  Unsinking menu WM_BUTTON1UP 2")); | 
|---|
| 572 | pmbd->fButtonSunk = FALSE; | 
|---|
| 573 | WinSendMsg(hwndButton, | 
|---|
| 574 | BM_SETHILITE, | 
|---|
| 575 | (MPARAM)FALSE, | 
|---|
| 576 | (MPARAM)0); | 
|---|
| 577 | } | 
|---|
| 578 | } | 
|---|
| 579 | } | 
|---|
| 580 |  | 
|---|
| 581 | mrc = (MPARAM)TRUE;     // message processed | 
|---|
| 582 | break; | 
|---|
| 583 |  | 
|---|
| 584 | /* | 
|---|
| 585 | * WM_BUTTON1CLICK: | 
|---|
| 586 | *      swallow this | 
|---|
| 587 | */ | 
|---|
| 588 |  | 
|---|
| 589 | case WM_BUTTON1CLICK: | 
|---|
| 590 | mrc = (MPARAM)TRUE; | 
|---|
| 591 | break; | 
|---|
| 592 |  | 
|---|
| 593 | /* | 
|---|
| 594 | * WM_SETFOCUS: | 
|---|
| 595 | *      swallow this, the button keeps painting | 
|---|
| 596 | *      itself otherwise | 
|---|
| 597 | */ | 
|---|
| 598 |  | 
|---|
| 599 | case WM_SETFOCUS: | 
|---|
| 600 | break; | 
|---|
| 601 |  | 
|---|
| 602 | /* | 
|---|
| 603 | * WM_MENUEND: | 
|---|
| 604 | *      menu is destroyed; we get this | 
|---|
| 605 | *      because we're the owner | 
|---|
| 606 | */ | 
|---|
| 607 |  | 
|---|
| 608 | case WM_MENUEND: | 
|---|
| 609 | if ((HWND)mp2 == pmbd->hwndMenu) // V0.9.14 (2001-07-31) [umoeller] | 
|---|
| 610 | { | 
|---|
| 611 | BOOL fUnHilite = TRUE; | 
|---|
| 612 | // _Pmpf(("WM_MENUEND")); | 
|---|
| 613 | // At this point, the menu has been | 
|---|
| 614 | // destroyed already. | 
|---|
| 615 | // Since WM_BUTTON1UP handles the | 
|---|
| 616 | // default case that the user presses | 
|---|
| 617 | // the menu button a second time while | 
|---|
| 618 | // the menu is open, we only need | 
|---|
| 619 | // to handle the case that the user | 
|---|
| 620 | // c)   presses some key on the menu (ESC, menu selection) or | 
|---|
| 621 | // a)   selects a menu item (which | 
|---|
| 622 | //      dismisses the menu) or | 
|---|
| 623 | // b)   clicks anywhere else. | 
|---|
| 624 |  | 
|---|
| 625 | // Case a) if mouse button 1 is not currently down | 
|---|
| 626 | if ((WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000) == 0) | 
|---|
| 627 | // button 1 _not_ down: | 
|---|
| 628 | // must be keyboard | 
|---|
| 629 | fUnHilite = TRUE; | 
|---|
| 630 | else | 
|---|
| 631 | // button 1 _is_ down: | 
|---|
| 632 | // query window under mouse pointer | 
|---|
| 633 | ; | 
|---|
| 634 |  | 
|---|
| 635 | if (fUnHilite) | 
|---|
| 636 | { | 
|---|
| 637 | // _Pmpf(("  Unsinking menu WM_MENUEND")); | 
|---|
| 638 | pmbd->fButtonSunk = FALSE; | 
|---|
| 639 | WinSendMsg(hwndButton, | 
|---|
| 640 | BM_SETHILITE, | 
|---|
| 641 | (MPARAM)FALSE, | 
|---|
| 642 | (MPARAM)0); | 
|---|
| 643 | } | 
|---|
| 644 | pmbd->hwndMenu = NULLHANDLE; | 
|---|
| 645 | } // end if ((HWND)mp1 == pmbd->pmbd->hwndMenu) // V0.9.14 (2001-07-31) [umoeller] | 
|---|
| 646 | break; | 
|---|
| 647 |  | 
|---|
| 648 | /* | 
|---|
| 649 | * WM_COMMAND: | 
|---|
| 650 | *      this must be from the menu, so | 
|---|
| 651 | *      forward this to the button's owner | 
|---|
| 652 | */ | 
|---|
| 653 |  | 
|---|
| 654 | case WM_COMMAND: | 
|---|
| 655 | WinPostMsg(WinQueryWindow(hwndButton, QW_OWNER), | 
|---|
| 656 | msg, | 
|---|
| 657 | mp1, | 
|---|
| 658 | mp2); | 
|---|
| 659 | break; | 
|---|
| 660 |  | 
|---|
| 661 | /* | 
|---|
| 662 | * WM_DESTROY: | 
|---|
| 663 | *      clean up allocated data | 
|---|
| 664 | */ | 
|---|
| 665 |  | 
|---|
| 666 | case WM_DESTROY: | 
|---|
| 667 | mrc = pmbd->pfnwpButtonOriginal(hwndButton, msg, mp1, mp2); | 
|---|
| 668 | free(pmbd); | 
|---|
| 669 | break; | 
|---|
| 670 |  | 
|---|
| 671 | default: | 
|---|
| 672 | mrc = pmbd->pfnwpButtonOriginal(hwndButton, msg, mp1, mp2); | 
|---|
| 673 | } | 
|---|
| 674 |  | 
|---|
| 675 | return mrc; | 
|---|
| 676 | } | 
|---|
| 677 |  | 
|---|
| 678 | /* | 
|---|
| 679 | *@@ ctlMakeMenuButton: | 
|---|
| 680 | *      this turns the specified button into a "menu button", | 
|---|
| 681 | *      which shows a popup menu when the button is depressed. | 
|---|
| 682 | *      This is done by subclassing the menu button with | 
|---|
| 683 | *      ctl_fnwpSubclassedMenuButton. | 
|---|
| 684 | * | 
|---|
| 685 | *      Simply call this function upon any button, and it'll | 
|---|
| 686 | *      turn in to a menu button. | 
|---|
| 687 | * | 
|---|
| 688 | *      When the user presses the button, the specified menu | 
|---|
| 689 | *      is loaded from the resources. The button will then | 
|---|
| 690 | *      be set as the owner, but it will forward all WM_COMMAND | 
|---|
| 691 | *      messages from the menu to its own owner (probably your | 
|---|
| 692 | *      dialog), so you can handle WM_COMMAND messages just as | 
|---|
| 693 | *      if the menu was owned by your dialog. | 
|---|
| 694 | * | 
|---|
| 695 | *      Alternatively, if you don't want to load a menu from | 
|---|
| 696 | *      the resources, you can specify idMenu == 0. In that case, | 
|---|
| 697 | *      when the menu button is pressed, it sends (!) a WM_COMMAND | 
|---|
| 698 | *      message to its owner with its ID in mp1 (as usual). The | 
|---|
| 699 | *      difference is that the return value from that message will | 
|---|
| 700 | *      be interpreted as a menu handle (HWND) to use for the button | 
|---|
| 701 | *      menu. | 
|---|
| 702 | * | 
|---|
| 703 | *      The subclassed button also handles menu destruction etc. | 
|---|
| 704 | *      by itself. | 
|---|
| 705 | * | 
|---|
| 706 | *@@added V0.9.0 [umoeller] | 
|---|
| 707 | */ | 
|---|
| 708 |  | 
|---|
| 709 | BOOL ctlMakeMenuButton(HWND hwndButton,      // in: button to subclass | 
|---|
| 710 | HMODULE hmodMenu,     // in: resource module (can be NULLHANDLE for | 
|---|
| 711 | // current EXE) | 
|---|
| 712 | ULONG idMenu)         // in: resource menu ID (or 0) | 
|---|
| 713 | { | 
|---|
| 714 | BOOL brc = FALSE; | 
|---|
| 715 | PMENUBUTTONDATA pmbd; | 
|---|
| 716 | if (pmbd = (PMENUBUTTONDATA)malloc(sizeof(MENUBUTTONDATA))) | 
|---|
| 717 | { | 
|---|
| 718 | memset(pmbd, 0, sizeof(MENUBUTTONDATA)); | 
|---|
| 719 | if (pmbd->pfnwpButtonOriginal = WinSubclassWindow(hwndButton, | 
|---|
| 720 | ctl_fnwpSubclassedMenuButton)) | 
|---|
| 721 | { | 
|---|
| 722 | pmbd->hmodMenu = hmodMenu; | 
|---|
| 723 | pmbd->idMenu = idMenu; | 
|---|
| 724 | WinSetWindowULong(hwndButton, QWL_USER, (ULONG)pmbd); | 
|---|
| 725 | brc = TRUE; | 
|---|
| 726 | } | 
|---|
| 727 | else | 
|---|
| 728 | free(pmbd); | 
|---|
| 729 | } | 
|---|
| 730 |  | 
|---|
| 731 | return brc; | 
|---|
| 732 | } | 
|---|
| 733 |  | 
|---|
| 734 | /* | 
|---|
| 735 | *@@category: Helpers\PM helpers\Window classes\Static bitmaps | 
|---|
| 736 | *      See comctl.c and ctl_fnwpBitmapStatic. | 
|---|
| 737 | */ | 
|---|
| 738 |  | 
|---|
| 739 | /* ****************************************************************** | 
|---|
| 740 | * | 
|---|
| 741 | *   Subclassed Static Bitmap Control | 
|---|
| 742 | * | 
|---|
| 743 | ********************************************************************/ | 
|---|
| 744 |  | 
|---|
| 745 | /* | 
|---|
| 746 | *@@ ctl_fnwpBitmapStatic: | 
|---|
| 747 | *      subclassed wnd proc for both static controls which | 
|---|
| 748 | *      should display icons and stretched bitmaps. | 
|---|
| 749 | * | 
|---|
| 750 | *      This is not a stand-alone window procedure, but must only | 
|---|
| 751 | *      be used with static controls subclassed by the functions | 
|---|
| 752 | *      listed below. | 
|---|
| 753 | * | 
|---|
| 754 | *      This is now (V0.9.0) used in two contexts: | 
|---|
| 755 | *      --  when subclassed from ctlPrepareStaticIcon, | 
|---|
| 756 | *          this displays transparent icons properly | 
|---|
| 757 | *          (for regular icons or icon animations); | 
|---|
| 758 | *      --  when subclassed from ctlPrepareStretchedBitmap, | 
|---|
| 759 | *          this displays a stretched bitmap. | 
|---|
| 760 | * | 
|---|
| 761 | *      The behavior depends on ANIMATIONDATA.ulFlags, | 
|---|
| 762 | *      which is set by both of these functions (either to | 
|---|
| 763 | *      ANF_ICON or ANF_BITMAP). | 
|---|
| 764 | * | 
|---|
| 765 | *      Only one msg is of interest to the "user" application | 
|---|
| 766 | *      of this control, which is SM_SETHANDLE, | 
|---|
| 767 | *      the normal message sent to a static icon control to change | 
|---|
| 768 | *      its icon or bitmap. | 
|---|
| 769 | *      The new handle (HPOINTER or HBITMAP) is | 
|---|
| 770 | *      in mp1; mp2 must be null. | 
|---|
| 771 | * | 
|---|
| 772 | *      Depending on ANIMATIONDATA.ulFlags, we do the following: | 
|---|
| 773 | * | 
|---|
| 774 | *      --  ANF_ICON:  Unfortunately, the | 
|---|
| 775 | *          standard static control paints garbage if | 
|---|
| 776 | *          the icons contain transparent areas, and the | 
|---|
| 777 | *          display often flickers too. | 
|---|
| 778 | *          We improve this by creating one bitmap from | 
|---|
| 779 | *          the icon that we were given which we can then | 
|---|
| 780 | *          simply copy to the screen in one step in | 
|---|
| 781 | *          WM_PAINT. | 
|---|
| 782 | * | 
|---|
| 783 | *      --  ANF_BITMAP: we create a bitmap which is | 
|---|
| 784 | *          stretched to the size of the static control, | 
|---|
| 785 | *          using gpihStretchBitmap. | 
|---|
| 786 | * | 
|---|
| 787 | *      In any case, a new bitmap is produced internally and | 
|---|
| 788 | *      stored so that it can easily be painted when WM_PAINT | 
|---|
| 789 | *      comes in. The source icon/bitmap can therefore | 
|---|
| 790 | *      be safely destroyed by the caller after sending | 
|---|
| 791 | *      SM_SETHANDLE. This bitmap is automatically deleted when | 
|---|
| 792 | *      the window is destroyed. | 
|---|
| 793 | * | 
|---|
| 794 | *@@changed V0.9.0 [umoeller]: function renamed | 
|---|
| 795 | *@@changed V0.9.0 [umoeller]: added support for stretched bitmaps | 
|---|
| 796 | *@@changed V0.9.0 [umoeller]: added halftoned display for WS_DISABLED | 
|---|
| 797 | *@@changed V0.9.0 [umoeller]: exported gpihIcon2Bitmap function to gpih.c | 
|---|
| 798 | *@@changed V0.9.0 [umoeller]: fixed paint errors when SM_SETHANDLE had NULL argument in mp1 | 
|---|
| 799 | *@@changed V0.9.16 (2001-10-15) [umoeller]: now centering icon in static properly | 
|---|
| 800 | *@@changed V0.9.16 (2001-10-15) [umoeller]: this always used the presparam colors of the parent instead of its own ones | 
|---|
| 801 | */ | 
|---|
| 802 |  | 
|---|
| 803 | MRESULT EXPENTRY ctl_fnwpBitmapStatic(HWND hwndStatic, ULONG msg, MPARAM mp1, MPARAM mp2) | 
|---|
| 804 | { | 
|---|
| 805 | PANIMATIONDATA pa = (PANIMATIONDATA)WinQueryWindowULong(hwndStatic, QWL_USER); | 
|---|
| 806 | // animation data which was stored in window words | 
|---|
| 807 |  | 
|---|
| 808 | PFNWP   OldStaticProc = NULL; | 
|---|
| 809 | MRESULT mrc = NULL; | 
|---|
| 810 |  | 
|---|
| 811 | if (pa) | 
|---|
| 812 | { | 
|---|
| 813 | OldStaticProc = pa->OldStaticProc; | 
|---|
| 814 |  | 
|---|
| 815 | switch(msg) | 
|---|
| 816 | { | 
|---|
| 817 | /* | 
|---|
| 818 | * WM_TIMER: | 
|---|
| 819 | *      this timer is started by the ctl* funcs | 
|---|
| 820 | *      below. Proceed to the next animation step. | 
|---|
| 821 | * | 
|---|
| 822 | *      Note: this timer is only used with | 
|---|
| 823 | *      ANF_ICON, and even then, it | 
|---|
| 824 | *      is not necessarily running. | 
|---|
| 825 | */ | 
|---|
| 826 |  | 
|---|
| 827 | case WM_TIMER: | 
|---|
| 828 | pa->usAniCurrent++; | 
|---|
| 829 | if (pa->usAniCurrent >= pa->usAniCount) | 
|---|
| 830 | pa->usAniCurrent = 0; | 
|---|
| 831 |  | 
|---|
| 832 | WinSendMsg(hwndStatic, | 
|---|
| 833 | SM_SETHANDLE, | 
|---|
| 834 | (MPARAM)pa->ahptrAniIcons[pa->usAniCurrent], | 
|---|
| 835 | (MPARAM)NULL); | 
|---|
| 836 | break; | 
|---|
| 837 |  | 
|---|
| 838 | /* | 
|---|
| 839 | * SM_SETHANDLE: | 
|---|
| 840 | * | 
|---|
| 841 | */ | 
|---|
| 842 |  | 
|---|
| 843 | case SM_SETHANDLE: | 
|---|
| 844 | { | 
|---|
| 845 | HDC hdcMem; | 
|---|
| 846 | HPS hpsMem; | 
|---|
| 847 | SIZEL szlPage; | 
|---|
| 848 |  | 
|---|
| 849 | LONG lBkgndColor | 
|---|
| 850 | /* = winhQueryPresColor(WinQueryWindow(hwndStatic, QW_PARENT), | 
|---|
| 851 | PP_BACKGROUNDCOLOR, | 
|---|
| 852 | FALSE, | 
|---|
| 853 | SYSCLR_DIALOGBACKGROUND); */ | 
|---|
| 854 | // fixed this... V0.9.16 (2001-10-15) [umoeller] | 
|---|
| 855 | = winhQueryPresColor(hwndStatic, | 
|---|
| 856 | PP_BACKGROUNDCOLOR, | 
|---|
| 857 | TRUE, | 
|---|
| 858 | SYSCLR_DIALOGBACKGROUND); | 
|---|
| 859 |  | 
|---|
| 860 | HPS hps = WinGetPS(hwndStatic); | 
|---|
| 861 |  | 
|---|
| 862 | // if we have created bitmaps previously, delete them | 
|---|
| 863 | if (pa->hbm) | 
|---|
| 864 | { | 
|---|
| 865 | GpiDeleteBitmap(pa->hbm); | 
|---|
| 866 | pa->hbm = NULLHANDLE; | 
|---|
| 867 | } | 
|---|
| 868 | if (pa->hbmHalftoned) | 
|---|
| 869 | { | 
|---|
| 870 | GpiDeleteBitmap(pa->hbmHalftoned); | 
|---|
| 871 | pa->hbmHalftoned = NULLHANDLE; | 
|---|
| 872 | } | 
|---|
| 873 |  | 
|---|
| 874 | // switch to RGB mode | 
|---|
| 875 | gpihSwitchToRGB(hps); | 
|---|
| 876 |  | 
|---|
| 877 | // create a memory PS | 
|---|
| 878 | szlPage.cx = pa->rclIcon.xRight - pa->rclIcon.xLeft; | 
|---|
| 879 | szlPage.cy = pa->rclIcon.yTop - pa->rclIcon.yBottom; | 
|---|
| 880 | if (gpihCreateMemPS(pa->hab, | 
|---|
| 881 | &szlPage, | 
|---|
| 882 | &hdcMem, | 
|---|
| 883 | &hpsMem)) | 
|---|
| 884 | { | 
|---|
| 885 | // switch the memory PS to RGB mode too | 
|---|
| 886 | gpihSwitchToRGB(hpsMem); | 
|---|
| 887 |  | 
|---|
| 888 | // create a suitable bitmap w/ the size of the | 
|---|
| 889 | // static control | 
|---|
| 890 | if (    ((pa->hbm = gpihCreateBitmap(hpsMem, | 
|---|
| 891 | szlPage.cx, | 
|---|
| 892 | szlPage.cy))) | 
|---|
| 893 | // associate the bit map with the memory PS | 
|---|
| 894 | && (GpiSetBitmap(hpsMem, pa->hbm) != HBM_ERROR) | 
|---|
| 895 | ) | 
|---|
| 896 | { | 
|---|
| 897 | // fill the bitmap with the current static | 
|---|
| 898 | // background color | 
|---|
| 899 | POINTL ptl = {0, 0}; | 
|---|
| 900 | GpiMove(hpsMem, &ptl); | 
|---|
| 901 | ptl.x = pa->rclIcon.xRight; | 
|---|
| 902 | ptl.y = pa->rclIcon.yTop; | 
|---|
| 903 | GpiSetColor(hpsMem, | 
|---|
| 904 | lBkgndColor); | 
|---|
| 905 | GpiBox(hpsMem, | 
|---|
| 906 | DRO_FILL, // interior only | 
|---|
| 907 | &ptl, | 
|---|
| 908 | 0, 0);    // no corner rounding | 
|---|
| 909 |  | 
|---|
| 910 | /* | 
|---|
| 911 | * ANF_ICON: | 
|---|
| 912 | * | 
|---|
| 913 | */ | 
|---|
| 914 |  | 
|---|
| 915 | if (pa->ulFlags & ANF_ICON) | 
|---|
| 916 | { | 
|---|
| 917 | // store new icon in our own structure | 
|---|
| 918 | if (pa->hptr = (HPOINTER)mp1) | 
|---|
| 919 | { | 
|---|
| 920 | // center the icon in the bitmap | 
|---|
| 921 | // V0.9.16 (2001-10-15) [umoeller] | 
|---|
| 922 |  | 
|---|
| 923 | // replaced call V0.9.19 (2002-06-18) [umoeller] | 
|---|
| 924 | gpihDrawPointer(hpsMem, | 
|---|
| 925 | (   (pa->rclIcon.xRight - pa->rclIcon.xLeft) | 
|---|
| 926 | - pa->szlIcon.cx | 
|---|
| 927 | ) / 2, | 
|---|
| 928 | (   (pa->rclIcon.yTop - pa->rclIcon.yBottom) | 
|---|
| 929 | - pa->szlIcon.cy | 
|---|
| 930 | ) / 2, | 
|---|
| 931 | pa->hptr, | 
|---|
| 932 | &pa->szlIcon, | 
|---|
| 933 | NULL,       // no clipping | 
|---|
| 934 | 0);         // no mini | 
|---|
| 935 | } | 
|---|
| 936 |  | 
|---|
| 937 | } // end if (pa->ulFlags & ANF_ICON) | 
|---|
| 938 |  | 
|---|
| 939 | /* | 
|---|
| 940 | * ANF_BITMAP: | 
|---|
| 941 | * | 
|---|
| 942 | */ | 
|---|
| 943 |  | 
|---|
| 944 | else if (pa->ulFlags & ANF_BITMAP) | 
|---|
| 945 | { | 
|---|
| 946 | // store passed bitmap | 
|---|
| 947 | HBITMAP     hbmSource; | 
|---|
| 948 | if (hbmSource = (HBITMAP)mp1) | 
|---|
| 949 | gpihStretchBitmap(hpsMem,       // target | 
|---|
| 950 | hbmSource,    // source | 
|---|
| 951 | NULL,     // use size of bitmap | 
|---|
| 952 | &pa->rclIcon, | 
|---|
| 953 | ((pa->ulFlags & ANF_PROPORTIONAL) | 
|---|
| 954 | != 0)); | 
|---|
| 955 |  | 
|---|
| 956 | } // end if (pa->ulFlags & ANF_BITMAP) | 
|---|
| 957 |  | 
|---|
| 958 | } // end if (GpiSetBitmap(... | 
|---|
| 959 | // && (pa->hbm = gpihCreateBitmap(hpsMem, &(pa->rclIcon))) | 
|---|
| 960 |  | 
|---|
| 961 | // in any case, clean up now | 
|---|
| 962 | GpiDestroyPS(hpsMem); | 
|---|
| 963 | DevCloseDC(hdcMem); | 
|---|
| 964 | } // end if (gpihCreateMemPS(hab, &hdcMem, &hpsMem)) | 
|---|
| 965 |  | 
|---|
| 966 | WinReleasePS(hps); | 
|---|
| 967 |  | 
|---|
| 968 | // enforce WM_PAINT | 
|---|
| 969 | WinInvalidateRect(hwndStatic, NULL, FALSE); | 
|---|
| 970 | } | 
|---|
| 971 | break; | 
|---|
| 972 |  | 
|---|
| 973 | /* | 
|---|
| 974 | * WM_PAINT: | 
|---|
| 975 | *      "normal" paint; this only arrives here if the | 
|---|
| 976 | *      icon needs to be repainted. We simply paint | 
|---|
| 977 | *      the bitmap we created in WM_SETHANDLE. | 
|---|
| 978 | */ | 
|---|
| 979 |  | 
|---|
| 980 | case WM_PAINT: | 
|---|
| 981 | { | 
|---|
| 982 | RECTL rcl; | 
|---|
| 983 | HPS hps = WinBeginPaint(hwndStatic, NULLHANDLE, &rcl); | 
|---|
| 984 | POINTL ptl = {0, 0}; | 
|---|
| 985 |  | 
|---|
| 986 | if (pa->hbm) | 
|---|
| 987 | { | 
|---|
| 988 | if (WinQueryWindowULong(hwndStatic, QWL_STYLE) | 
|---|
| 989 | & WS_DISABLED) | 
|---|
| 990 | { | 
|---|
| 991 | // if the control is currently disabled, | 
|---|
| 992 | // draw in half-toned (grayed) | 
|---|
| 993 |  | 
|---|
| 994 | LONG lBkgndColor = winhQueryPresColor( | 
|---|
| 995 | WinQueryWindow(hwndStatic, QW_PARENT), | 
|---|
| 996 | PP_BACKGROUNDCOLOR, | 
|---|
| 997 | FALSE, | 
|---|
| 998 | SYSCLR_DIALOGBACKGROUND); | 
|---|
| 999 |  | 
|---|
| 1000 | // 1) check if we created the half-tone | 
|---|
| 1001 | // bitmap already (WinDrawBitmap doesn't | 
|---|
| 1002 | // work with half-toned color bitmaps, so | 
|---|
| 1003 | // here's yet another thing we have to do | 
|---|
| 1004 | // all alone) | 
|---|
| 1005 | if (pa->hbmHalftoned == NULLHANDLE) | 
|---|
| 1006 | pa->hbmHalftoned = gpihCreateHalftonedBitmap(pa->hab, | 
|---|
| 1007 | pa->hbm, | 
|---|
| 1008 | lBkgndColor); | 
|---|
| 1009 |  | 
|---|
| 1010 | if (pa->hbmHalftoned) | 
|---|
| 1011 | WinDrawBitmap(hps, | 
|---|
| 1012 | pa->hbmHalftoned, | 
|---|
| 1013 | NULL,     // whole bmp | 
|---|
| 1014 | &ptl,     // lower left corner | 
|---|
| 1015 | 0, 0,     // no colors | 
|---|
| 1016 | DBM_NORMAL); | 
|---|
| 1017 | } | 
|---|
| 1018 | else | 
|---|
| 1019 | { | 
|---|
| 1020 | // not disabled: draw regular bitmap | 
|---|
| 1021 | // we created previously | 
|---|
| 1022 | // draw the bitmap that we created previously | 
|---|
| 1023 | WinDrawBitmap(hps, | 
|---|
| 1024 | pa->hbm, | 
|---|
| 1025 | NULL,     // whole bmp | 
|---|
| 1026 | &ptl,     // lower left corner | 
|---|
| 1027 | 0, 0,     // no colors | 
|---|
| 1028 | DBM_NORMAL); | 
|---|
| 1029 | } | 
|---|
| 1030 | } | 
|---|
| 1031 |  | 
|---|
| 1032 | WinEndPaint(hps); | 
|---|
| 1033 | } | 
|---|
| 1034 | break; | 
|---|
| 1035 |  | 
|---|
| 1036 | /* | 
|---|
| 1037 | * WM_DESTROY: | 
|---|
| 1038 | *      clean up. | 
|---|
| 1039 | */ | 
|---|
| 1040 |  | 
|---|
| 1041 | case WM_DESTROY: | 
|---|
| 1042 | // undo subclassing in case more WM_TIMERs come in | 
|---|
| 1043 | WinSubclassWindow(hwndStatic, OldStaticProc); | 
|---|
| 1044 |  | 
|---|
| 1045 | if (pa->hbm) | 
|---|
| 1046 | GpiDeleteBitmap(pa->hbm); | 
|---|
| 1047 | if (pa->hbmHalftoned) | 
|---|
| 1048 | GpiDeleteBitmap(pa->hbm); | 
|---|
| 1049 |  | 
|---|
| 1050 | // clean up ANIMATIONDATA struct | 
|---|
| 1051 | WinSetWindowULong(hwndStatic, QWL_USER, (ULONG)NULL); | 
|---|
| 1052 | free(pa); | 
|---|
| 1053 |  | 
|---|
| 1054 | mrc = OldStaticProc(hwndStatic, msg, mp1, mp2); | 
|---|
| 1055 | break; | 
|---|
| 1056 |  | 
|---|
| 1057 | default: | 
|---|
| 1058 | mrc = OldStaticProc(hwndStatic, msg, mp1, mp2); | 
|---|
| 1059 | } | 
|---|
| 1060 | } | 
|---|
| 1061 | return mrc; | 
|---|
| 1062 | } | 
|---|
| 1063 |  | 
|---|
| 1064 | /* ****************************************************************** | 
|---|
| 1065 | * | 
|---|
| 1066 | *   Icon animation | 
|---|
| 1067 | * | 
|---|
| 1068 | ********************************************************************/ | 
|---|
| 1069 |  | 
|---|
| 1070 | /* | 
|---|
| 1071 | *@@ CreateAnimationData: | 
|---|
| 1072 | * | 
|---|
| 1073 | *@@added V0.9.16 (2001-10-15) [umoeller] | 
|---|
| 1074 | */ | 
|---|
| 1075 |  | 
|---|
| 1076 | STATIC PANIMATIONDATA CreateAnimationData(HAB hab, | 
|---|
| 1077 | HWND hwndStatic, | 
|---|
| 1078 | USHORT cAnimations) | 
|---|
| 1079 | { | 
|---|
| 1080 | PANIMATIONDATA pa = NULL; | 
|---|
| 1081 |  | 
|---|
| 1082 | if (cAnimations >= 1) | 
|---|
| 1083 | { | 
|---|
| 1084 | // create the ANIMATIONDATA structure, | 
|---|
| 1085 | // initialize some fields, | 
|---|
| 1086 | // and store it in QWL_USER of the static control | 
|---|
| 1087 | ULONG   cbStruct =   sizeof(ANIMATIONDATA) | 
|---|
| 1088 | + ((cAnimations - 1) * sizeof(HPOINTER)); | 
|---|
| 1089 |  | 
|---|
| 1090 | if (pa = (PANIMATIONDATA)malloc(cbStruct)) | 
|---|
| 1091 | { | 
|---|
| 1092 | memset(pa, 0, cbStruct); | 
|---|
| 1093 |  | 
|---|
| 1094 | WinSetWindowULong(hwndStatic, QWL_USER, (ULONG)pa); | 
|---|
| 1095 |  | 
|---|
| 1096 | pa->hab = hab; | 
|---|
| 1097 | WinQueryWindowRect(hwndStatic, &pa->rclIcon); | 
|---|
| 1098 | pa->OldStaticProc = WinSubclassWindow(hwndStatic, ctl_fnwpBitmapStatic); | 
|---|
| 1099 | pa->szlIcon.cx = WinQuerySysValue(HWND_DESKTOP, SV_CXICON); | 
|---|
| 1100 | pa->szlIcon.cy = WinQuerySysValue(HWND_DESKTOP, SV_CYICON); | 
|---|
| 1101 | } | 
|---|
| 1102 | } | 
|---|
| 1103 |  | 
|---|
| 1104 | return pa; | 
|---|
| 1105 | } | 
|---|
| 1106 |  | 
|---|
| 1107 | /* | 
|---|
| 1108 | *@@ ctlPrepareStaticIcon: | 
|---|
| 1109 | *      turns a static control into one which properly | 
|---|
| 1110 | *      displays transparent icons when given a | 
|---|
| 1111 | *      SM_SETHANDLE msg. | 
|---|
| 1112 | *      This is done by subclassing the static control | 
|---|
| 1113 | *      with ctl_fnwpBitmapStatic. | 
|---|
| 1114 | * | 
|---|
| 1115 | *      This function gets called automatically by | 
|---|
| 1116 | *      ctlPrepareAnimation, so you need not call it | 
|---|
| 1117 | *      independently for animations. See the notes there | 
|---|
| 1118 | *      how this can be done. | 
|---|
| 1119 | * | 
|---|
| 1120 | *      You can, however, call this function if you | 
|---|
| 1121 | *      have some static control with transparent icons | 
|---|
| 1122 | *      which is not animated but changes sometimes | 
|---|
| 1123 | *      (because you have the same repaint problems there). | 
|---|
| 1124 | * | 
|---|
| 1125 | *      This func does _not_ start an animation yet. | 
|---|
| 1126 | * | 
|---|
| 1127 | *      To change the icon being displayed, send the control | 
|---|
| 1128 | *      a SM_SETHANDLE msg with the icon handle in (HPOINTER)mp1. | 
|---|
| 1129 | * | 
|---|
| 1130 | *      Returns a PANIMATIONDATA if subclassing succeeded or | 
|---|
| 1131 | *      NULL upon errors. If you only call this function, you | 
|---|
| 1132 | *      do not need this structure; it is needed by | 
|---|
| 1133 | *      ctlPrepareAnimation though. | 
|---|
| 1134 | * | 
|---|
| 1135 | *      The subclassed static icon func above automatically | 
|---|
| 1136 | *      cleans up resources, so you don't have to worry about | 
|---|
| 1137 | *      that either. | 
|---|
| 1138 | * | 
|---|
| 1139 | *@@changed V0.9.0 [umoeller]: adjusted for ctl_fnwpBitmapStatic changes | 
|---|
| 1140 | */ | 
|---|
| 1141 |  | 
|---|
| 1142 | PANIMATIONDATA ctlPrepareStaticIcon(HWND hwndStatic, | 
|---|
| 1143 | USHORT usAnimCount) // needed for allocating extra memory, | 
|---|
| 1144 | // this must be at least 1 | 
|---|
| 1145 | { | 
|---|
| 1146 | PANIMATIONDATA pa; | 
|---|
| 1147 | HAB     hab; | 
|---|
| 1148 | if (    (hwndStatic) | 
|---|
| 1149 | && (hab = WinQueryAnchorBlock(hwndStatic)) | 
|---|
| 1150 | && (WinIsWindow(hab, hwndStatic)) | 
|---|
| 1151 | && (pa = CreateAnimationData(hab, | 
|---|
| 1152 | hwndStatic, | 
|---|
| 1153 | usAnimCount)) | 
|---|
| 1154 | ) | 
|---|
| 1155 | { | 
|---|
| 1156 | // switch static to icon mode | 
|---|
| 1157 | pa->ulFlags = ANF_ICON; | 
|---|
| 1158 | return (pa); | 
|---|
| 1159 | } | 
|---|
| 1160 |  | 
|---|
| 1161 | return NULL; | 
|---|
| 1162 | } | 
|---|
| 1163 |  | 
|---|
| 1164 | /* | 
|---|
| 1165 | *@@ ctlPrepareAnimation: | 
|---|
| 1166 | *      this function turns a regular static icon | 
|---|
| 1167 | *      control an animated one. This is the one-shot | 
|---|
| 1168 | *      function for animating static icon controls. | 
|---|
| 1169 | * | 
|---|
| 1170 | *      It calls ctlPrepareStaticIcon first, then uses | 
|---|
| 1171 | *      the passed parameters to prepare an animation: | 
|---|
| 1172 | * | 
|---|
| 1173 | *      pahptr must point to an array of HPOINTERs | 
|---|
| 1174 | *      which must contain usAnimCount icon handles. | 
|---|
| 1175 | *      If (fStartAnimation == TRUE), the animation | 
|---|
| 1176 | *      is started already. Otherwise you'll have | 
|---|
| 1177 | *      to call ctlStartAnimation yourself. | 
|---|
| 1178 | * | 
|---|
| 1179 | *      To create an animated icon, simply create a static | 
|---|
| 1180 | *      control with the dialog editor (can be any static, | 
|---|
| 1181 | *      e.g. a text control). Then do the following in your code: | 
|---|
| 1182 | * | 
|---|
| 1183 | *      1) load the dlg box template (using WinLoadDlg); | 
|---|
| 1184 | * | 
|---|
| 1185 | *      2) load all the icons for the animation in an array of | 
|---|
| 1186 | *         HPOINTERs (check xsdLoadAnimation in shutdown.c for an | 
|---|
| 1187 | *         example); | 
|---|
| 1188 | * | 
|---|
| 1189 | *      3) call ctlPrepareAnimation, e.g.: | 
|---|
| 1190 | +             ctlPrepareAnimation(WinWindowFromID(hwndDlg, ID_ICON), // get icon hwnd | 
|---|
| 1191 | +                             8,                   // no. of icons for the anim | 
|---|
| 1192 | +                             &ahptr[0],           // ptr to first icon in the array | 
|---|
| 1193 | +                             150,                 // delay | 
|---|
| 1194 | +                             TRUE);               // start animation now | 
|---|
| 1195 | * | 
|---|
| 1196 | *      4) call WinProcessDlg(hwndDlg); | 
|---|
| 1197 | * | 
|---|
| 1198 | *      5) stop the animation, e.g.: | 
|---|
| 1199 | +              ctlStopAnimation(WinWindowFromID(hwndDlg, ID_ICON)); | 
|---|
| 1200 | * | 
|---|
| 1201 | *      6) destroy the dlg window; | 
|---|
| 1202 | * | 
|---|
| 1203 | *      7) free all the HPOINTERS loaded above (check xsdFreeAnimation | 
|---|
| 1204 | *         in shutdown.c for an example). | 
|---|
| 1205 | * | 
|---|
| 1206 | *      When the icon control is destroyed, the | 
|---|
| 1207 | *      subclassed window proc (ctl_fnwpBitmapStatic) | 
|---|
| 1208 | *      automatically cleans up resources. However, | 
|---|
| 1209 | *      the icons in *pahptr are not freed. | 
|---|
| 1210 | */ | 
|---|
| 1211 |  | 
|---|
| 1212 | BOOL ctlPrepareAnimation(HWND hwndStatic,   // icon hwnd | 
|---|
| 1213 | USHORT usAnimCount,         // no. of anim steps | 
|---|
| 1214 | HPOINTER *pahptr,           // array of HPOINTERs | 
|---|
| 1215 | ULONG ulDelay,              // delay per anim step (in ms) | 
|---|
| 1216 | BOOL fStartAnimation)       // TRUE: start animation now | 
|---|
| 1217 | { | 
|---|
| 1218 | PANIMATIONDATA paNew; | 
|---|
| 1219 | if (paNew = ctlPrepareStaticIcon(hwndStatic, usAnimCount)) | 
|---|
| 1220 | { | 
|---|
| 1221 | paNew->ulDelay = ulDelay; | 
|---|
| 1222 | // paNew->OldStaticProc already set | 
|---|
| 1223 | paNew->hptr = NULLHANDLE; | 
|---|
| 1224 | // paNew->rclIcon already set | 
|---|
| 1225 | paNew->usAniCurrent = 0; | 
|---|
| 1226 | paNew->usAniCount = usAnimCount; | 
|---|
| 1227 | memcpy(&paNew->ahptrAniIcons, | 
|---|
| 1228 | pahptr, | 
|---|
| 1229 | (usAnimCount * sizeof(HPOINTER))); | 
|---|
| 1230 |  | 
|---|
| 1231 | if (fStartAnimation) | 
|---|
| 1232 | { | 
|---|
| 1233 | WinStartTimer(paNew->hab, | 
|---|
| 1234 | hwndStatic, | 
|---|
| 1235 | 1, | 
|---|
| 1236 | ulDelay); | 
|---|
| 1237 | WinPostMsg(hwndStatic, WM_TIMER, (MPARAM)1, NULL); | 
|---|
| 1238 | } | 
|---|
| 1239 | } | 
|---|
| 1240 |  | 
|---|
| 1241 | return (paNew != NULL); | 
|---|
| 1242 | } | 
|---|
| 1243 |  | 
|---|
| 1244 | /* | 
|---|
| 1245 | *@@ ctlStartAnimation: | 
|---|
| 1246 | *      starts an animation that not currently running. You | 
|---|
| 1247 | *      must prepare the animation by calling ctlPrepareAnimation | 
|---|
| 1248 | *      first. | 
|---|
| 1249 | */ | 
|---|
| 1250 |  | 
|---|
| 1251 | BOOL ctlStartAnimation(HWND hwndStatic) | 
|---|
| 1252 | { | 
|---|
| 1253 | BOOL brc = FALSE; | 
|---|
| 1254 | PANIMATIONDATA pa; | 
|---|
| 1255 | if (    (pa = (PANIMATIONDATA)WinQueryWindowULong(hwndStatic, QWL_USER)) | 
|---|
| 1256 | && (WinStartTimer(pa->hab, | 
|---|
| 1257 | hwndStatic, | 
|---|
| 1258 | 1, | 
|---|
| 1259 | pa->ulDelay)) | 
|---|
| 1260 | ) | 
|---|
| 1261 | { | 
|---|
| 1262 | brc = TRUE; | 
|---|
| 1263 | WinPostMsg(hwndStatic, WM_TIMER, (MPARAM)1, NULL); | 
|---|
| 1264 | } | 
|---|
| 1265 |  | 
|---|
| 1266 | return brc; | 
|---|
| 1267 | } | 
|---|
| 1268 |  | 
|---|
| 1269 | /* | 
|---|
| 1270 | *@@ ctlStopAnimation: | 
|---|
| 1271 | *      stops an animation that is currently running. | 
|---|
| 1272 | *      This does not free any resources. | 
|---|
| 1273 | */ | 
|---|
| 1274 |  | 
|---|
| 1275 | BOOL ctlStopAnimation(HWND hwndStatic) | 
|---|
| 1276 | { | 
|---|
| 1277 | return (WinStopTimer(WinQueryAnchorBlock(hwndStatic), hwndStatic, 1)); | 
|---|
| 1278 | } | 
|---|
| 1279 |  | 
|---|
| 1280 | /* | 
|---|
| 1281 | *@@category: Helpers\PM helpers\Window classes\Stretched bitmaps | 
|---|
| 1282 | *      See comctl.c and ctlPrepareStretchedBitmap. | 
|---|
| 1283 | */ | 
|---|
| 1284 |  | 
|---|
| 1285 | /* ****************************************************************** | 
|---|
| 1286 | * | 
|---|
| 1287 | *   Bitmap functions | 
|---|
| 1288 | * | 
|---|
| 1289 | ********************************************************************/ | 
|---|
| 1290 |  | 
|---|
| 1291 | /* | 
|---|
| 1292 | *@@ ctlPrepareStretchedBitmap: | 
|---|
| 1293 | *      turns a static control into a bitmap control | 
|---|
| 1294 | *      which stretches the bitmap to the size of the | 
|---|
| 1295 | *      control when given an SM_SETHANDLE msg. | 
|---|
| 1296 | * | 
|---|
| 1297 | *      If (fPreserveProportions == TRUE), the control | 
|---|
| 1298 | *      will size the bitmap proportionally only. Otherwise, | 
|---|
| 1299 | *      it will always stretch the bitmap to the whole | 
|---|
| 1300 | *      size of the static control (possibly distorting | 
|---|
| 1301 | *      the proportions). See gpihStretchBitmap for | 
|---|
| 1302 | *      details. | 
|---|
| 1303 | * | 
|---|
| 1304 | *      This function subclasses the static control | 
|---|
| 1305 | *      with ctl_fnwpBitmapStatic, setting the flags as | 
|---|
| 1306 | *      necessary. However, this does not set the bitmap | 
|---|
| 1307 | *      to display yet. | 
|---|
| 1308 | *      To have a bitmap displayed, send the control | 
|---|
| 1309 | *      a SM_SETHANDLE message with the bitmap to be | 
|---|
| 1310 | *      displayed in (HBITMAP)mp1 after having used this | 
|---|
| 1311 | *      function. | 
|---|
| 1312 | * | 
|---|
| 1313 | *      ctl_fnwpBitmapStatic will then create a private | 
|---|
| 1314 | *      copy of that bitmap, stretched to its own size. | 
|---|
| 1315 | *      You can therefore delete the "source" bitmap | 
|---|
| 1316 | *      after sending SM_SETHANDLE. | 
|---|
| 1317 | * | 
|---|
| 1318 | *      You can also send SM_SETHANDLE several times. | 
|---|
| 1319 | *      The control will then readjust itself and delete | 
|---|
| 1320 | *      its old bitmap. | 
|---|
| 1321 | *      But note that GpiWCBitBlt is invoked on that new | 
|---|
| 1322 | *      bitmap with every new message, so this is not | 
|---|
| 1323 | *      terribly fast. | 
|---|
| 1324 | * | 
|---|
| 1325 | *      Also note that you should not resize the static | 
|---|
| 1326 | *      control after creation, because the bitmap will | 
|---|
| 1327 | *      _not_ be adjusted. | 
|---|
| 1328 | * | 
|---|
| 1329 | *      This returns a PANIMATIONDATA if subclassing succeeded or | 
|---|
| 1330 | *      NULL upon errors. You do not need to save this structure; | 
|---|
| 1331 | *      it is cleaned up automatically when the control is destroyed. | 
|---|
| 1332 | * | 
|---|
| 1333 | *@@added V0.9.0 [umoeller] | 
|---|
| 1334 | *@@changed V0.9.16 (2001-10-15) [umoeller]: some cleanup | 
|---|
| 1335 | */ | 
|---|
| 1336 |  | 
|---|
| 1337 | PANIMATIONDATA ctlPrepareStretchedBitmap(HWND hwndStatic, | 
|---|
| 1338 | BOOL fPreserveProportions) | 
|---|
| 1339 | { | 
|---|
| 1340 | PANIMATIONDATA pa; | 
|---|
| 1341 | HAB hab; | 
|---|
| 1342 | if (    (hwndStatic) | 
|---|
| 1343 | && (hab = WinQueryAnchorBlock(hwndStatic)) | 
|---|
| 1344 | && (WinIsWindow(hab, hwndStatic)) | 
|---|
| 1345 | && (pa = CreateAnimationData(hab, hwndStatic, 1)) | 
|---|
| 1346 | ) | 
|---|
| 1347 | { | 
|---|
| 1348 | // switch static to bitmap mode | 
|---|
| 1349 | pa->ulFlags = ANF_BITMAP; | 
|---|
| 1350 | if (fPreserveProportions) | 
|---|
| 1351 | pa->ulFlags |= ANF_PROPORTIONAL; | 
|---|
| 1352 | return (pa); | 
|---|
| 1353 | } | 
|---|
| 1354 |  | 
|---|
| 1355 | return NULL; | 
|---|
| 1356 | } | 
|---|
| 1357 |  | 
|---|
| 1358 | /* | 
|---|
| 1359 | *@@category: Helpers\PM helpers\Window classes\Hotkey entry field | 
|---|
| 1360 | *      See comctl.c and ctl_fnwpObjectHotkeyEntryField. | 
|---|
| 1361 | */ | 
|---|
| 1362 |  | 
|---|
| 1363 | /* ****************************************************************** | 
|---|
| 1364 | * | 
|---|
| 1365 | *   Hotkey entry field | 
|---|
| 1366 | * | 
|---|
| 1367 | ********************************************************************/ | 
|---|
| 1368 |  | 
|---|
| 1369 | /* | 
|---|
| 1370 | *@@ ctl_fnwpHotkeyEntryField: | 
|---|
| 1371 | *      this is the window proc for a subclassed entry | 
|---|
| 1372 | *      field which displays a description of a keyboard | 
|---|
| 1373 | *      combination upon receiving WM_CHAR. | 
|---|
| 1374 | * | 
|---|
| 1375 | *      Use ctlMakeHotkeyEntryField to turn any existing | 
|---|
| 1376 | *      entry field into such an "hotkey entry field". | 
|---|
| 1377 | * | 
|---|
| 1378 | *      The entry field is deleted on every WM_CHAR that | 
|---|
| 1379 | *      comes in. | 
|---|
| 1380 | * | 
|---|
| 1381 | *      For this to work, this window proc needs the | 
|---|
| 1382 | *      cooperation of its owner. Whenever a WM_CHAR | 
|---|
| 1383 | *      message is received by the entry field which | 
|---|
| 1384 | *      looks like a meaningful key or key combination | 
|---|
| 1385 | *      (some filtering is done by this func), then | 
|---|
| 1386 | *      the owner of the entry field receives a WM_CONTROL | 
|---|
| 1387 | *      message with the new EN_HOTKEY notification code | 
|---|
| 1388 | *      (see comctl.h for details). | 
|---|
| 1389 | * | 
|---|
| 1390 | *      It is then the responsibility of the owner to | 
|---|
| 1391 | *      check whether the HOTKEYNOTIFY structure pointed | 
|---|
| 1392 | *      to by WM_CONTROL's mp2 is a meaningful keyboard | 
|---|
| 1393 | *      combination. | 
|---|
| 1394 | * | 
|---|
| 1395 | *      If not, the owner must return FALSE, and the | 
|---|
| 1396 | *      entry field's contents are deleted. | 
|---|
| 1397 | * | 
|---|
| 1398 | *      If yes however, the owner must fill the szDescription | 
|---|
| 1399 | *      field with a description of the keyboard combination | 
|---|
| 1400 | *      (e.g. "Shift+Alt+C") and return TRUE. The entry field | 
|---|
| 1401 | *      will then be set to that description. | 
|---|
| 1402 | * | 
|---|
| 1403 | *@@added V0.9.1 (99-12-19) [umoeller] | 
|---|
| 1404 | *@@changed V0.9.16 (2001-12-08) [umoeller]: fixed empty entry field on tab key | 
|---|
| 1405 | */ | 
|---|
| 1406 |  | 
|---|
| 1407 | MRESULT EXPENTRY ctl_fnwpObjectHotkeyEntryField(HWND hwndEdit, ULONG msg, MPARAM mp1, MPARAM mp2) | 
|---|
| 1408 | { | 
|---|
| 1409 | MRESULT mrc = (MPARAM)FALSE; // WM_CHAR not-processed flag | 
|---|
| 1410 |  | 
|---|
| 1411 | // get object window data; this was stored in QWL_USER by | 
|---|
| 1412 | // WM_INITDLG of obj_fnwpSettingsObjDetails | 
|---|
| 1413 | // PXFOBJWINDATA   pWinData = (PXFOBJWINDATA)WinQueryWindowULong(hwndEdit, QWL_USER); | 
|---|
| 1414 | PFNWP           pfnwpOrig = (PFNWP)WinQueryWindowULong(hwndEdit, QWL_USER); | 
|---|
| 1415 |  | 
|---|
| 1416 | switch (msg) | 
|---|
| 1417 | { | 
|---|
| 1418 | case WM_CHAR: | 
|---|
| 1419 | { | 
|---|
| 1420 | /* | 
|---|
| 1421 | #define KC_CHAR                    0x0001 | 
|---|
| 1422 | #define KC_VIRTUALKEY              0x0002 | 
|---|
| 1423 | #define KC_SCANCODE                0x0004 | 
|---|
| 1424 | #define KC_SHIFT                   0x0008 | 
|---|
| 1425 | #define KC_CTRL                    0x0010 | 
|---|
| 1426 | #define KC_ALT                     0x0020 | 
|---|
| 1427 | #define KC_KEYUP                   0x0040 | 
|---|
| 1428 | #define KC_PREVDOWN                0x0080 | 
|---|
| 1429 | #define KC_LONEKEY                 0x0100 | 
|---|
| 1430 | #define KC_DEADKEY                 0x0200 | 
|---|
| 1431 | #define KC_COMPOSITE               0x0400 | 
|---|
| 1432 | #define KC_INVALIDCOMP             0x0800 | 
|---|
| 1433 | */ | 
|---|
| 1434 |  | 
|---|
| 1435 | /* | 
|---|
| 1436 | Examples:           usFlags  usKeyCode | 
|---|
| 1437 | F3                02       22 | 
|---|
| 1438 | Ctrl+F4           12       23 | 
|---|
| 1439 | Ctrl+Shift+F4     1a       23 | 
|---|
| 1440 | Ctrl              12       0a | 
|---|
| 1441 | Alt               22       0b | 
|---|
| 1442 | Shift             0a       09 | 
|---|
| 1443 | */ | 
|---|
| 1444 |  | 
|---|
| 1445 | // USHORT usCommand; | 
|---|
| 1446 | // USHORT usKeyCode; | 
|---|
| 1447 | USHORT usFlags    = SHORT1FROMMP(mp1); | 
|---|
| 1448 | // UCHAR  ucRepeat   = CHAR3FROMMP(mp1); | 
|---|
| 1449 | UCHAR  ucScanCode = CHAR4FROMMP(mp1); | 
|---|
| 1450 | USHORT usch       = SHORT1FROMMP(mp2); | 
|---|
| 1451 | USHORT usvk       = SHORT2FROMMP(mp2); | 
|---|
| 1452 |  | 
|---|
| 1453 | if ( | 
|---|
| 1454 | // process only key-down messages | 
|---|
| 1455 | ((usFlags & KC_KEYUP) == 0) | 
|---|
| 1456 | // check flags: | 
|---|
| 1457 | // filter out those ugly composite key (accents etc.) | 
|---|
| 1458 | && ((usFlags & (KC_DEADKEY | KC_COMPOSITE | KC_INVALIDCOMP)) == 0) | 
|---|
| 1459 | ) | 
|---|
| 1460 | { | 
|---|
| 1461 | HOTKEYNOTIFY    hkn; | 
|---|
| 1462 | ULONG           flReturned; | 
|---|
| 1463 | HWND            hwndOwner = WinQueryWindow(hwndEdit, QW_OWNER); | 
|---|
| 1464 |  | 
|---|
| 1465 | usFlags &= (KC_VIRTUALKEY | KC_CTRL | KC_ALT | KC_SHIFT); | 
|---|
| 1466 |  | 
|---|
| 1467 | hkn.usFlags = usFlags; | 
|---|
| 1468 | hkn.usvk = usvk; | 
|---|
| 1469 | hkn.usch = usch; | 
|---|
| 1470 | hkn.ucScanCode = ucScanCode; | 
|---|
| 1471 |  | 
|---|
| 1472 | if (usFlags & KC_VIRTUALKEY) | 
|---|
| 1473 | hkn.usKeyCode = usvk; | 
|---|
| 1474 | else | 
|---|
| 1475 | hkn.usKeyCode = usch; | 
|---|
| 1476 |  | 
|---|
| 1477 | hkn.szDescription[0] = 0; | 
|---|
| 1478 |  | 
|---|
| 1479 | flReturned = (ULONG)WinSendMsg(hwndOwner, | 
|---|
| 1480 | WM_CONTROL, | 
|---|
| 1481 | MPFROM2SHORT(WinQueryWindowUShort(hwndEdit, | 
|---|
| 1482 | QWS_ID), | 
|---|
| 1483 | EN_HOTKEY),  // new notification code | 
|---|
| 1484 | (MPARAM)&hkn); | 
|---|
| 1485 | if (flReturned & HEFL_SETTEXT) | 
|---|
| 1486 | WinSetWindowText(hwndEdit, hkn.szDescription); | 
|---|
| 1487 | else if (flReturned & HEFL_FORWARD2OWNER) | 
|---|
| 1488 | WinPostMsg(hwndOwner, | 
|---|
| 1489 | WM_CHAR, | 
|---|
| 1490 | mp1, mp2); | 
|---|
| 1491 | else | 
|---|
| 1492 | // fixed V0.9.16 (2001-12-06) [umoeller]: | 
|---|
| 1493 | // do not clear the entry field if we had HEFL_FORWARD2OWNER | 
|---|
| 1494 | WinSetWindowText(hwndEdit, ""); | 
|---|
| 1495 |  | 
|---|
| 1496 | mrc = (MPARAM)TRUE; // WM_CHAR processed flag; | 
|---|
| 1497 | } | 
|---|
| 1498 | } | 
|---|
| 1499 | break; | 
|---|
| 1500 |  | 
|---|
| 1501 | default: | 
|---|
| 1502 | mrc = pfnwpOrig(hwndEdit, msg, mp1, mp2); | 
|---|
| 1503 | } | 
|---|
| 1504 | return mrc; | 
|---|
| 1505 | } | 
|---|
| 1506 |  | 
|---|
| 1507 | /* | 
|---|
| 1508 | *@@ ctlMakeHotkeyEntryField: | 
|---|
| 1509 | *      this turns any entry field into a "hotkey entry field" | 
|---|
| 1510 | *      by subclassing it with ctl_fnwpObjectHotkeyEntryField. | 
|---|
| 1511 | *      See remarks there for details. | 
|---|
| 1512 | * | 
|---|
| 1513 | *      Returns FALSE upon errors, TRUE otherwise. | 
|---|
| 1514 | * | 
|---|
| 1515 | *@@added V0.9.1 (99-12-19) [umoeller] | 
|---|
| 1516 | */ | 
|---|
| 1517 |  | 
|---|
| 1518 | BOOL ctlMakeHotkeyEntryField(HWND hwndHotkeyEntryField) | 
|---|
| 1519 | { | 
|---|
| 1520 | PFNWP pfnwpOrig; | 
|---|
| 1521 | if (pfnwpOrig = WinSubclassWindow(hwndHotkeyEntryField, | 
|---|
| 1522 | ctl_fnwpObjectHotkeyEntryField)) | 
|---|
| 1523 | { | 
|---|
| 1524 | WinSetWindowPtr(hwndHotkeyEntryField, QWL_USER, (PVOID)pfnwpOrig); | 
|---|
| 1525 | return TRUE; | 
|---|
| 1526 | } | 
|---|
| 1527 |  | 
|---|
| 1528 | return FALSE; | 
|---|
| 1529 | } | 
|---|
| 1530 |  | 
|---|
| 1531 | /* ****************************************************************** | 
|---|
| 1532 | * | 
|---|
| 1533 | *   Color rectangle | 
|---|
| 1534 | * | 
|---|
| 1535 | ********************************************************************/ | 
|---|
| 1536 |  | 
|---|
| 1537 | STATIC PFNWP G_pfnwpColorRectOrigStatic = NULL; | 
|---|
| 1538 |  | 
|---|
| 1539 | /* | 
|---|
| 1540 | *@@ ctl_fnwpSubclassedColorRect: | 
|---|
| 1541 | *      window procedure for subclassed static frames representing | 
|---|
| 1542 | *      a color. | 
|---|
| 1543 | * | 
|---|
| 1544 | *      The control simply paints itself as a rectangle with the | 
|---|
| 1545 | *      color specified in its PP_BACKGROUNDCOLOR presentation | 
|---|
| 1546 | *      parameter. If a window text is set for the control, it is | 
|---|
| 1547 | *      painted with the PP_FOREGROUNDCOLOR color. | 
|---|
| 1548 | * | 
|---|
| 1549 | *      If the user drags a color onto the control, it notifies | 
|---|
| 1550 | *      its owner with the WM_CONTROL message and the EN_CHANGE | 
|---|
| 1551 | *      notification code, as with any entry field (since the | 
|---|
| 1552 | *      static control knows no notifications, we use that code | 
|---|
| 1553 | *      instead). | 
|---|
| 1554 | * | 
|---|
| 1555 | *@@added V0.9.16 (2002-01-05) [umoeller] | 
|---|
| 1556 | *@@changed V0.9.19 (2002-06-02) [umoeller]: moved this here from w_pulse.c | 
|---|
| 1557 | */ | 
|---|
| 1558 |  | 
|---|
| 1559 | STATIC MRESULT EXPENTRY ctl_fnwpSubclassedColorRect(HWND hwndStatic, ULONG msg, MPARAM mp1, MPARAM mp2) | 
|---|
| 1560 | { | 
|---|
| 1561 | MRESULT mrc = 0; | 
|---|
| 1562 |  | 
|---|
| 1563 | switch (msg) | 
|---|
| 1564 | { | 
|---|
| 1565 | case WM_PAINT: | 
|---|
| 1566 | { | 
|---|
| 1567 | LONG    lColor; | 
|---|
| 1568 | RECTL   rclPaint; | 
|---|
| 1569 | PSZ     pszText; | 
|---|
| 1570 |  | 
|---|
| 1571 | HPS hps = WinBeginPaint(hwndStatic, | 
|---|
| 1572 | NULLHANDLE, // HPS | 
|---|
| 1573 | NULL); // PRECTL | 
|---|
| 1574 | gpihSwitchToRGB(hps); | 
|---|
| 1575 | WinQueryWindowRect(hwndStatic, | 
|---|
| 1576 | &rclPaint);      // exclusive | 
|---|
| 1577 | lColor = winhQueryPresColor(hwndStatic, | 
|---|
| 1578 | PP_BACKGROUNDCOLOR, | 
|---|
| 1579 | FALSE,      // no inherit | 
|---|
| 1580 | SYSCLR_DIALOGBACKGROUND); | 
|---|
| 1581 |  | 
|---|
| 1582 | // make rect inclusive | 
|---|
| 1583 | rclPaint.xRight--; | 
|---|
| 1584 | rclPaint.yTop--; | 
|---|
| 1585 |  | 
|---|
| 1586 | // draw interior | 
|---|
| 1587 | GpiSetColor(hps, lColor); | 
|---|
| 1588 | gpihBox(hps, | 
|---|
| 1589 | DRO_FILL, | 
|---|
| 1590 | &rclPaint); | 
|---|
| 1591 |  | 
|---|
| 1592 | // draw frame | 
|---|
| 1593 | GpiSetColor(hps, RGBCOL_BLACK); | 
|---|
| 1594 | gpihBox(hps, | 
|---|
| 1595 | DRO_OUTLINE, | 
|---|
| 1596 | &rclPaint); | 
|---|
| 1597 |  | 
|---|
| 1598 | if (pszText = winhQueryWindowText(hwndStatic)) | 
|---|
| 1599 | { | 
|---|
| 1600 | GpiSetColor(hps, | 
|---|
| 1601 | winhQueryPresColor(hwndStatic, | 
|---|
| 1602 | PP_FOREGROUNDCOLOR, | 
|---|
| 1603 | FALSE, | 
|---|
| 1604 | -1)); | 
|---|
| 1605 | WinDrawText(hps, | 
|---|
| 1606 | strlen(pszText), | 
|---|
| 1607 | pszText, | 
|---|
| 1608 | &rclPaint, | 
|---|
| 1609 | 0, | 
|---|
| 1610 | 0, | 
|---|
| 1611 | DT_CENTER | DT_VCENTER | DT_TEXTATTRS); | 
|---|
| 1612 |  | 
|---|
| 1613 | free(pszText); | 
|---|
| 1614 | } | 
|---|
| 1615 |  | 
|---|
| 1616 | WinEndPaint(hps); | 
|---|
| 1617 | } | 
|---|
| 1618 | break; | 
|---|
| 1619 |  | 
|---|
| 1620 | case WM_PRESPARAMCHANGED: | 
|---|
| 1621 | switch ((ULONG)mp1) | 
|---|
| 1622 | { | 
|---|
| 1623 | case PP_BACKGROUNDCOLOR: | 
|---|
| 1624 | WinInvalidateRect(hwndStatic, | 
|---|
| 1625 | NULL, | 
|---|
| 1626 | FALSE); | 
|---|
| 1627 | // notify owner; since the static control | 
|---|
| 1628 | // doesn't send any notifications, we | 
|---|
| 1629 | // use EN_CHANGED | 
|---|
| 1630 | WinSendMsg(WinQueryWindow(hwndStatic, QW_OWNER), | 
|---|
| 1631 | WM_CONTROL, | 
|---|
| 1632 | MPFROM2SHORT(WinQueryWindowUShort(hwndStatic, QWS_ID), | 
|---|
| 1633 | EN_CHANGE), | 
|---|
| 1634 | (MPARAM)hwndStatic); | 
|---|
| 1635 | break; | 
|---|
| 1636 | } | 
|---|
| 1637 | break; | 
|---|
| 1638 |  | 
|---|
| 1639 | default: | 
|---|
| 1640 | mrc = G_pfnwpColorRectOrigStatic(hwndStatic, msg, mp1, mp2); | 
|---|
| 1641 | break; | 
|---|
| 1642 | } | 
|---|
| 1643 |  | 
|---|
| 1644 | return mrc; | 
|---|
| 1645 | } | 
|---|
| 1646 |  | 
|---|
| 1647 | /* | 
|---|
| 1648 | *@@ ctlMakeColorRect: | 
|---|
| 1649 | *      turns a static rectangle into a color rectangle. | 
|---|
| 1650 | * | 
|---|
| 1651 | *@@added V0.9.19 (2002-06-02) [umoeller] | 
|---|
| 1652 | */ | 
|---|
| 1653 |  | 
|---|
| 1654 | BOOL ctlMakeColorRect(HWND hwndStatic) | 
|---|
| 1655 | { | 
|---|
| 1656 | PFNWP pfnwp; | 
|---|
| 1657 |  | 
|---|
| 1658 | if (pfnwp = WinSubclassWindow(hwndStatic, | 
|---|
| 1659 | ctl_fnwpSubclassedColorRect)) | 
|---|
| 1660 | { | 
|---|
| 1661 | G_pfnwpColorRectOrigStatic = pfnwp; | 
|---|
| 1662 | return TRUE; | 
|---|
| 1663 | } | 
|---|
| 1664 |  | 
|---|
| 1665 | return FALSE; | 
|---|
| 1666 | } | 
|---|
| 1667 |  | 
|---|
| 1668 |  | 
|---|