xoreos  0.0.5
tooltip.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include <boost/bind.hpp>
26 
27 #include "src/common/util.h"
28 #include "src/common/configman.h"
29 
30 #include "src/graphics/graphics.h"
31 #include "src/graphics/font.h"
32 #include "src/graphics/camera.h"
33 
38 
41 
44 
45 namespace Engines {
46 
47 namespace NWN {
48 
49 Tooltip::Tooltip(Type type) : _type(type),
50  _parentWidget(0), _parentModel(0),
51  _empty(true), _visible(false), _align(0.0f),
52  _offscreen(false), _x(0.0f), _y(0.0f), _z(0.0f),
53  _lineHeight(0.0f), _lineSpacing(0.0f), _width(0.0f), _height(0.0f),
54  _needCamera(false), _detectEdge(false) {
55 
57 }
58 
59 Tooltip::Tooltip(Type type, Widget &parent) : _type(type),
60  _parentWidget(&parent), _parentModel(0),
61  _empty(true), _visible(false), _align(0.0f),
62  _offscreen(false), _x(0.0f), _y(0.0f), _z(0.0f),
63  _lineHeight(0.0f), _lineSpacing(0.0f), _width(0.0f), _height(0.0f),
64  _needCamera(false), _detectEdge(true) {
65 
67 }
68 
69 Tooltip::Tooltip(Type type, Graphics::Aurora::Model &parent) : _type(type),
70  _parentWidget(0), _parentModel(&parent),
71  _empty(true), _visible(false), _align(0.0f),
72  _offscreen(false), _x(0.0f), _y(0.0f), _z(0.0f),
73  _lineHeight(0.0f), _lineSpacing(0.0f), _width(0.0f), _height(0.0f),
74  _needCamera(true), _detectEdge(false) {
75 
77 }
78 
80  hide();
81 
82  deleteTexts();
83 }
84 
86  hide();
87 
88  _lines.clear();
89 
90  redoLines(true);
91 }
92 
94  hide();
95 
96  _portrait.reset();
97 
98  redoLayout();
99 }
100 
101 void Tooltip::addLine(const Common::UString &text, float r, float g, float b, float a) {
102  hide();
103 
104  if (text.empty())
105  return;
106 
107  std::vector<Common::UString> lines;
108  Common::UString::split(text, '\n', lines);
109 
110  for (std::vector<Common::UString>::const_iterator l = lines.begin();
111  l != lines.end(); ++l) {
112 
113  _lines.push_back(Line());
114 
115  _lines.back().r = r;
116  _lines.back().g = g;
117  _lines.back().b = b;
118  _lines.back().a = a;
119  _lines.back().line = *l;
120  }
121 
122  redoLines(true);
123 }
124 
126  hide();
127 
128  if (_portrait)
129  _portrait->setPortrait(image);
130  else
131  _portrait.reset(new Portrait(image, Portrait::kSizeTiny, 1.0f));
132 
133  redoLayout();
134 }
135 
136 void Tooltip::setAlign(float align) {
137  hide();
138 
139  _align = align;
140  redoLayout();
141 }
142 
144  updatePosition();
145 }
146 
147 bool Tooltip::getParentPosition(float &x, float &y, float &z) const {
148  x = y = z = 0.0f;
149 
150  bool onscreen = true;
151 
152  if (_parentWidget)
153  _parentWidget->getPosition(x, y, z);
154 
155  if (_parentModel) {
156  float aX, aY, aZ;
157 
158  _parentModel->getTooltipAnchor(aX, aY, aZ);
159  if (!GfxMan.project(aX, aY, aZ, x, y, z))
160  return false;
161 
162  onscreen = ((z >= 0.0f) && (z <= 1.0f));
163 
164  z = 0.0f;
165  }
166 
167  return onscreen;
168 }
169 
171  if (_empty)
172  return;
173 
175 
176  float pX, pY, pZ;
177  if (!getParentPosition(pX, pY, pZ)) {
178  _offscreen = true;
179  doHide();
180  return;
181  } else {
182  _offscreen = false;
183  doShow();
184  }
185 
186  // Set bubble position
187 
188  const bool hasBubble = _showBubble && _bubble;
189 
190  const float bubbleWidth = hasBubble ? (_bubble->getWidth () - 30.0f) : _width;
191  const float bubbleHeight = hasBubble ? (_bubble->getHeight() - 8.0f) : _height;
192 
193  const float bubbleWantX = pX + _x - (bubbleWidth / 2.0f);
194  const float bubbleRight = bubbleWantX + bubbleWidth + 15.0f;
195 
196  const float maxX = _detectEdge ? WindowMan.getWindowWidth() / 2.0f : 0.0f;
197  const float overX = _detectEdge ? MAX(0.0f, bubbleRight - maxX) : 0.0f;
198 
199  const float bubbleX = bubbleWantX - overX;
200  const float bubbleY = pY + bubbleHeight + _y;
201  const float bubbleZ = pZ + _z;
202 
203  if (hasBubble)
204  _bubble->setPosition(floorf(bubbleX), floorf(bubbleY), floorf(bubbleZ));
205 
206 
207  // Set portrait position
208 
209  const bool hasPortrait = _showPortrait && _portrait;
210 
211  const float portraitWidth = hasPortrait ? _portrait->getWidth () : 0.0f;
212  const float portraitHeight = hasPortrait ? _portrait->getHeight() : 0.0f;
213 
214  const float portraitX = bubbleX;
215  const float portraitY = bubbleY - portraitHeight - 3.0f;
216  const float portraitZ = bubbleZ - 1.0f;
217 
218  if (hasPortrait)
219  _portrait->setPosition(floorf(portraitX), floorf(portraitY), floorf(portraitZ));
220 
221 
222  // Set text position
223 
224  const float portraitSpacerWidth = portraitWidth + (_portrait ? 2.0f : 0.0f);
225 
226  const float bubbleTextWidth = bubbleWidth - portraitSpacerWidth;
227 
228  const float textHeight = _texts.size() * _lineHeight + (_texts.size() - 1) * _lineSpacing;
229 
230  const float textBorderY = (bubbleHeight - textHeight) / 2.0f;
231 
232  const float textBottomX = bubbleX + portraitSpacerWidth;
233  const float textBottomY = bubbleY - textBorderY + 1.0f;
234  const float textBottomZ = bubbleZ - 1.0f;
235 
236  float textY = textBottomY;
237  for (std::vector<Graphics::Aurora::Text *>::iterator t = _texts.begin(); t != _texts.end(); ++t) {
238  const float textWidth = (*t)->getWidth();
239  const float textBorderX = (bubbleTextWidth - textWidth) * _align;
240  const float textX = textBottomX + textBorderX;
241  const float lineY = textY - (*t)->getHeight();
242  (*t)->setPosition(floorf(textX), floorf(lineY), floorf(textBottomZ));
243 
244  textY -= (_lineHeight + _lineSpacing);
245  }
246 }
247 
248 void Tooltip::setPosition(float x, float y, float z) {
249  hide();
250 
251  _x = x;
252  _y = y;
253  _z = z;
254 
255  updatePosition();
256 }
257 
258 void Tooltip::show(uint32 delay, uint32 timeOut) {
259  if (_visible || _empty)
260  return;
261 
262  redoLines();
263 
264  _visible = true;
265 
266  if (delay == 0)
267  doShow(0);
268 
269  if (delay != 0)
270  TimerMan.addTimer(delay , _timerShow, boost::bind(&Tooltip::doShow, this, _1));
271  if (timeOut != 0)
272  TimerMan.addTimer(delay + timeOut, _timerHide, boost::bind(&Tooltip::doHide, this, _1));
273 }
274 
277 
278  if (!_visible)
279  return;
280 
281  _visible = false;
282 
283  TimerMan.removeTimer(_timerHide);
284  TimerMan.removeTimer(_timerShow);
285 
286  doHide();
287 }
288 
289 void Tooltip::getSize(float &width, float &height) {
290  width = 0.0f;
292  width = MAX(width, (*t)->getWidth());
293 
294  if (_portrait)
295  width += _portrait->getWidth() + 2.0f;
296 
297  height = 0.0f;
298  if (_texts.size() > 0)
299  height = (_texts.size() * _lineHeight) + ((_texts.size() - 1) * _lineSpacing);
300 
301  if (_portrait)
302  height = MAX(height, _portrait->getHeight());
303 }
304 
306  _empty = !_portrait && _lines.empty();
307 }
308 
310  _texts.clear();
311 }
312 
313 bool Tooltip::createTexts(float width, size_t maxLines) {
314  deleteTexts();
315 
317 
318  const float maxWidth = _showBubble ? (width - (_showPortrait ? 18.0f : 0.0f)) : 0.0f;
319 
320  for (std::vector<Line>::const_iterator l = _lines.begin(); l != _lines.end(); l++) {
321  std::vector<Common::UString> lineLines;
322 
323  font.getFont().split(l->line, lineLines, maxWidth);
324 
325  for (std::vector<Common::UString>::const_iterator i = lineLines.begin(); i != lineLines.end(); ++i) {
326  _texts.push_back(new Graphics::Aurora::Text(font, *i, l->r, l->g, l->b, l->a));
327  _texts.back()->setTag("Tooltip#Text");
328  }
329  }
330 
331  return !_showBubble || !maxLines || (_texts.size() <= maxLines);
332 }
333 
334 void Tooltip::redoLines(bool force) {
335  bool needRedo = force;
336 
337  bool showBubble, showText, showPortrait;
338  getFeedbackMode(showBubble, showText, showPortrait);
339 
340  const Common::UString fontName = getFontName();
341 
342  if ((fontName != _font ) ||
343  (showBubble != _showBubble ) ||
344  (showText != _showText ) ||
345  (showPortrait != _showPortrait)) {
346 
347  _font = fontName;
348  _showBubble = showBubble;
349  _showText = showText;
350  _showPortrait = showPortrait;
351 
352  needRedo = true;
353  }
354 
355  if (!needRedo)
356  return;
357 
359 
360  _lineHeight = font.getFont().getHeight();
362 
363  _width = 0.0f;
364  _height = 0.0f;
365 
366  if (!createTexts(100.0f, 3))
367  if (!createTexts(150.f, 3))
368  createTexts(300.0f);
369 
370  redoLayout();
371 }
372 
374  _bubble.reset();
375 
376  if (!_showBubble || (_height <= 0.0f))
377  return;
378 
379  float height = _height - _lineHeight;
380  uint32 lines = 1;
381 
382  while (height > _lineSpacing) {
383  height -= (_lineSpacing + _lineHeight);
384  lines++;
385  }
386 
387  Common::UString bubbleModel = getBubbleModel(lines, _width);
388 
389  _bubble.reset(loadModelGUI(bubbleModel));
390  if (!_bubble) {
391  warning("Tooltip::redoBubble(): Failed loading model \"%s\"", bubbleModel.c_str());
392  return;
393  }
394 
395  _bubble->setTag("Tooltip#Bubble");
396 }
397 
399  checkEmpty();
400  if (_empty)
401  return;
402 
403  if (_font.empty())
404  _font = getFontName();
405 
407 
408  _lineHeight = font.getFont().getHeight();
410 
411  float width, height;
412  getSize(width, height);
413 
414  if ((_width != width) || (_height != height)) {
415  _width = width;
416  _height = height;
417 
418  redoBubble();
419  }
420 
421  updatePosition();
422 }
423 
425  if (_empty || _offscreen || !_visible)
426  return;
427 
428  GfxMan.lockFrame();
429 
430  if (_bubble && _showBubble)
431  _bubble->show();
432  if (_portrait && _showPortrait)
433  _portrait->show();
434 
435  if (_showText)
436  for (Common::PtrVector<Graphics::Aurora::Text>::iterator t = _texts.begin(); t != _texts.end(); ++t)
437  (*t)->show();
438 
439  GfxMan.unlockFrame();
440 }
441 
443  GfxMan.lockFrame();
444 
445  if (_bubble)
446  _bubble->hide();
447  if (_portrait)
448  _portrait->hide();
449 
450  for (Common::PtrVector<Graphics::Aurora::Text>::iterator t = _texts.begin(); t != _texts.end(); ++t)
451  (*t)->hide();
452 
453  GfxMan.unlockFrame();
454 }
455 
458  doShow();
459  return 0;
460 }
461 
464 
465  if (!_visible)
466  return 0;
467 
468  _visible = false;
469 
470  TimerMan.removeTimer(_timerShow);
471 
472  doHide();
473  return 0;
474 }
475 
476 void Tooltip::getFeedbackMode(bool &showBubble, bool &showText, bool &showPortrait) const {
477  uint32 mode = ConfigMan.getInt("feedbackmode", 2);
478 
479  showBubble = mode == 2;
480  showText = mode >= 1;
481  showPortrait = mode == 2;
482 
483  switch (_type) {
484  case kTypeHelp:
485  showBubble = true;
486  showText = true;
487  showPortrait = false;
488  break;
489 
490  case kTypeSpeech:
491  showText = true;
492  break;
493 
494  default:
495  break;
496  }
497 }
498 
500  return ConfigMan.getBool("largefonts") ? "fnt_dialog_big16" : "fnt_dialog16x16";
501 }
502 
504  uint32 modelLines = 0;
505  uint32 modelWidth = 0;
506 
507  if (lines <= 1)
508  modelLines = 1;
509  else if (lines == 2)
510  modelLines = 2;
511  else if (lines == 3)
512  modelLines = 3;
513  else if (lines == 4)
514  modelLines = 4;
515  else if (lines == 5)
516  modelLines = 5;
517  else if (lines <= 7)
518  modelLines = 7;
519  else if (lines <= 10)
520  modelLines = 10;
521  else if (lines <= 16)
522  modelLines = 16;
523  else
524  modelLines = 32;
525 
526  if ((modelLines >= 1) && (modelLines <= 3)) {
527  if (width <= 100.0f)
528  modelWidth = 100;
529  else if (width <= 150.0f)
530  modelWidth = 150;
531  else
532  modelWidth = 300;
533  } else
534  modelWidth = 300;
535 
536  return Common::UString::format("pnl_bubble%d_%d", modelLines, modelWidth);
537 }
538 
540  return (uint32) ConfigMan.getInt("tooltipdelay", 100);
541 }
542 
543 } // End of namespace NWN
544 
545 } // End of namespace Engines
Help string when mousing over a GUI widget.
Definition: tooltip.h:53
void setAlign(float align)
Definition: tooltip.cpp:136
Events::TimerHandle _timerShow
Definition: tooltip.h:136
void hide()
Hide the tooltip again.
Definition: tooltip.cpp:275
Common::UString _font
Definition: tooltip.h:134
The global graphics manager.
void getFeedbackMode(bool &showBubble, bool &showText, bool &showPortrait) const
Definition: tooltip.cpp:476
A class holding an UTF-8 string.
Definition: ustring.h:48
Graphics::Aurora::Model * _parentModel
Definition: tooltip.h:104
void reset(PointerType o=0)
Resets the pointer with the new value.
Definition: scopedptr.h:87
Widget * _parentWidget
Definition: tooltip.h:103
The global config manager.
virtual float getLineSpacing() const
Return the size of space between lines.
Definition: font.cpp:39
A handle to a font.
Definition: fonthandle.h:52
A text object.
Camera management.
void getSize(float &width, float &height)
Definition: tooltip.cpp:289
virtual void getPosition(float &x, float &y, float &z) const
Get the widget&#39;s position.
Definition: widget.cpp:140
float split(const Common::UString &line, std::vector< Common::UString > &lines, float maxWidth=0.0f, float maxHeight=0.0f, bool trim=true) const
Definition: font.cpp:69
#define TimerMan
Shortcut for accessing the timer manager.
Definition: timerman.h:112
A tooltip.
The Aurora font manager.
A scripted speech line on an object.
Definition: tooltip.h:55
A vector of pointer to objects, with automatic deletion.
Definition: ptrvector.h:44
static Common::UString getFontName()
Definition: tooltip.cpp:499
std::vector< Line > _lines
Definition: tooltip.h:119
A text object.
Definition: text.h:42
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
static UString format(const char *s,...) GCC_PRINTF(1
Print formatted data into an UString object, similar to sprintf().
Definition: ustring.cpp:718
#define ConfigMan
Shortcut for accessing the config manager.
Definition: configman.h:176
#define UNUSED(x)
Definition: system.h:170
Utility templates and functions.
static uint32 getDefaultDelay()
Returns the configured default delay, in ms, before a tooltip appears.
Definition: tooltip.cpp:539
void setPosition(float x, float y, float z)
Definition: tooltip.cpp:248
bool getParentPosition(float &x, float &y, float &z) const
Definition: tooltip.cpp:147
A 3D model of an object.
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
Common::Mutex _mutex
Definition: tooltip.h:142
void warning(const char *s,...)
Definition: util.cpp:33
void show(uint32 delay, uint32 timeOut=0)
Show the tooltip.
Definition: tooltip.cpp:258
Events::TimerHandle _timerHide
Definition: tooltip.h:137
Convenience class that locks a mutex on creation and unlocks it on destruction.
Definition: mutex.h:71
A widget in a GUI.
void redoLines(bool force=false)
Definition: tooltip.cpp:334
bool createTexts(float width, size_t maxLines=0)
Definition: tooltip.cpp:313
#define WindowMan
Shortcut for accessing the window manager.
Definition: windowman.h:137
Common::ScopedPtr< Graphics::Aurora::Model > _bubble
Definition: tooltip.h:115
void getTooltipAnchor(float &x, float &y, float &z) const
Get the point where the feedback tooltip is anchored.
Definition: model.cpp:293
uint32 _height
Definition: h263.cpp:54
A NWN portrait model.
Definition: portrait.h:47
A widget in a GUI.
Definition: widget.h:40
void setPortrait(const Common::UString &image)
Definition: tooltip.cpp:125
uint32_t uint32
Definition: types.h:204
Tooltip(Type type)
Definition: tooltip.cpp:49
Graphics::Aurora::Model * loadModelGUI(const Common::UString &resref)
Definition: model.cpp:65
A portrait model and widget.
void split(iterator splitPoint, UString &left, UString &right, bool remove=false) const
Definition: ustring.cpp:621
uint32 _width
Definition: h263.cpp:53
Common::PtrVector< Graphics::Aurora::Text > _texts
Definition: tooltip.h:120
A textured quad for a GUI element.
T MAX(T a, T b)
Definition: util.h:71
Common::ScopedPtr< Portrait > _portrait
Definition: tooltip.h:117
virtual float getHeight() const =0
Return the height of a character.
A font.
#define GfxMan
Shortcut for accessing the graphics manager.
Definition: graphics.h:299
static Common::UString getBubbleModel(uint32 lines, float width)
Definition: tooltip.cpp:503
#define FontMan
Shortcut for accessing the font manager.
Definition: fontman.h:105
void addLine(const Common::UString &text, float r, float g, float b, float a)
Definition: tooltip.cpp:101
Generic Aurora engines model functions.