MyGUI enable tooltips         A sample implementation of MyGUI tooltips.
Target Audience
User.png

MyGUI supports tooltips, also known as flyovers. Unfortunately there's still some manual work to be done to actually implement them in your application.

Layout


First, as with all things MyGUI, you should start with a layout:

ToolTip.layout
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
    <Widget type="Widget" skin="PanelSmall" position="200 480 144 32" layer="ToolTip" name="tooltipPanel">
        <Property key="Widget_Visible" value="false"/>
        <Widget type="Edit" skin="WordWrapSimple" position="3 3 138 92" align="Stretch">
            <Property key="Edit_WordWrap" value="true"/>
            <Property key="Edit_Static" value="true"/>
            <Property key="Text_TextAlign" value="Left Top"/>
            <Property key="Widget_Caption" value="[ToolTip Info]"/>
        </Widget>
    </Widget>
</MyGUI>


This layout is complete and directly usable by MyGUI. You can use any MyGUI widgets you like, but this combination of an Edit widget inside a Panel serves the purpose (and has the added advantage of being the combination preferred by the MyGUI author in the MyGUI Layout Editor). The Edit caption is an unimportant placeholder - make it anything you like or leave it out. The position attributes are also unimportant, since they will be manipulated in code. This snippet can be standalone or included in other layouts that need tooltips. The only thing to be careful of when including it in other layouts is to be sure its parent tag is <MyGUI>.

Load Layout


Load the layout and save some pointers from it for later use:

Load Layout
MyGUI::VectorWidgetPtr widgets = MyGUI::LayoutManager::getInstance().loadLayout("ToolTip.layout");
MyGUI::Widget *mToolTip = MyGUI::Gui::getInstance().findWidget<MyGUI::Widget>("toolTip");
// Alternative if ToolTip.layout contains solely the sample elements
// MyGUI::Widget *toolTip = widgets[0]->castType<MyGUI::Widget>();
MyGUI::Edit *mToolTipEdit = mToolTip->getChildAt(0)->castType<MyGUI::Edit>();

 Snarky Comment

Or whatever convention you like to use for member variables. I know some of you perverts like m_.

The snippet above is not directly usable. It should be inserted into your UIClass initialization routine. The variables prefixed with an 'm' should be members.

Set Up Widgets


Set up a couple of widgets to use tooltips. First, a (not very useful) layout:

Widgets Needing Tooltips
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
    <Widget type="Button" skin="Button" position="184 133 96 24" name="someButton">
        <Property key="Widget_Caption" value="A Button"/>
        <Property key="Widget_NeedToolTip" value="true"/>
    </Widget>
    <Widget type="Edit" skin="Edit" position="152 65 160 24" name="passwordEdit">
        <Property key="Edit_Password" value="true"/>
        <Property key="Edit_MaxTextLength" value="512"/>
        <Property key="Widget_NeedToolTip" value="true"/>
    </Widget>
</MyGUI>


The above layout will load, but probably isn't very useful since the widgets it describes dangle somewhat randomly in the Ogre viewport.

Second, the accompanying C++ code (filling in the pointers has been omitted for brevity):

Set Up Widgets
mSomeButton->eventToolTip = MyGUI::newDelegate(this, &UIClass::notifyToolTip);
mSomePasswordEdit->eventToolTip = MyGUI::newDelegate(this, &UIClass::notifyToolTip);
// NOTE: MyGUI Edit widgets are actually composite widgets.
// They have an automatically created client widget.
// Note it is a client widget, NOT a child widget.
// It does not show up in a layout file, so the NeedToolTip property must be set manually in code.
// It is a descendant of MyGUI::Widget, so it has the usual API.
mSomePasswordEdit->getClientWidget()->setNeedTooltip();
mSomePasswordEdit->getClientWidget()->eventToolTip = MyGUI::newDelegate(this, &UIClass::notifyToolTip);
// Set some tooltip text.  This text can be stored anywhere, as long as the notifyToolTip method
// can get at it.  Adding it to the widgets themelves is handy.
mSomeButton->setUserString("tooltip", "Click me and nothing happens");
mSomePasswordEdit->setUserString("tooltip", "A password edit box.  Be creative!");
mSomePasswordEdit->getClientWidget()->setUserString("tooltip", "A password edit box.  Be creative!");

 Warning

