added multi-line tooltip support

This commit is contained in:
thrust26 2020-11-18 20:07:25 +01:00
parent 3690d83c7f
commit 3433a6f013
7 changed files with 84 additions and 49 deletions

View File

@ -40,7 +40,7 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& lfont,
_textcolorhi = kTextColor;
_editMode = false;
_dyCaret = 1;
_dyText = -1; // fixes the vertical position of selected text
_cols = w / _fontWidth;
_rows = h / _lineHeight;
@ -631,8 +631,8 @@ Common::Rect RomListWidget::getEditRect() const
{
const int yoffset = std::max(0, (_selectedItem - _currentPos) * _lineHeight);
return Common::Rect(2 + _w - _bytesWidth, 1 + yoffset,
_w, _lineHeight + yoffset);
return Common::Rect(2 + _w - _bytesWidth, 1 + yoffset + 1,
_w, _lineHeight + yoffset + 1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -296,21 +296,39 @@ void FBSurface::frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurface::wrapString(const string& inStr, int pos, string& leftStr, string& rightStr) const
void FBSurface::splitString(const GUI::Font& font, const string& s, int w,
string& left, string& right) const
{
uInt32 pos;
int w2 = 0;
bool split = false;
// SLOW algorithm to find the acceptable length. But it is good enough for now.
for(pos = 0; pos < s.size(); ++pos)
{
int charWidth = font.getCharWidth(s[pos]);
if(w2 + charWidth > w)
{
split = true;
break;
}
w2 += charWidth;
}
if(split)
for(int i = pos; i > 0; --i)
{
if(isWhiteSpace(inStr[i]))
if(isWhiteSpace(s[i]))
{
leftStr = inStr.substr(0, i);
if(inStr[i] == ' ') // skip leading space after line break
left = s.substr(0, i);
if(s[i] == ' ') // skip leading space after line break
i++;
rightStr = inStr.substr(i);
right = s.substr(i);
return;
}
}
leftStr = inStr.substr(0, pos);
rightStr = inStr.substr(pos);
left = s.substr(0, pos);
right = s.substr(pos);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -340,21 +358,9 @@ int FBSurface::drawString(const GUI::Font& font, const string& s,
while (font.getStringWidth(inStr) > w && h >= font.getFontHeight() * 2)
{
// String is too wide.
uInt32 i;
string leftStr, rightStr;
int w2 = 0;
// SLOW algorithm to find the acceptable length. But it is good enough for now.
for(i = 0; i < inStr.size(); ++i)
{
int charWidth = font.getCharWidth(inStr[i]);
if(w2 + charWidth > w)
break;
w2 += charWidth;
//str += inStr[i];
}
wrapString(inStr, i, leftStr, rightStr);
splitString(font, inStr, w, leftStr, rightStr);
drawString(font, leftStr, x, y, w, color, align, deltax, false, shadowColor);
h -= font.getFontHeight();
y += font.getFontHeight();

View File

@ -247,6 +247,18 @@ class FBSurface
ColorId color, TextAlign align = TextAlign::Left,
int deltax = 0, bool useEllipsis = true, ColorId shadowColor = kNone);
/**
Splits a given string to a given width considering whitespaces.
@param font The font to draw the string with
@param s The string to split
@param w The width of the string area
@param left The left part of the split string
@param right The right part of the split string
*/
void splitString(const GUI::Font& font, const string& s, int w,
string& left, string& right) const;
/**
The rendering attributes that can be modified for this texture.
These probably can only be implemented in child FBSurfaces where
@ -383,9 +395,6 @@ class FBSurface
*/
bool checkBounds(const uInt32 x, const uInt32 y) const;
void wrapString(const string& inStr, int pos,
string& leftStr, string& rightStr) const;
/**
Check if the given character is a whitespace.
@param s Character to check

View File

@ -379,8 +379,8 @@ void EditableWidget::drawCaretSelection()
x += _x;
y += _y;
s.fillRect(x - 1, y + 1 + _dyCaret, w + 1, h - 3, kTextColorHi);
s.drawString(_font, text, x, y + 1, w, h,
s.fillRect(x - 1, y + 1, w + 1, h - 3, kTextColorHi);
s.drawString(_font, text, x, y + 1 + _dyText, w, h,
kTextColorInv, TextAlign::Left, 0, false);
}
@ -397,8 +397,8 @@ void EditableWidget::drawCaretSelection()
x += _x;
y += _y;
s.vLine(x, y + 1 + _dyCaret, y + editRect.h() - 3, color);
s.vLine(x - 1, y + 1 + _dyCaret, y + editRect.h() - 3, color);
s.vLine(x, y + 1, y + editRect.h() - 3, color);
s.vLine(x - 1, y + 1, y + editRect.h() - 3, color);
clearDirty();
}
}

View File

@ -125,7 +125,7 @@ class EditableWidget : public Widget, public CommandSender
protected:
int _editScrollOffset{0};
bool _editMode{true};
int _dyCaret{0};
int _dyText{0};
private:
TextFilter _filter;

View File

@ -27,7 +27,6 @@
// TODOs:
// - option to disable tips
// - multi line tips
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ToolTip::ToolTip(Dialog& dialog, const GUI::Font& font)
@ -47,8 +46,8 @@ void ToolTip::setFont(const GUI::Font& font)
myTextXOfs = fontHeight < 24 ? 5 : 8;
myTextYOfs = fontHeight < 24 ? 2 : 3;
myWidth = fontWidth * MAX_LEN + myTextXOfs * 2;
myHeight = fontHeight + myTextYOfs * 2;
myWidth = fontWidth * MAX_COLUMNS + myTextXOfs * 2;
myHeight = fontHeight * MAX_ROWS + myTextYOfs * 2;
mySurface = myDialog.instance().frameBuffer().allocateSurface(myWidth, myHeight);
}
@ -129,9 +128,30 @@ void ToolTip::show(const string& tip)
{
myTipPos = myMousePos;
uInt32 maxWidth = std::min(myWidth - myTextXOfs * 2, uInt32(myFont->getStringWidth(tip)));
mySurface->fillRect(1, 1, maxWidth + myTextXOfs * 2 - 2, myHeight - 2, kWidColor);
int lines = std::min(MAX_ROWS,
uInt32(mySurface->drawString(*myFont, tip, myTextXOfs, myTextYOfs,
maxWidth, myHeight - myTextYOfs * 2,
kTextColor)));
// Calculate maximum width of drawn string lines
uInt32 width = 0;
string inStr = tip;
for(int i = 0; i < lines; ++i)
{
string leftStr, rightStr;
mySurface->splitString(*myFont, inStr, maxWidth, leftStr, rightStr);
width = std::max(width, uInt32(myFont->getStringWidth(leftStr)));
inStr = rightStr;
}
width += myTextXOfs * 2;
// Calculate and set surface size and position
const uInt32 height = std::min(myHeight, myFont->getFontHeight() * lines + myTextYOfs * 2);
const uInt32 V_GAP = 1;
const uInt32 H_CURSOR = 18;
uInt32 width = std::min(myWidth, myFont->getStringWidth(tip) + myTextXOfs * 2);
// Note: The rects include HiDPI scaling
const Common::Rect imageRect = myDialog.instance().frameBuffer().imageRect();
const Common::Rect dialogRect = myDialog.surface().dstRect();
@ -139,24 +159,20 @@ void ToolTip::show(const string& tip)
const Int32 xAbs = myTipPos.x + dialogRect.x() / myScale;
const uInt32 yAbs = myTipPos.y + dialogRect.y() / myScale;
Int32 x = std::min(xAbs, Int32(imageRect.w() / myScale - width));
const uInt32 y = (yAbs + myHeight + H_CURSOR > imageRect.h() / myScale)
? yAbs - myHeight - V_GAP
const uInt32 y = (yAbs + height + H_CURSOR > imageRect.h() / myScale)
? yAbs - height - V_GAP
: yAbs + H_CURSOR / myScale + V_GAP;
if(x < 0)
{
x = 0;
width = imageRect.w() / myScale;
width = std::min(width, imageRect.w() / myScale);
}
mySurface->setSrcSize(width, myHeight);
mySurface->setDstSize(width * myScale, myHeight * myScale);
mySurface->setSrcSize(width, height);
mySurface->setDstSize(width * myScale, height * myScale);
mySurface->setDstPos(x * myScale, y * myScale);
mySurface->frameRect(0, 0, width, myHeight, kColor);
mySurface->fillRect(1, 1, width - 2, myHeight - 2, kWidColor);
mySurface->drawString(*myFont, tip, myTextXOfs, myTextYOfs,
width - myTextXOfs * 2, myHeight - myTextYOfs * 2, kTextColor);
mySurface->frameRect(0, 0, width, height, kColor);
myTipShown = true;
myDialog.instance().frameBuffer().setPendingRender();

View File

@ -33,9 +33,13 @@ class FBSurface;
class ToolTip
{
private:
static constexpr uInt32 MAX_COLUMNS = 60;
static constexpr uInt32 MAX_ROWS = 5;
public:
// Maximum tooltip length
static constexpr uInt32 MAX_LEN = 80;
static constexpr uInt32 MAX_LEN = MAX_COLUMNS * MAX_ROWS;
ToolTip(Dialog& dialog, const GUI::Font& font);
~ToolTip() = default;