Basic text rendering working;

Added Font (done) and SymbolFont (skeleton);
Added styling to set;
Added CountourMap;
Some script fixes

git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@73 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
twanvl
2006-11-17 17:57:04 +00:00
parent ea5be88bdb
commit ce6a83e34b
45 changed files with 1595 additions and 84 deletions
+5 -2
View File
@@ -33,6 +33,8 @@ void DataViewer::draw(RotatedDC& dc) {
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(set->stylesheet->card_background);
dc.DrawRectangle(dc.getInternalRect());
// update style scripts
if (card) set->updateFor(card);
// draw values
FOR_EACH(v, viewers) { // draw low z index fields first
if (v->getStyle()->visible) {// visible
@@ -52,10 +54,11 @@ Context& DataViewer::getContext() const { return set->getContext(); }
// ----------------------------------------------------------------------------- : Setting data
void DataViewer::setCard(Card& card) {
void DataViewer::setCard(const CardP& card) {
assert(set);
this->card = card;
setStyles(set->stylesheet->card_style);
setData(card.data);
setData(card->data);
}
// ----------------------------------------------------------------------------- : Viewers
+3 -2
View File
@@ -54,7 +54,7 @@ class DataViewer : public SetView {
// --------------------------------------------------- : Setting data
/// Display a card in this viewer
void setCard(Card& card);
void setCard(const CardP& card);
// --------------------------------------------------- : The viewers
protected:
@@ -74,7 +74,8 @@ class DataViewer : public SetView {
virtual void onChange() {}
private:
vector<ValueViewerP> viewers; ///< The viewers for the different values in the data
vector<ValueViewerP> viewers; ///< The viewers for the different values in the data
CardP card; ///< The card that is currently displayed, if any
};
// ----------------------------------------------------------------------------- : EOF
+143
View File
@@ -0,0 +1,143 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <render/text/element.hpp>
#include <util/tagged_string.hpp>
#include <data/field/text.hpp>
DECLARE_TYPEOF_COLLECTION(TextElementP);
// ----------------------------------------------------------------------------- : TextElements
void TextElements::draw(RotatedDC& dc, double scale, const RealRect& rect, 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, rect, 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
for (size_t i = start ; i < e->start ; ++i) {
out.push_back(CharInfo(RealSize(0,0), BREAK_NO));
}
e->getCharInfo(dc, scale, out);
start = min(end, e->end);
}
for (size_t i = start ; i < end ; ++i) {
out.push_back(CharInfo(RealSize(0,0), BREAK_NO));
}
}
/*//@@
RealSize TextElements::charSize(const Rotation& rot, double scale, size_t index) const {
vector<TextElementP>::const_iterator e = findByIndex(index);
if (e != elements.end()) {
return (*e)->charSize(rot, scale, index);
} else {
return RealSize(0,0);
}
}
bool ends_before_index(const TextElementP& e, size_t index) {
return index < e->end;
}
vector<TextElementP>::const_iterator TextElements::findByIndex(size_t index) const {
// Note: slightly abusing lower_bound, since typeof(index) != elements.element_type
vector<TextElementP>::const_iterator it = lower_bound(elements.begin(), elements.end(), index, ends_before_index);
if ((*it)->start <= index && (*it)->end > index) return it;
else return elements.end();
}*/
// 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;
TextElementsFromString()
: bold(0), italic(0), symbol(0), soft(0), kwpph(0) {}
// 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();
// for each character...
for (size_t pos = start ; pos < end ; ) {
Char c = text.GetChar(pos);
if (c == _('<')) {
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, _( "<sep-soft"))) soft += 1;
else if (is_substr(text, tag_start, _("</sep-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, _("<line"))) {
// horizontal line
te.elements.push_back(new_shared3<HorizontalLineTextElement>(text, tag_start, pos));
/* } else if (is_substr(text, start, _("<error"))) {
// underline with wavy 'error' indicator
size_t end = match_close_tag(text, tag_start);
shared_ptr<ErrorTextElement> e(new ErrorTextElement(text, pos, end));
fromString(e->elements, text, pos, end, style, ctx);
pos = skip_tag(text, end);
} else if (is_substr(text, start, _("<atom"))) {
// 'atomic' indicator
size_t end = match_close_tag(text, tag_start);
shared_ptr<AtomTextElement> e(new AtomTextElement(text, pos, end));
fromString(e->elements, text, pos, end, style, ctx);
pos = skip_tag(text, end);
*/ } else {
// ignore other tags
}
} else {
// A character of normal text, add to the last text element (if possible)
SimpleTextElement* e = nullptr;
if (!te.elements.empty()) e = dynamic_cast<SimpleTextElement*>(te.elements.back().get());
if (e && e->end == pos) {
e->end = pos + 1; // just move the end, no need to make a new element
} else {
// add a new element for this text
if (symbol > 0) {
te.elements.push_back(new_shared3<SymbolTextElement>(text, pos, pos + 1));
} else {
te.elements.push_back(new_shared4<FontTextElement> (text, pos, pos + 1, style.font.make(bold > 0, italic > 0)));
}
}
pos += 1;
}
}
}
};
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);
}
/*
// ----------------------------------------------------------------------------- : 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);
}
RealSize CompoundTextElement::charSize(RotatedDC& dc, double scale, size_t index) const {
return elements.charSize(rot, scale, index);
}
*/
+186
View File
@@ -0,0 +1,186 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_RENDER_TEXT_ELEMENT
#define HEADER_RENDER_TEXT_ELEMENT
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <util/rotation.hpp>
#include <util/real_point.hpp>
DECLARE_POINTER_TYPE(TextElement);
DECLARE_POINTER_TYPE(Font);
class TextStyle;
class Context;
// ----------------------------------------------------------------------------- : TextElement
/// What should be drawn?
enum DrawWhat
{ DRAW_NOTHING = 0x00
, DRAW_NORMAL = 0x01 // draw normal things, like the text
, DRAW_EDITOR = 0x02 // draw editor stuff, such as borders/lines
, DRAW_ACTIVE = 0x04 // draw active editor stuff, such as hidden separators and atom highlights
};
/// Information on a linebreak
enum LineBreak
{ BREAK_NO // no line break
, BREAK_SOFT // optional line 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;
LineBreak break_after;
inline CharInfo(RealSize size, LineBreak break_after = BREAK_NO) : size(size), break_after(break_after) {}
};
/// A section of text that can be rendered using a TextViewer
class TextElement {
public:
/// What section of the input string is this element?
size_t start, end;
/// The text of which a subsection is drawn
String text;
inline TextElement(const String& text, size_t start ,size_t end) : text(text), start(start), end(end) {}
virtual ~TextElement() {}
/// Draw a subsection section of the text in the given rectangle
/** this->start <= start < end <= this->end <= text.size() */
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const = 0;
// /// The size of a single character at position index
// /** index is in the range [start..end) */
// virtual RealSize charSize(const Rotation& rot, double scale, size_t index) 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;
/*
// draw the section <start...end)
// drawSeparators indicates what we should draw, separators or normal text
// h is the height of the current line
virtual void draw(RotatedDC& dc, UInt shrink, RealRect rect, size_t start, size_t end, DrawWhat draw) const = 0;
/// Returns the width and height of the character at charId
virtual RealSize charSize(RotatedDC& dc, double scale, size_t charId) const = 0;
/// May the text be broken after char_id?
virtual BreakAfter breakAfter(size_t char_id) const = 0;
// number of characters in this object
abstract size_t size() const;
// maximum shrink factor allowed
// shrink indicates by how much the thing to render should be shrunk, there is no indication
// what it means (probably pixels or points), but size(shrink = k+1) <= size(shrink = k)
abstract UInt maxShrink() const;
// Size of an entire section
RealSize sectionSize(RotatedDC& dc, double scale, size_t start, size_t end) const;
RealSize for::sectionSize(RotatedDC& dc, double scale, size_t start, size_t end) const {
RealSize size;
for(i = start ; i < end ; ++i) {
size = addHorizontal(size, charSize(dc, scale, i));
}
return size;
}*/
};
// ----------------------------------------------------------------------------- : TextElements
/// A list of text elements
class TextElements : public vector<TextElementP> {
public:
/// Draw all the elements (as need to show the range start..end)
void draw (RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const;
// RealSize charSize(const Rotation& rot, double scale, size_t index) 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;
/// 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
/// A text element that just shows text
class SimpleTextElement : public TextElement {
public:
SimpleTextElement(const String& text, size_t start ,size_t end) : TextElement(text, start, end) {}
};
/// A text element that uses a normal font
class FontTextElement : public SimpleTextElement {
public:
FontTextElement(const String& text, size_t start ,size_t end, const FontP& font)
: SimpleTextElement(text, start, end)
, font(font)
{}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
private:
FontP font;
DrawWhat draw_as;
};
/// A text element that uses a symbol font
class SymbolTextElement : public SimpleTextElement {
public:
SymbolTextElement(const String& text, size_t start ,size_t end) : SimpleTextElement(text, start, end) {}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
};
// ----------------------------------------------------------------------------- : CompoundTextElement
/// A TextElement consisting of sub elements
class CompoundTextElement : public TextElement {
public:
CompoundTextElement(const String& text, size_t start ,size_t end) : TextElement(text, start, end) {}
TextElements elements; ///< the elements
};
// ----------------------------------------------------------------------------- : Other text elements
/// A text element that displays a horizontal separator line
class HorizontalLineTextElement : public TextElement {
public:
HorizontalLineTextElement(const String& text, size_t start ,size_t end) : TextElement(text, start, end) {}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
};
/*
// ----------------------------------------------------------------------------- : CompoundTextElement
/// A TextElement consisting of sub elements
class CompoundTextElement : public TextElement {
public:
CompoundTextElement(const String& text, size_t start ,size_t end) : TextElement(text, start, end) {}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const;
virtual RealSize charSize(RotatedDC& dc, double scale, size_t index) const;
private:
TextElements elements;
};
*/
// ----------------------------------------------------------------------------- : EOF
#endif
+52
View File
@@ -0,0 +1,52 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <render/text/element.hpp>
#include <data/font.hpp>
// ----------------------------------------------------------------------------- : FontTextElement
void FontTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const {
dc.SetFont(font->font, font->size * scale);
if (end != start && text.substr(end-1, 1) == _("\n")) end -= 1; // don't draw the newline character at the end
/* if ((draw & DRAW_NORMAL) != DRAW_NORMAL) {
// don't draw
if (what == DRAW_ACTIVE) {
// we are drawing a separator
dc.SetTextForeground(font->separator_color);
dc.DrawText(text.substr(start, end-start), rect.position);
}
} else {*/
// draw normally
// draw shadow
if (font->hasShadow()) {
dc.SetTextForeground(font->shadow_color);
dc.DrawText(text.substr(start, end - start), rect.position + font->shadow_displacement);
}
// draw
dc.SetTextForeground(font->color);
dc.DrawText(text.substr(start, end - start), rect.position);
// }
}
void FontTextElement::getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const {
// font
dc.SetFont(font->font, font->size * scale);
// find sizes & breaks
double prev_width = 0;
for (size_t i = start ; i < end ; ++i) {
Char c = text.GetChar(i);
RealSize s = dc.GetTextExtent(text.substr(start, i - start));
out.push_back(CharInfo(RealSize(s.width - prev_width, s.height),
c == _('\n') ? BREAK_HARD :
c == _(' ') ? BREAK_SOFT : BREAK_NO
));
prev_width = s.width;
}
}
+19
View File
@@ -0,0 +1,19 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <render/text/element.hpp>
// ----------------------------------------------------------------------------- : HorizontalLineTextElement
void HorizontalLineTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const {
// TODO
}
void HorizontalLineTextElement::getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const {
// TODO
}
+19
View File
@@ -0,0 +1,19 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <render/text/element.hpp>
// ----------------------------------------------------------------------------- : SymbolTextElement
void SymbolTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const {
// TODO
}
void SymbolTextElement::getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const {
// TODO
}
+263
View File
@@ -0,0 +1,263 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <render/text/viewer.hpp>
#include <algorithm>
DECLARE_TYPEOF_COLLECTION(TextViewer::Line);
DECLARE_TYPEOF_COLLECTION(double);
// ----------------------------------------------------------------------------- : Line
struct TextViewer::Line {
size_t start; ///< Index of the first character in this line
vector<double> positions; ///< x position of each character in this line, gives the number of characters + 1, never empty
double top; ///< y position of (the top of) this line
double line_height; ///< The height of this line in pixels
bool separator_after; ///< Is there a saparator after this line?
Line()
: start(0), top(0), line_height(0), separator_after(false)
{}
/// The position (just beyond) the bottom of this line
double bottom() const { return top + line_height; }
/// The width of this line
double width() const { return positions.back() - positions.front(); }
/// Index just beyond the last character on this line
size_t end() const { return start + positions.size() - 1; }
/// Find the index of the character at the given position on this line
/** Always returns a value in the range [start..end()) */
size_t posToIndex(double x) const;
/// Is this line visible using the given rectangle?
bool visible(const Rotation& rot) const {
return top + line_height > 0 && top < rot.getInternalSize().height;
}
/// Draws a selection indicator on this line from start to end
/** start and end need not be in this line */
void drawSelection(RotatedDC& dc, size_t start, size_t end);
};
size_t TextViewer::Line::posToIndex(double x) const {
// largest index with pos <= x
vector<double>::const_iterator it1 = lower_bound(positions.begin(), positions.end(), x);
if (it1 == positions.end()) return end();
// first index with pos > x
vector<double>::const_iterator it2 = it1 + 1;
if (it2 == positions.end()) return it1 - positions.begin();
if (x - *it1 <= *it2 - x) return it1 - positions.begin(); // it1 is closer
else return it2 - positions.begin(); // it2 is closer
}
// ----------------------------------------------------------------------------- : TextViewer
// can't be declared in header because we need to know sizeof(Line)
TextViewer:: TextViewer() {}
TextViewer::~TextViewer() {}
// ----------------------------------------------------------------------------- : Drawing
void TextViewer::draw(RotatedDC& dc, const String& text, const TextStyle& style, Context& ctx, DrawWhat what) {
Rotater r(dc, Rotation(style.angle, style.getRect()));
if (lines.empty()) {
// not prepared yet
prepareElements(text, style, ctx);
prepareLines(dc, text, style);
}
// Draw the text line by line
FOR_EACH(l, lines) {
if (l.visible(dc)) {
RealRect rect(l.positions.front(), l.top, l.width(), l.line_height);
elements.draw(dc, scale, rect, what, l.start, l.end());
}
}
}
void TextViewer::drawSelection(RotatedDC& dc, const TextStyle& style, size_t sel_start, size_t sel_end) {
Rotater r(dc, Rotation(style.angle, style.getRect()));
if (sel_start == sel_end) return;
if (sel_end < sel_start) swap(sel_start, sel_end);
dc.SetBrush(*wxBLACK_BRUSH);
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetLogicalFunction(wxINVERT);
FOR_EACH(l, lines) {
l.drawSelection(dc, sel_start, sel_end);
}
dc.SetLogicalFunction(wxCOPY);
}
void TextViewer::Line::drawSelection(RotatedDC& dc, size_t sel_start, size_t sel_end) {
if (!visible(dc)) return;
if (sel_start < end() && sel_end > start) {
double x1 = positions[sel_start];
double x2 = positions[max(end(), sel_end)];
dc.DrawRectangle(RealRect(x1, top, x2 - x1, line_height));
}
}
void TextViewer::reset() {
elements.clear();
lines.clear();
}
// ----------------------------------------------------------------------------- : Positions
size_t TextViewer::lineStart(size_t index) const {
if (lines.empty()) return 0;
return findLine(index).start;
}
size_t TextViewer::lineEnd(size_t index) const {
if (lines.empty()) return 0;
return findLine(index).end();
}
const TextViewer::Line& TextViewer::findLine(size_t index) const {
FOR_EACH_CONST(l, lines) {
if (l.end() > index) return l;
}
return lines.front();
}
// ----------------------------------------------------------------------------- : Elements
void TextViewer::prepareElements(const String& text, const TextStyle& style, Context& ctx) {
elements.fromString(text, 0, text.size(), style, ctx);
}
// ----------------------------------------------------------------------------- : Layout
void TextViewer::prepareLines(RotatedDC& dc, const String& text, const TextStyle& style) {
scale = 1;
prepareLinesScale(dc, text, style, false);
}
bool TextViewer::prepareLinesScale(RotatedDC& dc, const String& text, const TextStyle& style, bool stop_if_too_long) {
// Try to layout the text at the current scale
// find character sizes
vector<CharInfo> chars;
elements.getCharInfo(dc, scale, 0, text.size(), chars);
// first line
lines.clear();
Line line;
// size of the line so far
RealSize line_size(lineLeft(dc, style, 0), 0);
line.positions.push_back(line_size.width);
// The word we are currently reading
RealSize word_size;
vector<double> positions_word; // positios for this word
size_t word_start = 0;
// For each character ...
for(size_t i = 0 ; i < chars.size() ; ++i) {
CharInfo& c = chars[i];
// Should we break?
bool break_now = false;
bool accept_word = false; // the current word should be added to the line
bool hide_breaker = true; // hide the \n or _(' ') that caused a line break
double line_height_multiplier = 1; // multiplier for line height for next line top
if (c.break_after == BREAK_HARD) {
break_now = true;
accept_word = true;
line_height_multiplier = style.line_height_hard;
} else if (c.break_after == BREAK_LINE) {
line.separator_after = true;
break_now = true;
accept_word = true;
line_height_multiplier = style.line_height_line;
} else if (c.break_after == BREAK_SOFT && style.field().multi_line) {
// Soft break == end of word
accept_word = true;
}
// Add size of the character
word_size = addHorizontal(word_size, c.size);
positions_word.push_back(word_size.width);
// Did the word become too long?
if (style.field().multi_line && !break_now) {
double max_width = lineRight(dc, style, line.top);
if (word_start == line.start && word_size.width > max_width) {
// single word on this line; the word is too long
if (stop_if_too_long) {
return false; // just give up
} else {
// force a word break
break_now = true;
accept_word = true;
hide_breaker = false;
line_height_multiplier = style.line_height_soft;
}
} else if (line_size.width + word_size.width > max_width) {
// line would become too long, break before the current word
break_now = true;
line_height_multiplier = style.line_height_soft;
}
}
// Ending the current word
if (accept_word) {
// move word pos to line
FOR_EACH(p, positions_word) {
line.positions.push_back(line_size.width + p);
}
// add size; next word
line_size = addHorizontal(line_size, word_size);
word_size = RealSize(0, 0);
word_start = i + 1;
positions_word.clear();
}
// Breaking (ending the current line)
if (break_now) {
// remove the _('\n') or _(' ') that caused the break
if (hide_breaker && line.positions.size() > 1) {
line.positions.pop_back();
}
// height of the line
if (line_size.height < 0.01 && !lines.empty()) {
// if a line has 0 height, use the height of the line above it, but at most once
} else {
line.line_height = line_size.height;
}
// push
lines.push_back(line);
// reset line object for next line
line.top += line.line_height * line_height_multiplier;
line.start = word_start;
line.positions.clear();
if (line.separator_after) line.line_height = 0;
line.separator_after = false;
// reset line_size
line_size = RealSize(lineLeft(dc, style, line.top), 0);
line.positions.push_back(line_size.width); // start position
}
}
// the last word
FOR_EACH(p, positions_word) {
line.positions.push_back(line_size.width + p);
}
line_size = addHorizontal(line_size, word_size);
// the last line
if (line_size.height < 0.01 && !lines.empty()) {
// if a line has 0 height, use the height of the line above it, but at most once
} else {
line.line_height = line_size.height;
}
lines.push_back(line);
return true;
}
double TextViewer::lineLeft(RotatedDC& dc, const TextStyle& style, double y) {
return 0;
// return style.mask.rowLeft(y, dc.getInternalSize()) + style.padding_left;
}
double TextViewer::lineRight(RotatedDC& dc, const TextStyle& style, double y) {
return style.width;
// return style.mask.rowRight(y, dc.getInternalSize()) - style.padding_right;
}
ContourMask::ContourMask() {} // MOVEME //@@
ContourMask::~ContourMask() {}
+97
View File
@@ -0,0 +1,97 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_RENDER_TEXT_VIEWER
#define HEADER_RENDER_TEXT_VIEWER
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <util/rotation.hpp>
#include <data/field/text.hpp>
#include <render/text/element.hpp>
// ----------------------------------------------------------------------------- : TextViewer
/// Class for viewing and determining positions in formated text
/** It can:
* - Draw text to a DC
* - Draw selection to a DC
* - Convert between screen coordinates and cursor position
*
* To refer to positions in the text this class uses several concepts:
* - index An index in the input string.
* For cursor positions char_id = 0 means the cursor is BEFORE character 0
* - pos The position of a character in real world x,y coordinates (in pixels)
* The position is the top-left of the character.
* A char_pos is often only the x coordinate.
* A line_pos is often only the y coordinate.
* - Line A line on the screen, this does not neccessarly correspond to explicit linebreaks,
* since textwrapping also leads to a new line.
* - line_id The index of a line, 0 is the first line.
*/
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 String& text, const TextStyle& style, Context&, DrawWhat);
/// Draw an indicator for selected text
void drawSelection(RotatedDC& dc, const TextStyle& style, size_t sel_start, size_t sel_end);
/// Reset the cached data, at a new call to draw it will be recalculated
void reset();
// --------------------------------------------------- : Positions
/// Find the character index that is before the given index, and which has a nonzero width
size_t moveLeft(size_t index) const;
/// 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;
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, const TextStyle& style);
/// Prepare the lines, layout the text; at a specific scale
bool prepareLinesScale(RotatedDC& dc, const String& text, const TextStyle& style, bool stop_if_too_long);
/// 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);
// 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);
};
// ----------------------------------------------------------------------------- : EOF
#endif
+1 -1
View File
@@ -35,7 +35,7 @@ void ColorValueViewer::draw(RotatedDC& dc) {
dc.DrawRectangle(RealRect(style().left, style().top, 40, style().height));
dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(style().getRect() + RealRect(40, 0, -40, 0));
dc.DrawRectangle(style().getRect().move(40, 0, -40, 0));
dc.DrawText(color_name, style().getPos() + RealSize(43, 3));
} else {
// do we need clipping?
+15 -1
View File
@@ -7,5 +7,19 @@
// ----------------------------------------------------------------------------- : Includes
#include <render/value/text.hpp>
#include <render/card/viewer.hpp>
// ----------------------------------------------------------------------------- :
// ----------------------------------------------------------------------------- : TextValueViewer
void TextValueViewer::draw(RotatedDC& dc) {
drawFieldBorder(dc);
v.draw(dc, value().value(), style(), viewer.getContext(), DRAW_NORMAL);
}
void TextValueViewer::onValueChange() {
v.reset();
}
void TextValueViewer::onStyleChange() {
v.reset();
}
+17 -1
View File
@@ -10,8 +10,24 @@
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <render/value/viewer.hpp>
#include <render/text/viewer.hpp>
#include <data/field/text.hpp>
// ----------------------------------------------------------------------------- :
// ----------------------------------------------------------------------------- : TextValueViewer
/// Viewer that displays a text value
class TextValueViewer : public ValueViewer {
public:
DECLARE_VALUE_VIEWER(Text) : ValueViewer(parent,style) {}
virtual void draw(RotatedDC& dc);
virtual void onValueChange();
virtual void onStyleChange();
private:
TextViewer v;
};
// ----------------------------------------------------------------------------- : EOF
+2 -1
View File
@@ -78,11 +78,12 @@ ValueViewerP BooleanStyle ::makeViewer(DataViewer& parent, const StyleP& t
ValueViewerP MultipleChoiceStyle::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); }
//ValueViewerP ColorStyle ::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); }
//ValueViewerP ImageStyle ::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); }
IMPLEMENT_MAKE_VIEWER(Text);
IMPLEMENT_MAKE_VIEWER(Choice);
IMPLEMENT_MAKE_VIEWER(Color);
IMPLEMENT_MAKE_VIEWER(Image);
ValueViewerP SymbolStyle ::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); }
ValueViewerP TextStyle ::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); }
//ValueViewerP TextStyle ::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); }
ValueEditorP ChoiceStyle ::makeEditor(DataEditor& parent, const StyleP& thisP) { return ValueEditorP(); }
ValueEditorP BooleanStyle ::makeEditor(DataEditor& parent, const StyleP& thisP) { return ValueEditorP(); }