Skip to content

Commit

Permalink
libgui|Font: Rich formatting of text
Browse files Browse the repository at this point in the history
The format escape sequences in styled text can be interpreted using
RichFormat. RichFormat can then be given to Font, FontLineWrapping, and
GLTextComposer to modify the appearance of the text.
  • Loading branch information
skyjake committed May 23, 2013
1 parent 0daff78 commit a01c580
Show file tree
Hide file tree
Showing 2 changed files with 536 additions and 13 deletions.
135 changes: 130 additions & 5 deletions doomsday/libgui/include/de/gui/font.h
Expand Up @@ -24,9 +24,11 @@
#include <de/Rectangle>
#include <de/String>
#include <de/Vector>
#include <de/Range>

#include <QFont>
#include <QImage>
#include <QList>

#include "libgui.h"

Expand All @@ -37,6 +39,121 @@ namespace de {
*/
class LIBGUI_PUBLIC Font
{
public:
/**
* Rich formatting instructions for a string of text.
*
* The formatting instructions are composed of a sequence of ranges that
* specify various modifications to the original font. It is important to
* note that a RichFormat instance always needs to be set up for a specific
* source text string. Also, RichFormat is out-of-band data: when operating
* on a piece of rich text (using the methods of Font), the formatting is
* always provided in parallel to the plain version of the text.
*
* Use RichFormat::fromPlainText() to set up a RichFormat for a string of
* plain text.
*
* Use RichFormat::initFromStyledText() to set up a RichFormat for a string
* of text that contains style information (as escape sequences that start
* with the Esc ASCII code 0x1b).
*/
class RichFormat
{
public:
RichFormat();
RichFormat(RichFormat const &other);

/**
* Constructs a RichFormat that specifies no formatting instructions.
*
* @param plainText Plain text.
*
* @return RichFormat instance with a single range that uses the
* default formatting.
*/
static RichFormat fromPlainText(String const &plainText);

/**
* Initializes this RichFormat instance with the styles found in the
* provided styled text (using escape sequences).
*
* @param styledText Text with style markup.
*
* @return Corresponding plain text for use with the methods of Font.
*/
String initFromStyledText(String const &styledText);

enum Weight {
OriginalWeight = -1,
Normal = 0,
Light = 1,
Bold = 2
};
enum Style {
OriginalStyle = -1,
Regular = 0,
Italic = 1
};
enum Color
{
OriginalColor = -1,
NormalColor = 0,
HighlightColor = 1,
DimmedColor = 2,
AccentColor = 3
};

/**
* Clips this RichFormat so that it covers only the specified range.
* The indices are translated to be relative to the provided range.
*
* @param range Target range for clipping.
*
* @return RichFormat with only those ranges covering @a range.
*/
RichFormat subRange(Rangei const &range) const;

/**
* Iterates the rich format ranges of a RichFormat.
*
* @note Iterator::next() must be called before at least once after
* constructing the instance to move the iterator onto the first range.
*/
struct Iterator
{
RichFormat const &format;
int index;

Iterator(RichFormat const &f);
bool hasNext() const;
void next();

bool isOriginal() const;
Rangei range() const;
float sizeFactor() const;
Weight weight() const;
Style style() const;
int color() const;
bool markIndent() const;
};

private:
struct FormatRange
{
Rangei range;
float sizeFactor;
Weight weight;
Style style;
int colorIndex;
bool markIndent;

FormatRange() : sizeFactor(1.f), weight(OriginalWeight),
style(OriginalStyle), colorIndex(-1), markIndent(false) {}
};
typedef QList<FormatRange> Ranges;
Ranges _ranges;
};

public:
Font();

Expand All @@ -47,17 +164,18 @@ class LIBGUI_PUBLIC Font
QFont toQFont() const;

/**
* Determines the size of the given line of text (as in how large an area
* is covered by the glyphs). (0,0) is the corner of is at the baseline,
* left edge of the line. The rectangle may extend into negative
* coordinates.
* Determines the size of the given line of text, i.e., how large an area
* is covered by the glyphs. (0,0) is at the baseline, left edge of the
* line. The rectangle may extend into negative coordinates.
*
* @param textLine Text to measure.
*
* @return Rectangle covered by the text.
*/
Rectanglei measure(String const &textLine) const;

Rectanglei measure(String const &textLine, RichFormat const &format) const;

/**
* Returns the advance width of a line of text. This is not the same as
* the width of the rectangle returned by measure().
Expand All @@ -69,19 +187,26 @@ class LIBGUI_PUBLIC Font
*/
int advanceWidth(String const &textLine) const;

int advanceWidth(String const &textLine, RichFormat const &format) const;

/**
* Rasterizes a line of text onto a 32-bit RGBA image.
*
* @param textLine Text to rasterize.
* @param foreground Text foreground color.
* @param background Background color.
*
* @return
* @return Image containing the rasterized text.
*/
QImage rasterize(String const &textLine,
Vector4ub const &foreground = Vector4ub(255, 255, 255, 255),
Vector4ub const &background = Vector4ub(255, 255, 255, 0)) const;

QImage rasterize(String const &textLine,
RichFormat const &format,
Vector4ub const &foreground = Vector4ub(255, 255, 255, 255),
Vector4ub const &background = Vector4ub(255, 255, 255, 0)) const;

Rule const &height() const;
Rule const &ascent() const;
Rule const &descent() const;
Expand Down

0 comments on commit a01c580

Please sign in to comment.