Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

XSuperTooltip - Office 2007 Super Tooltip class

0.00/5 (No votes)
31 Jul 2006 5  
XSuperTooltip implements class for displaying super tooltips, which were introduced in Office 2007. The demo download includes super tooltip code generator, that makes it easy to add super tooltips to your application.

Introduction

Since last December, blogs of user interface gurus have been filled with comments about new help features in Office 2007 (aka Office 12), and in particular comments about new super tooltips. I was excited when I first saw them; super tooltips seem to take tooltips to whole new level, making application features much more discoverable to the user, and bridging the gap between popup help and the application's main help documentation. I have been looking forward to when I would have some time to experiment with super tooltips, and I was happy to discover that implementation is easier than I thought; this is mainly due to Eugene Pustovoyt's excellent CPPToolTip class.

First, though, some background on super tooltips. The blog that everyone refers to is Jensen Harris' An Office User Interface Blog from December 2, 2005. Harris includes some stunning screenshots of (beta) versions of super tooltips in Office 2007. Here's a fairly simple one:

screenshot This tooltip gives a brief description of a feature, followed by a concrete example.

But super tooltips in Office 2007 can include images too:

screenshot This picture makes clear what would probably require a hundred words.

One of coolest features of new tooltips is that they can provide a link between simple popup and the application's main help system:

screenshot The user now has an opportunity to go from a very concise feature description to jumping directly to the relevant article in the help system, without having to bother with the help index, or problematic search for keyword.

Another use that Harris says will be natural for super tooltips is to help user understand the status of user interface. For example, it is common to see features that are disabled in an application, but sometimes it is not obvious what has caused them to be disabled:

screenshot This one tooltip does four things: it shows user the status of feature; it explains why feature has that status; it tells user how to enable feature; and it offers an express (F1) way into help system. This means that users will be able to learn new applications very quickly, and will pick up new features with minimal frustration.

Another example that Harris gives is finding the right dialog. Many users recognize a dialog box and what it does, but have trouble finding how to get to it. Again, using embedded image, super tooltips show a preview of dialog:

screenshot

Super Tooltip Requirements

From the above summary, I put together the following list of requirements for super tooltip implementation:

  • Hot keys to link to documentation: In addition to the obvious F1, it should be possible to specify any function key; pressing function key will cause message to be sent back to tooltip's parent.
  • Embedded images: Displaying thumbnail image in the body of tooltip, and smaller image in footer, is the primary requirement.
  • Easy, flexible formatting: To use super tooltips widely throughout an application, it must be possible to efficiently generate and modify various formatting elements, such as font weight, underlining, etc. This makes HTML a natural choice for use in super tooltips.
  • Programmatic interface to display attributes: The programmer (and possibly the user) should be able to easily change background color, text color, and effects such as gradient colors and shading.
  • Customize tooltip elements: To make possible wide variety of tooltips, it should be possible to pick and choose elements that will be included - header, horizontal rule underneath header, image in body, footer, and horizontal rule before footer.

Testing CXSuperTooltip

With these requirements, I put together a demo app that gives me control over various aspects of super tooltip formatting and appearance. I first tried one of the examples that Harris used:

screenshot

I press F1 and demo app receives registered message WM_PPTOOLTIP_VIRTUAL_KEY_CODE:

screenshot

