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

Last change on this file since 184 was 184, checked in by umoeller, 23 years ago

Second round of fixes for 0.9.19.

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