Heed the comments in the source that mention composite widgets. If you don't, you may find yourself on your knees, hands outstretched, imploring the universe "Why?! Why oh why do my tooltips not show up??"

You've been warned.

As with the first snippet, this one isn't directly usable. It should be inserted into your UIClass initialization method. If you want to omit the tip on the Edit widget itself, you can. It's visible only in the outer 3 pixels of an edit box. The majority of the widget's screen area is occupied by its client widget.

Note this sample uses hard coded strings, rather than language manager tags.

Tooltip Notify Method


Finally, the liberally commented tooltip callback method, along with a helper method:

Notify Method
void UIClass::notifyToolTip(MyGUI::Widget *sender, const MyGUI::ToolTipInfo &info)
{
  if (info.type == MyGUI::ToolTipInfo::Show)
  {
    // First fetch the viewport size.  (Do not try to getParent()->getSize().
    // Top level widgets do not have parents, but getParentSize() returns something useful anyway.)
    const MyGUI::IntSize &viewSize = mToolTip->getParentSize();
    // Then set our tooltip panel size to something excessive...
    mToolTip->setSize(viewSize.width/2, viewSize.height/2);
    // ... update its caption to whatever the sender widget has for tooltip text
    // (You did use setUserString(), right?)...
    mToolTipText->setCaption(sender->getUserString("tooltip"));
    // ... fetch the new text size from the tooltip's Edit control...
    const MyGUI::IntSize &textsize = mToolTipText->getTextSize();
    // ... and resize the tooltip panel to match it.  The Stretch property on the Edit
    // control will see to it that the Edit control resizes along with it.
    // The constants are padding to fit in the edges of the PanelSmall skin; adjust as
    // necessary for your theme.
    mToolTip->setSize(textsize.width +  6, textsize.height + 6);
    // You can fade it in smooth if you like, but that gets obnoxious.
    mToolTip->setVisible(true);
    boundedMove(mToolTip, info.point);
  }
  else if (info.type == MyGUI::ToolTipInfo::Hide)
  {
    mToolTip->setVisible(false);
  }
  else if (info.type == MyGUI::ToolTipInfo::Move)
  {
    boundedMove(mToolTip, info.point);
  }
}

/** Move a widget to a point while making it stay in the viewport.
    @param moving The widget that will be moving.
    @param point The desired destination viewport coordinates
                 (which may not be the final resting place of the widget).
 */
void UIClass::boundedMove(MyGUI::Widget *moving, const MyGUI::IntPoint & point)
{
  const MyGUI::IntPoint offset(16, 16);  // typical mouse cursor size - offset out from under it

  MyGUI::IntPoint boundedpoint = point + offset;

  const MyGUI::IntSize& size = moving->getSize();
  const MyGUI::IntSize& view_size = moving->getParentSize();

  if ((boundedpoint.left + size.width) > view_size.width)
  {
    boundedpoint.left -= offset.left + offset.left + size.width;
  }
  if ((boundedpoint.top + size.height) > view_size.height)
  {
    boundedpoint.top -= offset.top + offset.top + size.height;
  }

  moving->setPosition(boundedpoint);
}


The above snippet was shamelessly adapted from MyGUI's Layout Editor, with the addition of new code to size the tip window to match the tip text exactly.

There you have it: How to enable tooltips in MyGUI. The only difficult thing to figure out, and the reason I wrote this page, is the fact that some MyGUI widgets are composite widgets. There's a little extra work involved in enabling tips on their clients.