The lParam and wParam values contain information set up in call to AddTool(), so an app will know what tool the message is coming from. In this example, I used IDC_PREVIEW (the button's resource ID) as the tool ID, and the number '12345' as the key code ID. If this was an app with help file, I would have used the button's help topic ID as the key code ID, to make it easy to call HtmlHelp().

I can also click on message string, because it is a hyperlink:

screenshot

Clicking on hyperlink sends the user-defined message UNM_HYPERLINK_CLICKED to dialog:

screenshot Notice that hyperlink click also returns the tool ID. The 'F1' message string could have been the string version of the help topic ID.

Next, I disable the preview button by checking both the checkboxes on the right (Disable Preview button and Enable tooltip on disabled Preview button):

screenshot

Now I display an embedded image in super tooltip:

screenshot

I can also dynamically choose the style of tooltip displayed, without changing any text strings, by using SetScreenTipScheme() function. When "normal" tooltips are selected, only header text is displayed:

screenshot

The above examples do not show all combinations of features possible with the demo app, so I hope you will experiment with demo app and let me know what you think.

Demo App — A Super Tooltip Code Generator

One of the things that took the most time was figuring out the exact HTML code I needed for super tooltip. To make it easy to implement in your code, demo app provides two dynamic clipboard export mechanisms, which give you the starting point for your own super tooltip:

  1. Copy HTML to Clipboard

    This gives you HTML code that is passed to CPPToolTip::AddTool() as sTooltip value in PPTOOLTIP_INFO struct.

    <font color=#000000><b>Merge and Center</b>
    <indent>
    Joins the selected cells into one larger cell and centers
        the contents in the new cell.</indent>
    <indent>
    This is often used to create labels that span
        multiple columns.</indent></font><indent size=-50><br>
    <hr width=500px color=#69696B></indent>
    <table>
    <tr>
    <td width=20><ilst idres=131 mask cx=16 cy=16 width=100%
                        height=100%></td><br>
    <td><b><font color=#000000>Press F1 for more help</b>
                        </td></font></tr></table>
  2. Copy C++ Code to Clipboard

    This gives you C++ code that is used to set up SUPER_TOOLTIP_INFO struct before CXSuperTooltip::AddTool() is called.

    // Generated by XSuperTooltipTest on 2006 July 31
    
    SUPER_TOOLTIP_INFO sti;
    
    sti.bSuperTooltip     = TRUE;
    sti.nVirtualKeyCode   = VK_F1;                      // zero if none
    sti.nKeyCodeId        = <insert key code id here>;  // can be anything you want
    sti.nIDTool           = <IDC_XXXXX>;                // can be anything you want
    sti.nSizeX            = 212;
    sti.pWnd              = GetDlgItem(IDC_XXXXX);
    sti.strHeader         = _T("Merge and Center");
    sti.bLineAfterHeader  = FALSE;
    sti.strBody           =
      _T("Joins the selected cells into one larger cell and
                centers the contents in the new cell.\n")
      _T("This is often used to create labels that span multiple columns.\n")
            ;
    sti.strFooter         = _T("Press F1 for more help");
    sti.nFooterImage      = IDB_YYYYY;
    sti.bLineBeforeFooter = TRUE;
    sti.rgbBegin          = RGB(255, 255, 255);
    sti.rgbMid            = RGB(242, 242, 246);
    sti.rgbEnd            = RGB(212, 212, 224);
    sti.rgbText           = RGB(0, 0, 0);
    
    CString strHtml = m_tooltip.AddTool(&sti);
    
  3. Note

    The complete code that is used to generate super tooltips in the demo app can be found in CXSuperTooltipTestDlg::Generate().

Implementation Details

HTML Engine

An important thing to understand about CXSuperTooltip is that it is based on CPPToolTip, which uses custom HTML rendering engine to display HTML, and not Microsoft browser APIs. This means that you will find some differences in the way HTML looks. For the most part, once you try a few examples, you will have no problems. To implement CXSuperTooltip, I found it necessary to tweak the CPPToolTip classes a little bit, and I also applied bug fixes that were reported in CPPToolTip article forum.

CXSuperTooltip Class

The CXSuperTooltip class serves as an interface to CPPToolTip. This means that when you call CXSuperTooltip::AddTool() in your code, in addition to setting up HTML, CXSuperTooltip is also calling various CPPToolTip functions.

Here is function CXSuperTooltip::InitSuper(), which is called by CXSuperTooltip::AddTool():

void CXSuperTooltip::InitSuper()
{
    int yMargin = GetSize(CPPToolTip::PPTTSZ_MARGIN_CY);
    SetSize(CPPToolTip::PPTTSZ_MARGIN_CY, yMargin/2);
    SetSize(CPPToolTip::PPTTSZ_ROUNDED_CX, 0);
    SetSize(CPPToolTip::PPTTSZ_ROUNDED_CY, 0);
    SetSize(CPPToolTip::PPTTSZ_WIDTH_ANCHOR, 0);
    SetSize(CPPToolTip::PPTTSZ_HEIGHT_ANCHOR, 0);
    SetBorder(RGB(105,105,107));
    SetTooltipShadow(6, 5, 50);
    //SetDebugMode(TRUE);
    SetNotify();
    SetColorBk(RGB(255, 0, 0));
    SetMaxTipWidth(XSUPERTOOLTIP_DEFAULT_WIDTH);
    SetDelayTime(TTDT_AUTOPOP, 60000);
}

Some other CPPToolTip functions are called from within CXSuperTooltip::AddTool(), depending on options specified in SUPER_TOOLTIP_INFO struct:

struct SUPER_TOOLTIP_INFO
{
    SUPER_TOOLTIP_INFO()
    {
        bSuperTooltip     = TRUE;
        pWnd              = NULL;
        nIDText           = 0;
        nIDTool           = 0;
        rectBounds        = CRect(0,0,0,0);
        nBehaviour        = 0;
        nSizeX            = 0;
        strHeader         = _T("");
        strBody           = _T("must not be empty");
        strFooter         = _T("");
        bLineAfterHeader  = FALSE;
        bLineBeforeFooter = FALSE;
        nBodyImage        = 0;
        nFooterImage      = 0;
        nVirtualKeyCode   = 0;
        nKeyCodeId        = 0;
        // default to black text on silver
        rgbBegin          = RGB(255,255,255);
        rgbMid            = RGB(242,242,246);
        rgbEnd            = RGB(212,212,224);
        rgbText           = RGB(0,0,0);
    };

    BOOL     bSuperTooltip;      // TRUE = super tooltip
    CWnd *   pWnd;               // pointer to window that contains the tool
    UINT     nIDText;            // ID of the string resource that contains
                                 // the text for the tool
    UINT     nIDTool;            // ID of tool (can be anything)
    CRect    rectBounds;         // bounding rect for toolinfo to be
                                 // displayed
    UINT     nBehaviour;         // the tooltip's behaviour
    int      nSizeX;             // custom size (0 if none) -
                                 // defaults to XSUPERTOOLTIP_DEFAULT_WIDTH
    CString  strHeader;          // super tooltip header (can be _T(""))
    CString  strBody;            //               body
    CString  strFooter;          //               footer (can be _T(""))
    BOOL     bLineAfterHeader;   // TRUE = draw line after header
    BOOL     bLineBeforeFooter;  // TRUE = draw line before footer
    UINT     nBodyImage;         // id of image to display in body
                                 // (0 if none)
    UINT     nFooterImage;       // id of image to display in footer
                                 // (0 if none)
    UINT     nVirtualKeyCode;    // virtual control code (VK_F1, etc.)
    UINT     nKeyCodeId;         // id that is sent to parent when
                                 // nVirtualKeyCodeis seen (can be anything)
    COLORREF rgbBegin;           // background begin color
    COLORREF rgbMid;             // background mid color
    COLORREF rgbEnd;             // background end color
    COLORREF rgbText;            // text color
};

How To Use

To integrate CXSuperTooltip class into your app, you first need to add following files to your project:

  • CeXDib.cpp
  • CeXDib.h
  • Monitors.cpp — new in v1.1
  • Monitors.h — new in v1.1
  • MultiMonitor.cpp — new in v1.1
  • MultiMonitor.h — new in v1.1
  • PPDrawManager.cpp
  • PPDrawManager.h
  • PPHtmlDrawer.cpp
  • PPHtmlDrawer.h
  • PPTooltip.cpp
  • PPTooltip.h
  • XSuperTooltip.cpp
  • XSuperTooltip.h

Next, include header file XSuperTooltip.h in appropriate project files (usually, this will be in the header file for dialog class). Then replace declaration of tooltip control with this:

CXSuperTooltip   m_tooltip;
(use whatever variable name already exists).

Now you are ready to start using CXSuperTooltip. In dialog's OnInitDialog() function, insert line

m_tooltip.Create(this);
(this line will already be there if you are already using tooltips).

After calling Create(), you can add controls to tooltip by using CXSuperTooltip::AddTool() — see code in XSuperTooltipTestDlg.cpp.

If you want to process virtual key click, you should also add entry to message map:

ON_REGISTERED_MESSAGE(WM_PPTOOLTIP_VIRTUAL_KEY_CODE, OnVirtualKey)
and add function OnVirtualKey() to dialog class:
// receives WM_PPTOOLTIP_VIRTUAL_KEY_CODE from tooltip
LRESULT CXSuperTooltipTestDlg::OnVirtualKey(WPARAM wParam, LPARAM lParam)
{
    CString msg = _T("");
    CString strMagic = _T("");
    if (wParam == 0x4d)
        strMagic = _T("MFC magic help message!");
    msg.Format(_T("WM_PPTOOLTIP_VIRTUAL_KEY_CODE received from
                        CPPToolTip:  \n\n")
        _T("     key code ID = %d  (0x%X)  %s\n")
        _T("     tool ID = %d  (0x%X)"),
        wParam, wParam, strMagic, lParam, lParam);
    AfxMessageBox(msg, MB_OK | MB_ICONINFORMATION);
    return 0;
}
In your implementation of OnVirtualKey(), you will want to call HtmlHelp() or whatever help system your app is using. To facilitate this, you could use help topic id as key code id (nKeyCodeId), and call HtmlHelp() like this:
TCHAR szPathName[MAX_PATH*2] = { _T('\0') };
::GetModuleFileName(AfxGetInstanceHandle(), szPathName,
            sizeof(szPathName)/sizeof(TCHAR)-1);
TCHAR *cp = _tcsrchr(szPathName, _T('.'));
if (cp != NULL)
        *(cp+1) = _T('\0');
_tcscat(szPathName, _T("chm"));
if (_taccess(szPathName, 04) == 0)
{
    HtmlHelp(AfxGetApp()->m_pMainWnd->m_hWnd, szPathName,
                                    HH_HELP_CONTEXT, wParam);
}

Next add the function PreTranslateMessage(MSG* pMsg) to your dialog:

BOOL CXSuperTooltipTestDlg::PreTranslateMessage(MSG* pMsg)
{
    // if RelayEvent returns TRUE, it means CXSuperTooltip
    // processed a virtual key code, and this message should
    // not be sent to CDialog
    if (m_tooltip.RelayEvent(pMsg))
        return TRUE;

    return CDialog::PreTranslateMessage(pMsg);
}

Frequently Asked Questions

  1. Why use CXSuperTooltip at all? Why not just use CPPToolTip?
    You can certainly do that, although you would be duplicating much of the code in CXSuperTooltip. I recommend that you use PPTooltip.cpp, etc., files that I include with demo app — I have made numerous bug fixes and additions to accommodate super tooltips.
  2. Does XSuperTooltip support Unicode?
    Yes.
  3. Can I use XSuperTooltip in non-MFC apps?
    Not currently. XSuperTooltip is dependent on MFC framework and classes.
  4. When I try to build the demo app, I get the linker error LINK : fatal error LNK1104: cannot open file "mfc42u.lib" Error executing link.exe. How can I fix this?
    The default installation options of Visual C++ v6.0 don't install the Unicode libraries of MFC, so you might get an error that mfc42u.lib or mfc42ud.lib cannot be found. You can fix this either by installing Unicode libs from the VC++ install CD, or by going to Build | Set Active Configuration and selecting one of the non-Unicode configurations.
  5. I'm trying to use standard HTML in my super tooltip, but it doesn't work. What is wrong?
    XSuperTooltip is based on custom HTML rendering engine, not on official Microsoft browser APIs. Take a look at the code, you might be able to implement missing feature yourself.
  6. Is this the final version of XSuperTooltip?
    Probably not. Office 2007 has not yet been released, and so super tooltips may undergo more changes in functionality and appearance. When Office 2007 is completed (which some people are predicting will happen later this year), I will review any changes, and decide what to do. In the meantime, please feel free to experiment with XSuperTooltip, and let me know if you think there are features that would make it better.
  7. Can we use XSuperTooltip in our shareware/commercial app?
    Yes, you can use XSuperTooltip without charge or license fee. It would be nice to acknowledge my Copyright in your About box or splash screen, but this is up to you.

Acknowledgments

Please refer to the following articles for more information about controls I used to build the demo app:

Revision History

Version 1.1 — 2006 August 4

  • Fixed delete's in PPDrawManager.cpp and CexDib.cpp — thanks to Johnny_Boy for finding this.
  • Many tweaks to the UI — thanks to Geert van Horrik and Alisdair W for helping with these:
    • "Office 2007 blue" color, with text color of RGB(76, 76, 76)
    • border color is now RGB(118, 118, 118)
    • corners are now rounded
    • shading has been tweaked
    • margin has been reduced
    • horizontal rule is now 3D, and color is taken from background
    • added fadeout if system option set to fade
  • Fixed static build problem ("Use MFC in a static library") — thanks to bolivar123 for reporting on fix.
  • Fixed tooltip behavior — it is now much less twitchy, and mouse may be moved anywhere within control or tooltip without closing tooltip.
  • Added hyperlink support for "Press F1 ...".
  • Because the mouse may be moved into tooltip now, the tooltip's context menu was removed — "help" message can be hyperlink and may be directly clicked, without having to use the keyboard.
  • Added option to show super tooltip, normal tooltip (displays only header text), or nothing.
  • Added SetCapture() to fix problem where tooltip would not be hidden if cursor moved off bottom of tooltip.
  • Tooltip is now repositioned to top of control if it would be displayed off bottom of screen.

Version 1.0 — 2006 July 31

  • Initial public release

Usage

This software is released into the public domain. You are free to use it in any way you like, except that you may not sell this source code. If you modify it or extend it, please consider posting new code here for everyone to share. This software is provided "as is" with no expressed or implied warranty. I accept no liability for any damage or loss of business that this software may cause.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here