From 7bc76766cc0b044717d8d64f05b5657a04bd4f3a Mon Sep 17 00:00:00 2001 From: Robert Shearman Date: Tue, 7 Sep 2004 20:43:44 +0000 Subject: [PATCH] Implement titles. --- dlls/comctl32/tooltips.c | 214 +++++++++++++++++++++++++++++++++------ 1 file changed, 182 insertions(+), 32 deletions(-) diff --git a/dlls/comctl32/tooltips.c b/dlls/comctl32/tooltips.c index 2229dc114e0..f6ccb6a42c6 100644 --- a/dlls/comctl32/tooltips.c +++ b/dlls/comctl32/tooltips.c @@ -2,6 +2,7 @@ * Tool tip control * * Copyright 1998, 1999 Eric Kohl + * Copyright 2004 Robert Shearman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -87,6 +88,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(tooltips); +static HICON hTooltipIcons[TTI_ERROR+1]; + typedef struct { UINT uFlags; @@ -109,6 +112,7 @@ typedef struct COLORREF clrBk; COLORREF clrText; HFONT hFont; + HFONT hTitleFont; INT xTrackPos; INT yTrackPos; INT nMaxTipWidth; @@ -120,6 +124,8 @@ typedef struct INT nInitialTime; RECT rcMargin; BOOL bToolBelow; + LPWSTR pszTitle; + HICON hTitleIcon; TTTOOL_INFO *tools; } TOOLTIPS_INFO; @@ -141,10 +147,42 @@ typedef struct #define BALLOON_STEMWIDTH 10 #define BALLOON_STEMINDENT 20 +#define BALLOON_ICON_TITLE_SPACING 8 /* horizontal spacing between icon and title */ +#define BALLOON_TITLE_TEXT_SPACING 8 /* vertical spacing between icon/title and main text */ +#define ICON_HEIGHT 16 +#define ICON_WIDTH 16 + LRESULT CALLBACK TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uId, DWORD_PTR dwRef); +static inline UINT_PTR TOOLTIPS_GetTitleIconIndex(HICON hIcon) +{ + UINT i; + for (i = 0; i <= TTI_ERROR; i++) + if (hTooltipIcons[i] == hIcon) + return i; + return (UINT_PTR)hIcon; +} + +static void +TOOLTIPS_InitSystemSettings (TOOLTIPS_INFO *infoPtr) +{ + NONCLIENTMETRICSW nclm; + + infoPtr->clrBk = GetSysColor (COLOR_INFOBK); + infoPtr->clrText = GetSysColor (COLOR_INFOTEXT); + + DeleteObject (infoPtr->hFont); + nclm.cbSize = sizeof(nclm); + SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0); + infoPtr->hFont = CreateFontIndirectW (&nclm.lfStatusFont); + + DeleteObject (infoPtr->hTitleFont); + nclm.lfStatusFont.lfWeight = FW_BOLD; + infoPtr->hTitleFont = CreateFontIndirectW (&nclm.lfStatusFont); +} + static VOID TOOLTIPS_Refresh (HWND hwnd, HDC hdc) { @@ -165,6 +203,11 @@ TOOLTIPS_Refresh (HWND hwnd, HDC hdc) hBrush = CreateSolidBrush(infoPtr->clrBk); + /* already drawn the background; don't need to draw it again + * when drawing text */ + oldBkMode = SetBkMode (hdc, TRANSPARENT); + SetTextColor (hdc, infoPtr->clrText); + if (dwStyle & TTS_BALLOON) { /* create a region to store result into */ @@ -176,13 +219,6 @@ TOOLTIPS_Refresh (HWND hwnd, HDC hdc) FillRgn(hdc, hRgn, hBrush); DeleteObject(hBrush); hBrush = NULL; - - /* calculate text rectangle */ - rc.left += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.left); - rc.top += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.top); - rc.right -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.right); - rc.bottom -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.bottom); - if(infoPtr->bToolBelow) rc.top += BALLOON_STEMHEIGHT; } else { @@ -190,7 +226,41 @@ TOOLTIPS_Refresh (HWND hwnd, HDC hdc) FillRect(hdc, &rc, hBrush); DeleteObject(hBrush); hBrush = NULL; + } + if ((dwStyle & TTS_BALLOON) || infoPtr->pszTitle) + { + /* calculate text rectangle */ + rc.left += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.left); + rc.top += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.top); + rc.right -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.right); + rc.bottom -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.bottom); + if(infoPtr->bToolBelow) rc.top += BALLOON_STEMHEIGHT; + + if (infoPtr->pszTitle) + { + RECT rcTitle = {rc.left, rc.top, rc.right, rc.bottom}; + int height; + BOOL icon_present; + + /* draw icon */ + icon_present = infoPtr->hTitleIcon && + DrawIconEx(hdc, rc.left, rc.top, infoPtr->hTitleIcon, + ICON_WIDTH, ICON_HEIGHT, 0, NULL, DI_NORMAL); + if (icon_present) + rcTitle.left += ICON_WIDTH + BALLOON_ICON_TITLE_SPACING; + + rcTitle.bottom = rc.top + ICON_HEIGHT; + + /* draw title text */ + hOldFont = SelectObject (hdc, infoPtr->hTitleFont); + height = DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_BOTTOM | DT_SINGLELINE | DT_NOPREFIX); + SelectObject (hdc, hOldFont); + rc.top += height + BALLOON_TITLE_TEXT_SPACING; + } + } + else + { /* calculate text rectangle */ rc.left += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.left); rc.top += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.top); @@ -198,12 +268,8 @@ TOOLTIPS_Refresh (HWND hwnd, HDC hdc) rc.bottom -= (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.bottom); } - /* already drawn the background; don't need to draw it again - * when drawing text */ - oldBkMode = SetBkMode (hdc, TRANSPARENT); - SetTextColor (hdc, infoPtr->clrText); - hOldFont = SelectObject (hdc, infoPtr->hFont); /* draw text */ + hOldFont = SelectObject (hdc, infoPtr->hFont); DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags); /* be polite and reset the things we changed in the dc */ SelectObject (hdc, hOldFont); @@ -359,6 +425,7 @@ TOOLTIPS_CalcTipSize (HWND hwnd, TOOLTIPS_INFO *infoPtr, LPSIZE lpSize) DWORD style = GetWindowLongW(hwnd, GWL_STYLE); UINT uFlags = DT_EXTERNALLEADING | DT_CALCRECT; RECT rc = {0, 0, 0, 0}; + SIZE title = {0, 0}; if (infoPtr->nMaxTipWidth > -1) { rc.right = infoPtr->nMaxTipWidth; @@ -369,16 +436,32 @@ TOOLTIPS_CalcTipSize (HWND hwnd, TOOLTIPS_INFO *infoPtr, LPSIZE lpSize) TRACE("%s\n", debugstr_w(infoPtr->szTipText)); hdc = GetDC (hwnd); + if (infoPtr->pszTitle) + { + RECT rcTitle = {0, 0, 0, 0}; + TRACE("title %s\n", debugstr_w(infoPtr->pszTitle)); + if (infoPtr->hTitleIcon) + { + title.cx = ICON_WIDTH; + title.cy = ICON_HEIGHT; + } + if (title.cx != 0) title.cx += BALLOON_ICON_TITLE_SPACING; + hOldFont = SelectObject (hdc, infoPtr->hTitleFont); + DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT); + SelectObject (hdc, hOldFont); + title.cy = max(title.cy, rcTitle.bottom - rcTitle.top) + BALLOON_TITLE_TEXT_SPACING; + title.cx += (rcTitle.right - rcTitle.left); + } hOldFont = SelectObject (hdc, infoPtr->hFont); DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags); SelectObject (hdc, hOldFont); ReleaseDC (hwnd, hdc); - if (style & TTS_BALLOON) + if ((style & TTS_BALLOON) || infoPtr->pszTitle) { - lpSize->cx = rc.right - rc.left + 2*BALLOON_TEXT_MARGIN + + lpSize->cx = max(rc.right - rc.left, title.cx) + 2*BALLOON_TEXT_MARGIN + infoPtr->rcMargin.left + infoPtr->rcMargin.right; - lpSize->cy = rc.bottom - rc.top + 2*BALLOON_TEXT_MARGIN + + lpSize->cy = title.cy + rc.bottom - rc.top + 2*BALLOON_TEXT_MARGIN + infoPtr->rcMargin.bottom + infoPtr->rcMargin.top + BALLOON_STEMHEIGHT; } @@ -1823,6 +1906,56 @@ TOOLTIPS_SetTipTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam) } +static LRESULT +TOOLTIPS_SetTitleA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPCSTR pszTitle = (LPCSTR)lParam; + UINT uTitleIcon = (UINT)wParam; + UINT size; + + TRACE("hwnd = %p, title = %s, icon = %p\n", hwnd, pszTitle, (void*)uTitleIcon); + + size = sizeof(WCHAR)*MultiByteToWideChar(CP_ACP, 0, pszTitle, -1, NULL, 0); + infoPtr->pszTitle = Alloc(size); + if (!infoPtr->pszTitle) + return FALSE; + MultiByteToWideChar(CP_ACP, 0, pszTitle, -1, infoPtr->pszTitle, size/sizeof(WCHAR)); + if (uTitleIcon <= TTI_ERROR) + infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon]; + else + infoPtr->hTitleIcon = CopyIcon((HICON)wParam); + + return TRUE; +} + + +static LRESULT +TOOLTIPS_SetTitleW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPCWSTR pszTitle = (LPCWSTR)lParam; + UINT uTitleIcon = (UINT)wParam; + UINT size; + + TRACE("hwnd = %p, title = %s, icon = %p\n", hwnd, debugstr_w(pszTitle), (void*)uTitleIcon); + + size = (strlenW(pszTitle)+1)*sizeof(WCHAR); + infoPtr->pszTitle = Alloc(size); + if (!infoPtr->pszTitle) + return FALSE; + memcpy(infoPtr->pszTitle, pszTitle, size); + if (uTitleIcon <= TTI_ERROR) + infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon]; + else + infoPtr->hTitleIcon = CopyIcon((HICON)wParam); + + TRACE("icon = %p\n", infoPtr->hTitleIcon); + + return TRUE; +} + + static LRESULT TOOLTIPS_SetToolInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam) { @@ -2134,7 +2267,6 @@ static LRESULT TOOLTIPS_Create (HWND hwnd, const CREATESTRUCTW *lpcs) { TOOLTIPS_INFO *infoPtr; - NONCLIENTMETRICSA nclm; /* allocate memory for info structure */ infoPtr = (TOOLTIPS_INFO *)Alloc (sizeof(TOOLTIPS_INFO)); @@ -2143,18 +2275,15 @@ TOOLTIPS_Create (HWND hwnd, const CREATESTRUCTW *lpcs) /* initialize info structure */ infoPtr->bActive = TRUE; infoPtr->bTrackActive = FALSE; - infoPtr->clrBk = GetSysColor (COLOR_INFOBK); - infoPtr->clrText = GetSysColor (COLOR_INFOTEXT); - - nclm.cbSize = sizeof(NONCLIENTMETRICSA); - SystemParametersInfoA (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0); - infoPtr->hFont = CreateFontIndirectA (&nclm.lfStatusFont); infoPtr->nMaxTipWidth = -1; infoPtr->nTool = -1; infoPtr->nCurrentTool = -1; infoPtr->nTrackTool = -1; + /* initialize colours and fonts */ + TOOLTIPS_InitSystemSettings(infoPtr); + TOOLTIPS_SetDelayTime(hwnd, TTDT_AUTOMATIC, 0L); SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE); @@ -2196,8 +2325,15 @@ TOOLTIPS_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) Free (infoPtr->tools); } - /* delete font */ + /* free title string */ + Free (infoPtr->pszTitle); + /* free title icon if not a standard one */ + if (TOOLTIPS_GetTitleIconIndex(infoPtr->hTitleIcon) > TTI_ERROR) + DeleteObject(infoPtr->hTitleIcon); + + /* delete fonts */ DeleteObject (infoPtr->hFont); + DeleteObject (infoPtr->hTitleFont); /* free tool tips info data */ Free (infoPtr); @@ -2299,9 +2435,13 @@ TOOLTIPS_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam) if(!GetObjectW((HFONT)wParam, sizeof(lf), &lf)) return 0; - if(infoPtr->hFont) DeleteObject (infoPtr->hFont); + DeleteObject (infoPtr->hFont); infoPtr->hFont = CreateFontIndirectW(&lf); + DeleteObject (infoPtr->hTitleFont); + lf.lfWeight = FW_BOLD; + infoPtr->hTitleFont = CreateFontIndirectW(&lf); + if ((LOWORD(lParam)) & (infoPtr->nCurrentTool != -1)) { FIXME("full redraw needed!\n"); } @@ -2402,15 +2542,8 @@ static LRESULT TOOLTIPS_WinIniChange (HWND hwnd, WPARAM wParam, LPARAM lParam) { TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - NONCLIENTMETRICSA nclm; - infoPtr->clrBk = GetSysColor (COLOR_INFOBK); - infoPtr->clrText = GetSysColor (COLOR_INFOTEXT); - - DeleteObject (infoPtr->hFont); - nclm.cbSize = sizeof(NONCLIENTMETRICSA); - SystemParametersInfoA (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0); - infoPtr->hFont = CreateFontIndirectA (&nclm.lfStatusFont); + TOOLTIPS_InitSystemSettings (infoPtr); return 0; } @@ -2544,6 +2677,12 @@ TOOLTIPS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case TTM_SETTIPTEXTCOLOR: return TOOLTIPS_SetTipTextColor (hwnd, wParam, lParam); + case TTM_SETTITLEA: + return TOOLTIPS_SetTitleA (hwnd, wParam, lParam); + + case TTM_SETTITLEW: + return TOOLTIPS_SetTitleW (hwnd, wParam, lParam); + case TTM_SETTOOLINFOA: return TOOLTIPS_SetToolInfoA (hwnd, wParam, lParam); @@ -2644,11 +2783,22 @@ TOOLTIPS_Register (void) wndClass.lpszClassName = TOOLTIPS_CLASSA; RegisterClassA (&wndClass); + + hTooltipIcons[TTI_NONE] = NULL; + hTooltipIcons[TTI_INFO] = LoadImageW(COMCTL32_hModule, + (LPCWSTR)MAKEINTRESOURCE(IDI_TT_INFO_SM), IMAGE_ICON, 0, 0, 0); + hTooltipIcons[TTI_WARNING] = LoadImageW(COMCTL32_hModule, + (LPCWSTR)MAKEINTRESOURCE(IDI_TT_WARN_SM), IMAGE_ICON, 0, 0, 0); + hTooltipIcons[TTI_ERROR] = LoadImageW(COMCTL32_hModule, + (LPCWSTR)MAKEINTRESOURCE(IDI_TT_ERROR_SM), IMAGE_ICON, 0, 0, 0); } VOID TOOLTIPS_Unregister (void) { + int i; + for (i = 0; i < TTI_ERROR+1; i++) + DeleteObject(hTooltipIcons[i]); UnregisterClassA (TOOLTIPS_CLASSA, NULL); }