source: trunk/src/helpers/cctl_tooltip.c@ 81

Last change on this file since 81 was 81, checked in by umoeller, 24 years ago

Tons of changes from the last weeks.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 67.9 KB
Line 
1
2/*
3 *@@sourcefile cctl_tooltip.c:
4 * implementation for the "tooltip" common control.
5 * See comctl.c for an overview.
6 *
7 * This has been extracted from comctl.c with V0.9.3 (2000-05-21) [umoeller].
8 *
9 * Note: Version numbering in this file relates to XWorkplace version
10 * numbering.
11 *
12 *@@header "helpers\comctl.h"
13 *@@added V0.9.3 (2000-05-21) [umoeller].
14 */
15
16/*
17 * Copyright (C) 1997-2000 Ulrich M”ller.
18 * This file is part of the "XWorkplace helpers" source package.
19 * This is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published
21 * by the Free Software Foundation, in version 2 as it comes in the
22 * "COPYING" file of the XWorkplace main distribution.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 */
28
29#define OS2EMX_PLAIN_CHAR
30 // this is needed for "os2emx.h"; if this is defined,
31 // emx will define PSZ as _signed_ char, otherwise
32 // as unsigned char
33
34#define INCL_DOSEXCEPTIONS
35#define INCL_DOSPROCESS
36#define INCL_DOSSEMAPHORES
37#define INCL_DOSERRORS
38
39#define INCL_WINWINDOWMGR
40#define INCL_WINFRAMEMGR
41#define INCL_WINMESSAGEMGR
42#define INCL_WININPUT
43#define INCL_WINPOINTERS
44#define INCL_WINTRACKRECT
45#define INCL_WINTIMER
46#define INCL_WINSYS
47
48#define INCL_WINRECTANGLES /// xxx temporary
49
50#define INCL_WINMENUS
51#define INCL_WINSTATICS
52#define INCL_WINBUTTONS
53#define INCL_WINSTDCNR
54
55#define INCL_GPIPRIMITIVES
56#define INCL_GPILOGCOLORTABLE
57#define INCL_GPILCIDS
58#define INCL_GPIPATHS
59#define INCL_GPIREGIONS
60#define INCL_GPIBITMAPS // added V0.9.1 (2000-01-04) [umoeller]: needed for EMX headers
61#include <os2.h>
62
63#include <stdlib.h>
64#include <stdio.h>
65#include <string.h>
66#include <setjmp.h> // needed for except.h
67#include <assert.h> // needed for except.h
68
69#include "setup.h" // code generation and debugging options
70
71#include "helpers\cnrh.h"
72#include "helpers\except.h" // exception handling
73#include "helpers\gpih.h"
74#include "helpers\linklist.h"
75#include "helpers\winh.h"
76
77#include "helpers\comctl.h"
78
79#pragma hdrstop
80
81/*
82 *@@category: Helpers\PM helpers\Window classes\Tooltips
83 * See cctl_tooltip.c.
84 */
85
86/* ******************************************************************
87 *
88 * Global variables
89 *
90 ********************************************************************/
91
92// linked list of all tools which were subclassed for tooltip
93HMTX G_hmtxSubclassedTools = NULLHANDLE;
94LINKLIST G_llSubclassedTools; // linked list of SUBCLASSEDTOOL items
95
96/* ******************************************************************
97 *
98 * "Tooltip" control
99 *
100 ********************************************************************/
101
102/*
103 *@@ ctlRegisterTooltip:
104 * this registers the Tooltip window class (ctl_fnwpTooltip)
105 * for an application. This is required before the tooltip
106 * control can be used.
107 *
108 *@@added V0.9.0 [umoeller]
109 */
110
111BOOL ctlRegisterTooltip(HAB hab)
112{
113 return (WinRegisterClass(hab,
114 COMCTL_TOOLTIP_CLASS,
115 ctl_fnwpTooltip,
116 CS_HITTEST, // class styles;
117 // CS_FRAME not working,
118 // CS_CLIPSIBLINGS not working
119 sizeof(PVOID)*2)); // addt'l bytes to reserve:
120 // one pointer for QWL_USER,
121 // one more for instance data
122}
123
124/* ******************************************************************
125 *
126 * Subclassing
127 *
128 ********************************************************************/
129
130/*
131 *@@ LockSubclassedTools:
132 * locks the global list of subclassed tools.
133 *
134 *@@added V0.9.12 (2001-04-28) [umoeller]
135 */
136
137BOOL LockSubclassedTools(VOID)
138{
139 if (!G_hmtxSubclassedTools)
140 {
141 // first call:
142
143 // initialize the list
144 lstInit(&G_llSubclassedTools,
145 TRUE); // auto-free
146
147 // create mutex and request it right away
148 return (!DosCreateMutexSem(NULL,
149 &G_hmtxSubclassedTools,
150 0,
151 TRUE)); // request!
152 }
153
154 return (!WinRequestMutexSem(G_hmtxSubclassedTools, SEM_INDEFINITE_WAIT));
155}
156
157/*
158 *@@ UnlockSubclassedTools:
159 * unlocks the global list of subclassed tools.
160 *
161 *@@added V0.9.12 (2001-04-28) [umoeller]
162 *@@changed V0.9.12 (2001-05-03) [umoeller]: this did nothing... fixed
163 */
164
165VOID UnlockSubclassedTools(VOID)
166{
167 DosReleaseMutexSem(G_hmtxSubclassedTools); // was missing V0.9.12 (2001-05-03) [umoeller]
168}
169
170/*
171 *@@ SUBCLASSEDTOOL:
172 * structure created for each control which is
173 * subclassed by the tooltip control (ctl_fnwpTooltip).
174 *
175 *@@added V0.9.0 [umoeller]
176 */
177
178typedef struct _SUBCLASSEDTOOL
179{
180 HWND hwndTool;
181 PFNWP pfnwpOrig;
182 HWND hwndTooltip;
183 HAB hab;
184} SUBCLASSEDTOOL, *PSUBCLASSEDTOOL;
185
186/*
187 *@@ FindSubclassedTool:
188 * returns the SUBCLASSEDTOOL struct from the
189 * global list which matches hwndTool or NULL
190 * if not found.
191 *
192 * Preconditions: Caller must hold the subclassed
193 * tools mutex.
194 *
195 *@@added V0.9.12 (2001-04-28) [umoeller]
196 */
197
198PSUBCLASSEDTOOL FindSubclassedTool(HWND hwndTool)
199{
200 PLISTNODE pNode = lstQueryFirstNode(&G_llSubclassedTools);
201 while (pNode)
202 {
203 PSUBCLASSEDTOOL pstThis = (PSUBCLASSEDTOOL)pNode->pItemData;
204 if (pstThis->hwndTool == hwndTool)
205 {
206 return (pstThis);
207 }
208 pNode = pNode->pNext;
209 }
210
211 return (NULL);
212}
213
214/*
215 *@@ ctl_fnwpSubclassedTool:
216 * window procedure for tools which were subclassed
217 * to support tooltips.
218 *
219 *@@added V0.9.0 [umoeller]
220 *@@changed V0.9.12 (2001-04-28) [umoeller]: added mutex protection
221 */
222
223MRESULT EXPENTRY ctl_fnwpSubclassedTool(HWND hwndTool, ULONG msg, MPARAM mp1, MPARAM mp2)
224{
225 MRESULT mrc = 0;
226
227 PFNWP pfnwpOrig = NULL;
228
229 if (LockSubclassedTools())
230 {
231 PSUBCLASSEDTOOL pst = FindSubclassedTool(hwndTool);
232
233 switch (msg)
234 {
235 case WM_MOUSEMOVE:
236 case WM_BUTTON1DOWN:
237 case WM_BUTTON1UP:
238 case WM_BUTTON2DOWN:
239 case WM_BUTTON2UP:
240 case WM_BUTTON3DOWN:
241 case WM_BUTTON3UP:
242 {
243 QMSG qmsg;
244 qmsg.hwnd = hwndTool;
245 qmsg.msg = msg;
246 qmsg.mp1 = mp1;
247 qmsg.mp2 = mp2;
248 // _Pmpf((__FUNCTION__ ": sending TTM_RELAYEVENT"));
249 WinSendMsg(pst->hwndTooltip,
250 TTM_RELAYEVENT,
251 (MPARAM)0,
252 (MPARAM)&qmsg);
253 pfnwpOrig = pst->pfnwpOrig; // call default
254 break; }
255
256 case WM_DESTROY:
257 lstRemoveItem(&G_llSubclassedTools, pst); // this frees the item
258 pfnwpOrig = pst->pfnwpOrig; // call default
259 break;
260
261 default:
262 pfnwpOrig = pst->pfnwpOrig; // call default
263 }
264
265 UnlockSubclassedTools();
266 }
267
268 if (pfnwpOrig)
269 mrc = (pfnwpOrig)(hwndTool, msg, mp1, mp2);
270
271 return (mrc);
272}
273
274/*
275 *@@ SubclassTool:
276 * this gets called from ctl_fnwpTooltip if a control
277 * is to be subclassed to support mouse messaging
278 * (TTF_SUBCLASS flag).
279 *
280 * Preconditions: Caller must hold the subclassed
281 * tools mutex.
282 *
283 *@@added V0.9.0 [umoeller]
284 *@@changed V0.9.12 (2001-04-28) [umoeller]: renamed from SubclassToolForToolInfo
285 */
286
287BOOL SubclassTool(HWND hwndTooltip,
288 HWND hwndTool)
289{
290 BOOL brc = FALSE;
291
292 // make sure the tool is not on the list yet
293 // V0.9.12 (2001-04-28) [umoeller]
294 if (!FindSubclassedTool(hwndTool))
295 {
296 PFNWP pfnwpOrig = WinSubclassWindow(hwndTool,
297 ctl_fnwpSubclassedTool);
298 if (pfnwpOrig)
299 {
300 PSUBCLASSEDTOOL pst = (PSUBCLASSEDTOOL)malloc(sizeof(SUBCLASSEDTOOL));
301 if (pst)
302 {
303 pst->pfnwpOrig = pfnwpOrig;
304 pst->hwndTooltip = hwndTooltip;
305 pst->hwndTool = hwndTool;
306 pst->hab = WinQueryAnchorBlock(hwndTool);
307
308 brc = !!lstAppendItem(&G_llSubclassedTools, pst);
309 }
310 }
311 }
312
313 return (brc);
314}
315
316/*
317 *@@ UnSubclassTool:
318 * un-subclasses a tool previously subclassed by
319 * SubclassToolForToolinfo.
320 *
321 * Preconditions: Caller must hold the subclassed
322 * tools mutex.
323 *
324 *@@added V0.9.12 (2001-04-28) [umoeller]
325 */
326
327BOOL UnSubclassTool(HWND hwndTool)
328{
329 PSUBCLASSEDTOOL pst = FindSubclassedTool(hwndTool);
330 if (pst)
331 {
332 WinSubclassWindow(hwndTool,
333 pst->pfnwpOrig);
334 // orig winproc == un-subclass
335 return (lstRemoveItem(&G_llSubclassedTools, pst));
336 // this frees the item
337 }
338
339 return (FALSE);
340}
341
342/* ******************************************************************
343 *
344 * Implementation
345 *
346 ********************************************************************/
347
348/*
349 *@@ TOOLTIPDATA:
350 * private data structure stored in the window
351 * words of ctl_fnwpTooltip to hold information for
352 * a tooltip instance.
353 *
354 *@@added V0.9.0 [umoeller]
355 */
356
357typedef struct _TOOLTIPDATA
358{
359 HWND hwndOwner; // from WM_CREATE
360 HAB hab; // from WM_CREATE
361 ULONG ulTooltipID; // from WM_CREATE
362
363 LONG cxScreen,
364 cyScreen;
365
366 BOOL fIsActive; // TRUE per default; changed by TTM_ACTIVATE
367
368 ULONG idTimerInitial, // if != 0, "initial" timer is running
369 idTimerAutopop; // if != 0, "autopop" (hide) timer is running
370
371 ULONG ulTimeoutInitial, // "initial" timer timeout (ms)
372 ulTimeoutAutopop, // "autopop" (hide) timer timeout (ms)
373 ulTimeoutReshow; // "reshow" timer timeout (ms)
374
375 LINKLIST llTools; // linked list of TOOLINFO structures
376 // containing the tools
377 FONTMETRICS fontmetrics; // current font
378 LONG lForeColor, // current foreground color
379 lBackColor, // current background color
380 l3DHiColor, // 3D border light color
381 l3DLoColor; // 3D border dark color
382 PSZ pszPaintText; // text to paint (new buffer)
383
384 POINTL ptlPointerLast; // last mouse pointer position
385
386 PTOOLINFO ptiMouseOver; // tool info over which the mouse resides
387
388 BOOL fIsVisible; // TRUE if tooltip is visible
389
390 // CHAR szTextBuf[256]; // static buffer for copying/loading strings
391} TOOLTIPDATA, *PTOOLTIPDATA;
392
393// timer IDs
394#define TOOLTIP_ID_TIMER_INITIAL 1
395#define TOOLTIP_ID_TIMER_AUTOPOP 2
396
397// tooltip window border (free spaces)
398#define TOOLTIP_CX_BORDER 5
399#define TOOLTIP_CY_BORDER 3
400
401/*
402 *@@ UpdateTooltipPresColors:
403 * this gets called during WM_CREATE and WM_PRESPARAMCHANGED
404 * in ctl_fnwpTooltip to set the colors in TOOLTIPDATA according
405 * to the control's presparams.
406 */
407
408VOID UpdateTooltipPresColors(HWND hwndTooltip) // in: tooltip control
409{
410 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
411
412 // tooltip background color:
413 pttd->lBackColor = winhQueryPresColor(hwndTooltip,
414 PP_MENUBACKGROUNDCOLOR,
415 FALSE, // no inherit
416 SYSCLR_ENTRYFIELD);
417 // tooltip text color:
418 pttd->lForeColor = winhQueryPresColor(hwndTooltip,
419 PP_MENUFOREGROUNDCOLOR,
420 FALSE, // no inherit
421 SYSCLR_WINDOWTEXT);
422 // 3D border light color:
423 pttd->l3DHiColor = winhQueryPresColor(hwndTooltip,
424 PP_MENUHILITEFGNDCOLOR,
425 FALSE, // no inherit
426 SYSCLR_WINDOWTEXT);
427 // 3D border dark color:
428 pttd->l3DLoColor = winhQueryPresColor(hwndTooltip,
429 PP_MENUHILITEBGNDCOLOR,
430 FALSE, // no inherit
431 SYSCLR_WINDOWTEXT);
432}
433
434/*
435 *@@ TtmCreate:
436 * implementation for WM_CREATE in ctl_fnwpTooltip.
437 *
438 *@@added V0.9.13 (2001-06-21) [umoeller]
439 */
440
441MRESULT TtmCreate(HWND hwndTooltip,
442 MPARAM mp2)
443{
444 PTOOLTIPDATA pttd;
445 PCREATESTRUCT pcs = (PCREATESTRUCT)mp2;
446
447 // allocate and initialize tooltip data
448 pttd = (PTOOLTIPDATA)malloc(sizeof(TOOLTIPDATA));
449 if (pttd)
450 {
451 CHAR szFont[256];
452 memset(pttd, 0, sizeof(TOOLTIPDATA));
453 WinSetWindowPtr(hwndTooltip, 1, pttd);
454
455 pttd->hwndOwner = pcs->hwndOwner;
456 pttd->hab = WinQueryAnchorBlock(hwndTooltip);
457 pttd->ulTooltipID = pcs->id;
458
459 pttd->cxScreen = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
460 pttd->cyScreen = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
461
462 pttd->fIsActive = TRUE;
463
464 // default timeouts
465 pttd->ulTimeoutInitial = 1000;
466 pttd->ulTimeoutAutopop = 5000;
467 pttd->ulTimeoutReshow = 500;
468
469 // get colors from presparams/syscolors
470 UpdateTooltipPresColors(hwndTooltip);
471
472 // check if font presparam set
473 if (WinQueryPresParam(hwndTooltip,
474 PP_FONTNAMESIZE, 0,
475 NULL,
476 sizeof(szFont),
477 szFont,
478 QPF_NOINHERIT)
479 == 0)
480 {
481 // no: set default font presparam
482 // (we never want the System Proportional font)
483 winhSetWindowFont(hwndTooltip,
484 NULL); // default (WarpSans or 8.Helv)
485 }
486
487 pttd->pszPaintText = strdup("undefined");
488
489 lstInit(&pttd->llTools, TRUE); // auto-free items
490
491 // override CREATESTRUCT
492 WinSetWindowPos(hwndTooltip,
493 HWND_TOP,
494 50, 50,
495 100, 100,
496 SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_HIDE);
497
498 return (MPARAM)FALSE;
499 }
500 else
501 // malloc failed:
502 return (MPARAM)TRUE;
503}
504
505/*
506 *@@ TtmTimer:
507 * implementation for WM_TIMER in ctl_fnwpTooltip.
508 *
509 *@@added V0.9.13 (2001-06-21) [umoeller]
510 */
511
512BOOL TtmTimer(HWND hwndTooltip, MPARAM mp1)
513{
514 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
515 USHORT usTimer = SHORT1FROMMP(mp1);
516
517 switch (usTimer)
518 {
519 case TOOLTIP_ID_TIMER_INITIAL:
520 // _Pmpf(("WM_TIMER: Stopping initial timer: %d", usTimer));
521 // _Pmpf((__FUNCTION__ ": TOOLTIP_ID_TIMER_INITIAL"));
522 WinStopTimer(pttd->hab,
523 hwndTooltip,
524 usTimer);
525 pttd->idTimerInitial = 0;
526
527 if (pttd->fIsActive)
528 // show tooltip
529 WinPostMsg(hwndTooltip, TTM_SHOWTOOLTIPNOW, (MPARAM)TRUE, 0);
530 break;
531
532 case TOOLTIP_ID_TIMER_AUTOPOP:
533 // _Pmpf(("WM_TIMER: Stopping autopop timer: %d", usTimer));
534 WinStopTimer(pttd->hab,
535 hwndTooltip,
536 usTimer);
537 pttd->idTimerAutopop = 0;
538 WinPostMsg(hwndTooltip, TTM_SHOWTOOLTIPNOW, (MPARAM)FALSE, 0);
539 break;
540
541 default:
542 return FALSE;
543 } // end switch
544
545 return (TRUE);
546}
547
548/*
549 *@@ TtmPaint:
550 * implementation for WM_PAINT in ctl_fnwpTooltip.
551 *
552 *@@added V0.9.1 (99-11-30) [umoeller]
553 */
554
555VOID TtmPaint(HWND hwndTooltip)
556{
557 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
558 HPS hps = WinBeginPaint(hwndTooltip, NULLHANDLE, NULL);
559 POINTL ptl = {0, 0};
560 RECTL rclWindow,
561 rclWindowBak;
562 ULONG ulStyle = WinQueryWindowULong(hwndTooltip, QWL_STYLE);
563
564 ULONG ulRounding = 0;
565 if (ulStyle & TTS_ROUNDED)
566 ulRounding = TT_ROUNDING;
567
568
569 gpihSwitchToRGB(hps);
570
571 // get tooltip size; this has been properly calculated
572 // by TTM_SHOWTOOLTIPNOW earlier
573 WinQueryWindowRect(hwndTooltip, &rclWindow);
574 memcpy(&rclWindowBak, &rclWindow, sizeof(RECTL));
575
576 if (ulStyle & TTS_SHADOW)
577 {
578 // if shadows are on, the window is too large;
579 // make rectl smaller for rest of paint
580 rclWindow.xRight -= TT_SHADOWOFS;
581 rclWindow.yBottom += TT_SHADOWOFS;
582 // restore old pattern
583 GpiSetPattern(hps, PATSYM_DEFAULT);
584 }
585
586 // draw shadow
587 if (ulStyle & TTS_SHADOW)
588 {
589 GpiSetColor(hps, CLR_BLACK);
590 GpiSetPattern(hps, PATSYM_HALFTONE);
591 ptl.x = rclWindowBak.xLeft + TT_SHADOWOFS;
592 ptl.y = rclWindowBak.yBottom;
593 GpiMove(hps, &ptl);
594 ptl.x = rclWindowBak.xRight - 1;
595 ptl.y = rclWindowBak.yTop - TT_SHADOWOFS;
596 GpiBox(hps,
597 DRO_FILL,
598 &ptl,
599 ulRounding, ulRounding);
600 // restore pattern
601 GpiSetPattern(hps, PATSYM_DEFAULT);
602 }
603
604 // draw "real" rectangle
605 ptl.x = rclWindow.xLeft;
606 ptl.y = rclWindow.yBottom;
607 GpiMove(hps, &ptl);
608 ptl.x = rclWindow.xRight - 1;
609 ptl.y = rclWindow.yTop - 1;
610 GpiSetColor(hps, pttd->lBackColor);
611 GpiBox(hps,
612 DRO_FILL,
613 &ptl,
614 6, 6);
615
616 GpiSetColor(hps, pttd->lForeColor);
617 GpiBox(hps,
618 DRO_OUTLINE,
619 &ptl,
620 ulRounding, ulRounding);
621
622 if (pttd->pszPaintText)
623 {
624 RECTL rclText;
625 GpiSetColor(hps, pttd->lForeColor);
626 GpiSetBackColor(hps, pttd->lBackColor);
627 rclText.xLeft = rclWindow.xLeft + TOOLTIP_CX_BORDER;
628 rclText.xRight = rclWindow.xRight - TOOLTIP_CX_BORDER;
629 rclText.yBottom = rclWindow.yBottom + TOOLTIP_CY_BORDER;
630 rclText.yTop = rclWindow.yTop - TOOLTIP_CY_BORDER;
631 winhDrawFormattedText(hps,
632 &rclText,
633 pttd->pszPaintText,
634 DT_LEFT | DT_TOP | DT_WORDBREAK);
635 }
636
637 WinEndPaint(hps);
638}
639
640/*
641 *@@ TtmDestroy:
642 * implementation for WM_DESTROY in ctl_fnwpTooltip.
643 *
644 *@@added V0.9.13 (2001-06-21) [umoeller]
645 */
646
647VOID TtmDestroy(HWND hwndTooltip)
648{
649 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
650 // stop timers
651 if (pttd->idTimerInitial)
652 WinStopTimer(pttd->hab,
653 hwndTooltip,
654 pttd->idTimerInitial);
655 if (pttd->idTimerAutopop)
656 WinStopTimer(pttd->hab,
657 hwndTooltip,
658 pttd->idTimerAutopop);
659 if (pttd->pszPaintText)
660 free(pttd->pszPaintText);
661
662 // un-subclass all tools that we subclassed
663 // V0.9.12 (2001-04-28) [umoeller]
664 if (LockSubclassedTools())
665 {
666 PLISTNODE pNode;
667 PSUBCLASSEDTOOL pst;
668 for (pNode = lstQueryFirstNode(&pttd->llTools);
669 pNode;
670 pNode = pNode->pNext)
671 {
672 PTOOLINFO pti = (PTOOLINFO)pNode->pItemData;
673 if (pst = FindSubclassedTool(pti->hwndTool))
674 UnSubclassTool(pti->hwndTool);
675 }
676
677 UnlockSubclassedTools();
678 }
679 // end V0.9.12 (2001-04-28) [umoeller]
680
681 lstClear(&pttd->llTools);
682
683 free(pttd);
684}
685
686/*
687 *@@ TtmAddTool:
688 * implementation for TTM_ADDTOOL in ctl_fnwpTooltip.
689 *
690 *@@added V0.9.13 (2001-06-21) [umoeller]
691 */
692
693MRESULT TtmAddTool(HWND hwndTooltip, MPARAM mp2)
694{
695 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
696 if (mp2)
697 {
698 PTOOLINFO ptiPassed = (PTOOLINFO)mp2,
699 ptiNew = (PTOOLINFO)malloc(sizeof(TOOLINFO));
700 if (ptiNew)
701 {
702 memcpy(ptiNew, ptiPassed, sizeof(TOOLINFO));
703 lstAppendItem(&pttd->llTools,
704 ptiNew);
705
706 if ( (ptiPassed->ulFlags & TTF_SUBCLASS)
707 && (LockSubclassedTools()) // V0.9.12 (2001-04-28) [umoeller]
708 )
709 {
710 // caller wants this tool to be subclassed:
711 // well, do it then
712 SubclassTool(hwndTooltip,
713 ptiPassed->hwndTool);
714
715 UnlockSubclassedTools();
716 }
717
718 return ((MPARAM)TRUE);
719 }
720 }
721
722 return (MPARAM)FALSE;
723}
724
725/*
726 *@@ TtmDelTool:
727 * implementation for TTM_DELTOOL in ctl_fnwpTooltip.
728 *
729 *@@added V0.9.13 (2001-06-21) [umoeller]
730 *@@changed V0.9.13 (2001-06-21) [umoeller]: fixed missing unlock
731 *@@changed V0.9.13 (2001-06-21) [umoeller]: fixed endless loop
732 */
733
734VOID TtmDelTool(HWND hwndTooltip, MPARAM mp2)
735{
736 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
737 PTOOLINFO ptiSearch = (PTOOLINFO)mp2;
738 if (ptiSearch)
739 {
740 PLISTNODE pToolNode = lstQueryFirstNode(&pttd->llTools);
741 while (pToolNode)
742 {
743 PTOOLINFO ptiThis = (PTOOLINFO)pToolNode->pItemData;
744 if ( (ptiThis->hwndToolOwner == ptiSearch->hwndToolOwner)
745 && (ptiThis->hwndTool == ptiSearch->hwndTool)
746 )
747 {
748 // found:
749
750 // V0.9.12 (2001-04-28) [umoeller]
751 // unsubclass if this was subclassed
752 if (ptiThis->ulFlags & TTF_SUBCLASS)
753 {
754 if (LockSubclassedTools())
755 {
756 UnSubclassTool(ptiSearch->hwndTool);
757
758 UnlockSubclassedTools();
759 // was missing V0.9.13 (2001-06-21) [umoeller]
760 }
761 }
762
763 // remove the tool from the list
764 lstRemoveNode(&pttd->llTools, pToolNode);
765
766 break;
767 }
768
769 pToolNode = pToolNode->pNext;
770 // fixed endless loop V0.9.13 (2001-06-21) [umoeller]
771 }
772 }
773}
774
775/*
776 *@@ TtmRelayEvent:
777 * implementation for TTM_RELAYEVENT in ctl_fnwpTooltip.
778 *
779 *@@added V0.9.13 (2001-06-21) [umoeller]
780 */
781
782VOID TtmRelayEvent(HWND hwndTooltip, MPARAM mp2)
783{
784 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
785 PQMSG pqmsg = (PQMSG)mp2;
786 if (pqmsg)
787 {
788 POINTL ptlPointer;
789 PLISTNODE pToolNode;
790
791 if (pttd->idTimerInitial)
792 {
793 // _Pmpf(("TTM_RELAYEVENT: Stopping timer: %d", pttd->idTimerInitial));
794 WinStopTimer(pttd->hab,
795 hwndTooltip,
796 TOOLTIP_ID_TIMER_INITIAL);
797 pttd->idTimerInitial = 0;
798 }
799
800 WinQueryPointerPos(HWND_DESKTOP, &ptlPointer);
801
802 // find TOOLINFO from mouse position
803 pttd->ptiMouseOver = NULL;
804 pToolNode = lstQueryFirstNode(&pttd->llTools);
805 while (pToolNode)
806 {
807 PTOOLINFO pti = (PTOOLINFO)pToolNode->pItemData;
808 if (pti->hwndTool == pqmsg->hwnd)
809 {
810 // _Pmpf((__FUNCTION__ ": found tool"));
811 pttd->ptiMouseOver = pti;
812 break;
813 }
814 pToolNode = pToolNode->pNext;
815 }
816
817 if ( (ptlPointer.x != pttd->ptlPointerLast.x)
818 || (ptlPointer.y != pttd->ptlPointerLast.y)
819 || (pqmsg->msg == WM_BUTTON1DOWN)
820 || (pqmsg->msg == WM_BUTTON2DOWN)
821 || (pqmsg->msg == WM_BUTTON3DOWN)
822 )
823 {
824 // mouse pos changed:
825 // hide tooltip
826 WinPostMsg(hwndTooltip,
827 TTM_SHOWTOOLTIPNOW,
828 (MPARAM)FALSE,
829 0);
830 memcpy(&pttd->ptlPointerLast, &ptlPointer, sizeof(POINTL));
831
832 // _Pmpf((__FUNCTION__ ": pttd->ptiMouseOver: 0x%lX", pttd->ptiMouseOver));
833 // _Pmpf((__FUNCTION__ ": pttd->fIsActive: 0x%lX", pttd->fIsActive));
834 if ( (pttd->ptiMouseOver)
835 && (pttd->fIsActive)
836 )
837 {
838 // tool found and tooltip is activated:
839 pttd->idTimerInitial = WinStartTimer(pttd->hab,
840 hwndTooltip,
841 TOOLTIP_ID_TIMER_INITIAL,
842 pttd->ulTimeoutInitial);
843 // _Pmpf(("TTM_RELAYEVENT: Started timer: %d", pttd->idTimerInitial));
844 }
845 }
846 } // end if (pqmsg)
847}
848
849/*
850 *@@ TtmGetDelayTime:
851 * implementation for TTM_GETDELAYTIME in ctl_fnwpTooltip.
852 *
853 *@@added V0.9.13 (2001-06-21) [umoeller]
854 */
855
856MRESULT TtmGetDelayTime(HWND hwndTooltip, MPARAM mp1)
857{
858 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
859 switch ((ULONG)mp1)
860 {
861 case TTDT_AUTOPOP:
862 return (MRESULT)pttd->ulTimeoutAutopop;
863
864 case TTDT_INITIAL:
865 return (MRESULT)pttd->ulTimeoutInitial;
866
867 case TTDT_RESHOW:
868 return (MRESULT)pttd->ulTimeoutReshow;
869 }
870
871 return (0);
872}
873
874/*
875 *@@ TtmSetDelayTime:
876 * implementation for TTM_SETDELAYTIME in ctl_fnwpTooltip.
877 *
878 *@@added V0.9.13 (2001-06-21) [umoeller]
879 */
880
881VOID TtmSetDelayTime(HWND hwndTooltip, MPARAM mp1, MPARAM mp2)
882{
883 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
884 ULONG iDelay = (ULONG)mp2;
885 switch (SHORT1FROMMP(mp1))
886 {
887 case TTDT_AUTOMATIC:
888 pttd->ulTimeoutInitial = iDelay;
889 pttd->ulTimeoutAutopop = iDelay * 5;
890 pttd->ulTimeoutReshow = iDelay / 2;
891 break;
892
893 case TTDT_AUTOPOP:
894 pttd->ulTimeoutAutopop = iDelay;
895 break;
896
897 case TTDT_INITIAL:
898 pttd->ulTimeoutInitial = iDelay;
899 break;
900
901 case TTDT_RESHOW:
902 pttd->ulTimeoutReshow = iDelay;
903 break;
904 }
905}
906
907/*
908 *@@ TtmGetText:
909 * implementation for TTM_GETTEXT in ctl_fnwpTooltip.
910 *
911 *@@added V0.9.13 (2001-06-21) [umoeller]
912 */
913
914VOID TtmGetText(HWND hwndTooltip, MPARAM mp2)
915{
916 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
917 PTOOLINFO pti = (PTOOLINFO)mp2;
918
919 if (pti->pszText == PSZ_TEXTCALLBACK)
920 {
921 // TTN_NEEDTEXT notification desired:
922 // compose values for that msg
923 TOOLTIPTEXT ttt = {0};
924 // _Pmpf(("TTM_GETTEXT: PSZ_TEXTCALLBACK... sending TTN_NEEDTEXT"));
925 ttt.hwndTooltip = hwndTooltip;
926 ttt.hwndTool = pti->hwndTool;
927 WinSendMsg(pti->hwndToolOwner,
928 WM_CONTROL,
929 MPFROM2SHORT(pttd->ulTooltipID, // tooltip control wnd ID
930 TTN_NEEDTEXT),
931 &ttt);
932
933 // in case of error: set lpszText to NULL; this
934 // is not specified in the docs however.
935 pti->pszText = NULL;
936
937 switch (ttt.ulFormat)
938 {
939 case TTFMT_PSZ:
940 if (ttt.pszText)
941 pti->pszText = ttt.pszText;
942 break;
943
944 case TTFMT_STRINGRES:
945 // @@todo
946 break;
947 }
948 }
949}
950
951/*
952 *@@ TtmEnumTools:
953 * implementation for TTM_ENUMTOOLS in ctl_fnwpTooltip.
954 *
955 *@@added V0.9.13 (2001-06-21) [umoeller]
956 */
957
958MRESULT TtmEnumTools(HWND hwndTooltip, MPARAM mp1, MPARAM mp2)
959{
960 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
961 PTOOLINFO ptiTarget = (PTOOLINFO)mp2;
962 if (ptiTarget)
963 {
964 PTOOLINFO ptiFound = (PTOOLINFO)lstItemFromIndex(&pttd->llTools,
965 SHORT1FROMMP(mp1));
966 if (ptiFound)
967 {
968 memcpy(ptiTarget, ptiFound, sizeof(TOOLINFO));
969 return (MRESULT)TRUE;
970 }
971 }
972
973 return (MRESULT)FALSE;
974}
975
976/*
977 *@@ TtmGetCurrentTool:
978 * implementation for TTM_GETCURRENTTOOL in ctl_fnwpTooltip.
979 *
980 *@@added V0.9.13 (2001-06-21) [umoeller]
981 */
982
983MRESULT TtmGetCurrentTool(HWND hwndTooltip, MPARAM mp2)
984{
985 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
986 PTOOLINFO ptiTarget = (PTOOLINFO)mp2;
987 if (ptiTarget)
988 {
989 if (pttd->ptiMouseOver)
990 {
991 memcpy(ptiTarget, pttd->ptiMouseOver, sizeof(TOOLINFO));
992 return (MPARAM)TRUE;
993 }
994 }
995
996 return ((MPARAM)FALSE);
997}
998
999/*
1000 *@@ TtmGetToolInfo:
1001 * implementation for TTM_GETTOOLINFO in ctl_fnwpTooltip.
1002 *
1003 *@@added V0.9.13 (2001-06-21) [umoeller]
1004 */
1005
1006MRESULT TtmGetToolInfo(HWND hwndTooltip, MPARAM mp2)
1007{
1008 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
1009 PTOOLINFO ptiSearch = (PTOOLINFO)mp2;
1010 if (ptiSearch)
1011 {
1012 PLISTNODE pToolNode = lstQueryFirstNode(&pttd->llTools);
1013 while (pToolNode)
1014 {
1015 PTOOLINFO ptiThis = (PTOOLINFO)pToolNode->pItemData;
1016 if ( (ptiThis->hwndToolOwner == ptiSearch->hwndToolOwner)
1017 && (ptiThis->hwndTool == ptiSearch->hwndTool)
1018 )
1019 {
1020 // found:
1021 memcpy(ptiSearch, ptiThis, sizeof(TOOLINFO));
1022 return (MPARAM)TRUE;
1023 }
1024 pToolNode = pToolNode->pNext;
1025 }
1026 }
1027
1028 return ((MPARAM)FALSE);
1029}
1030
1031/*
1032 *@@ FormatTooltip:
1033 * formats the tooltip window according to
1034 * its text (which is assumed to be in
1035 * pttd->pszPaintText) and positions it
1036 * on the screen.
1037 *
1038 * This does not change the visibility
1039 * of the tooltip; if it is not yet visible,
1040 * you must show it afterwards.
1041 *
1042 *@@added V0.9.13 (2001-06-21) [umoeller]
1043 */
1044
1045VOID FormatTooltip(HWND hwndTooltip,
1046 PTOOLTIPDATA pttd,
1047 PPOINTL pptlPointer) // in: current pointer pos or NULL
1048{
1049 // find out how much space we need
1050 RECTL rcl = { 0, 0, 300, 1000 };
1051 POINTL ptlTooltip;
1052 LONG cx, cy;
1053 ULONG ulStyle = WinQueryWindowULong(hwndTooltip, QWL_STYLE);
1054
1055 HPS hps = WinGetPS(hwndTooltip);
1056
1057 winhDrawFormattedText(hps,
1058 &rcl,
1059 pttd->pszPaintText,
1060 DT_LEFT | DT_TOP | DT_WORDBREAK | DT_QUERYEXTENT);
1061 WinReleasePS(hps);
1062
1063 // calc width and height of tooltip
1064 cx = rcl.xRight + 2*TOOLTIP_CX_BORDER;
1065 cy = (rcl.yTop - rcl.yBottom) + 2*TOOLTIP_CY_BORDER;
1066
1067 // calc x and y pos of tooltip:
1068
1069 // per default, use pointer pos
1070 ptlTooltip.x = pptlPointer->x - cx/2;
1071 ptlTooltip.y = pptlPointer->y - cy;
1072
1073 // do we need the tool's position?
1074 if ( pttd->ptiMouseOver->ulFlags
1075 & (TTF_CENTER_X_ON_TOOL | TTF_POS_Y_ABOVE_TOOL | TTF_POS_Y_BELOW_TOOL)
1076 )
1077 {
1078 // yes:
1079 SWP swpTool;
1080 POINTL ptlTool;
1081 WinQueryWindowPos(pttd->ptiMouseOver->hwndTool, &swpTool);
1082 ptlTool.x = swpTool.x;
1083 ptlTool.y = swpTool.y;
1084 // convert x, y to desktop points
1085 WinMapWindowPoints(WinQueryWindow(pttd->ptiMouseOver->hwndTool,
1086 QW_PARENT), // hwndFrom
1087 HWND_DESKTOP, // hwndTo
1088 &ptlTool,
1089 1);
1090
1091 // X
1092 if (pttd->ptiMouseOver->ulFlags & TTF_CENTER_X_ON_TOOL)
1093 // center X on tool:
1094 ptlTooltip.x = ptlTool.x + ((swpTool.cx - cx) / 2L);
1095
1096 // Y
1097 if (pttd->ptiMouseOver->ulFlags & TTF_POS_Y_ABOVE_TOOL)
1098 ptlTooltip.y = ptlTool.y + swpTool.cy;
1099 else if (pttd->ptiMouseOver->ulFlags & TTF_POS_Y_BELOW_TOOL)
1100 ptlTooltip.y = ptlTool.y - cy;
1101 }
1102
1103 // if "shy mouse" is enabled, make
1104 // sure the tool tip is not under the
1105 // mouse pointer
1106 if (ulStyle & TTF_SHYMOUSE)
1107 {
1108 // we need to subtract the current mouse
1109 // pointer's hot spot from the current
1110 // pointer position
1111 HPOINTER hptr = WinQueryPointer(HWND_DESKTOP);
1112 POINTERINFO pi;
1113 if (WinQueryPointerInfo(hptr, &pi))
1114 {
1115 // calc bottom edge of mouse pointer rect
1116 ULONG yBottomPointer = (pptlPointer->y - pi.yHotspot);
1117 // _Pmpf(("yHotspot: %d", pi.yHotspot));
1118 if ( (ptlTooltip.y + cy) // top edge of tool tip
1119 > yBottomPointer
1120 )
1121 {
1122 ptlTooltip.y = pptlPointer->y - cy - pi.yHotspot;
1123 }
1124 }
1125 }
1126
1127 // constrain to screen
1128 if (ptlTooltip.x < 0)
1129 ptlTooltip.x = 0;
1130 if (ptlTooltip.y < 0)
1131 ptlTooltip.y = 0;
1132 if (ptlTooltip.x + cx > pttd->cxScreen)
1133 ptlTooltip.x = pttd->cxScreen-cx;
1134 if (ptlTooltip.y + cy > pttd->cyScreen)
1135 ptlTooltip.y = pttd->cyScreen-cy;
1136
1137 // if shadow is enabled,
1138 // enlarge; the shadow might by
1139 // off-screen now, but that's OK
1140 if (ulStyle & TTS_SHADOW)
1141 {
1142 cx += TT_SHADOWOFS;
1143 cy += TT_SHADOWOFS;
1144 ptlTooltip.y -= TT_SHADOWOFS;
1145 }
1146
1147 // set tooltip position at the pos we calculated
1148 // and show tooltip
1149 WinSetWindowPos(hwndTooltip,
1150 HWND_TOP,
1151 ptlTooltip.x,
1152 ptlTooltip.y,
1153 cx,
1154 cy,
1155 SWP_MOVE | SWP_SIZE | SWP_ZORDER);
1156}
1157
1158/*
1159 *@@ TtmUpdateTipText:
1160 * implementation for TTM_UPDATETIPTEXT in ctl_fnwpTooltip.
1161 *
1162 *@@added V0.9.13 (2001-06-21) [umoeller]
1163 */
1164
1165VOID TtmUpdateTipText(HWND hwndTooltip,
1166 const char *pcszNewText)
1167{
1168 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
1169
1170 // has text really changed?
1171 if ( ( (pttd->pszPaintText)
1172 && (pcszNewText)
1173 && (strcmp(pttd->pszPaintText, pcszNewText))
1174 )
1175 || (pttd->pszPaintText && !pcszNewText)
1176 || (!pttd->pszPaintText && pcszNewText)
1177 )
1178 {
1179 // yes:
1180 if (pttd->pszPaintText)
1181 {
1182 free(pttd->pszPaintText);
1183 pttd->pszPaintText = NULL;
1184 }
1185
1186 if (pcszNewText)
1187 pttd->pszPaintText = strdup(pcszNewText);
1188
1189 if (pttd->fIsVisible)
1190 {
1191 // currently showing:
1192 // reformat
1193 POINTL ptlPointer;
1194 WinQueryPointerPos(HWND_DESKTOP, &ptlPointer);
1195 FormatTooltip(hwndTooltip,
1196 pttd,
1197 &ptlPointer);
1198 WinInvalidateRect(hwndTooltip, NULL, FALSE);
1199 }
1200 }
1201}
1202
1203/*
1204 *@@ TtmShowTooltip:
1205 * implementation for TTM_SHOW_TOOLTIP.
1206 *
1207 * Depending on fShow, this shows or hides the
1208 * tool tip at the position specified by the
1209 * current tool or the mouse pointer (specified
1210 * by the tool's style flags).
1211 *
1212 *@@added V0.9.1 (2000-02-04) [umoeller]
1213 */
1214
1215VOID TtmShowTooltip(HWND hwndTooltip,
1216 BOOL fShow) // if TRUE: show, else: HIDE
1217{
1218 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
1219 if (fShow)
1220 {
1221 /*
1222 * show tooltip::
1223 *
1224 */
1225
1226 POINTL ptlPointer;
1227 HPS hps;
1228
1229 // free old text
1230 if (pttd->pszPaintText)
1231 {
1232 free(pttd->pszPaintText);
1233 pttd->pszPaintText = NULL;
1234 }
1235
1236 WinQueryPointerPos(HWND_DESKTOP, &ptlPointer);
1237
1238 if ( (ptlPointer.x == pttd->ptlPointerLast.x)
1239 && (ptlPointer.y == pttd->ptlPointerLast.y)
1240 )
1241 {
1242 // mouse not moved since timer was started:
1243 // find the current TOOLINFO
1244 if (pttd->ptiMouseOver)
1245 {
1246 TOOLINFO tiTemp;
1247 memcpy(&tiTemp, pttd->ptiMouseOver, sizeof(TOOLINFO));
1248 // get the text for the TOOLINFO
1249 WinSendMsg(hwndTooltip,
1250 TTM_GETTEXT,
1251 (MPARAM)0,
1252 (MPARAM)&tiTemp);
1253 if (tiTemp.pszText)
1254 pttd->pszPaintText = strdup(tiTemp.pszText);
1255 else
1256 pttd->pszPaintText = NULL;
1257 }
1258
1259 if (pttd->pszPaintText)
1260 {
1261 FormatTooltip(hwndTooltip,
1262 pttd,
1263 &ptlPointer);
1264
1265 // notify owner (TTN_SHOW)
1266 WinSendMsg(pttd->hwndOwner,
1267 WM_CONTROL,
1268 MPFROM2SHORT(pttd->ulTooltipID, // tooltip control wnd ID
1269 TTN_SHOW),
1270 pttd->ptiMouseOver);
1271
1272 WinShowWindow(hwndTooltip, TRUE);
1273 pttd->fIsVisible = TRUE;
1274
1275 // start autopop timer
1276 pttd->idTimerAutopop = WinStartTimer(pttd->hab,
1277 hwndTooltip,
1278 TOOLTIP_ID_TIMER_AUTOPOP,
1279 pttd->ulTimeoutAutopop);
1280 } // end if (pttd->pszPaintText)
1281 } // end if ( (ptlPointer.x == pttd->ptlPointerLast.x)...
1282 } // end if (mp1)
1283 else
1284 {
1285 /*
1286 * hide tooltip::
1287 *
1288 */
1289
1290 if (pttd->fIsVisible)
1291 {
1292 // notify owner (TTN_POP)
1293 WinSendMsg(pttd->hwndOwner,
1294 WM_CONTROL,
1295 MPFROM2SHORT(pttd->ulTooltipID, // tooltip control wnd ID
1296 TTN_POP),
1297 pttd->ptiMouseOver);
1298 WinShowWindow(hwndTooltip, FALSE);
1299 }
1300
1301 // stop autopop timer
1302 if (pttd->idTimerAutopop)
1303 {
1304 WinStopTimer(pttd->hab,
1305 hwndTooltip,
1306 TOOLTIP_ID_TIMER_AUTOPOP);
1307 pttd->idTimerAutopop = 0;
1308 }
1309 }
1310
1311 // store new visibility
1312 pttd->fIsVisible = fShow;
1313}
1314
1315/*
1316 *@@ ctl_fnwpTooltip:
1317 * window procedure for the "tooltip" control. This control is
1318 * largely source-code compatible to the Win32 version and has
1319 * been modelled according to the Win32 programmer's reference.
1320 *
1321 * A tooltip control is a small pop-up window that displays a
1322 * single line of descriptive text giving the purpose of "tools"
1323 * in an application.
1324 * A "tool" is either a window, such as a child window or control,
1325 * or an application-defined rectangular area within a window.
1326 * See the TTM_ADDTOOL message for details.
1327 *
1328 * To clarify: There is usually one tooltip control, which is hidden
1329 * most of the time, for many "tools" (parts of a visible window).
1330 * When the user puts the cursor on a tool and leaves it there for
1331 * approximately one-half second, the tooltip control is set up for
1332 * that tool and made visible. The tooltip control appears near the
1333 * pointer and disappears when the user clicks a mouse button or moves
1334 * the pointer off of the tool.
1335 *
1336 * The Win32 concept has been extended with this implementation to
1337 * display even longer texts, including line breaks. The tooltip
1338 * window is formatted accordingly.
1339 *
1340 * All default window styles are ignored when you create the tooltip,
1341 * but will rather be set by this window proc automatically. The
1342 * only valid window styles are the TTS_* flags (see notes below).
1343 *
1344 * Presentation parameters are fully supported.
1345 *
1346 * To create a tooltip control using comctl.c, use
1347 + ctlRegisterTooltip(hab);
1348 + hwndTooltip = WinCreateWindow(HWND_DESKTOP, // parent
1349 + COMCTL_TOOLTIP_CLASS, // wnd class (comctl.h)
1350 + NULL, // window text
1351 + TTS_ALWAYSTIP, // window style, ignored except for TTS_* flags
1352 + 0, 0, 0, 0, // window pos and size, ignored
1353 + hwndOwner, // owner window -- important!
1354 + NULLHANDLE, // hwndInsertBehind, ignored
1355 + ulID, // window ID, optional
1356 + NULL, // control data
1357 + NULL); // presparams
1358 +
1359 * ctl_fnwpTooltip automatically sets the size, position, and visibility
1360 * of the tooltip control. The size of the tooltip window will vary
1361 * depending on the text to be displayed and on the font presentation
1362 * parameters, which are supported by this control (OS/2 only).
1363 *
1364 * Note: OS/2 normally does not destroy windows which are only owned by
1365 * another window. As a result, when the tooltip's owner is destroyed,
1366 * you must explicitly also destroy the tooltip window.
1367 *
1368 * Under both Win32 and OS/2, a tooltip control has two class-specific styles:
1369 *
1370 * -- TTS_ALWAYSTIP: the tooltip appears when the cursor is on a tool,
1371 * regardless of whether the tooltip control's owner window is active
1372 * or inactive. Without this style, the tooltip control appears when the
1373 * tool's owner window is active, but not when it is inactive.
1374 *
1375 * -- TTS_NOPREFIX: this prevents the system from stripping the ampersand (&)
1376 * character from a string. If a tooltip control does not have the TTS_NOPREFIX
1377 * style, the system automatically strips ampersand characters, allowing an
1378 * application to use the same string as both a menu item and tooltip text.
1379 *
1380 * The tooltip control can be (de)activated using the TTM_ACTIVATE message.
1381 *
1382 * To register tools with the tooltip control (to make it do anything
1383 * meaningful), send the TTM_ADDTOOL message to the tooltip control.
1384 *
1385 * This control supports the following presentation parameters (if the
1386 * PP_* value is not found, the SYSCLR_* system color is used):
1387 * -- PP_MENUBACKGROUNDCOLOR / SYSCLR_ENTRYFIELD: tooltip background color.
1388 * -- PP_MENUFOREGROUNDCOLOR / SYSCLR_WINDOWTEXT: tooltip text color.
1389 * -- PP_MENUHILITEFGNDCOLOR / SYSCLR_WINDOWTEXT: 3D border light color.
1390 * -- PP_MENUHILITEBGNDCOLOR / SYSCLR_WINDOWTEXT: 3D border dark color.
1391 * -- PP_FONTNAMESIZE: font to use for the tooltip. The default is "8.Helv"
1392 * on Warp 3 and "9.WarpSans" on Warp 4.
1393 *
1394 * So per default, if no presentation parameters are set, the control
1395 * paints the background like an entry field and the text and the border
1396 * in the same window text color (usually black).
1397 * The tooltip does _not_ inherit presentation parameters from the parent,
1398 * so unless you explicitly set presparams, the tooltip looks pretty much
1399 * like the Win32 counterpart (with the default system colors, black border
1400 * and text on yellow background).
1401 *
1402 *@@added V0.9.0 [umoeller]
1403 *@@changed V0.9.12 (2001-04-28) [umoeller]: various fixes WRT subclassing
1404 */
1405
1406MRESULT EXPENTRY ctl_fnwpTooltip(HWND hwndTooltip, ULONG msg, MPARAM mp1, MPARAM mp2)
1407{
1408 MRESULT mrc = 0;
1409
1410 TRY_LOUD(excpt1)
1411 {
1412 switch (msg)
1413 {
1414 /*
1415 * WM_CREATE:
1416 * this message is sent to the window procedure of
1417 * the window being created, thus offering it an
1418 * opportunity to initialize that window.
1419 *
1420 * The window procedure receives this after the window
1421 * is created but before the window becomes visible.
1422 */
1423
1424 case WM_CREATE:
1425 mrc = TtmCreate(hwndTooltip, mp2);
1426 break;
1427
1428 /*
1429 * WM_HITTEST:
1430 * since we have the CS_HITTEST class style set,
1431 * we get this message. We return HT_TRANSPARENT
1432 * always so the tooltip does not block mouse clicks
1433 * for the windows which lie below.
1434 */
1435
1436 case WM_HITTEST: // done
1437 mrc = (MPARAM)HT_TRANSPARENT;
1438 break;
1439
1440 /*
1441 * WM_TIMER:
1442 * posted when either the "initial" timer
1443 * or the "autopop" timer times out.
1444 * We'll show or hide the tooltip then.
1445 */
1446
1447 case WM_TIMER: // done
1448 if (!TtmTimer(hwndTooltip, mp1))
1449 mrc = WinDefWindowProc(hwndTooltip, msg, mp1, mp2);
1450 break;
1451
1452 /*
1453 * WM_PAINT:
1454 *
1455 */
1456
1457 case WM_PAINT: // done
1458 TtmPaint(hwndTooltip);
1459 break;
1460
1461 /*
1462 * WM_PRESPARAMCHANGED:
1463 * presentation parameter has changed.
1464 */
1465
1466 case WM_PRESPARAMCHANGED:
1467 {
1468 LONG lPPIndex = (LONG)mp1;
1469 switch (lPPIndex)
1470 {
1471 case 0: // layout palette thing dropped
1472 case PP_MENUBACKGROUNDCOLOR:
1473 case PP_MENUFOREGROUNDCOLOR:
1474 case PP_MENUHILITEFGNDCOLOR:
1475 case PP_MENUHILITEBGNDCOLOR:
1476 // re-query our presparams
1477 UpdateTooltipPresColors(hwndTooltip);
1478 }
1479 break; }
1480
1481 /*
1482 * WM_SYSCOLORCHANGE:
1483 * system color has changed.
1484 */
1485
1486 case WM_SYSCOLORCHANGE:
1487 UpdateTooltipPresColors(hwndTooltip);
1488 break;
1489
1490 /*
1491 * WM_DESTROY:
1492 * clean up upon destruction.
1493 */
1494
1495 case WM_DESTROY:
1496 TtmDestroy(hwndTooltip);
1497 break;
1498
1499 /*
1500 *@@ TTM_ACTIVATE:
1501 * activates or deactives the tooltip control.
1502 *
1503 * Parameters:
1504 * -- BOOL mp1: if TRUE, activate, if FALSE, deactivate.
1505 * -- mp2: always 0.
1506 *
1507 * Return value: 0 always.
1508 */
1509
1510 case TTM_ACTIVATE: // done
1511 {
1512 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
1513 if (!(pttd->fIsActive = (BOOL)mp1))
1514 // disable: hide tooltip
1515 WinPostMsg(hwndTooltip, TTM_SHOWTOOLTIPNOW, (MPARAM)FALSE, 0);
1516 }
1517 break;
1518
1519 /*
1520 *@@ TTM_ADDTOOL:
1521 * registers a tool with a tooltip control.
1522 *
1523 * Parameters:
1524 * -- mp1: always 0.
1525 * -- PTOOLINFO mp2: information about the tool.
1526 *
1527 * Return value: TRUE if successful or FALSE otherwise.
1528 *
1529 * A tooltip control can support any number of tools. To
1530 * support a particular tool, you must register the tool
1531 * with the tooltip control by sending the TTM_ADDTOOL
1532 * message to the tooltip control. The message includes
1533 * the address of a TOOLINFO structure, which provides
1534 * information the tooltip control needs to display text
1535 * for the tool.
1536 *
1537 * A tooltip control supports tools implemented as windows
1538 * (such as child windows or control windows) and as
1539 * rectangular areas within a window's client area.
1540 *
1541 * -- When you add a tool implemented as a rectangular
1542 * area, the "hwndToolOwner" member of TOOLINFO must
1543 * specify the handle of the window that contains the
1544 * area, and the "rect" member must specify the client
1545 * coordinates of the area's bounding rectangle.
1546 *
1547 * -- When you add a tool implemented as a window, the
1548 * "hwndTool" member of TOOLINFO must contain the
1549 * window handle of the tool. hwndToolOwner should be
1550 * the owner of the tool.
1551 *
1552 * When you add a tool to a tooltip control, the "pszText"
1553 * member of the TOOLINFO structure must specify the string
1554 * to display for the tool. You can change the text any time
1555 * after adding the tool by using the TTM_UPDATETIPTEXT message.
1556 *
1557 * If you specify the PSZ_TEXTCALLBACK value in the pszText
1558 * member, whenever the tooltip control needs the text for the
1559 * tool, it sends a WM_CONTROL message to hwndToolOwner with
1560 * the TTN_NEEDTEXT notification code.
1561 *
1562 * The message includes the address of a TOOLTIPTEXT structure,
1563 * which contains the window handle of the tool. You can then
1564 * fill the TOOLTIPTEXT structure with the tool text.
1565 *
1566 * To retrieve the text for a tool, use the TTM_GETTEXT message.
1567 *
1568 *@@todo: add tool rectangles
1569 */
1570
1571 case TTM_ADDTOOL: // done
1572 mrc = TtmAddTool(hwndTooltip, mp2);
1573 break;
1574
1575 /*
1576 *@@ TTM_DELTOOL:
1577 * removes a tool from a tooltip control.
1578 *
1579 * Parameters:
1580 * -- mp1: always 0.
1581 * -- PTOOLINFO mp2: information about the tool;
1582 * all fields except cbSize, hwndToolOwner,
1583 * and hwndTool are ignored.
1584 *
1585 * Return value: 0 always.
1586 */
1587
1588 case TTM_DELTOOL: // done
1589 TtmDelTool(hwndTooltip, mp2);
1590 break;
1591
1592 /*
1593 *@@ TTM_NEWTOOLRECT:
1594 * sets a new bounding rectangle for a tool
1595 * already registered with a tooltip control.
1596 *
1597 * Parameters:
1598 * -- mp1: always 0.
1599 * -- PTOOLINFO mp2: information about the tool;
1600 * all fields except hwnd, uID, and rect
1601 * are ignored.
1602 *
1603 * Return value: 0 always.
1604 *
1605 * If an application includes a tool implemented as a rectangular
1606 * area and the size or position of the control changes, it can
1607 * use the TTM_NEWTOOLRECT message to report the change to the
1608 * tooltip control. An application does not need to report size
1609 * and position changes for a tool implemented as a window.
1610 * Reporting that is not necessary because the tooltip control
1611 * uses the window handle of a tool to determine if the cursor
1612 * is on the tool, not the tool's bounding rectangle.
1613 */
1614
1615 case TTM_NEWTOOLRECT:
1616
1617 break;
1618
1619 /*
1620 *@@ TTM_RELAYEVENT:
1621 * passes a mouse message to a tooltip control
1622 * for further processing.
1623 *
1624 * Parameters:
1625 * -- mp1: always 0.
1626 * -- PQMSG mp2: pointer to a QMSG struct (Win95: MSG struct)
1627 * containing a mouse message. Only the above messages
1628 * are processed.
1629 *
1630 * Return value: 0 always.
1631 *
1632 * A tooltip control needs to receive mouse messages to determine
1633 * when to display the tooltip window. Because mouse messages are
1634 * sent only to the window that contains the cursor, you must
1635 * use the TTM_RELAYEVENT message to relay mouse messages to the
1636 * tooltip control.
1637 *
1638 * If a tool is implemented as a rectangular area in an
1639 * application-defined window, the window procedure receives all
1640 * mouse messages and can relay the ones listed below to the
1641 * tooltip control, using this message.
1642 *
1643 * However, if a tool is implemented as a system-defined window,
1644 * the mouse messages are sent to that window and are not readily
1645 * available to the application. There are two ways you can have
1646 * the tooltip control notified of these mouse messages:
1647 *
1648 * -- You can specify the TTF_SUBCLASS flag when adding the tool
1649 * to the tooltip control. The tooltip control will then subclass
1650 * the tool window to get mouse-related messages, and you're off.
1651 *
1652 * -- You can implement a message hook for your process and check
1653 * for your tool windows there and send TTM_RELAYEVENT to the
1654 * tooltip control. In that case, you need to intercept the
1655 * messages specified below.
1656 *
1657 * When a tooltip control receives a relayed WM_MOUSEMOVE message,
1658 * it determines whether the cursor is in the bounding rectangle of
1659 * a tool. If the cursor is there, the tooltip control sets a timer.
1660 * At the end of the time-out duration, the tooltip control checks
1661 * the position of the cursor to see whether it has moved. If the
1662 * cursor has not, the tooltip control retrieves the text for the tool,
1663 * copies the text into the tooltip window, and shows the window.
1664 * The tooltip control continues to show the window until it receives
1665 * a relayed button-up or button-down message or until a relayed
1666 * WM_MOUSEMOVE message indicates that the cursor has moved outside
1667 * the bounding rectangle of the tool.
1668 *
1669 * For the timer descriptions, see TTM_SETDELAYTIME.
1670 *
1671 * When it is about to be displayed, a tootip control sends the
1672 * TTN_SHOW notification to the owner window. A tooltip control
1673 * sends the TTN_POP notification when it is about to be hidden.
1674 * Each notification is sent in the context of a WM_NOTIFY message
1675 * (OS/2: WM_CONTROL).
1676 *
1677 * Relevant messages:
1678 * -- WM_MOUSEMOVE
1679 * -- WM_BUTTON1DOWN (Win95: WM_LBUTTONDOWN)
1680 * -- WM_BUTTON1UP (Win95: WM_LBUTTONUP)
1681 * -- WM_BUTTON2DOWN (Win95: WM_RBUTTONDOWN)
1682 * -- WM_BUTTON2UP (Win95: WM_RBUTTONUP)
1683 * -- WM_BUTTON3DOWN (Win95: WM_MBUTTONDOWN)
1684 * -- WM_BUTTON3UP (Win95: WM_MBUTTONUP)
1685 */
1686
1687 case TTM_RELAYEVENT:
1688 TtmRelayEvent(hwndTooltip, mp2);
1689 break;
1690
1691 /*
1692 *@@ TTM_GETDELAYTIME:
1693 * returns the current value of the specified
1694 * timeout value. See TTM_SETDELAYTIME.
1695 *
1696 * Parameters:
1697 *
1698 * -- USHORT mp1: timer value to query. One of:
1699 * -- TTDT_AUTOPOP
1700 * -- TTDT_INITIAL
1701 * -- TTDT_RESHOW
1702 *
1703 * Returns: ULONG timeout value.
1704 *
1705 *@@added V0.9.12 (2001-04-28) [umoeller]
1706 */
1707
1708 case TTM_GETDELAYTIME:
1709 mrc = TtmGetDelayTime(hwndTooltip, mp1);
1710 break;
1711
1712 /*
1713 *@@ TTM_SETDELAYTIME:
1714 * overrides a few default timeout values for the
1715 * tooltip control.
1716 *
1717 * A tooltip control actually has three time-out durations
1718 * associated with it. The initial duration is the length
1719 * of time that the cursor must remain stationary within
1720 * the bounding rectangle of a tool before the tooltip window
1721 * is displayed. The reshow duration is the length of the delay
1722 * before subsequent tooltip windows are displayed when the
1723 * cursor moves from one tool to another. The autopopup duration
1724 * is the length of time that the tooltip window remains
1725 * displayed before it is hidden. That is, if the cursor remains
1726 * stationary within the bounding rectangle after the tooltip
1727 * window is displayed, the tooltip window is automatically
1728 * hidden at the end of the autopopup duration.
1729 *
1730 * You can adjust all of the time-out durations by using this
1731 * message.
1732 *
1733 * Parameters:
1734 * -- USHORT mp1: parameter selection. One of the following:
1735 * -- TTDT_AUTOMATIC: automatically calculates the initial,
1736 * reshow, and autopopup durations based on the value of mp2.
1737 * -- TTDT_AUTOPOP: sets the length of time before the tooltip
1738 * window is hidden if the cursor remains stationary
1739 * in the tool's bounding rectangle after the tooltip window
1740 * has appeared.
1741 * -- TTDT_INITIAL: sets the length of time that the cursor must
1742 * remain stationary within the bounding rectangle of
1743 * a tool before the tooltip window is displayed.
1744 * -- TTDT_RESHOW: sets the length of the delay before subsequent
1745 * tooltip windows are displayed when the cursor is moved
1746 * from one tool to another.
1747 * -- ULONG mp2: new duration, in milliseconds.
1748 *
1749 * Return value: 0 always.
1750 */
1751
1752 case TTM_SETDELAYTIME: // done
1753 TtmSetDelayTime(hwndTooltip, mp1, mp2);
1754 break;
1755
1756 /*
1757 *@@ TTM_GETTEXT:
1758 * retrieves the text for a tool in the tooltip control.
1759 *
1760 * Parameters:
1761 * -- mp1: always 0
1762 * -- PTOOLINFO mp2: pointer to a TOOLINFO structure.
1763 * hwndTool identifies a tool. If the tooltip control
1764 * includes the tool, the pszText member receives
1765 * the pointer to the string on output.
1766 *
1767 * Return value: 0 always.
1768 *
1769 * Additional note: On input, if TOOLINFO.lpszText == PSZ_TEXTCALLBACK,
1770 * this sends the TTN_NEEDTEXT notification to TOOLINFO.hwnd.
1771 *
1772 */
1773
1774 case TTM_GETTEXT: // done, I think
1775 TtmGetText(hwndTooltip, mp2);
1776 break;
1777
1778 /*
1779 *@@ TTM_UPDATETIPTEXT:
1780 * sets the current tooltip text explicitly,
1781 * no matter for what tool the tooltip is
1782 * currently being displayed. This might be
1783 * useful if you want to dynamically update
1784 * the tooltip display.
1785 *
1786 * If the tooltip is currently showing,
1787 * it is reformatted with the new text.
1788 *
1789 * Note that the change is not permanent;
1790 * if the mouse moves over a different
1791 * tool next, the change will be lost.
1792 *
1793 * Parameters:
1794 * -- PSZ mp1: new text to display.
1795 *
1796 *@@added V0.9.13 (2001-06-21) [umoeller]
1797 */
1798
1799 case TTM_UPDATETIPTEXT:
1800 TtmUpdateTipText(hwndTooltip, (PSZ)mp1);
1801 break;
1802
1803 /*
1804 *@@ TTM_HITTEST:
1805 * tests a point to determine whether it is within the
1806 * bounding rectangle of the specified tool and, if the
1807 * point is within, retrieves information about the tool.
1808 *
1809 * Parameters:
1810 * -- mp1: always 0.
1811 * -- PHITTESTINFO mp2: pointer to a TTHITTESTINFO structure.
1812 * When sending the message, the "hwnd" member must specify
1813 * the handle of a tool and the "pt" member must specify the
1814 * coordinates of a point. If the return value is TRUE, the
1815 * "ti" member receives information about the tool that
1816 * occupies the point.
1817 *
1818 * Return value: returns TRUE if the tool occupies the specified
1819 * point or FALSE otherwise.
1820 */
1821
1822 case TTM_HITTEST:
1823 break;
1824
1825 /*
1826 *@@ TTM_WINDOWFROMPOINT:
1827 * this message allows a subclass procedure to cause a tooltip
1828 * to display text for a window other than the one beneath the
1829 * mouse cursor.
1830 *
1831 * Parameters:
1832 * -- mp1: always 0.
1833 * -- mp2: PPOINTL lppt (Win95: (POINT FAR *)lppt):
1834 * pointer to a POINTL structure that defines the point to be checked.
1835 *
1836 * Return value: the handle to the window that contains the point, or
1837 * NULL if no window exists at the specified point.
1838 *
1839 * This message is intended to be processed by an application that
1840 * subclasses a tooltip. It is not intended to be sent by an
1841 * application. A tooltip sends this message to itself before
1842 * displaying the text for a window. By changing the coordinates
1843 * of the point specified by lppt, the subclass procedure can cause
1844 * the tooltip to display text for a window other than the one
1845 * beneath the mouse cursor.
1846 */
1847
1848 case TTM_WINDOWFROMPOINT:
1849 break;
1850
1851 /*
1852 *@@ TTM_ENUMTOOLS:
1853 * this message retrieves the information that a tooltip control
1854 * maintains about a certain tool.
1855 *
1856 * Parameters:
1857 * -- USHORT mp1: zero-based index of the tool for which to
1858 * retrieve information.
1859 * -- PTOOLINFO mp2: pointer to a TOOLINFO structure that
1860 * receives information about the tool. Before sending
1861 * this message, the cbSize member must specify the size
1862 * of the structure.
1863 *
1864 * Return value: TRUE if any tools are enumerated or FALSE otherwise.
1865 */
1866
1867 case TTM_ENUMTOOLS: // done
1868 mrc = TtmEnumTools(hwndTooltip, mp1, mp2);
1869 break;
1870
1871 /*
1872 *@@ TTM_GETCURRENTTOOL:
1873 * this message retrieves the information that the
1874 * tooltip control maintains for the _current_ tool;
1875 * that is, the one for which the tooltip control
1876 * is currently displaying text.
1877 *
1878 * Parameters:
1879 * -- mp1: always 0.
1880 * -- PTOOLINFO mp2: pointer to a TOOLINFO structure that receives
1881 * information about the current tool.
1882 *
1883 * Return value: TRUE if successful or FALSE otherwise.
1884 */
1885
1886 case TTM_GETCURRENTTOOL: // done
1887 mrc = TtmGetCurrentTool(hwndTooltip, mp2);
1888 break;
1889
1890 /*
1891 *@@ TTM_GETTOOLCOUNT:
1892 * returns the number of tools in the tooltip control.
1893 *
1894 * No parameters.
1895 */
1896
1897 case TTM_GETTOOLCOUNT: // done
1898 {
1899 PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1);
1900 mrc = (MPARAM)lstCountItems(&pttd->llTools);
1901 break; }
1902
1903 /*
1904 *@@ TTM_GETTOOLINFO:
1905 * this message retrieves the information that a tooltip
1906 * control maintains about a tool.
1907 *
1908 * Parameters:
1909 * -- mp1: always 0.
1910 * -- PTOOLINFO mp2:
1911 * pointer to a TOOLINFO structure. When sending the message,
1912 * the hwnd and uId members identify a tool, and the cbSize
1913 * member must specify the size of the structure. If the
1914 * tooltip control includes the tool, the structure receives
1915 * information about the tool.
1916 *
1917 * Return value: TRUE if successful or FALSE otherwise.
1918 */
1919
1920 case TTM_GETTOOLINFO: // done
1921 mrc = TtmGetToolInfo(hwndTooltip, mp2);
1922 break;
1923
1924 /*
1925 *@@ TTM_SETTOOLINFO:
1926 * this message sets the information that a tooltip control
1927 * maintains for a tool.
1928 *
1929 * Parameters:
1930 * -- mp1: always 0.
1931 * -- PTOOLINFO mp2: pointer to a TOOLINFO structure that
1932 * specifies the information to set.
1933 *
1934 * Return value: 0 always.
1935 */
1936
1937 case TTM_SETTOOLINFO:
1938 break;
1939
1940 /*
1941 *@@ TTM_SHOWTOOLTIPNOW:
1942 * depending on BOOL mp1, shows or hides the tooltip.
1943 * This is required because we cannot show or hide
1944 * the window during processing of WM_MOUSEMOVE etc,
1945 * which will lead to strange PM hangs.
1946 *
1947 * This is not part of the Win95 message set but used
1948 * in the OS/2 implementation only. This calls
1949 * TtmShowTooltip in turn.
1950 */
1951
1952 case TTM_SHOWTOOLTIPNOW:
1953 TtmShowTooltip(hwndTooltip, (BOOL)mp1);
1954 break;
1955
1956 default:
1957 mrc = WinDefWindowProc(hwndTooltip, msg, mp1, mp2);
1958 }
1959 }
1960 CATCH(excpt1) {} END_CATCH();
1961
1962 return (mrc);
1963}
1964
1965
Note: See TracBrowser for help on using the repository browser.