Skip to content

Commit

Permalink
libshell|Client|LineWrapping: Determining content index at a width
Browse files Browse the repository at this point in the history
The ILineWrapping interface now contains methods that allow
determining which content index is at a given width in a range.

FontLineWrapping also now correctly uses advance width when suitable.
Visible width is only used for determining the actual wrapping points.
  • Loading branch information
skyjake committed May 21, 2013
1 parent 7ce4769 commit 53104cb
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 8 deletions.
2 changes: 2 additions & 0 deletions doomsday/client/include/ui/widgets/fontlinewrapping.h
Expand Up @@ -42,6 +42,8 @@ class FontLineWrapping : public de::shell::ILineWrapping
de::shell::WrappedLine line(int index) const;
int width() const;
int height() const;
int rangeWidth(de::shell::Range const &range) const;
int indexAtWidth(de::shell::Range const &range, int width) const;

/**
* Calculates the total height of the wrapped lined in pixels, taking into
Expand Down
51 changes: 44 additions & 7 deletions doomsday/client/src/ui/widgets/fontlinewrapping.cpp
Expand Up @@ -34,14 +34,23 @@ DENG2_PIMPL_NOREF(FontLineWrapping)
return text.substr(range.start, range.size());
}

int rangeWidth(Range const &range) const
int rangeVisibleWidth(Range const &range) const
{
if(font)
{
return font->measure(rangeText(range)).width();
}
return 0;
}

int rangeAdvanceWidth(Range const &range) const
{
if(font)
{
return font->advanceWidth(rangeText(range));
}
return 0;
}
};

FontLineWrapping::FontLineWrapping() : d(new Instance)
Expand Down Expand Up @@ -89,7 +98,7 @@ void FontLineWrapping::wrapTextToWidth(String const &text, int maxWidth)
forever
{
// Quick check: does the remainder fit?
if(d->rangeWidth(Range(begin, text.size())) <= maxWidth)
if(d->rangeVisibleWidth(Range(begin, text.size())) <= maxWidth)
{
d->lines.append(WrappedLine(Range(begin, text.size())));
break;
Expand All @@ -102,7 +111,7 @@ void FontLineWrapping::wrapTextToWidth(String const &text, int maxWidth)
{
++end;

if(d->rangeWidth(Range(begin, end)) > maxWidth)
if(d->rangeVisibleWidth(Range(begin, end)) > maxWidth)
{
// Went too far.
wrapPosMax = --end;
Expand Down Expand Up @@ -136,10 +145,10 @@ void FontLineWrapping::wrapTextToWidth(String const &text, int maxWidth)
}
else
{
//if(text.at(end).isSpace()) ++end;
while(text.at(end).isSpace()) ++end;
d->lines.append(WrappedLine(Range(begin, end)));
begin = end;
while(text.at(begin).isSpace()) ++begin;
//while(text.at(begin).isSpace()) ++begin;
}
}

Expand All @@ -161,7 +170,7 @@ int FontLineWrapping::width() const
for(int i = 0; i < d->lines.size(); ++i)
{
WrappedLine const &span = d->lines[i];
w = de::max(w, d->rangeWidth(span.range));
w = de::max(w, d->rangeVisibleWidth(span.range));
}
return w;
}
Expand All @@ -171,6 +180,33 @@ int FontLineWrapping::height() const
return d->lines.size();
}

int FontLineWrapping::rangeWidth(Range const &range) const
{
return d->rangeAdvanceWidth(range);
}

int FontLineWrapping::indexAtWidth(Range const &range, int width) const
{
int prevWidth = 0;

for(int i = range.start; i < range.end; ++i)
{
int const rw = d->rangeAdvanceWidth(Range(range.start, i));
if(rw >= width)
{
// Which is closer, this or the previous char?
if(de::abs(rw - width) <= de::abs(prevWidth - width))
{
qDebug() << "this" << i;
return i;
}
return i - 1;
}
prevWidth = rw;
}
return range.end;
}

int FontLineWrapping::totalHeightInPixels() const
{
if(!d->font) return 0;
Expand All @@ -197,7 +233,8 @@ Vector2i FontLineWrapping::charTopLeftInPixels(int line, int charIndex)
Range const range(span.range.start, de::min(span.range.end, span.range.start + charIndex));

Vector2i cp;
cp.x = d->font->measure(d->rangeText(range)).width();
cp.x = d->font->advanceWidth(d->rangeText(range));
cp.y = line * d->font->lineSpacing().valuei();

return cp;
}
13 changes: 12 additions & 1 deletion doomsday/libshell/include/de/shell/libshell.h
Expand Up @@ -54,7 +54,7 @@ struct LIBSHELL_PUBLIC Range
}
};

/// Word wrapping.
/// Line of word-wrapped text.
struct LIBSHELL_PUBLIC WrappedLine
{
Range range;
Expand All @@ -73,8 +73,19 @@ class LIBSHELL_PUBLIC ILineWrapping
virtual void clear() = 0;
virtual void wrapTextToWidth(String const &text, int maxWidth) = 0;
virtual WrappedLine line(int index) const = 0;

/// Determines the visible maximum width of the wrapped content.
virtual int width() const = 0;

/// Determines the number of lines in the wrapped content.
virtual int height() const = 0;

/// Returns the advance width of the range.
virtual int rangeWidth(Range const &range) const = 0;

/// Calculates which index in the provided content range occupies a
/// character at a given width.
virtual int indexAtWidth(Range const &range, int width) const = 0;
};

} // namespace shell
Expand Down
2 changes: 2 additions & 0 deletions doomsday/libshell/include/de/shell/monospacelinewrapping.h
Expand Up @@ -52,6 +52,8 @@ class LIBSHELL_PUBLIC MonospaceLineWrapping : public ILineWrapping
WrappedLine line(int index) const { return _lines[index]; }
int width() const;
int height() const;
int rangeWidth(Range const &range) const;
int indexAtWidth(Range const &range, int width) const;

private:
QList<WrappedLine> _lines;
Expand Down
14 changes: 14 additions & 0 deletions doomsday/libshell/src/monospacelinewrapping.cpp
Expand Up @@ -107,5 +107,19 @@ int MonospaceLineWrapping::height() const
return _lines.size();
}

int MonospaceLineWrapping::rangeWidth(Range const &range) const
{
return range.size();
}

int MonospaceLineWrapping::indexAtWidth(Range const &range, int width) const
{
if(width <= range.size())
{
return range.start + width;
}
return range.end;
}

} // namespace shell
} // namespace de

0 comments on commit 53104cb

Please sign in to comment.