mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
Attemp at scaling the spacing between lines to better fill the text box;
Did some profiling, conclusions: - we want to buffer our input streams, apperantly wx doesn't do this automatically - compiling regexes is SLOW. This is not just in the numbers, but it is actually noticable! The textbox used to be quite unresponsive. I wrapped the call to filter_text in the game file with a quick contains() call, so usually, the regex doesn't fire. It would be nicer if this was somehow automatic, but that will not be easy. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@627 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -262,6 +262,8 @@ card style:
|
||||
line height hard: 1.2
|
||||
line height line: 1.5
|
||||
line height soft: 0.9
|
||||
line height hard max: 1.3
|
||||
line height line max: 1.6
|
||||
|
||||
watermark:
|
||||
left: 117
|
||||
|
||||
@@ -103,13 +103,15 @@ init script:
|
||||
|
||||
# Look for a CDA that defines colors
|
||||
text_to_color := {
|
||||
text := filter_text(match: card_name+"(</[-a-z]+>)? is (colorless|all colors|((blue|white|green|red|black)((,|,? and) (blue|white|green|red|black))*))\\.")
|
||||
if text == "" then ""
|
||||
else if contains(text, match: "all colors") then (
|
||||
# Note: running filter_text is quite slow, do a quick 'contains' check first
|
||||
if contains(match: card_name) then (
|
||||
text := filter_text(match: card_name+"(</[-a-z]+>)? is (colorless|all colors|((blue|white|green|red|black)((,|,? and) (blue|white|green|red|black))*))\\.")
|
||||
if text != "" then (
|
||||
if contains(text, match: "all colors") then (
|
||||
colors := "WUBRG"
|
||||
if land = "land" then land_multicolor()
|
||||
else mana_to_color(hybrid: "")
|
||||
) else (
|
||||
) else (
|
||||
colors := ""
|
||||
if contains(text, match: "white") then colors := colors + "W"
|
||||
if contains(text, match: "blue") then colors := colors + "U"
|
||||
@@ -118,6 +120,8 @@ init script:
|
||||
if contains(text, match: "green") then colors := colors + "G"
|
||||
if land = "land" then land_multicolor()
|
||||
else mana_to_color(hybrid: "")
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -129,7 +133,7 @@ init script:
|
||||
is_spell := match_rule(match: "(?i)Instant|Sorcery")
|
||||
card_color := {
|
||||
# usually the color of mana
|
||||
text_color := text_to_color(rules_text, land: is_land(type), card_name: card_name);
|
||||
text_color := text_to_color(rules_text, land: is_land(type));
|
||||
if text_color == "" then (
|
||||
mana_color := mana_to_color(colors: color_filter(casting_cost), hybrid: color_filterH(casting_cost))
|
||||
if mana_color == "colorless" and is_land (type) then land_to_color(watermark)
|
||||
|
||||
@@ -52,6 +52,9 @@ TextStyle::TextStyle(const TextFieldP& field)
|
||||
, line_height_soft(1.0)
|
||||
, line_height_hard(1.0)
|
||||
, line_height_line(1.0)
|
||||
, line_height_soft_max(0.0)
|
||||
, line_height_hard_max(0.0)
|
||||
, line_height_line_max(0.0)
|
||||
, direction(LEFT_TO_RIGHT)
|
||||
{}
|
||||
|
||||
@@ -108,6 +111,9 @@ IMPLEMENT_REFLECTION(TextStyle) {
|
||||
REFLECT(line_height_soft);
|
||||
REFLECT(line_height_hard);
|
||||
REFLECT(line_height_line);
|
||||
REFLECT(line_height_soft_max);
|
||||
REFLECT(line_height_hard_max);
|
||||
REFLECT(line_height_line_max);
|
||||
REFLECT_N("mask", mask_filename);
|
||||
REFLECT(direction);
|
||||
reflect_content(tag, *this);
|
||||
|
||||
@@ -65,6 +65,9 @@ class TextStyle : public Style {
|
||||
double line_height_soft; ///< Line height for soft linebreaks
|
||||
double line_height_hard; ///< Line height for hard linebreaks
|
||||
double line_height_line; ///< Line height for <line> tags
|
||||
double line_height_soft_max; ///< Maximum line height
|
||||
double line_height_hard_max; ///< Maximum line height
|
||||
double line_height_line_max; ///< Maximum line height
|
||||
String mask_filename; ///< Filename of the mask
|
||||
ContourMask mask; ///< Mask to fit the text to (may be null)
|
||||
Direction direction; ///< In what direction is text layed out?
|
||||
|
||||
+60
-24
@@ -19,10 +19,11 @@ struct TextViewer::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?
|
||||
LineBreak break_after; ///< Is there a saparator after this line?
|
||||
//% Alignment alignment; ///< Alignment of this line
|
||||
|
||||
Line()
|
||||
: start(0), top(0), line_height(0), separator_after(false)
|
||||
: start(0), top(0), line_height(0), break_after(BREAK_NO)
|
||||
{}
|
||||
|
||||
/// The position (just beyond) the bottom of this line
|
||||
@@ -136,7 +137,7 @@ void TextViewer::drawSeparators(RotatedDC& dc) {
|
||||
y = (y + l.top) / 2;
|
||||
dc.DrawLine(RealPoint(0, y), RealPoint(dc.getInternalRect().width, y));
|
||||
}
|
||||
separator = l.separator_after;
|
||||
separator = l.break_after == BREAK_LINE;
|
||||
y = y2;
|
||||
}
|
||||
// separator at the end?
|
||||
@@ -376,14 +377,18 @@ void TextViewer::prepareLines(RotatedDC& dc, const String& text, TextStyle& styl
|
||||
|
||||
// bound on max_scale, given that scale fits and produces the given lines
|
||||
inline double bound_on_max_scale(RotatedDC& dc, const TextStyle& style, const vector<TextViewer::Line>& lines, double scale) {
|
||||
if (lines.empty()) return 1.0;
|
||||
double tot_height = dc.getInternalSize().height + 1;
|
||||
double height = min(tot_height, lines.back().bottom() + style.padding_bottom);
|
||||
if (height < 1) return 1.0;
|
||||
return scale * tot_height / height;
|
||||
}
|
||||
// bound on min_scale, given that scale doesn't fit and produces the given lines
|
||||
inline double bound_on_min_scale(RotatedDC& dc, const TextStyle& style, const vector<TextViewer::Line>& lines, double scale) {
|
||||
if (lines.empty()) return 0.0;
|
||||
double tot_height = dc.getInternalSize().height;
|
||||
double height = lines.back().bottom() + style.padding_bottom;
|
||||
if (height < 1) return 0.0;
|
||||
return scale * tot_height / height;
|
||||
}
|
||||
|
||||
@@ -511,23 +516,13 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector<CharInfo>& chars,
|
||||
for(size_t i = 0 ; i < chars.size() ; ++i) {
|
||||
const 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_SOFT) {
|
||||
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
|
||||
if (c.break_after == BREAK_SOFT || c.break_after == BREAK_HARD || c.break_after == BREAK_LINE) {
|
||||
break_now = true;
|
||||
accept_word = true;
|
||||
line_height_multiplier = style.line_height_soft;
|
||||
} else 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;
|
||||
line.break_after = c.break_after;
|
||||
} else if (c.break_after == BREAK_SPACE && style.field().multi_line) {
|
||||
// Soft break == end of word
|
||||
accept_word = true;
|
||||
@@ -535,7 +530,7 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector<CharInfo>& chars,
|
||||
break_now = true;
|
||||
accept_word = true;
|
||||
hide_breaker = false;
|
||||
line_height_multiplier = style.line_height_soft;
|
||||
line.break_after = BREAK_SOFT;
|
||||
}
|
||||
// Add size of the character
|
||||
if (c.break_after != BREAK_LINE) {
|
||||
@@ -556,12 +551,12 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector<CharInfo>& chars,
|
||||
break_now = true;
|
||||
accept_word = true;
|
||||
hide_breaker = false;
|
||||
line_height_multiplier = style.line_height_soft;
|
||||
line.break_after = BREAK_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;
|
||||
line.break_after = BREAK_SOFT;
|
||||
}
|
||||
}
|
||||
// Ending the current word
|
||||
@@ -595,11 +590,14 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector<CharInfo>& chars,
|
||||
// push
|
||||
lines.push_back(line);
|
||||
// reset line object for next line
|
||||
double line_height_multiplier = line.break_after == BREAK_HARD ? style.line_height_hard
|
||||
: line.break_after == BREAK_LINE ? style.line_height_line
|
||||
: style.line_height_soft;
|
||||
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;
|
||||
if (line.break_after == BREAK_LINE) line.line_height = 0;
|
||||
line.break_after = BREAK_NO;
|
||||
// reset line_size
|
||||
line_size = RealSize(lineLeft(dc, style, line.top), 0);
|
||||
while (line.top < style.height && line_size.width + 1 >= style.width - style.padding_right) {
|
||||
@@ -636,7 +634,6 @@ double TextViewer::lineRight(RotatedDC& dc, const TextStyle& style, double y) co
|
||||
|
||||
|
||||
void TextViewer::alignLines(RotatedDC& dc, const vector<CharInfo>& chars, const TextStyle& style) {
|
||||
if (style.alignment == ALIGN_TOP_LEFT) return;
|
||||
// Find height of the text, don't count the last lines if they are empty
|
||||
double height = 0;
|
||||
FOR_EACH_REVERSE(l, lines) {
|
||||
@@ -647,6 +644,45 @@ void TextViewer::alignLines(RotatedDC& dc, const vector<CharInfo>& chars, const
|
||||
RealSize s = add_diagonal(
|
||||
dc.getInternalSize(),
|
||||
-RealSize(style.padding_left+style.padding_right, style.padding_top + style.padding_bottom));
|
||||
|
||||
// stretch lines by increasing the space between them
|
||||
if (height < s.height) {
|
||||
double d_soft = max(0.0, style.line_height_soft_max - style.line_height_soft);
|
||||
double d_hard = max(0.0, style.line_height_hard_max - style.line_height_hard);
|
||||
double d_line = max(0.0, style.line_height_line_max - style.line_height_line);
|
||||
double stops[] = {0.0, d_soft, d_hard, d_line};
|
||||
sort(stops + 1, stops + 4);
|
||||
for (int i = 1 ; i < 4 && height < s.height ; ++i) {
|
||||
double stop = stops[i] - stops[i-1];
|
||||
if (stop <= 0) continue;
|
||||
// which types can use this stop?
|
||||
bool soft = d_soft >= stop;
|
||||
bool hard = d_hard >= stop;
|
||||
bool line = d_line >= stop;
|
||||
// sum of the line height we can apply this to?
|
||||
double sum = 0;
|
||||
FOR_EACH(l, lines) {
|
||||
if ((soft && l.break_after == BREAK_SOFT)
|
||||
|| (hard && l.break_after == BREAK_HARD)
|
||||
|| (line && l.break_after == BREAK_LINE)) sum += l.line_height;
|
||||
}
|
||||
if (sum == 0) break;
|
||||
// how much do we need to add?
|
||||
double to_add = min(stop, (s.height - height) / sum);
|
||||
// apply
|
||||
double add = 0;
|
||||
FOR_EACH(l, lines) {
|
||||
l.top += add;
|
||||
// adjust next line by..
|
||||
if ((soft && l.break_after == BREAK_SOFT)
|
||||
|| (hard && l.break_after == BREAK_HARD)
|
||||
|| (line && l.break_after == BREAK_LINE)) add += to_add * l.line_height;
|
||||
}
|
||||
height += add;
|
||||
}
|
||||
}
|
||||
if (style.alignment == ALIGN_TOP_LEFT) return;
|
||||
// align
|
||||
double vdelta = align_delta_y(style.alignment, s.height, height);
|
||||
// align all lines
|
||||
FOR_EACH(l, lines) {
|
||||
|
||||
+22
-2
@@ -155,6 +155,26 @@ class ZipFileInputStream : private wxFileInputStream, public wxZipInputStream {
|
||||
};
|
||||
#endif
|
||||
|
||||
class BufferedFileInputStream_aux {
|
||||
protected:
|
||||
wxFileInputStream file_stream;
|
||||
inline BufferedFileInputStream_aux(const String& filename)
|
||||
: file_stream(filename)
|
||||
{}
|
||||
};
|
||||
/// A buffered version of wxFileInputStream
|
||||
/** 2007-08-24:
|
||||
* According to profiling this gives a significant speedup
|
||||
* Bringing the avarage run time of read_utf8_line from 186k to 54k (in cpu time units)
|
||||
*/
|
||||
class BufferedFileInputStream : private BufferedFileInputStream_aux, public wxBufferedInputStream {
|
||||
public:
|
||||
inline BufferedFileInputStream(const String& filename)
|
||||
: BufferedFileInputStream_aux(filename)
|
||||
, wxBufferedInputStream(file_stream)
|
||||
{}
|
||||
};
|
||||
|
||||
InputStreamP Package::openIn(const String& file) {
|
||||
if (!file.empty() && file.GetChar(0) == _('/')) {
|
||||
// absolute path, open file from another package
|
||||
@@ -167,10 +187,10 @@ InputStreamP Package::openIn(const String& file) {
|
||||
InputStreamP stream;
|
||||
if (it->second.wasWritten()) {
|
||||
// written to this file, open the temp file
|
||||
stream = new_shared1<wxFileInputStream>(it->second.tempName);
|
||||
stream = new_shared1<BufferedFileInputStream>(it->second.tempName);
|
||||
} else if (wxFileExists(filename+_("/")+file)) {
|
||||
// a file in directory package
|
||||
stream = new_shared1<wxFileInputStream>(filename+_("/")+file);
|
||||
stream = new_shared1<BufferedFileInputStream>(filename+_("/")+file);
|
||||
} else if (wxFileExists(filename) && it->second.zipEntry) {
|
||||
// a file in a zip archive
|
||||
// somebody in wx thought seeking was no longer needed, it now only works with the 'compatability constructor'
|
||||
|
||||
Reference in New Issue
Block a user