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

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

Misc fixes.

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