Change tabs to two spaces.

This commit is contained in:
Lymia Aluysia
2017-01-18 08:43:21 -06:00
parent d7f5f0dc3b
commit d2c635f739
329 changed files with 41307 additions and 41496 deletions
+27 -27
View File
@@ -12,47 +12,47 @@
// ----------------------------------------------------------------------------- : CompoundTextElement
void CompoundTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const {
elements.draw(dc, scale, rect, xs, what, start, end);
elements.draw(dc, scale, rect, xs, what, start, end);
}
void CompoundTextElement::getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const {
elements.getCharInfo(dc, scale, start, end, out);
elements.getCharInfo(dc, scale, start, end, out);
}
double CompoundTextElement::minScale() const {
return elements.minScale();
return elements.minScale();
}
double CompoundTextElement::scaleStep() const {
return elements.scaleStep();
return elements.scaleStep();
}
// ----------------------------------------------------------------------------- : AtomTextElement
void AtomTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const {
if (what & DRAW_ACTIVE) {
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(Color(210,210,210));
dc.DrawRectangle(rect);
}
CompoundTextElement::draw(dc, scale, rect, xs, what, start, end);
if (what & DRAW_ACTIVE) {
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(Color(210,210,210));
dc.DrawRectangle(rect);
}
CompoundTextElement::draw(dc, scale, rect, xs, what, start, end);
}
// ----------------------------------------------------------------------------- : ErrorTextElement
void ErrorTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const {
// Draw wavy underline
if (what & DRAW_ERRORS) {
dc.SetPen(*wxRED_PEN);
RealPoint pos = rect.bottomLeft() - dc.trInvS(RealSize(0,2));
RealSize dx(dc.trInvS(2), 0), dy(0, dc.trInvS(1));
while (pos.x + 1 < rect.right()) {
dc.DrawLine(pos - dy, pos + dx + dy);
pos += dx;
dy = -dy;
}
if (pos.x < rect.right()) {
// final piece
dc.DrawLine(pos - dy, pos + dx * 0.5);
}
}
// Draw the contents
CompoundTextElement::draw(dc, scale, rect, xs, what, start, end);
// Draw wavy underline
if (what & DRAW_ERRORS) {
dc.SetPen(*wxRED_PEN);
RealPoint pos = rect.bottomLeft() - dc.trInvS(RealSize(0,2));
RealSize dx(dc.trInvS(2), 0), dy(0, dc.trInvS(1));
while (pos.x + 1 < rect.right()) {
dc.DrawLine(pos - dy, pos + dx + dy);
pos += dx;
dy = -dy;
}
if (pos.x < rect.right()) {
// final piece
dc.DrawLine(pos - dy, pos + dx * 0.5);
}
}
// Draw the contents
CompoundTextElement::draw(dc, scale, rect, xs, what, start, end);
}
+225 -225
View File
@@ -18,258 +18,258 @@ DECLARE_POINTER_TYPE(FontTextElement);
// ----------------------------------------------------------------------------- : TextElements
void TextElements::draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const {
FOR_EACH_CONST(e, elements) {
size_t start_ = max(start, e->start);
size_t end_ = min(end, e->end);
if (start_ < end_) {
e->draw(dc, scale,
RealRect(rect.x + xs[start_-start] - xs[0], rect.y,
xs[end_-start] - xs[start_-start], rect.height),
xs + start_ - start, what, start_, end_);
}
if (end <= e->end) return; // nothing can be after this
}
FOR_EACH_CONST(e, elements) {
size_t start_ = max(start, e->start);
size_t end_ = min(end, e->end);
if (start_ < end_) {
e->draw(dc, scale,
RealRect(rect.x + xs[start_-start] - xs[0], rect.y,
xs[end_-start] - xs[start_-start], rect.height),
xs + start_ - start, what, start_, end_);
}
if (end <= e->end) return; // nothing can be after this
}
}
void TextElements::getCharInfo(RotatedDC& dc, double scale, size_t start, size_t end, vector<CharInfo>& out) const {
FOR_EACH_CONST(e, elements) {
// characters before this element, after the previous
while (out.size() < e->start) {
out.push_back(CharInfo());
}
e->getCharInfo(dc, scale, out);
}
while (out.size() < end) {
out.push_back(CharInfo());
}
FOR_EACH_CONST(e, elements) {
// characters before this element, after the previous
while (out.size() < e->start) {
out.push_back(CharInfo());
}
e->getCharInfo(dc, scale, out);
}
while (out.size() < end) {
out.push_back(CharInfo());
}
}
double TextElements::minScale() const {
double m = 0.0001;
FOR_EACH_CONST(e, elements) {
m = max(m, e->minScale());
}
return m;
double m = 0.0001;
FOR_EACH_CONST(e, elements) {
m = max(m, e->minScale());
}
return m;
}
double TextElements::scaleStep() const {
double m = 1;
FOR_EACH_CONST(e, elements) {
m = min(m, e->scaleStep());
}
return m;
double m = 1;
FOR_EACH_CONST(e, elements) {
m = min(m, e->scaleStep());
}
return m;
}
// Colors for <atom-param> tags
AColor param_colors[] =
{ AColor(0,170,0)
, AColor(0,0,200)
, AColor(200,0,100)
, AColor(200,200,0)
, AColor(0,170,170)
, AColor(200,0,0)
};
{ AColor(0,170,0)
, AColor(0,0,200)
, AColor(200,0,100)
, AColor(200,200,0)
, AColor(0,170,170)
, AColor(200,0,0)
};
const size_t param_colors_count = sizeof(param_colors) / sizeof(param_colors[0]);
// Helper class for TextElements::fromString, to allow persistent formating state accross recusive calls
struct TextElementsFromString {
// What formatting is enabled?
int bold, italic, symbol;
int soft, kwpph, param, line, soft_line;
int code, code_kw, code_string, param_ref, error;
int param_id;
vector<AColor> colors;
vector<double> sizes;
/// put angle brackets around the text?
bool bracket;
TextElementsFromString()
: bold(0), italic(0), symbol(0), soft(0), kwpph(0), param(0), line(0), soft_line(0)
, code(0), code_kw(0), code_string(0), param_ref(0), error(0)
, param_id(0), bracket(false) {}
// read TextElements from a string
void fromString(TextElements& te, const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx) {
te.elements.clear();
end = min(end, text.size());
size_t text_start = start;
// for each character...
for (size_t pos = start ; pos < end ; ) {
Char c = text.GetChar(pos);
if (c == _('<')) {
if (text_start < pos) {
// text element before this tag?
addText(te, text, text_start, pos, style, ctx);
}
// a (formatting) tag
size_t tag_start = pos;
pos = skip_tag(text, tag_start);
if (is_substr(text, tag_start, _( "<b"))) bold += 1;
else if (is_substr(text, tag_start, _("</b"))) bold -= 1;
else if (is_substr(text, tag_start, _( "<i"))) italic += 1;
else if (is_substr(text, tag_start, _("</i"))) italic -= 1;
else if (is_substr(text, tag_start, _( "<sym"))) symbol += 1;
else if (is_substr(text, tag_start, _("</sym"))) symbol -= 1;
else if (is_substr(text, tag_start, _( "<line"))) line += 1;
else if (is_substr(text, tag_start, _("</line"))) line -= 1;
else if (is_substr(text, tag_start, _( "<soft-line"))) soft_line += 1;
else if (is_substr(text, tag_start, _("</soft-line"))) soft_line -= 1;
else if (is_substr(text, tag_start, _( "<sep-soft"))) soft += 1;
else if (is_substr(text, tag_start, _("</sep-soft"))) soft -= 1;
else if (is_substr(text, tag_start, _( "<soft"))) soft += 1; // must be after <soft-line
else if (is_substr(text, tag_start, _("</soft"))) soft -= 1;
else if (is_substr(text, tag_start, _( "<atom-kwpph"))) kwpph += 1;
else if (is_substr(text, tag_start, _("</atom-kwpph"))) kwpph -= 1;
else if (is_substr(text, tag_start, _( "<code-kw"))) code_kw += 1;
else if (is_substr(text, tag_start, _("</code-kw"))) code_kw -= 1;
else if (is_substr(text, tag_start, _( "<code-str"))) code_string += 1;
else if (is_substr(text, tag_start, _("</code-str"))) code_string -= 1;
else if (is_substr(text, tag_start, _( "<code"))) code += 1;
else if (is_substr(text, tag_start, _("</code"))) code -= 1;
else if (is_substr(text, tag_start, _( "<color"))) {
size_t colon = text.find_first_of(_(">:"), tag_start);
if (colon < pos - 1 && text.GetChar(colon) == _(':')) {
AColor c = parse_acolor(text.substr(colon+1, pos-colon-2));
if (!c.Ok()) c = style.font.color;
colors.push_back(c);
}
} else if (is_substr(text, tag_start, _("</color"))) {
if (!colors.empty()) colors.pop_back();
}
else if (is_substr(text, tag_start, _( "<size"))) {
size_t colon = text.find_first_of(_(">:"), tag_start);
if (colon < pos - 1 && text.GetChar(colon) == _(':')) {
double size = style.font.size;
String v = text.substr(colon+1, pos-colon-2);
v.ToDouble(&size);
sizes.push_back(size);
}
} else if (is_substr(text, tag_start, _("</size"))) {
if (!sizes.empty()) sizes.pop_back();
}
else if (is_substr(text, tag_start, _( "<ref-param"))) {
// determine the param being referenced
// from a tag <ref-param123>
if (pos != String::npos) {
String ref = text.substr(tag_start + 10, pos - tag_start - 11);
long ref_n;
if (ref.ToLong(&ref_n)) {
param_id = (ref_n - 1)%param_colors_count + param_colors_count;
}
}
param_ref += 1;
}
else if (is_substr(text, tag_start, _("</ref-param"))) param_ref -= 1;
else if (is_substr(text, tag_start, _( "<atom-param"))) param += 1;
else if (is_substr(text, tag_start, _("</atom-param"))) param -= 1;
else if (is_substr(text, tag_start, _("<atom"))) {
// 'atomic' indicator
size_t end_tag = min(end, match_close_tag(text, tag_start));
intrusive_ptr<AtomTextElement> e(new AtomTextElement(pos, end_tag));
fromString(e->elements, text, pos, end_tag, style, ctx);
te.elements.push_back(e);
pos = skip_tag(text, end_tag);
} else if (is_substr(text, tag_start, _( "<error"))) {
// error indicator
size_t end_tag = min(end, match_close_tag(text, tag_start));
intrusive_ptr<ErrorTextElement> e(new ErrorTextElement(pos, end_tag));
fromString(e->elements, text, pos, end_tag, style, ctx);
te.elements.push_back(e);
pos = skip_tag(text, end_tag);
} else {
// ignore other tags
}
// text starts again after the tag
text_start = pos;
} else {
// normal text
pos += 1;
}
}
if (text_start < end) {
// remaining text at the end
addText(te, text, text_start, end, style, ctx);
}
}
// What formatting is enabled?
int bold, italic, symbol;
int soft, kwpph, param, line, soft_line;
int code, code_kw, code_string, param_ref, error;
int param_id;
vector<AColor> colors;
vector<double> sizes;
/// put angle brackets around the text?
bool bracket;
TextElementsFromString()
: bold(0), italic(0), symbol(0), soft(0), kwpph(0), param(0), line(0), soft_line(0)
, code(0), code_kw(0), code_string(0), param_ref(0), error(0)
, param_id(0), bracket(false) {}
// read TextElements from a string
void fromString(TextElements& te, const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx) {
te.elements.clear();
end = min(end, text.size());
size_t text_start = start;
// for each character...
for (size_t pos = start ; pos < end ; ) {
Char c = text.GetChar(pos);
if (c == _('<')) {
if (text_start < pos) {
// text element before this tag?
addText(te, text, text_start, pos, style, ctx);
}
// a (formatting) tag
size_t tag_start = pos;
pos = skip_tag(text, tag_start);
if (is_substr(text, tag_start, _( "<b"))) bold += 1;
else if (is_substr(text, tag_start, _("</b"))) bold -= 1;
else if (is_substr(text, tag_start, _( "<i"))) italic += 1;
else if (is_substr(text, tag_start, _("</i"))) italic -= 1;
else if (is_substr(text, tag_start, _( "<sym"))) symbol += 1;
else if (is_substr(text, tag_start, _("</sym"))) symbol -= 1;
else if (is_substr(text, tag_start, _( "<line"))) line += 1;
else if (is_substr(text, tag_start, _("</line"))) line -= 1;
else if (is_substr(text, tag_start, _( "<soft-line"))) soft_line += 1;
else if (is_substr(text, tag_start, _("</soft-line"))) soft_line -= 1;
else if (is_substr(text, tag_start, _( "<sep-soft"))) soft += 1;
else if (is_substr(text, tag_start, _("</sep-soft"))) soft -= 1;
else if (is_substr(text, tag_start, _( "<soft"))) soft += 1; // must be after <soft-line
else if (is_substr(text, tag_start, _("</soft"))) soft -= 1;
else if (is_substr(text, tag_start, _( "<atom-kwpph"))) kwpph += 1;
else if (is_substr(text, tag_start, _("</atom-kwpph"))) kwpph -= 1;
else if (is_substr(text, tag_start, _( "<code-kw"))) code_kw += 1;
else if (is_substr(text, tag_start, _("</code-kw"))) code_kw -= 1;
else if (is_substr(text, tag_start, _( "<code-str"))) code_string += 1;
else if (is_substr(text, tag_start, _("</code-str"))) code_string -= 1;
else if (is_substr(text, tag_start, _( "<code"))) code += 1;
else if (is_substr(text, tag_start, _("</code"))) code -= 1;
else if (is_substr(text, tag_start, _( "<color"))) {
size_t colon = text.find_first_of(_(">:"), tag_start);
if (colon < pos - 1 && text.GetChar(colon) == _(':')) {
AColor c = parse_acolor(text.substr(colon+1, pos-colon-2));
if (!c.Ok()) c = style.font.color;
colors.push_back(c);
}
} else if (is_substr(text, tag_start, _("</color"))) {
if (!colors.empty()) colors.pop_back();
}
else if (is_substr(text, tag_start, _( "<size"))) {
size_t colon = text.find_first_of(_(">:"), tag_start);
if (colon < pos - 1 && text.GetChar(colon) == _(':')) {
double size = style.font.size;
String v = text.substr(colon+1, pos-colon-2);
v.ToDouble(&size);
sizes.push_back(size);
}
} else if (is_substr(text, tag_start, _("</size"))) {
if (!sizes.empty()) sizes.pop_back();
}
else if (is_substr(text, tag_start, _( "<ref-param"))) {
// determine the param being referenced
// from a tag <ref-param123>
if (pos != String::npos) {
String ref = text.substr(tag_start + 10, pos - tag_start - 11);
long ref_n;
if (ref.ToLong(&ref_n)) {
param_id = (ref_n - 1)%param_colors_count + param_colors_count;
}
}
param_ref += 1;
}
else if (is_substr(text, tag_start, _("</ref-param"))) param_ref -= 1;
else if (is_substr(text, tag_start, _( "<atom-param"))) param += 1;
else if (is_substr(text, tag_start, _("</atom-param"))) param -= 1;
else if (is_substr(text, tag_start, _("<atom"))) {
// 'atomic' indicator
size_t end_tag = min(end, match_close_tag(text, tag_start));
intrusive_ptr<AtomTextElement> e(new AtomTextElement(pos, end_tag));
fromString(e->elements, text, pos, end_tag, style, ctx);
te.elements.push_back(e);
pos = skip_tag(text, end_tag);
} else if (is_substr(text, tag_start, _( "<error"))) {
// error indicator
size_t end_tag = min(end, match_close_tag(text, tag_start));
intrusive_ptr<ErrorTextElement> e(new ErrorTextElement(pos, end_tag));
fromString(e->elements, text, pos, end_tag, style, ctx);
te.elements.push_back(e);
pos = skip_tag(text, end_tag);
} else {
// ignore other tags
}
// text starts again after the tag
text_start = pos;
} else {
// normal text
pos += 1;
}
}
if (text_start < end) {
// remaining text at the end
addText(te, text, text_start, end, style, ctx);
}
}
private:
/// Create a text element for a piece of text, text[start..end)
void addText(TextElements& te, const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx) {
String content = untag(text.substr(start, end - start));
assert(content.size() == end-start);
// use symbol font?
if (symbol > 0 && style.symbol_font.valid()) {
te.elements.push_back(intrusive(new SymbolTextElement(content, start, end, style.symbol_font, &ctx)));
} else {
// text, possibly mixed with symbols
DrawWhat what = soft > 0 ? DRAW_ACTIVE : DRAW_NORMAL;
LineBreak line_break = line > 0 ? BREAK_LINE :
soft_line > 0 ? BREAK_SOFT : BREAK_HARD;
if (kwpph > 0 || param > 0) {
// bracket the text
content = String(LEFT_ANGLE_BRACKET) + content + RIGHT_ANGLE_BRACKET;
start -= 1;
end += 1;
}
if (style.always_symbol && style.symbol_font.valid()) {
// mixed symbols/text, autodetected by symbol font
size_t text_pos = 0;
size_t pos = 0;
FontP font;
while (pos < end-start) {
if (size_t n = style.symbol_font.font->recognizePrefix(content,pos)) {
// at 'pos' there are n symbol font characters
if (text_pos < pos) {
// text before it?
if (!font) font = makeFont(style);
te.elements.push_back(intrusive(new FontTextElement(content.substr(text_pos, pos-text_pos), start+text_pos, start+pos, font, what, line_break)));
}
te.elements.push_back(intrusive(new SymbolTextElement(content.substr(pos,n), start+pos, start+pos+n, style.symbol_font, &ctx)));
text_pos = pos += n;
} else {
++pos;
}
}
if (text_pos < pos) {
if (!font) font = makeFont(style);
te.elements.push_back(intrusive(new FontTextElement(content.substr(text_pos), start+text_pos, end, font, what, line_break)));
}
} else {
te.elements.push_back(intrusive(new FontTextElement(content, start, end, makeFont(style), what, line_break)));
}
}
}
FontP makeFont(const TextStyle& style) {
return style.font.make(
(bold > 0 ? FONT_BOLD : FONT_NORMAL) |
(italic > 0 ? FONT_ITALIC : FONT_NORMAL) |
(soft > 0 ? FONT_SOFT : FONT_NORMAL) |
(kwpph > 0 ? FONT_SOFT : FONT_NORMAL) |
(code > 0 ? FONT_CODE : FONT_NORMAL) |
(code_kw > 0 ? FONT_CODE_KW : FONT_NORMAL) |
(code_string > 0 ? FONT_CODE_STRING : FONT_NORMAL),
param > 0 || param_ref > 0
? &param_colors[(param_id++) % param_colors_count]
: !colors.empty()
? &colors.back()
: nullptr,
!sizes.empty() ? &sizes.back() : nullptr
);
}
/// Create a text element for a piece of text, text[start..end)
void addText(TextElements& te, const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx) {
String content = untag(text.substr(start, end - start));
assert(content.size() == end-start);
// use symbol font?
if (symbol > 0 && style.symbol_font.valid()) {
te.elements.push_back(intrusive(new SymbolTextElement(content, start, end, style.symbol_font, &ctx)));
} else {
// text, possibly mixed with symbols
DrawWhat what = soft > 0 ? DRAW_ACTIVE : DRAW_NORMAL;
LineBreak line_break = line > 0 ? BREAK_LINE :
soft_line > 0 ? BREAK_SOFT : BREAK_HARD;
if (kwpph > 0 || param > 0) {
// bracket the text
content = String(LEFT_ANGLE_BRACKET) + content + RIGHT_ANGLE_BRACKET;
start -= 1;
end += 1;
}
if (style.always_symbol && style.symbol_font.valid()) {
// mixed symbols/text, autodetected by symbol font
size_t text_pos = 0;
size_t pos = 0;
FontP font;
while (pos < end-start) {
if (size_t n = style.symbol_font.font->recognizePrefix(content,pos)) {
// at 'pos' there are n symbol font characters
if (text_pos < pos) {
// text before it?
if (!font) font = makeFont(style);
te.elements.push_back(intrusive(new FontTextElement(content.substr(text_pos, pos-text_pos), start+text_pos, start+pos, font, what, line_break)));
}
te.elements.push_back(intrusive(new SymbolTextElement(content.substr(pos,n), start+pos, start+pos+n, style.symbol_font, &ctx)));
text_pos = pos += n;
} else {
++pos;
}
}
if (text_pos < pos) {
if (!font) font = makeFont(style);
te.elements.push_back(intrusive(new FontTextElement(content.substr(text_pos), start+text_pos, end, font, what, line_break)));
}
} else {
te.elements.push_back(intrusive(new FontTextElement(content, start, end, makeFont(style), what, line_break)));
}
}
}
FontP makeFont(const TextStyle& style) {
return style.font.make(
(bold > 0 ? FONT_BOLD : FONT_NORMAL) |
(italic > 0 ? FONT_ITALIC : FONT_NORMAL) |
(soft > 0 ? FONT_SOFT : FONT_NORMAL) |
(kwpph > 0 ? FONT_SOFT : FONT_NORMAL) |
(code > 0 ? FONT_CODE : FONT_NORMAL) |
(code_kw > 0 ? FONT_CODE_KW : FONT_NORMAL) |
(code_string > 0 ? FONT_CODE_STRING : FONT_NORMAL),
param > 0 || param_ref > 0
? &param_colors[(param_id++) % param_colors_count]
: !colors.empty()
? &colors.back()
: nullptr,
!sizes.empty() ? &sizes.back() : nullptr
);
}
};
void TextElements::fromString(const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx) {
TextElementsFromString f;
f.fromString(*this, text, start, end, style, ctx);
TextElementsFromString f;
f.fromString(*this, text, start, end, style, ctx);
}
/*
// ----------------------------------------------------------------------------- : CompoundTextElement
void CompoundTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const {
elements.draw(dc, scale, rect, what, start, end);
elements.draw(dc, scale, rect, what, start, end);
}
RealSize CompoundTextElement::charSize(RotatedDC& dc, double scale, size_t index) const {
return elements.charSize(rot, scale, index);
return elements.charSize(rot, scale, index);
}
*/
+93 -93
View File
@@ -25,47 +25,47 @@ class SymbolFontRef;
/// Information on a linebreak
enum LineBreak
{ BREAK_NO // no line break ever
, BREAK_MAYBE // break here when in "direction:vertical" mode
, BREAK_SPACE // optional line break (' ')
, BREAK_SOFT // always a line break, spacing as a soft break
, BREAK_HARD // always a line break ('\n')
, BREAK_LINE // line break with a separator line (<line>)
{ BREAK_NO // no line break ever
, BREAK_MAYBE // break here when in "direction:vertical" mode
, BREAK_SPACE // optional line break (' ')
, BREAK_SOFT // always a line break, spacing as a soft break
, BREAK_HARD // always a line break ('\n')
, BREAK_LINE // line break with a separator line (<line>)
};
/// Information on a character in a TextElement
struct CharInfo {
RealSize size; ///< Size of this character
LineBreak break_after : 31; ///< How/when to break after it?
bool soft : 1; ///< Is this a 'soft' character? soft characters are ignored for alignment
explicit CharInfo()
: break_after(BREAK_NO), soft(true)
{}
inline CharInfo(RealSize size, LineBreak break_after, bool soft = false)
: size(size), break_after(break_after), soft(soft)
{}
RealSize size; ///< Size of this character
LineBreak break_after : 31; ///< How/when to break after it?
bool soft : 1; ///< Is this a 'soft' character? soft characters are ignored for alignment
explicit CharInfo()
: break_after(BREAK_NO), soft(true)
{}
inline CharInfo(RealSize size, LineBreak break_after, bool soft = false)
: size(size), break_after(break_after), soft(soft)
{}
};
/// A section of text that can be rendered using a TextViewer
class TextElement : public IntrusivePtrBase<TextElement> {
public:
/// What section of the input string is this element?
size_t start, end;
inline TextElement(size_t start ,size_t end) : start(start), end(end) {}
virtual ~TextElement() {}
/// Draw a subsection section of the text in the given rectangle
/** xs give the x coordinates for each character
* this->start <= start < end <= this->end <= text.size() */
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const = 0;
/// Get information on all characters in the range [start...end) and store them in out
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const = 0;
/// Return the minimum scale factor allowed (starts at 1)
virtual double minScale() const = 0;
/// Return the steps the scale factor should take
virtual double scaleStep() const = 0;
/// What section of the input string is this element?
size_t start, end;
inline TextElement(size_t start ,size_t end) : start(start), end(end) {}
virtual ~TextElement() {}
/// Draw a subsection section of the text in the given rectangle
/** xs give the x coordinates for each character
* this->start <= start < end <= this->end <= text.size() */
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const = 0;
/// Get information on all characters in the range [start...end) and store them in out
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const = 0;
/// Return the minimum scale factor allowed (starts at 1)
virtual double minScale() const = 0;
/// Return the steps the scale factor should take
virtual double scaleStep() const = 0;
};
// ----------------------------------------------------------------------------- : TextElements
@@ -73,26 +73,26 @@ class TextElement : public IntrusivePtrBase<TextElement> {
/// A list of text elements
class TextElements {
public:
/// Draw all the elements (as need to show the range start..end)
void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
// Get information on all characters in the range [start...end) and store them in out
void getCharInfo(RotatedDC& dc, double scale, size_t start, size_t end, vector<CharInfo>& out) const;
/// Return the minimum scale factor allowed by all elements
double minScale() const;
/// Return the steps the scale factor should take
double scaleStep() const;
/// The actual elements
/** They must be in order of positions and not overlap, i.e.
* i < j ==> elements[i].end <= elements[j].start
*/
vector<TextElementP> elements;
/// Find the element that contains the given index, if there is any
vector<TextElementP>::const_iterator findByIndex(size_t index) const;
/// Read the elements from a string
void fromString(const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx);
/// Draw all the elements (as need to show the range start..end)
void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
// Get information on all characters in the range [start...end) and store them in out
void getCharInfo(RotatedDC& dc, double scale, size_t start, size_t end, vector<CharInfo>& out) const;
/// Return the minimum scale factor allowed by all elements
double minScale() const;
/// Return the steps the scale factor should take
double scaleStep() const;
/// The actual elements
/** They must be in order of positions and not overlap, i.e.
* i < j ==> elements[i].end <= elements[j].start
*/
vector<TextElementP> elements;
/// Find the element that contains the given index, if there is any
vector<TextElementP>::const_iterator findByIndex(size_t index) const;
/// Read the elements from a string
void fromString(const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx);
};
// ----------------------------------------------------------------------------- : SimpleTextElement
@@ -100,45 +100,45 @@ class TextElements {
/// A text element that just shows text
class SimpleTextElement : public TextElement {
public:
SimpleTextElement(const String& content, size_t start, size_t end)
: TextElement(start, end), content(content)
{}
String content; ///< Text to show
SimpleTextElement(const String& content, size_t start, size_t end)
: TextElement(start, end), content(content)
{}
String content; ///< Text to show
};
/// A text element that uses a normal font
class FontTextElement : public SimpleTextElement {
public:
FontTextElement(const String& content, size_t start, size_t end, const FontP& font, DrawWhat draw_as, LineBreak break_style)
: SimpleTextElement(content, start, end)
, font(font), draw_as(draw_as), break_style(break_style)
{}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
virtual double minScale() const;
virtual double scaleStep() const;
FontTextElement(const String& content, size_t start, size_t end, const FontP& font, DrawWhat draw_as, LineBreak break_style)
: SimpleTextElement(content, start, end)
, font(font), draw_as(draw_as), break_style(break_style)
{}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
virtual double minScale() const;
virtual double scaleStep() const;
private:
FontP font;
DrawWhat draw_as;
LineBreak break_style;
FontP font;
DrawWhat draw_as;
LineBreak break_style;
};
/// A text element that uses a symbol font
class SymbolTextElement : public SimpleTextElement {
public:
SymbolTextElement(const String& content, size_t start, size_t end, const SymbolFontRef& font, Context* ctx)
: SimpleTextElement(content, start, end)
, font(font), ctx(*ctx)
{}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
virtual double minScale() const;
virtual double scaleStep() const;
SymbolTextElement(const String& content, size_t start, size_t end, const SymbolFontRef& font, Context* ctx)
: SimpleTextElement(content, start, end)
, font(font), ctx(*ctx)
{}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
virtual double minScale() const;
virtual double scaleStep() const;
private:
const SymbolFontRef& font; // owned by TextStyle
Context& ctx;
const SymbolFontRef& font; // owned by TextStyle
Context& ctx;
};
// ----------------------------------------------------------------------------- : CompoundTextElement
@@ -146,30 +146,30 @@ class SymbolTextElement : public SimpleTextElement {
/// A TextElement consisting of sub elements
class CompoundTextElement : public TextElement {
public:
CompoundTextElement(size_t start, size_t end) : TextElement(start, end) {}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
virtual double minScale() const;
virtual double scaleStep() const;
TextElements elements; ///< the elements
CompoundTextElement(size_t start, size_t end) : TextElement(start, end) {}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
virtual double minScale() const;
virtual double scaleStep() const;
TextElements elements; ///< the elements
};
/// A TextElement drawn using a grey background
class AtomTextElement : public CompoundTextElement {
public:
AtomTextElement(size_t start, size_t end) : CompoundTextElement(start, end) {}
virtual void draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
AtomTextElement(size_t start, size_t end) : CompoundTextElement(start, end) {}
virtual void draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
};
/// A TextElement drawn using a red wavy underline
class ErrorTextElement : public CompoundTextElement {
public:
ErrorTextElement(size_t start, size_t end) : CompoundTextElement(start, end) {}
virtual void draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
ErrorTextElement(size_t start, size_t end) : CompoundTextElement(start, end) {}
virtual void draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
};
// ----------------------------------------------------------------------------- : EOF
+32 -32
View File
@@ -13,44 +13,44 @@
// ----------------------------------------------------------------------------- : FontTextElement
void FontTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const {
if ((what & draw_as) != draw_as) return; // don't draw
// text
String text = content.substr(start - this->start, end - start);
if (!text.empty() && text.GetChar(text.size() - 1) == _('\n')) {
text = text.substr(0, text.size() - 1); // don't draw last \n
}
// draw
dc.SetFont(*font, scale);
dc.DrawTextWithShadow(text, *font, rect.position());
if ((what & draw_as) != draw_as) return; // don't draw
// text
String text = content.substr(start - this->start, end - start);
if (!text.empty() && text.GetChar(text.size() - 1) == _('\n')) {
text = text.substr(0, text.size() - 1); // don't draw last \n
}
// draw
dc.SetFont(*font, scale);
dc.DrawTextWithShadow(text, *font, rect.position());
}
void FontTextElement::getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const {
// font
dc.SetFont(*font, scale);
// find sizes & breaks
double prev_width = 0;
size_t line_start = start; // start of the current line
for (size_t i = start ; i < end ; ++i) {
Char c = content.GetChar(i - this->start);
if (c == _('\n')) {
out.push_back(CharInfo(RealSize(0, dc.GetCharHeight()), break_style, draw_as == DRAW_ACTIVE));
line_start = i + 1;
prev_width = 0;
} else {
RealSize s = dc.GetTextExtent(content.substr(line_start - this->start, i - line_start + 1));
out.push_back(CharInfo(
RealSize(s.width - prev_width, s.height),
c == _(' ') ? BREAK_SPACE : BREAK_MAYBE,
draw_as == DRAW_ACTIVE // from <soft> tag
));
prev_width = s.width;
}
}
// font
dc.SetFont(*font, scale);
// find sizes & breaks
double prev_width = 0;
size_t line_start = start; // start of the current line
for (size_t i = start ; i < end ; ++i) {
Char c = content.GetChar(i - this->start);
if (c == _('\n')) {
out.push_back(CharInfo(RealSize(0, dc.GetCharHeight()), break_style, draw_as == DRAW_ACTIVE));
line_start = i + 1;
prev_width = 0;
} else {
RealSize s = dc.GetTextExtent(content.substr(line_start - this->start, i - line_start + 1));
out.push_back(CharInfo(
RealSize(s.width - prev_width, s.height),
c == _(' ') ? BREAK_SPACE : BREAK_MAYBE,
draw_as == DRAW_ACTIVE // from <soft> tag
));
prev_width = s.width;
}
}
}
double FontTextElement::minScale() const {
return min(font->size(), font->scale_down_to) / max(0.01, font->size());
return min(font->size(), font->scale_down_to) / max(0.01, font->size());
}
double FontTextElement::scaleStep() const {
return 1. / max(font->size() * 4, 1.);
return 1. / max(font->size() * 4, 1.);
}
+9 -9
View File
@@ -13,21 +13,21 @@
// ----------------------------------------------------------------------------- : SymbolTextElement
void SymbolTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const {
if (!(what & DRAW_NORMAL)) return;
if (font.font) {
font.font->draw(dc, ctx, rect, font.size * scale, font.alignment, content.substr(start - this->start, end-start));
}
if (!(what & DRAW_NORMAL)) return;
if (font.font) {
font.font->draw(dc, ctx, rect, font.size * scale, font.alignment, content.substr(start - this->start, end-start));
}
}
void SymbolTextElement::getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const {
if (font.font) {
font.font->getCharInfo(dc, ctx, font.size * scale, content.substr(start - this->start, end-start), out);
}
if (font.font) {
font.font->getCharInfo(dc, ctx, font.size * scale, content.substr(start - this->start, end-start), out);
}
}
double SymbolTextElement::minScale() const {
return min(font.size(), font.scale_down_to) / max(0.01, font.size());
return min(font.size(), font.scale_down_to) / max(0.01, font.size());
}
double SymbolTextElement::scaleStep() const {
return 1. / max(font.size * 4, 1.);
return 1. / max(font.size * 4, 1.);
}
+664 -664
View File
File diff suppressed because it is too large Load Diff
+116 -116
View File
@@ -35,124 +35,124 @@
*/
class TextViewer {
public:
/// Information on a line in the textbox
struct Line;
TextViewer();
~TextViewer();
// --------------------------------------------------- : Drawing
/// Draw the given text with the given text style
/** The drawing information is cached,
* before calling draw again with different text/style reset() should be called
*/
void draw(RotatedDC& dc, const TextStyle& style, DrawWhat what);
/// Draw an indicator for selected text
void drawSelection(RotatedDC& dc, const TextStyle& style, size_t sel_start, size_t sel_end);
/// Draw separators for <line> tags
void drawSeparators(RotatedDC& dc);
/// Prepare the text for drawing, if it is not already prepared
/** Returns true if something has been done */
bool prepare(RotatedDC& dc, const String& text, TextStyle& style, Context&);
/// Reset the cached data, at a new call to draw it will be recalculated
/** If related, the new value is related to the old one, and layout information should be reused where possible
*/
void reset(bool related);
/// Is the viewer prepare()d?
bool prepared() const;
// --------------------------------------------------- : Positions
/// Find the character index that is on a line above/below index
/** If this would move outisde the text, returns the input index */
size_t moveLine(size_t index, int delta) const;
/// The character index of the start of the line that character #index is on
size_t lineStart(size_t index) const;
/// The character index past the end of the line that character #index is on
size_t lineEnd (size_t index) const;
/// Find the index of the character at the given position
/** If the position is before everything returns 0,
* if it is after everything returns text.size().
* The position is in internal coordinates */
size_t indexAt(const RealPoint& pos) const;
/// Find the position of the character at the given index
/** The position is in internal coordinates */
RealPoint posOf(size_t index) const;
/// Return the rectangle around a single character
/** If 'first' prefers earlier lines */
RealRect charRect(size_t index, bool first) const;
/// Is the character at the given index visible?
bool isVisible(size_t index) const;
/// Find the first character index that is at/before/after the given index, and which has a nonzero width
/** More precisely: it returns a position so that the character after it in the direction delta has nonzero width
*/
size_t firstVisibleChar(size_t index, int delta) const;
/// Return the height of the last line
double heightOfLastLine() const;
// --------------------------------------------------- : Lines/scrolling
/// The total number of lines
size_t lineCount() const;
/// number of fully visible lines, height gives the height of the box
size_t visibleLineCount(double height) const;
/// the index of the first visible line
size_t firstVisibleLine() const;
// scroll so line_id becomes the first visible line
void scrollTo(size_t line_id);
/// Ensure the specified character is fully visible
/* Always scrolls by a whole line.
* Returns true if the editor has scrolled.
*/
bool ensureVisible(double height, size_t char_id);
/// Get exact scroll position
double getExactScrollPosition() const;
/// Set exact scroll position
void setExactScrollPosition(double pos);
/// Information on a line in the textbox
struct Line;
TextViewer();
~TextViewer();
// --------------------------------------------------- : Drawing
/// Draw the given text with the given text style
/** The drawing information is cached,
* before calling draw again with different text/style reset() should be called
*/
void draw(RotatedDC& dc, const TextStyle& style, DrawWhat what);
/// Draw an indicator for selected text
void drawSelection(RotatedDC& dc, const TextStyle& style, size_t sel_start, size_t sel_end);
/// Draw separators for <line> tags
void drawSeparators(RotatedDC& dc);
/// Prepare the text for drawing, if it is not already prepared
/** Returns true if something has been done */
bool prepare(RotatedDC& dc, const String& text, TextStyle& style, Context&);
/// Reset the cached data, at a new call to draw it will be recalculated
/** If related, the new value is related to the old one, and layout information should be reused where possible
*/
void reset(bool related);
/// Is the viewer prepare()d?
bool prepared() const;
// --------------------------------------------------- : Positions
/// Find the character index that is on a line above/below index
/** If this would move outisde the text, returns the input index */
size_t moveLine(size_t index, int delta) const;
/// The character index of the start of the line that character #index is on
size_t lineStart(size_t index) const;
/// The character index past the end of the line that character #index is on
size_t lineEnd (size_t index) const;
/// Find the index of the character at the given position
/** If the position is before everything returns 0,
* if it is after everything returns text.size().
* The position is in internal coordinates */
size_t indexAt(const RealPoint& pos) const;
/// Find the position of the character at the given index
/** The position is in internal coordinates */
RealPoint posOf(size_t index) const;
/// Return the rectangle around a single character
/** If 'first' prefers earlier lines */
RealRect charRect(size_t index, bool first) const;
/// Is the character at the given index visible?
bool isVisible(size_t index) const;
/// Find the first character index that is at/before/after the given index, and which has a nonzero width
/** More precisely: it returns a position so that the character after it in the direction delta has nonzero width
*/
size_t firstVisibleChar(size_t index, int delta) const;
/// Return the height of the last line
double heightOfLastLine() const;
// --------------------------------------------------- : Lines/scrolling
/// The total number of lines
size_t lineCount() const;
/// number of fully visible lines, height gives the height of the box
size_t visibleLineCount(double height) const;
/// the index of the first visible line
size_t firstVisibleLine() const;
// scroll so line_id becomes the first visible line
void scrollTo(size_t line_id);
/// Ensure the specified character is fully visible
/* Always scrolls by a whole line.
* Returns true if the editor has scrolled.
*/
bool ensureVisible(double height, size_t char_id);
/// Get exact scroll position
double getExactScrollPosition() const;
/// Set exact scroll position
void setExactScrollPosition(double pos);
private:
/// Scroll all lines a given amount
void scrollBy(double delta);
/// Scroll all lines a given amount
void scrollBy(double delta);
private:
// --------------------------------------------------- : More drawing
double scale; ///< Scale when drawing
// --------------------------------------------------- : Elements
TextElements elements; ///< The elements of the prepared text
/// Find the elements in a string and add them to elements
void prepareElements(const String&, const TextStyle& style, Context& ctx);
// --------------------------------------------------- : Lines
vector<Line> lines; ///< The lines in the text box
/// Prepare the lines, layout the text
void prepareLines(RotatedDC& dc, const String& text, TextStyle& style, Context& ctx);
/// Find the scale to use for the text
void prepareLinesTryScales(RotatedDC& dc, const String& text, const TextStyle& style, vector<CharInfo>& chars_out);
/// Prepare the lines, layout the text; at a specific scale
/** Stores output in lines_out */
bool prepareLinesScale(RotatedDC& dc, const vector<CharInfo>& chars, const TextStyle& style, bool stop_if_too_long, vector<Line>& lines_out) const;
/// Align the lines within the textbox
void alignLines(RotatedDC& dc, const vector<CharInfo>& chars, const TextStyle& style);
/// Align the lines of a single paragraph (a set of lines)
void alignParagraph(size_t start_line, size_t end_line, const vector<CharInfo>& chars, const TextStyle& style, const RealRect& box);
/// Find the line the given index is on, returns the first line if the index is not found
const Line& findLine(size_t index) const;
// helper : get the start coordinate of a line, this is 0 unless there is a contour mask
double lineLeft (RotatedDC& dc, const TextStyle& style, double y) const;
// helper : get the end coordinate of a line, this is width unless there is a contour mask
double lineRight(RotatedDC& dc, const TextStyle& style, double y) const;
// --------------------------------------------------- : More drawing
double scale; ///< Scale when drawing
// --------------------------------------------------- : Elements
TextElements elements; ///< The elements of the prepared text
/// Find the elements in a string and add them to elements
void prepareElements(const String&, const TextStyle& style, Context& ctx);
// --------------------------------------------------- : Lines
vector<Line> lines; ///< The lines in the text box
/// Prepare the lines, layout the text
void prepareLines(RotatedDC& dc, const String& text, TextStyle& style, Context& ctx);
/// Find the scale to use for the text
void prepareLinesTryScales(RotatedDC& dc, const String& text, const TextStyle& style, vector<CharInfo>& chars_out);
/// Prepare the lines, layout the text; at a specific scale
/** Stores output in lines_out */
bool prepareLinesScale(RotatedDC& dc, const vector<CharInfo>& chars, const TextStyle& style, bool stop_if_too_long, vector<Line>& lines_out) const;
/// Align the lines within the textbox
void alignLines(RotatedDC& dc, const vector<CharInfo>& chars, const TextStyle& style);
/// Align the lines of a single paragraph (a set of lines)
void alignParagraph(size_t start_line, size_t end_line, const vector<CharInfo>& chars, const TextStyle& style, const RealRect& box);
/// Find the line the given index is on, returns the first line if the index is not found
const Line& findLine(size_t index) const;
// helper : get the start coordinate of a line, this is 0 unless there is a contour mask
double lineLeft (RotatedDC& dc, const TextStyle& style, double y) const;
// helper : get the end coordinate of a line, this is width unless there is a contour mask
double lineRight(RotatedDC& dc, const TextStyle& style, double y) const;
};