Files
Mozilla/mozilla/widget/src/os2/nsTooltipManager.cpp
mkaply%us.ibm.com a9df2ad157 # 33860
r= mkaply@us.ibm.com
OS/2 bringup


git-svn-id: svn://10.0.0.236/trunk@65081 18797224-902f-48f8-a5cc-f745e15eee43
2000-04-03 23:30:26 +00:00

378 lines
10 KiB
C++

/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is the Mozilla OS/2 libraries.
*
* The Initial Developer of the Original Code is John Fairhurst,
* <john_fairhurst@iname.com>. Portions created by John Fairhurst are
* Copyright (C) 1999 John Fairhurst. All Rights Reserved.
*
* Contributor(s):
*
*
* This Original Code has been modified by IBM Corporation.
* Modifications made by IBM described herein are
* Copyright (c) International Business Machines
* Corporation, 2000
*
* Modifications to Mozilla code or documentation
* identified per MPL Section 3.3
*
* Date Modified by Description of modification
* 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
* use in OS2
*
*/
#include "nsTooltipManager.h"
#include "nswindow.h"
// Created 25-9-98 mjf, improvising furiously...
// --> Bank on TTData->cRcls being smallish.
//
// This is probably a bad bet, seeing as the main use will be on a child
// window rendering content with many separate areas of interest (eg. 1
// per image with alt text).
//
// So it may turn out to be a good idea to make this data structure more
// sophisticated -- hash on the coordinates.
// Hashtable defs; key is HWND, element is TTData*
class HWNDHashKey : public nsHashKey
{
HWND hwnd;
public:
HWNDHashKey( HWND h) : hwnd(h) {}
virtual PRUint32 HashValue() const { return hwnd; }
virtual PRBool Equals( const nsHashKey *aKey) const
{ return (((HWNDHashKey*)aKey)->hwnd == hwnd) ? PR_TRUE : PR_FALSE; }
virtual nsHashKey *Clone() const
{ return new HWNDHashKey( hwnd); }
};
#define ID_TT_TIMER (TID_USERMAX-1)
struct TTData
{
HWND hwnd;
RECTL *aRcls; // could use a region to hold rects, but need to know
ULONG cRcls; // index of rectangle for notifications.
// [see large comment above]
LONG lIndex; // Index of last rectangle hit. -1 is none.
LONG lIndexShowing;
PFNWP oldFnWp;
BOOL bTimerSet;
POINTL ptStart;
TTData( HWND h) : hwnd(h), aRcls(0), cRcls(0), lIndex(-1),
lIndexShowing(-1), oldFnWp(0), bTimerSet(0)
{ ptStart.x = 0; ptStart.y = 0; }
~TTData()
{ delete [] aRcls; }
// if cRects is 0, same number as we already have.
void UpdateTooltips( nsWindow *w, nsRect *rects[], PRUint32 cRects = 0)
{
if( cRects > 0)
{
delete [] aRcls;
aRcls = new RECTL [cRects];
cRcls = cRects;
}
// Get bounds once..
nsRect bounds;
w->GetBounds( bounds);
for( ULONG i = 0; i < cRects; i++)
{
// convert the ith nsrect to the ith in-ex rectl
aRcls[i].yTop = bounds.height - rects[i]->y;
aRcls[i].xLeft = rects[i]->x;
aRcls[i].xRight = aRcls[i].xLeft + rects[i]->width;
aRcls[i].yBottom = aRcls[i].yTop - rects[i]->height;
}
}
void StopTimer()
{
if( bTimerSet)
{
WinStopTimer( 0/*hab*/, hwnd, ID_TT_TIMER);
bTimerSet = FALSE;
}
}
void StartTimer()
{
if( !bTimerSet)
{
WinStartTimer( 0/*hab*/, hwnd, ID_TT_TIMER, 1000); // 1 second?
bTimerSet = TRUE;
}
}
long Test( PPOINTL pt)
{
lIndex = -1;
for( ULONG i = 0; lIndex == -1 && i < cRcls; i++)
if( WinPtInRect( 0/*hab*/, aRcls + i, pt))
lIndex = i;
return lIndex;
}
void ShowTooltip()
{
NS_ASSERTION( lIndex >= 0, "Invalid tt index");
if( lIndex != lIndexShowing)
{
WinSendMsg( hwnd, WMU_SHOW_TOOLTIP, MPFROMLONG(lIndex), 0);
lIndexShowing = lIndex;
}
}
void HideTooltip()
{
if( lIndexShowing != -1)
{
WinSendMsg( hwnd, WMU_HIDE_TOOLTIP, 0, 0);
lIndexShowing = -1;
}
}
};
// subclass to watch for mouse messages
MRESULT EXPENTRY HandleMsg( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
return nsTooltipManager::GetManager()->HandleMsg( hwnd, msg, mp1, mp2);
}
#define HOVER_DIST_SQR 100
// Message handler ---------------------------------------------------------
MRESULT nsTooltipManager::HandleMsg( HWND hwnd, ULONG msg,
MPARAM mp1, MPARAM mp2)
{
MRESULT mRC = 0;
// find data area
TTData *pData = GetEntry( hwnd);
if( pData)
{
BOOL bSet = FALSE;
switch( msg)
{
case WMU_MOUSEENTER:
case WM_MOUSEMOVE:
{
// Is point in rectl list?
// Yes: Is tooltip mode on?
// Yes: Show tooltip
// No: Is timer set?
// Yes: Is point < HOVER_DIST from startpoint ?
// Yes: run away
// No: Stop timer
// No: nop
// Record startpoint
// Start timer
// No: No tooltip here: Stop timer, run away
pData->StopTimer();
POINTL pt = { SHORT1FROMMP(mp1), SHORT2FROMMP(mp1) };
if( pData->Test( &pt) >= 0)
{
if( mTTMode == PR_TRUE)
{
pData->ShowTooltip();
}
else
{
if( pData->bTimerSet)
{
// ..approx..
long lX = pt.x - pData->ptStart.x;
long lY = pt.y - pData->ptStart.y;
if( lX * lX + lY * lY < HOVER_DIST_SQR)
{
break;
}
else
{
pData->StopTimer();
}
}
memcpy( &pData->ptStart, &pt, sizeof pt);
pData->StartTimer();
}
}
else
{
pData->StopTimer();
}
break;
}
case WM_TIMER:
// Is it our timer?
// Yes: Set tooltip mode; cancel timer; show tooltip
// No: Run away
if( SHORT1FROMMP( mp1) == ID_TT_TIMER)
{
mTTMode = PR_TRUE;
pData->StopTimer();
pData->ShowTooltip();
bSet = TRUE;
}
break;
case WMU_MOUSELEAVE:
// Is tooltip mode on?
// Yes: hide tooltip; Is next window one of ours?
// Yes: do nothing
// No: unset tooltip mode
// No: stop timer
if( mTTMode)
{
pData->HideTooltip();
if( 0 == GetEntry( HWNDFROMMP(mp2)))
{
mTTMode = PR_FALSE;
}
}
else
{
pData->StopTimer();
}
break;
case WM_BUTTON1DOWN:
case WM_BUTTON2DOWN:
case WM_BUTTON3DOWN:
// Is tooltip mode on?
// Yes: hide tooltip; unset tooltip mode
// No: Stop timer
if( mTTMode)
{
pData->HideTooltip();
mTTMode = PR_FALSE;
}
else
{
pData->StopTimer();
}
break;
}
if( !bSet && pData->oldFnWp)
mRC = (*pData->oldFnWp)( hwnd, msg, mp1, mp2);
}
else // ..oops..
mRC = WinDefWindowProc( hwnd, msg, mp1, mp2);
return mRC;
}
// Manager methods ---------------------------------------------------------
TTData *nsTooltipManager::GetEntry( nsWindow *w)
{
HWND hwnd = (HWND) w->GetNativeData( NS_NATIVE_WINDOW);
return GetEntry( hwnd);
}
TTData *nsTooltipManager::GetEntry( HWND hwnd)
{
HWNDHashKey key( hwnd);
return (TTData*) mManaged.Get( &key);
}
void nsTooltipManager::SetTooltips( nsWindow *window,
PRUint32 cTips, nsRect *rects[])
{
TTData *pData = GetEntry( window);
if( !pData)
{
HWND hwnd = (HWND) window->GetNativeData( NS_NATIVE_WINDOW);
pData = new TTData( hwnd);
pData->oldFnWp = WinSubclassWindow( hwnd, ::HandleMsg);
HWNDHashKey key(hwnd);
mManaged.Put( &key, pData);
mElements++;
}
pData->UpdateTooltips( window, rects, cTips);
}
void nsTooltipManager::UpdateTooltips( nsWindow *window, nsRect *rects[])
{
TTData *pData = GetEntry( window);
NS_ASSERTION( pData, "Update tt for bad window");
pData->UpdateTooltips( window, rects);
}
void nsTooltipManager::RemoveTooltips( nsWindow *window)
{
HWND hwnd = (HWND) window->GetNativeData( NS_NATIVE_WINDOW);
HWNDHashKey key( hwnd);
TTData *pData = (TTData*) mManaged.Remove( &key);
if( pData)
{
pData->StopTimer(); // just for safety
WinSubclassWindow( hwnd, pData->oldFnWp);
delete pData;
mElements--;
}
if( 0 == mElements) // no clients, go away
{
delete this;
nsTooltipManager::sMgr = 0;
}
}
// Ctor/dtor stuff ---------------------------------------------------------
nsTooltipManager::nsTooltipManager() : mElements(0), mTTMode( PR_FALSE)
{}
PRBool PR_CALLBACK emptyHashtableFunc( nsHashKey *aKey, void *aData, void *pClosure)
{
delete (TTData*) aData;
return PR_TRUE; // keep going
}
nsTooltipManager::~nsTooltipManager()
{
// shouldn't be any elements...
// NS_ASSERTION( mElements == 0, "Non-deregistered tts");
mManaged.Enumerate( emptyHashtableFunc);
}
nsTooltipManager *nsTooltipManager::GetManager()
{
if( !sMgr)
sMgr = new nsTooltipManager;
return sMgr;
}
nsTooltipManager *nsTooltipManager::sMgr;