mirror of https://github.com/buggins/dlangui.git
support simple multiline text formatting and drawing
This commit is contained in:
parent
2155d8418b
commit
cd8c617e05
|
@ -417,6 +417,21 @@ class Font : RefCountedObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// measure multiline text with line splitting, returns width and height in pixels
|
||||||
|
Point measureMultilineText(const dchar[] text, int maxLines = 0, int maxWidth = 0, int tabSize = 4, int tabOffset = 0, uint textFlags = 0) {
|
||||||
|
SimpleTextFormatter fmt;
|
||||||
|
FontRef fnt = FontRef(this);
|
||||||
|
return fmt.format(text, fnt, maxLines, maxWidth, tabSize, tabOffset, textFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// draws multiline text with line splitting
|
||||||
|
void drawMultilineText(DrawBuf buf, int x, int y, const dchar[] text, uint color, int maxLines = 0, int maxWidth = 0, int tabSize = 4, int tabOffset = 0, uint textFlags = 0) {
|
||||||
|
SimpleTextFormatter fmt;
|
||||||
|
FontRef fnt = FontRef(this);
|
||||||
|
fmt.format(text, fnt, maxLines, maxWidth, tabSize, tabOffset, textFlags);
|
||||||
|
fmt.draw(buf, x, y, fnt, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// get character glyph information
|
/// get character glyph information
|
||||||
abstract Glyph * getCharGlyph(dchar ch, bool withImage = true);
|
abstract Glyph * getCharGlyph(dchar ch, bool withImage = true);
|
||||||
|
@ -434,6 +449,109 @@ class Font : RefCountedObject {
|
||||||
}
|
}
|
||||||
alias FontRef = Ref!Font;
|
alias FontRef = Ref!Font;
|
||||||
|
|
||||||
|
/// helper to split text into several lines and draw it
|
||||||
|
struct SimpleTextFormatter {
|
||||||
|
dstring[] _lines;
|
||||||
|
int _tabSize;
|
||||||
|
int _tabOffset;
|
||||||
|
uint _textFlags;
|
||||||
|
/// split text into lines and measure it; returns size in pixels
|
||||||
|
Point format(const dchar[] text, FontRef fnt, int maxLines = 0, int maxWidth = 0, int tabSize = 4, int tabOffset = 0, uint textFlags = 0) {
|
||||||
|
_tabSize = tabSize;
|
||||||
|
_tabOffset = tabOffset;
|
||||||
|
_textFlags = textFlags;
|
||||||
|
Point sz;
|
||||||
|
_lines.length = 0;
|
||||||
|
int lineHeight = fnt.height;
|
||||||
|
if (text.length == 0) {
|
||||||
|
sz.y = lineHeight;
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
int[] widths;
|
||||||
|
int charsMeasured = fnt.measureText(text, widths, MAX_WIDTH_UNSPECIFIED, _tabSize, _tabOffset, _textFlags);
|
||||||
|
int lineStart = 0;
|
||||||
|
int lineStartX = 0;
|
||||||
|
int lastWordEnd = 0;
|
||||||
|
int lastWordEndX = 0;
|
||||||
|
dchar prevChar = 0;
|
||||||
|
for (int i = 0; i <= charsMeasured; i++) {
|
||||||
|
dchar ch = text[i];
|
||||||
|
if (ch == '\n' || i == charsMeasured) {
|
||||||
|
// split by EOL char or at end of text
|
||||||
|
dstring line = cast(dstring)text[lineStart .. i];
|
||||||
|
int lineEndX = (i == charsMeasured) || (i == lineStart) ? lineStartX : widths[i - 1];
|
||||||
|
int lineWidth = lineEndX - lineStartX;
|
||||||
|
sz.y += lineHeight;
|
||||||
|
if (sz.x < lineWidth)
|
||||||
|
sz.x = lineWidth;
|
||||||
|
_lines ~= line;
|
||||||
|
if (i == charsMeasured) // end of text reached
|
||||||
|
break;
|
||||||
|
|
||||||
|
// check max lines constraint
|
||||||
|
if (maxLines && _lines.length >= maxLines) // max lines reached
|
||||||
|
break;
|
||||||
|
|
||||||
|
lineStart = i + 1;
|
||||||
|
lineStartX = widths[i];
|
||||||
|
} else {
|
||||||
|
// split by width
|
||||||
|
int x = widths[i];
|
||||||
|
if (ch == '\t' || ch == ' ') {
|
||||||
|
// track last word end
|
||||||
|
if (prevChar != '\t' && prevChar != ' ' && prevChar != 0) {
|
||||||
|
lastWordEnd = i - 1;
|
||||||
|
lastWordEndX = widths[i - 1];
|
||||||
|
}
|
||||||
|
prevChar = ch;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (maxWidth > 0 && x > maxWidth && x - lineStartX > maxWidth && i > lineStart) {
|
||||||
|
// need splitting
|
||||||
|
int lineEnd = i;
|
||||||
|
int lineEndX = widths[i - 1];
|
||||||
|
if (lastWordEnd > lineStart && lastWordEndX - lineStartX >= maxWidth / 3) {
|
||||||
|
// split on word bound
|
||||||
|
lineEnd = lastWordEnd;
|
||||||
|
lineEndX = widths[lastWordEnd - 1];
|
||||||
|
}
|
||||||
|
// add line
|
||||||
|
dstring line = cast(dstring)text[lineStart .. lastWordEnd];
|
||||||
|
int lineWidth = lineEndX - lineStartX;
|
||||||
|
sz.y += lineHeight;
|
||||||
|
if (sz.x < lineWidth)
|
||||||
|
sz.x = lineWidth;
|
||||||
|
_lines ~= line;
|
||||||
|
|
||||||
|
// check max lines constraint
|
||||||
|
if (maxLines && _lines.length >= maxLines) // max lines reached
|
||||||
|
break;
|
||||||
|
|
||||||
|
// find next line start
|
||||||
|
lineStart = lineEnd;
|
||||||
|
while(lineStart < text.length && (text[lineStart] == ' ' || text[lineStart] == '\t'))
|
||||||
|
lineStart++;
|
||||||
|
if (lineStart >= text.length)
|
||||||
|
break;
|
||||||
|
lineStartX = widths[lineStart - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevChar = ch;
|
||||||
|
}
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
/// draw formatted text
|
||||||
|
void draw(DrawBuf buf, int x, int y, FontRef fnt, uint color) {
|
||||||
|
int lineHeight = fnt.height;
|
||||||
|
for (int i = 0; i < _lines.length; i++) {
|
||||||
|
dstring line = _lines[i];
|
||||||
|
fnt.drawText(buf, x, y, line, color, _tabSize, _tabOffset, _textFlags);
|
||||||
|
y += lineHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// font instance collection - utility class, for font manager implementations
|
/// font instance collection - utility class, for font manager implementations
|
||||||
struct FontList {
|
struct FontList {
|
||||||
FontRef[] _list;
|
FontRef[] _list;
|
||||||
|
|
Loading…
Reference in New Issue