1 /*********************************************************************** 2 created: 21/2/2005 3 author: Paul D Turner 4 *************************************************************************/ 5 /*************************************************************************** 6 * Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining 9 * a copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be 17 * included in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 * OTHER DEALINGS IN THE SOFTWARE. 26 ***************************************************************************/ 27 #include "CEGUI/widgets/Tooltip.h" 28 #include "CEGUI/Logger.h" 29 #include "CEGUI/Font.h" 30 #include "CEGUI/Image.h" 31 32 // Start of CEGUI namespace section 33 namespace CEGUI 34 { 35 const String Tooltip::WidgetTypeName("CEGUI/Tooltip"); 36 37 ////////////////////////////////////////////////////////////////////////// 38 // Event name constants 39 const String Tooltip::EventNamespace("Tooltip"); 40 const String Tooltip::EventHoverTimeChanged("HoverTimeChanged"); 41 const String Tooltip::EventDisplayTimeChanged("DisplayTimeChanged"); 42 const String Tooltip::EventFadeTimeChanged("FadeTimeChanged"); 43 const String Tooltip::EventTooltipActive("TooltipActive"); 44 const String Tooltip::EventTooltipInactive("TooltipInactive"); 45 const String Tooltip::EventTooltipTransition("TooltipTransition"); 46 ////////////////////////////////////////////////////////////////////////// 47 48 /************************************************************************* 49 TooltipWindowRenderer 50 *************************************************************************/ TooltipWindowRenderer(const String & name)51 TooltipWindowRenderer::TooltipWindowRenderer(const String& name) : 52 WindowRenderer(name, Tooltip::EventNamespace) 53 { 54 } 55 56 ////////////////////////////////////////////////////////////////////////// Tooltip(const String & type,const String & name)57 Tooltip::Tooltip(const String& type, const String& name) : 58 Window(type, name), 59 60 d_hoverTime(0.4f), 61 d_displayTime(7.5f), 62 d_inPositionSelf(false) 63 { 64 addTooltipProperties(); 65 66 setClippedByParent(false); 67 setDestroyedByParent(false); 68 setAlwaysOnTop(true); 69 setMousePassThroughEnabled(true); 70 71 // we need updates even when not visible 72 setUpdateMode(WUM_ALWAYS); 73 74 switchToInactiveState(); 75 hide(); 76 } 77 ~Tooltip(void)78 Tooltip::~Tooltip(void) 79 {} 80 positionSelf(void)81 void Tooltip::positionSelf(void) 82 { 83 // no recusion allowed for this function! 84 if (d_inPositionSelf) 85 return; 86 87 d_inPositionSelf = true; 88 89 MouseCursor& cursor = getGUIContext().getMouseCursor(); 90 Rectf screen(Vector2f(0, 0), getRootContainerSize()); 91 Rectf tipRect(getUnclippedOuterRect().get()); 92 const Image* mouseImage = cursor.getImage(); 93 94 Vector2f mousePos(cursor.getPosition()); 95 Sizef mouseSz(0,0); 96 97 if (mouseImage) 98 { 99 mouseSz = mouseImage->getRenderedSize(); 100 } 101 102 Vector2f tmpPos(mousePos.d_x + mouseSz.d_width, mousePos.d_y + mouseSz.d_height); 103 tipRect.setPosition(tmpPos); 104 105 // if tooltip would be off the right of the screen, 106 // reposition to the other side of the mouse cursor. 107 if (screen.right() < tipRect.right()) 108 { 109 tmpPos.d_x = mousePos.d_x - tipRect.getWidth() - 5; 110 } 111 112 // if tooltip would be off the bottom of the screen, 113 // reposition to the other side of the mouse cursor. 114 if (screen.bottom() < tipRect.bottom()) 115 { 116 tmpPos.d_y = mousePos.d_y - tipRect.getHeight() - 5; 117 } 118 119 // set final position of tooltip window. 120 setPosition( 121 UVector2(cegui_absdim(tmpPos.d_x), 122 cegui_absdim(tmpPos.d_y))); 123 124 d_inPositionSelf = false; 125 } 126 sizeSelf(void)127 void Tooltip::sizeSelf(void) 128 { 129 Sizef textSize(getTextSize()); 130 131 setSize(USize(cegui_absdim(textSize.d_width), 132 cegui_absdim(textSize.d_height))); 133 } 134 setTargetWindow(Window * wnd)135 void Tooltip::setTargetWindow(Window* wnd) 136 { 137 if (!wnd) 138 { 139 d_target = wnd; 140 } 141 else if (wnd != this) 142 { 143 if (d_target != wnd) 144 { 145 wnd->getGUIContext().getRootWindow()->addChild(this); 146 d_target = wnd; 147 } 148 149 // set text to that of the tooltip text of the target 150 setText(wnd->getTooltipTextIncludingInheritance()); 151 152 // set size and position of the tooltip window. 153 sizeSelf(); 154 positionSelf(); 155 } 156 157 resetTimer(); 158 159 if (d_active) 160 { 161 WindowEventArgs args(this); 162 onTooltipTransition(args); 163 } 164 } 165 getTargetWindow()166 const Window* Tooltip::getTargetWindow() 167 { 168 return d_target; 169 } 170 getTextSize() const171 Sizef Tooltip::getTextSize() const 172 { 173 if (d_windowRenderer != 0) 174 { 175 TooltipWindowRenderer* wr = (TooltipWindowRenderer*)d_windowRenderer; 176 return wr->getTextSize(); 177 } 178 else 179 { 180 return getTextSize_impl(); 181 } 182 } 183 getTextSize_impl() const184 Sizef Tooltip::getTextSize_impl() const 185 { 186 const RenderedString& rs(getRenderedString()); 187 Sizef sz(0.0f, 0.0f); 188 189 for (size_t i = 0; i < rs.getLineCount(); ++i) 190 { 191 const Sizef line_sz(rs.getPixelSize(this, i)); 192 sz.d_height += line_sz.d_height; 193 194 if (line_sz.d_width > sz.d_width) 195 sz.d_width = line_sz.d_width; 196 } 197 198 return sz; 199 } 200 resetTimer(void)201 void Tooltip::resetTimer(void) 202 { 203 d_elapsed = 0; 204 } 205 getHoverTime(void) const206 float Tooltip::getHoverTime(void) const 207 { 208 return d_hoverTime; 209 } 210 setHoverTime(float seconds)211 void Tooltip::setHoverTime(float seconds) 212 { 213 if (d_hoverTime != seconds) 214 { 215 d_hoverTime = seconds; 216 217 WindowEventArgs args(this); 218 onHoverTimeChanged(args); 219 } 220 } 221 getDisplayTime(void) const222 float Tooltip::getDisplayTime(void) const 223 { 224 return d_displayTime; 225 } 226 setDisplayTime(float seconds)227 void Tooltip::setDisplayTime(float seconds) 228 { 229 if (d_displayTime != seconds) 230 { 231 d_displayTime = seconds; 232 233 WindowEventArgs args(this); 234 onDisplayTimeChanged(args); 235 } 236 } 237 doActiveState(float elapsed)238 void Tooltip::doActiveState(float elapsed) 239 { 240 // if no target, switch immediately to inactive state. 241 if (!d_target || d_target->getTooltipTextIncludingInheritance().empty()) 242 { 243 // hide immediately since the text is empty 244 hide(); 245 246 switchToInactiveState(); 247 } 248 // else see if display timeout has been reached 249 else if ((d_displayTime > 0) && ((d_elapsed += elapsed) >= d_displayTime)) 250 { 251 // display time is up, switch states 252 switchToInactiveState(); 253 } 254 } 255 doInactiveState(float elapsed)256 void Tooltip::doInactiveState(float elapsed) 257 { 258 if (d_target && !d_target->getTooltipTextIncludingInheritance().empty() && ((d_elapsed += elapsed) >= d_hoverTime)) 259 { 260 switchToActiveState(); 261 } 262 } 263 switchToInactiveState(void)264 void Tooltip::switchToInactiveState(void) 265 { 266 d_active = false; 267 d_elapsed = 0; 268 269 // fire event before target gets reset in case that information is required in handler. 270 WindowEventArgs args(this); 271 onTooltipInactive(args); 272 273 d_target = 0; 274 } 275 switchToActiveState(void)276 void Tooltip::switchToActiveState(void) 277 { 278 positionSelf(); 279 show(); 280 281 d_active = true; 282 d_elapsed = 0; 283 284 WindowEventArgs args(this); 285 onTooltipActive(args); 286 } 287 validateWindowRenderer(const WindowRenderer * renderer) const288 bool Tooltip::validateWindowRenderer(const WindowRenderer* renderer) const 289 { 290 return dynamic_cast<const TooltipWindowRenderer*>(renderer) != 0; 291 } 292 updateSelf(float elapsed)293 void Tooltip::updateSelf(float elapsed) 294 { 295 // base class processing. 296 Window::updateSelf(elapsed); 297 298 // do something based upon current Tooltip state. 299 if (d_active) 300 { 301 doActiveState(elapsed); 302 } 303 else 304 { 305 doInactiveState(elapsed); 306 } 307 } 308 addTooltipProperties(void)309 void Tooltip::addTooltipProperties(void) 310 { 311 const String& propertyOrigin = WidgetTypeName; 312 313 CEGUI_DEFINE_PROPERTY(Tooltip, float, 314 "HoverTime", "Property to get/set the hover timeout value in seconds. Value is a float.", 315 &Tooltip::setHoverTime, &Tooltip::getHoverTime, 0.4f 316 ); 317 318 CEGUI_DEFINE_PROPERTY(Tooltip, float, 319 "DisplayTime", "Property to get/set the display timeout value in seconds. Value is a float.", 320 &Tooltip::setDisplayTime, &Tooltip::getDisplayTime, 7.5f 321 ); 322 } 323 onHidden(WindowEventArgs & e)324 void Tooltip::onHidden(WindowEventArgs& e) 325 { 326 Window::onHidden(e); 327 328 // The animation will take care of fade out or whatnot, 329 // at the end it will hide the tooltip to let us know the transition 330 // is done. At this point we will remove the tooltip from the 331 // previous parent. 332 333 // NOTE: There has to be a fadeout animation! Even if it's a 0 second 334 // immediate hide animation. 335 336 if (getParent()) 337 { 338 getParent()->removeChild(this); 339 } 340 } 341 onMouseEnters(MouseEventArgs & e)342 void Tooltip::onMouseEnters(MouseEventArgs& e) 343 { 344 positionSelf(); 345 346 Window::onMouseEnters(e); 347 } 348 onTextChanged(WindowEventArgs & e)349 void Tooltip::onTextChanged(WindowEventArgs& e) 350 { 351 // base class processing 352 Window::onTextChanged(e); 353 354 // set size and position of the tooltip window to consider new text 355 sizeSelf(); 356 positionSelf(); 357 358 // we do not signal we handled it, in case user wants to hear 359 // about text changes too. 360 } 361 onHoverTimeChanged(WindowEventArgs & e)362 void Tooltip::onHoverTimeChanged(WindowEventArgs& e) 363 { 364 fireEvent(EventHoverTimeChanged, e, EventNamespace); 365 } 366 onDisplayTimeChanged(WindowEventArgs & e)367 void Tooltip::onDisplayTimeChanged(WindowEventArgs& e) 368 { 369 fireEvent(EventDisplayTimeChanged, e, EventNamespace); 370 } 371 onTooltipActive(WindowEventArgs & e)372 void Tooltip::onTooltipActive(WindowEventArgs& e) 373 { 374 fireEvent(EventTooltipActive, e, EventNamespace); 375 } 376 onTooltipInactive(WindowEventArgs & e)377 void Tooltip::onTooltipInactive(WindowEventArgs& e) 378 { 379 fireEvent(EventTooltipInactive, e, EventNamespace); 380 } 381 onTooltipTransition(WindowEventArgs & e)382 void Tooltip::onTooltipTransition(WindowEventArgs& e) 383 { 384 fireEvent(EventTooltipTransition, e, EventNamespace); 385 } 386 } // End of CEGUI namespace section 387