aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--graphics/font.cpp88
-rw-r--r--graphics/font.h27
2 files changed, 107 insertions, 8 deletions
diff --git a/graphics/font.cpp b/graphics/font.cpp
index 533c564afd..f00e550c4d 100644
--- a/graphics/font.cpp
+++ b/graphics/font.cpp
@@ -156,4 +156,92 @@ void Font::drawString(Surface *dst, const Common::String &s, int x, int y, int w
}
+struct WordWrapper {
+ Common::StringList &lines;
+ int actualMaxLineWidth;
+
+ WordWrapper(Common::StringList &l) : lines(l), actualMaxLineWidth(0) {
+ }
+
+ void add(Common::String &line, int &w) {
+ if (actualMaxLineWidth < w)
+ actualMaxLineWidth = w;
+
+ lines.push_back(line);
+
+ line.clear();
+ w = 0;
+ }
+};
+
+int Font::wordWrapText(const Common::String &str, int maxWidth, Common::StringList &lines) const {
+ WordWrapper wrapper(lines);
+ Common::String line;
+ Common::String tmpStr;
+ int lineWidth = 0;
+ int tmpWidth = 0;
+
+ // The rough idea behind this algorithm is as follows:
+ // We accumulate characters into the string tmpStr. Whenever a full word
+ // has been gathered together this way, we 'commit' it to the line buffer
+ // 'line', i.e. we add tmpStr to the end of line, then clear it. Before
+ // we do that, we check whether it would cause 'line' to exceed maxWidth;
+ // in that case, we first add line to lines, then reset it.
+ //
+ // If a newline character is read, then we also add line to lines and clear it.
+ //
+ // Special care has to be taken to account for 'words' that exceed the width
+ // of a line. If we encounter such a word, we have to wrap it over multiple
+ // lines.
+
+ for (Common::String::const_iterator x = str.begin(); x != str.end(); ++x) {
+ const char c = *x;
+ const int w = getCharWidth(c);
+
+ // If this char is a whitespace, then it represents a potential
+ // 'wrap point' where wrapping could take place. Everything that
+ // came before it can now safely be added to the line, as we know
+ // that it will not have to be wrapped.
+ if (isspace(c)) {
+ line += tmpStr;
+ lineWidth += tmpWidth;
+
+ tmpStr.clear();
+ tmpWidth = 0;
+ }
+
+ // If we encounter a line break (\n), the line is complete.
+ if (c == '\n') {
+ wrapper.add(line, lineWidth);
+ continue;
+ }
+
+ // If the max line width would be exceeded by adding this char,
+ // insert a line break.
+ if (lineWidth + tmpWidth + w > maxWidth) {
+ // Commit what we have so far, *if* we have anything.
+ // If line is empty, then we are looking at a word
+ // which exceeds the maximum line width.
+ if (lineWidth > 0) {
+ wrapper.add(line, lineWidth);
+ } else {
+ wrapper.add(tmpStr, tmpWidth);
+ }
+ }
+
+
+ tmpWidth += w;
+ tmpStr += c;
+ }
+
+ // If some text is left over, add it as the final line
+ line += tmpStr;
+ lineWidth += tmpWidth;
+ if (lineWidth > 0) {
+ wrapper.add(line, lineWidth);
+ }
+ return wrapper.actualMaxLineWidth;
+}
+
+
} // End of namespace Graphics
diff --git a/graphics/font.h b/graphics/font.h
index 8f6aa7249f..230ae94c2b 100644
--- a/graphics/font.h
+++ b/graphics/font.h
@@ -37,14 +37,6 @@ enum TextAlignment {
* Instances of this class represent a distinct font, with a built-in renderer.
* @todo Maybe move the high-level methods (drawString etc.) to a separate
* FontRenderer class? That way, we could have different variants... ?
- * @todo Add more parameters to drawString, or additional similar methods,
- * featuring abilities like
- * - rendering with wrap-around instead of inserting an ellipsis or
- * cutting them; needs a 'height' parameter
- * - rendering multi-line strings (essentially, invoke the regular
- * drawString for each line, and advance one line)
- * - combinations of the two above: honor line feeds, and also wrap
- * overlong lines
*/
class Font {
public:
@@ -55,7 +47,26 @@ public:
virtual void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const = 0;
void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlignment align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const;
+
+ /**
+ * Compute and return the width the string str has when rendered using this font.
+ */
int getStringWidth(const Common::String &str) const;
+
+ /**
+ * Take a text (which may contain newlines characters) and word wrap it so thata
+ * no text line is wider than maxWidth pixels. If necessary, additional line breaks
+ * are generated, preferably between words (i.e. were whitespaces are).
+ * The resulting lines are appended to the string list lines.
+ * It returns the maximal width of any of the new lines (i.e. a value which is less
+ * or equal to maxWidth).
+ *
+ * @param str the string to word wrap
+ * @param maxWidth the maximum width a line may have
+ * @param lines the string list to which the text lines from str are appended
+ * @return the maximal width of any of the lines added to lines
+ */
+ int wordWrapText(const Common::String &str, int maxWidth, Common::StringList &lines) const;
};