mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
[EXPLORER] Implement rudimentary uVersion management, and notification balloons.
- uVersion will only be truly useful when Vista+'s V4 style notification icons are implemented. - Balloon notifications do not yet support queuing and auto-closing. - Force the notification icon tooltips to always show even if the taskbar isn't foreground. [ROSCTRLS.H] Implement CTooltips class which manages a comctl32 tooltips window.
This commit is contained in:
parent
c7ad200f8b
commit
bbca71c4a5
2 changed files with 421 additions and 21 deletions
|
@ -34,6 +34,12 @@ typedef struct _SYS_PAGER_COPY_DATA
|
||||||
NOTIFYICONDATA nicon_data;
|
NOTIFYICONDATA nicon_data;
|
||||||
} SYS_PAGER_COPY_DATA, *PSYS_PAGER_COPY_DATA;
|
} SYS_PAGER_COPY_DATA, *PSYS_PAGER_COPY_DATA;
|
||||||
|
|
||||||
|
struct InternalIconData : NOTIFYICONDATA
|
||||||
|
{
|
||||||
|
// Must keep a separate copy since the original is unioned with uTimeout.
|
||||||
|
UINT uVersionCopy;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct IconWatcherData
|
struct IconWatcherData
|
||||||
{
|
{
|
||||||
|
@ -310,15 +316,22 @@ private:
|
||||||
|
|
||||||
|
|
||||||
class CNotifyToolbar :
|
class CNotifyToolbar :
|
||||||
public CWindowImplBaseT< CToolbar<NOTIFYICONDATA>, CControlWinTraits >
|
public CWindowImplBaseT< CToolbar<InternalIconData>, CControlWinTraits >
|
||||||
{
|
{
|
||||||
HIMAGELIST m_ImageList;
|
HIMAGELIST m_ImageList;
|
||||||
int m_VisibleButtonCount;
|
int m_VisibleButtonCount;
|
||||||
|
|
||||||
|
HWND m_BalloonsParent;
|
||||||
|
CTooltips * m_Balloons;
|
||||||
|
InternalIconData * m_currentTooltip;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CNotifyToolbar() :
|
CNotifyToolbar() :
|
||||||
m_ImageList(NULL),
|
m_ImageList(NULL),
|
||||||
m_VisibleButtonCount(0)
|
m_VisibleButtonCount(0),
|
||||||
|
m_BalloonsParent(NULL),
|
||||||
|
m_Balloons(NULL),
|
||||||
|
m_currentTooltip(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,15 +344,13 @@ public:
|
||||||
return m_VisibleButtonCount;
|
return m_VisibleButtonCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FindItem(IN HWND hWnd, IN UINT uID, NOTIFYICONDATA ** pdata)
|
int FindItem(IN HWND hWnd, IN UINT uID, InternalIconData ** pdata)
|
||||||
{
|
{
|
||||||
int count = GetButtonCount();
|
int count = GetButtonCount();
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
NOTIFYICONDATA * data;
|
InternalIconData * data = GetItemData(i);
|
||||||
|
|
||||||
data = GetItemData(i);
|
|
||||||
|
|
||||||
if (data->hWnd == hWnd &&
|
if (data->hWnd == hWnd &&
|
||||||
data->uID == uID)
|
data->uID == uID)
|
||||||
|
@ -358,7 +369,7 @@ public:
|
||||||
int count = GetButtonCount();
|
int count = GetButtonCount();
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
NOTIFYICONDATA * data = GetItemData(i);
|
InternalIconData * data = GetItemData(i);
|
||||||
if (data->hIcon == handle)
|
if (data->hIcon == handle)
|
||||||
{
|
{
|
||||||
TBBUTTON btn;
|
TBBUTTON btn;
|
||||||
|
@ -373,7 +384,7 @@ public:
|
||||||
BOOL AddButton(IN CONST NOTIFYICONDATA *iconData)
|
BOOL AddButton(IN CONST NOTIFYICONDATA *iconData)
|
||||||
{
|
{
|
||||||
TBBUTTON tbBtn;
|
TBBUTTON tbBtn;
|
||||||
NOTIFYICONDATA * notifyItem;
|
InternalIconData * notifyItem;
|
||||||
WCHAR text[] = L"";
|
WCHAR text[] = L"";
|
||||||
|
|
||||||
TRACE("Adding icon %d from hWnd %08x flags%s%s state%s%s",
|
TRACE("Adding icon %d from hWnd %08x flags%s%s state%s%s",
|
||||||
|
@ -390,7 +401,7 @@ public:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyItem = new NOTIFYICONDATA();
|
notifyItem = new InternalIconData();
|
||||||
ZeroMemory(notifyItem, sizeof(*notifyItem));
|
ZeroMemory(notifyItem, sizeof(*notifyItem));
|
||||||
|
|
||||||
notifyItem->hWnd = iconData->hWnd;
|
notifyItem->hWnd = iconData->hWnd;
|
||||||
|
@ -437,6 +448,16 @@ public:
|
||||||
StringCchCopy(notifyItem->szTip, _countof(notifyItem->szTip), iconData->szTip);
|
StringCchCopy(notifyItem->szTip, _countof(notifyItem->szTip), iconData->szTip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iconData->uFlags & NIF_INFO)
|
||||||
|
{
|
||||||
|
// NOTE: In Vista+, the uTimeout value is disregarded, and the accessibility settings are used always.
|
||||||
|
StrNCpy(notifyItem->szInfo, iconData->szInfo, _countof(notifyItem->szInfo));
|
||||||
|
StrNCpy(notifyItem->szInfoTitle, iconData->szInfoTitle, _countof(notifyItem->szInfo));
|
||||||
|
notifyItem->dwInfoFlags = iconData->dwInfoFlags;
|
||||||
|
notifyItem->uTimeout = iconData->uTimeout;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
m_VisibleButtonCount++;
|
m_VisibleButtonCount++;
|
||||||
if (notifyItem->dwState & NIS_HIDDEN)
|
if (notifyItem->dwState & NIS_HIDDEN)
|
||||||
{
|
{
|
||||||
|
@ -444,17 +465,45 @@ public:
|
||||||
m_VisibleButtonCount--;
|
m_VisibleButtonCount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
|
/* TODO: support VERSION_4 (NIF_GUID, NIF_REALTIME, NIF_SHOWTIP) */
|
||||||
|
|
||||||
CToolbar::AddButton(&tbBtn);
|
CToolbar::AddButton(&tbBtn);
|
||||||
SetButtonSize(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
|
SetButtonSize(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
|
||||||
|
|
||||||
|
if (iconData->uFlags & NIF_INFO)
|
||||||
|
{
|
||||||
|
UpdateBalloonTip(notifyItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL SwitchVersion(IN CONST NOTIFYICONDATA *iconData)
|
||||||
|
{
|
||||||
|
InternalIconData * notifyItem;
|
||||||
|
int index = FindItem(iconData->hWnd, iconData->uID, ¬ifyItem);
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
WARN("Icon %d from hWnd %08x DOES NOT EXIST!", iconData->uID, iconData->hWnd);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iconData->uVersion != 0 && iconData->uVersion != NOTIFYICON_VERSION)
|
||||||
|
{
|
||||||
|
WARN("Tried to set the version of icon %d from hWnd %08x, to an unknown value %d. Vista+ program?", iconData->uID, iconData->hWnd, iconData->uVersion);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can not store the version in the uVersion field, because it's union'd with uTimeout,
|
||||||
|
// which we also need to keep track of.
|
||||||
|
notifyItem->uVersionCopy = iconData->uVersion;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL UpdateButton(IN CONST NOTIFYICONDATA *iconData)
|
BOOL UpdateButton(IN CONST NOTIFYICONDATA *iconData)
|
||||||
{
|
{
|
||||||
NOTIFYICONDATA * notifyItem;
|
InternalIconData * notifyItem;
|
||||||
TBBUTTONINFO tbbi = { 0 };
|
TBBUTTONINFO tbbi = { 0 };
|
||||||
|
|
||||||
TRACE("Updating icon %d from hWnd %08x flags%s%s state%s%s",
|
TRACE("Updating icon %d from hWnd %08x flags%s%s state%s%s",
|
||||||
|
@ -536,16 +585,30 @@ public:
|
||||||
StringCchCopy(notifyItem->szTip, _countof(notifyItem->szTip), iconData->szTip);
|
StringCchCopy(notifyItem->szTip, _countof(notifyItem->szTip), iconData->szTip);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
|
if (iconData->uFlags & NIF_INFO)
|
||||||
|
{
|
||||||
|
// NOTE: In Vista+, the uTimeout value is disregarded, and the accessibility settings are used always.
|
||||||
|
StrNCpy(notifyItem->szInfo, iconData->szInfo, _countof(notifyItem->szInfo));
|
||||||
|
StrNCpy(notifyItem->szInfoTitle, iconData->szInfoTitle, _countof(notifyItem->szInfo));
|
||||||
|
notifyItem->dwInfoFlags = iconData->dwInfoFlags;
|
||||||
|
notifyItem->uTimeout = iconData->uTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: support VERSION_4 (NIF_GUID, NIF_REALTIME, NIF_SHOWTIP) */
|
||||||
|
|
||||||
SetButtonInfo(index, &tbbi);
|
SetButtonInfo(index, &tbbi);
|
||||||
|
|
||||||
|
if (iconData->uFlags & NIF_INFO)
|
||||||
|
{
|
||||||
|
UpdateBalloonTip(notifyItem);
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL RemoveButton(IN CONST NOTIFYICONDATA *iconData)
|
BOOL RemoveButton(IN CONST NOTIFYICONDATA *iconData)
|
||||||
{
|
{
|
||||||
NOTIFYICONDATA * notifyItem;
|
InternalIconData * notifyItem;
|
||||||
|
|
||||||
TRACE("Removing icon %d from hWnd %08x", iconData->uID, iconData->hWnd);
|
TRACE("Removing icon %d from hWnd %08x", iconData->uID, iconData->hWnd);
|
||||||
|
|
||||||
|
@ -587,16 +650,86 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete notifyItem;
|
HideBalloonTip(notifyItem);
|
||||||
|
|
||||||
DeleteButton(index);
|
DeleteButton(index);
|
||||||
|
|
||||||
|
delete notifyItem;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateBalloonTip(InternalIconData* notifyItem)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
if (SUCCEEDED(StringCchLength(notifyItem->szInfo, _countof(notifyItem->szInfo), &len)) && len > 0)
|
||||||
|
{
|
||||||
|
ShowBalloonTip(notifyItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HideBalloonTip(notifyItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static WPARAM GetTitleIcon(DWORD dwFlags, HICON hIcon)
|
||||||
|
{
|
||||||
|
if (dwFlags & NIIF_USER)
|
||||||
|
return reinterpret_cast<WPARAM>(hIcon);
|
||||||
|
|
||||||
|
return dwFlags & 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL ShowBalloonTip(IN OUT InternalIconData *notifyItem)
|
||||||
|
{
|
||||||
|
DbgPrint("ShowBalloonTip called for flags=%x text=%ws; title=%ws", notifyItem->dwInfoFlags, notifyItem->szInfo, notifyItem->szInfoTitle);
|
||||||
|
|
||||||
|
// TODO: Queueing -> NIF_REALTIME? (Vista+)
|
||||||
|
// TODO: NIIF_NOSOUND, Vista+ flags
|
||||||
|
|
||||||
|
const WPARAM icon = GetTitleIcon(notifyItem->dwInfoFlags, notifyItem->hIcon);
|
||||||
|
BOOL ret = m_Balloons->SetTitle(notifyItem->szInfoTitle, icon);
|
||||||
|
if (!ret)
|
||||||
|
DbgPrint("SetTitle failed, GetLastError=%d", GetLastError());
|
||||||
|
|
||||||
|
const int index = FindItem(notifyItem->hWnd, notifyItem->uID, NULL);
|
||||||
|
RECT rc;
|
||||||
|
GetItemRect(index, &rc);
|
||||||
|
ClientToScreen(&rc); // I have no idea why this is needed! >_<
|
||||||
|
WORD x = (rc.left + rc.right) / 2;
|
||||||
|
WORD y = (rc.top + rc.bottom) / 2;
|
||||||
|
DbgPrint("ClientToScreen returned (%d, %d, %d, %d) x=%d, y=%d",
|
||||||
|
rc.left, rc.top,
|
||||||
|
rc.right, rc.bottom, x, y);
|
||||||
|
m_Balloons->TrackPosition(x, y);
|
||||||
|
m_Balloons->UpdateTipText(m_BalloonsParent, reinterpret_cast<LPARAM>(m_hWnd), notifyItem->szInfo);
|
||||||
|
m_Balloons->TrackActivate(m_BalloonsParent, reinterpret_cast<LPARAM>(m_hWnd));
|
||||||
|
m_currentTooltip = notifyItem;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID HideBalloonTip(IN OUT InternalIconData *notifyItem)
|
||||||
|
{
|
||||||
|
DbgPrint("HideBalloonTip called");
|
||||||
|
|
||||||
|
if (m_currentTooltip == notifyItem)
|
||||||
|
{
|
||||||
|
// Prevent Re-entry
|
||||||
|
m_currentTooltip = NULL;
|
||||||
|
m_Balloons->TrackDeactivate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID HideCurrentBalloon()
|
||||||
|
{
|
||||||
|
if (m_currentTooltip != NULL)
|
||||||
|
HideBalloonTip(m_currentTooltip);
|
||||||
|
}
|
||||||
|
|
||||||
VOID GetTooltipText(int index, LPTSTR szTip, DWORD cchTip)
|
VOID GetTooltipText(int index, LPTSTR szTip, DWORD cchTip)
|
||||||
{
|
{
|
||||||
NOTIFYICONDATA * notifyItem;
|
InternalIconData * notifyItem = GetItemData(index);
|
||||||
notifyItem = GetItemData(index);
|
|
||||||
|
|
||||||
if (notifyItem)
|
if (notifyItem)
|
||||||
{
|
{
|
||||||
|
@ -626,7 +759,7 @@ public:
|
||||||
int count = GetButtonCount();
|
int count = GetButtonCount();
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
NOTIFYICONDATA * data = GetItemData(i);
|
InternalIconData * data = GetItemData(i);
|
||||||
BOOL hasSharedIcon = data->dwState & NIS_SHAREDICON;
|
BOOL hasSharedIcon = data->dwState & NIS_SHAREDICON;
|
||||||
INT iIcon = hasSharedIcon ? FindExistingSharedIcon(data->hIcon) : -1;
|
INT iIcon = hasSharedIcon ? FindExistingSharedIcon(data->hIcon) : -1;
|
||||||
if (iIcon < 0)
|
if (iIcon < 0)
|
||||||
|
@ -659,7 +792,7 @@ private:
|
||||||
L"WM_XBUTTONDBLCLK"
|
L"WM_XBUTTONDBLCLK"
|
||||||
};
|
};
|
||||||
|
|
||||||
NOTIFYICONDATA * notifyItem = GetItemData(wIndex);
|
InternalIconData * notifyItem = GetItemData(wIndex);
|
||||||
|
|
||||||
if (!::IsWindow(notifyItem->hWnd))
|
if (!::IsWindow(notifyItem->hWnd))
|
||||||
{
|
{
|
||||||
|
@ -770,15 +903,17 @@ private:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BEGIN_MSG_MAP(CNotifyToolbar)
|
BEGIN_MSG_MAP(CNotifyToolbar)
|
||||||
MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseEvent)
|
MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseEvent)
|
||||||
NOTIFY_CODE_HANDLER(TTN_SHOW, OnTooltipShow)
|
NOTIFY_CODE_HANDLER(TTN_SHOW, OnTooltipShow)
|
||||||
END_MSG_MAP()
|
END_MSG_MAP()
|
||||||
|
|
||||||
void Initialize(HWND hWndParent)
|
void Initialize(HWND hWndParent, CTooltips * tooltips)
|
||||||
{
|
{
|
||||||
|
m_BalloonsParent = hWndParent;
|
||||||
|
m_Balloons = tooltips;
|
||||||
|
|
||||||
DWORD styles =
|
DWORD styles =
|
||||||
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |
|
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |
|
||||||
TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_TRANSPARENT |
|
TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_TRANSPARENT |
|
||||||
|
@ -786,6 +921,13 @@ public:
|
||||||
|
|
||||||
SubclassWindow(CToolbar::Create(hWndParent, styles));
|
SubclassWindow(CToolbar::Create(hWndParent, styles));
|
||||||
|
|
||||||
|
// Force the toolbar tooltips window to always show tooltips even if not foreground
|
||||||
|
HWND tooltipsWnd = (HWND)SendMessageW(TB_GETTOOLTIPS);
|
||||||
|
if (tooltipsWnd)
|
||||||
|
{
|
||||||
|
::SetWindowLong(tooltipsWnd, GWL_STYLE, ::GetWindowLong(tooltipsWnd, GWL_STYLE) | TTS_ALWAYSTIP);
|
||||||
|
}
|
||||||
|
|
||||||
SetWindowTheme(m_hWnd, L"TrayNotify", NULL);
|
SetWindowTheme(m_hWnd, L"TrayNotify", NULL);
|
||||||
|
|
||||||
m_ImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 0, 1000);
|
m_ImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 0, 1000);
|
||||||
|
@ -810,6 +952,8 @@ class CSysPagerWnd :
|
||||||
{
|
{
|
||||||
CNotifyToolbar Toolbar;
|
CNotifyToolbar Toolbar;
|
||||||
|
|
||||||
|
CTooltips m_Balloons;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CSysPagerWnd() {}
|
CSysPagerWnd() {}
|
||||||
virtual ~CSysPagerWnd() {}
|
virtual ~CSysPagerWnd() {}
|
||||||
|
@ -839,9 +983,27 @@ public:
|
||||||
|
|
||||||
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||||
{
|
{
|
||||||
Toolbar.Initialize(m_hWnd);
|
Toolbar.Initialize(m_hWnd, &m_Balloons);
|
||||||
CIconWatcher::Initialize(m_hWnd);
|
CIconWatcher::Initialize(m_hWnd);
|
||||||
|
|
||||||
|
HWND hWndTop = GetAncestor(m_hWnd, GA_ROOT);
|
||||||
|
|
||||||
|
m_Balloons.Create(hWndTop, TTS_NOPREFIX | TTS_BALLOON | TTS_CLOSE);
|
||||||
|
|
||||||
|
TOOLINFOW ti = { 0 };
|
||||||
|
ti.cbSize = TTTOOLINFOW_V1_SIZE;
|
||||||
|
ti.uFlags = TTF_TRACK | TTF_IDISHWND;
|
||||||
|
ti.uId = reinterpret_cast<UINT_PTR>(Toolbar.m_hWnd);
|
||||||
|
ti.hwnd = m_hWnd;
|
||||||
|
ti.lpszText = NULL;
|
||||||
|
ti.lParam = NULL;
|
||||||
|
|
||||||
|
BOOL ret = m_Balloons.AddTool(&ti);
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
DbgPrint("AddTool failed, LastError=%d (probably meaningless unless non-zero)", GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
// Explicitly request running applications to re-register their systray icons
|
// Explicitly request running applications to re-register their systray icons
|
||||||
::SendNotifyMessageW(HWND_BROADCAST,
|
::SendNotifyMessageW(HWND_BROADCAST,
|
||||||
RegisterWindowMessageW(L"TaskbarCreated"),
|
RegisterWindowMessageW(L"TaskbarCreated"),
|
||||||
|
@ -890,6 +1052,11 @@ public:
|
||||||
(void)RemoveIconFromWatcher(iconData);
|
(void)RemoveIconFromWatcher(iconData);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NIM_SETFOCUS:
|
||||||
|
Toolbar.SetFocus();
|
||||||
|
ret = TRUE;
|
||||||
|
case NIM_SETVERSION:
|
||||||
|
ret = Toolbar.SwitchVersion(iconData);
|
||||||
default:
|
default:
|
||||||
TRACE("NotifyIconCmd received with unknown code %d.\n", data->notify_code);
|
TRACE("NotifyIconCmd received with unknown code %d.\n", data->notify_code);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -996,6 +1163,13 @@ public:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LRESULT OnBalloonPop(UINT uCode, LPNMHDR hdr , BOOL& bHandled)
|
||||||
|
{
|
||||||
|
Toolbar.HideCurrentBalloon();
|
||||||
|
bHandled = TRUE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void ResizeImagelist()
|
void ResizeImagelist()
|
||||||
{
|
{
|
||||||
Toolbar.ResizeImagelist();
|
Toolbar.ResizeImagelist();
|
||||||
|
@ -1009,6 +1183,7 @@ public:
|
||||||
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
|
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
|
||||||
MESSAGE_HANDLER(WM_SIZE, OnSize)
|
MESSAGE_HANDLER(WM_SIZE, OnSize)
|
||||||
MESSAGE_HANDLER(WM_CONTEXTMENU, OnCtxMenu)
|
MESSAGE_HANDLER(WM_CONTEXTMENU, OnCtxMenu)
|
||||||
|
NOTIFY_CODE_HANDLER(TTN_POP, OnBalloonPop)
|
||||||
NOTIFY_CODE_HANDLER(TBN_GETINFOTIPW, OnGetInfoTip)
|
NOTIFY_CODE_HANDLER(TBN_GETINFOTIPW, OnGetInfoTip)
|
||||||
NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)
|
NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)
|
||||||
END_MSG_MAP()
|
END_MSG_MAP()
|
||||||
|
|
|
@ -581,3 +581,228 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CTooltips :
|
||||||
|
public CWindow
|
||||||
|
{
|
||||||
|
public: // Configuration methods
|
||||||
|
|
||||||
|
HWND Create(HWND hWndParent, DWORD dwStyles = WS_POPUP | TTS_NOPREFIX, DWORD dwExStyles = WS_EX_TOPMOST)
|
||||||
|
{
|
||||||
|
RECT r = { 0 };
|
||||||
|
return CWindow::Create(TOOLTIPS_CLASS, hWndParent, r, L"", dwStyles, dwExStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public: // Relay event
|
||||||
|
|
||||||
|
// Win7+: Can use GetMessageExtraInfo to provide the WPARAM value.
|
||||||
|
VOID RelayEvent(MSG * pMsg, WPARAM extraInfo = 0)
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_RELAYEVENT, extraInfo, reinterpret_cast<LPARAM>(pMsg));
|
||||||
|
}
|
||||||
|
|
||||||
|
public: // Helpers
|
||||||
|
|
||||||
|
INT GetToolCount()
|
||||||
|
{
|
||||||
|
return SendMessageW(TTM_GETTOOLCOUNT, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL AddTool(IN CONST TTTOOLINFOW * pInfo)
|
||||||
|
{
|
||||||
|
return SendMessageW(TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(pInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID DelTool(IN HWND hwndToolOwner, IN UINT uId)
|
||||||
|
{
|
||||||
|
TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 };
|
||||||
|
info.hwnd = hwndToolOwner;
|
||||||
|
info.uId = uId;
|
||||||
|
SendMessageW(TTM_DELTOOL, 0, reinterpret_cast<LPARAM>(&info));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID NewToolRect(IN HWND hwndToolOwner, IN UINT uId, IN RECT rect)
|
||||||
|
{
|
||||||
|
TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 };
|
||||||
|
info.hwnd = hwndToolOwner;
|
||||||
|
info.uId = uId;
|
||||||
|
info.rect = rect;
|
||||||
|
SendMessageW(TTM_NEWTOOLRECT, 0, reinterpret_cast<LPARAM>(&info));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL GetToolInfo(IN HWND hwndToolOwner, IN UINT uId, IN OUT TTTOOLINFOW * pInfo)
|
||||||
|
{
|
||||||
|
pInfo->hwnd = hwndToolOwner;
|
||||||
|
pInfo->uId = uId;
|
||||||
|
return SendMessageW(TTM_GETTOOLINFO, 0, reinterpret_cast<LPARAM>(pInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SetToolInfo(IN CONST TTTOOLINFOW * pInfo)
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_SETTOOLINFO, 0, reinterpret_cast<LPARAM>(pInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL HitTest(IN CONST TTHITTESTINFOW * pInfo)
|
||||||
|
{
|
||||||
|
return SendMessageW(TTM_HITTEST, 0, reinterpret_cast<LPARAM>(pInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID GetText(IN HWND hwndToolOwner, IN UINT uId, OUT PWSTR pBuffer, IN DWORD cchBuffer)
|
||||||
|
{
|
||||||
|
TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 };
|
||||||
|
info.hwnd = hwndToolOwner;
|
||||||
|
info.uId = uId;
|
||||||
|
info.lpszText = pBuffer;
|
||||||
|
SendMessageW(TTM_GETTEXT, cchBuffer, reinterpret_cast<LPARAM>(&info));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID UpdateTipText(IN HWND hwndToolOwner, IN UINT uId, IN PCWSTR szText, IN HINSTANCE hinstResourceOwner = NULL)
|
||||||
|
{
|
||||||
|
TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 };
|
||||||
|
info.hwnd = hwndToolOwner;
|
||||||
|
info.uId = uId;
|
||||||
|
info.lpszText = const_cast<PWSTR>(szText);
|
||||||
|
info.hinst = hinstResourceOwner;
|
||||||
|
SendMessageW(TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL EnumTools(IN CONST TTTOOLINFOW * pInfo)
|
||||||
|
{
|
||||||
|
return SendMessageW(TTM_ENUMTOOLS, 0, reinterpret_cast<LPARAM>(pInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL GetCurrentTool(OUT OPTIONAL TTTOOLINFOW * pInfo = NULL)
|
||||||
|
{
|
||||||
|
return SendMessageW(TTM_GETCURRENTTOOL, 0, reinterpret_cast<LPARAM>(pInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID GetTitle(TTGETTITLE * pTitleInfo)
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_GETTITLE, 0, reinterpret_cast<LPARAM>(pTitleInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL SetTitle(PCWSTR szTitleText, WPARAM icon = 0)
|
||||||
|
{
|
||||||
|
return SendMessageW(TTM_SETTITLE, icon, reinterpret_cast<LPARAM>(szTitleText));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TrackActivate(IN HWND hwndToolOwner, IN UINT uId)
|
||||||
|
{
|
||||||
|
TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 };
|
||||||
|
info.hwnd = hwndToolOwner;
|
||||||
|
info.uId = uId;
|
||||||
|
SendMessageW(TTM_TRACKACTIVATE, TRUE, reinterpret_cast<LPARAM>(&info));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TrackDeactivate()
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_TRACKACTIVATE, FALSE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TrackPosition(IN WORD x, IN WORD y)
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_TRACKPOSITION, 0, MAKELPARAM(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Opens the tooltip
|
||||||
|
VOID Popup()
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_POPUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closes the tooltip - Pressing the [X] for a TTF_CLOSE balloon is equivalent to calling this
|
||||||
|
VOID Pop()
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_POP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay times for AUTOMATIC tooltips (they don't affect balloons)
|
||||||
|
INT GetDelayTime(UINT which)
|
||||||
|
{
|
||||||
|
return SendMessageW(TTM_GETDELAYTIME, which);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SetDelayTime(UINT which, WORD time)
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_SETDELAYTIME, which, MAKELPARAM(time, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activates or deactivates the automatic tooltip display when hovering a control
|
||||||
|
VOID Activate(IN BOOL bActivate = TRUE)
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_ACTIVATE, bActivate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjusts the position of a tooltip when used to display trimmed text
|
||||||
|
VOID AdjustRect(IN BOOL bTextToWindow, IN OUT RECT * pRect)
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_ADJUSTRECT, bTextToWindow, reinterpret_cast<LPARAM>(pRect));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Useful for TTF_ABSOLUTE|TTF_TRACK tooltip positioning
|
||||||
|
SIZE GetBubbleSize(IN TTTOOLINFOW * pInfo)
|
||||||
|
{
|
||||||
|
DWORD ret = SendMessageW(TTM_GETBUBBLESIZE, 0, reinterpret_cast<LPARAM>(pInfo));
|
||||||
|
const SIZE sz = { LOWORD(ret), HIWORD(ret) };
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fills the RECT with the margin size previously set. Default is 0 margins.
|
||||||
|
VOID GetMargin(OUT RECT * pRect)
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_GETMARGIN, 0, reinterpret_cast<LPARAM>(pRect));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SetMargin(IN RECT * pRect)
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_SETMARGIN, 0, reinterpret_cast<LPARAM>(pRect));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a previously established max width. Returns -1 if no limit is set
|
||||||
|
INT GetMaxTipWidth()
|
||||||
|
{
|
||||||
|
return SendMessageW(TTM_GETMAXTIPWIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
INT SetMaxTipWidth(IN OPTIONAL INT width = -1)
|
||||||
|
{
|
||||||
|
return SendMessageW(TTM_SETMAXTIPWIDTH, 0, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the color of the tooltip text
|
||||||
|
COLORREF GetTipTextColor()
|
||||||
|
{
|
||||||
|
return SendMessageW(TTM_GETTIPTEXTCOLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SetTipTextColor(IN COLORREF textColor)
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_SETTIPTEXTCOLOR, textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
COLORREF GetTipBkColor()
|
||||||
|
{
|
||||||
|
return SendMessageW(TTM_GETTIPBKCOLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SetTipBkColor(IN COLORREF textColor)
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_SETTIPBKCOLOR, textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SetWindowTheme(IN PCWSTR szThemeName)
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_SETWINDOWTHEME, 0, reinterpret_cast<LPARAM>(szThemeName));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forces redraw
|
||||||
|
VOID Update()
|
||||||
|
{
|
||||||
|
SendMessageW(TTM_UPDATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND WindowFromPoint(IN POINT * pPoint)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<HWND>(SendMessageW(TTM_WINDOWFROMPOINT, 0, reinterpret_cast<LPARAM>(pPoint)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in a new issue