mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-12 21:47: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 hard: 1.2
|
||||||
line height line: 1.5
|
line height line: 1.5
|
||||||
line height soft: 0.9
|
line height soft: 0.9
|
||||||
|
line height hard max: 1.3
|
||||||
|
line height line max: 1.6
|
||||||
|
|
||||||
watermark:
|
watermark:
|
||||||
left: 117
|
left: 117
|
||||||
|
|||||||
@@ -103,13 +103,15 @@ init script:
|
|||||||
|
|
||||||
# Look for a CDA that defines colors
|
# Look for a CDA that defines colors
|
||||||
text_to_color := {
|
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))*))\\.")
|
# Note: running filter_text is quite slow, do a quick 'contains' check first
|
||||||
if text == "" then ""
|
if contains(match: card_name) then (
|
||||||
else if contains(text, match: "all colors") 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"
|
colors := "WUBRG"
|
||||||
if land = "land" then land_multicolor()
|
if land = "land" then land_multicolor()
|
||||||
else mana_to_color(hybrid: "")
|
else mana_to_color(hybrid: "")
|
||||||
) else (
|
) else (
|
||||||
colors := ""
|
colors := ""
|
||||||
if contains(text, match: "white") then colors := colors + "W"
|
if contains(text, match: "white") then colors := colors + "W"
|
||||||
if contains(text, match: "blue") then colors := colors + "U"
|
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 contains(text, match: "green") then colors := colors + "G"
|
||||||
if land = "land" then land_multicolor()
|
if land = "land" then land_multicolor()
|
||||||
else mana_to_color(hybrid: "")
|
else mana_to_color(hybrid: "")
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +133,7 @@ init script:
|
|||||||
is_spell := match_rule(match: "(?i)Instant|Sorcery")
|
is_spell := match_rule(match: "(?i)Instant|Sorcery")
|
||||||
card_color := {
|
card_color := {
|
||||||
# usually the color of mana
|
# 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 (
|
if text_color == "" then (
|
||||||
mana_color := mana_to_color(colors: color_filter(casting_cost), hybrid: color_filterH(casting_cost))
|
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)
|
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_soft(1.0)
|
||||||
, line_height_hard(1.0)
|
, line_height_hard(1.0)
|
||||||
, line_height_line(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)
|
, direction(LEFT_TO_RIGHT)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -108,6 +111,9 @@ IMPLEMENT_REFLECTION(TextStyle) {
|
|||||||
REFLECT(line_height_soft);
|
REFLECT(line_height_soft);
|
||||||
REFLECT(line_height_hard);
|
REFLECT(line_height_hard);
|
||||||
REFLECT(line_height_line);
|
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_N("mask", mask_filename);
|
||||||
REFLECT(direction);
|
REFLECT(direction);
|
||||||
reflect_content(tag, *this);
|
reflect_content(tag, *this);
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ class TextStyle : public Style {
|
|||||||
double line_height_soft; ///< Line height for soft linebreaks
|
double line_height_soft; ///< Line height for soft linebreaks
|
||||||
double line_height_hard; ///< Line height for hard linebreaks
|
double line_height_hard; ///< Line height for hard linebreaks
|
||||||
double line_height_line; ///< Line height for <line> tags
|
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
|
String mask_filename; ///< Filename of the mask
|
||||||
ContourMask mask; ///< Mask to fit the text to (may be null)
|
ContourMask mask; ///< Mask to fit the text to (may be null)
|
||||||
Direction direction; ///< In what direction is text layed out?
|
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
|
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 top; ///< y position of (the top of) this line
|
||||||
double line_height; ///< The height of this line in pixels
|
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()
|
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
|
/// The position (just beyond) the bottom of this line
|
||||||
@@ -136,7 +137,7 @@ void TextViewer::drawSeparators(RotatedDC& dc) {
|
|||||||
y = (y + l.top) / 2;
|
y = (y + l.top) / 2;
|
||||||
dc.DrawLine(RealPoint(0, y), RealPoint(dc.getInternalRect().width, y));
|
dc.DrawLine(RealPoint(0, y), RealPoint(dc.getInternalRect().width, y));
|
||||||
}
|
}
|
||||||
separator = l.separator_after;
|
separator = l.break_after == BREAK_LINE;
|
||||||
y = y2;
|
y = y2;
|
||||||
}
|
}
|
||||||
// separator at the end?
|
// 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
|
// 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) {
|
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 tot_height = dc.getInternalSize().height + 1;
|
||||||
double height = min(tot_height, lines.back().bottom() + style.padding_bottom);
|
double height = min(tot_height, lines.back().bottom() + style.padding_bottom);
|
||||||
|
if (height < 1) return 1.0;
|
||||||
return scale * tot_height / height;
|
return scale * tot_height / height;
|
||||||
}
|
}
|
||||||
// bound on min_scale, given that scale doesn't fit and produces the given lines
|
// 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) {
|
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 tot_height = dc.getInternalSize().height;
|
||||||
double height = lines.back().bottom() + style.padding_bottom;
|
double height = lines.back().bottom() + style.padding_bottom;
|
||||||
|
if (height < 1) return 0.0;
|
||||||
return scale * tot_height / height;
|
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) {
|
for(size_t i = 0 ; i < chars.size() ; ++i) {
|
||||||
const CharInfo& c = chars[i];
|
const CharInfo& c = chars[i];
|
||||||
// Should we break?
|
// Should we break?
|
||||||
bool break_now = false;
|
bool break_now = false;
|
||||||
bool accept_word = false; // the current word should be added to the line
|
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
|
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 || c.break_after == BREAK_HARD || c.break_after == BREAK_LINE) {
|
||||||
if (c.break_after == BREAK_SOFT) {
|
|
||||||
break_now = true;
|
break_now = true;
|
||||||
accept_word = true;
|
accept_word = true;
|
||||||
line_height_multiplier = style.line_height_soft;
|
line.break_after = c.break_after;
|
||||||
} 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;
|
|
||||||
} else if (c.break_after == BREAK_SPACE && style.field().multi_line) {
|
} else if (c.break_after == BREAK_SPACE && style.field().multi_line) {
|
||||||
// Soft break == end of word
|
// Soft break == end of word
|
||||||
accept_word = true;
|
accept_word = true;
|
||||||
@@ -535,7 +530,7 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector<CharInfo>& chars,
|
|||||||
break_now = true;
|
break_now = true;
|
||||||
accept_word = true;
|
accept_word = true;
|
||||||
hide_breaker = false;
|
hide_breaker = false;
|
||||||
line_height_multiplier = style.line_height_soft;
|
line.break_after = BREAK_SOFT;
|
||||||
}
|
}
|
||||||
// Add size of the character
|
// Add size of the character
|
||||||
if (c.break_after != BREAK_LINE) {
|
if (c.break_after != BREAK_LINE) {
|
||||||
@@ -556,12 +551,12 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector<CharInfo>& chars,
|
|||||||
break_now = true;
|
break_now = true;
|
||||||
accept_word = true;
|
accept_word = true;
|
||||||
hide_breaker = false;
|
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) {
|
} else if (line_size.width + word_size.width > max_width) {
|
||||||
// line would become too long, break before the current word
|
// line would become too long, break before the current word
|
||||||
break_now = true;
|
break_now = true;
|
||||||
line_height_multiplier = style.line_height_soft;
|
line.break_after = BREAK_SOFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Ending the current word
|
// Ending the current word
|
||||||
@@ -595,11 +590,14 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector<CharInfo>& chars,
|
|||||||
// push
|
// push
|
||||||
lines.push_back(line);
|
lines.push_back(line);
|
||||||
// reset line object for next 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.top += line.line_height * line_height_multiplier;
|
||||||
line.start = word_start;
|
line.start = word_start;
|
||||||
line.positions.clear();
|
line.positions.clear();
|
||||||
if (line.separator_after) line.line_height = 0;
|
if (line.break_after == BREAK_LINE) line.line_height = 0;
|
||||||
line.separator_after = false;
|
line.break_after = BREAK_NO;
|
||||||
// reset line_size
|
// reset line_size
|
||||||
line_size = RealSize(lineLeft(dc, style, line.top), 0);
|
line_size = RealSize(lineLeft(dc, style, line.top), 0);
|
||||||
while (line.top < style.height && line_size.width + 1 >= style.width - style.padding_right) {
|
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) {
|
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
|
// Find height of the text, don't count the last lines if they are empty
|
||||||
double height = 0;
|
double height = 0;
|
||||||
FOR_EACH_REVERSE(l, lines) {
|
FOR_EACH_REVERSE(l, lines) {
|
||||||
@@ -647,6 +644,45 @@ void TextViewer::alignLines(RotatedDC& dc, const vector<CharInfo>& chars, const
|
|||||||
RealSize s = add_diagonal(
|
RealSize s = add_diagonal(
|
||||||
dc.getInternalSize(),
|
dc.getInternalSize(),
|
||||||
-RealSize(style.padding_left+style.padding_right, style.padding_top + style.padding_bottom));
|
-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);
|
double vdelta = align_delta_y(style.alignment, s.height, height);
|
||||||
// align all lines
|
// align all lines
|
||||||
FOR_EACH(l, lines) {
|
FOR_EACH(l, lines) {
|
||||||
|
|||||||
+22
-2
@@ -155,6 +155,26 @@ class ZipFileInputStream : private wxFileInputStream, public wxZipInputStream {
|
|||||||
};
|
};
|
||||||
#endif
|
#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) {
|
InputStreamP Package::openIn(const String& file) {
|
||||||
if (!file.empty() && file.GetChar(0) == _('/')) {
|
if (!file.empty() && file.GetChar(0) == _('/')) {
|
||||||
// absolute path, open file from another package
|
// absolute path, open file from another package
|
||||||
@@ -167,10 +187,10 @@ InputStreamP Package::openIn(const String& file) {
|
|||||||
InputStreamP stream;
|
InputStreamP stream;
|
||||||
if (it->second.wasWritten()) {
|
if (it->second.wasWritten()) {
|
||||||
// written to this file, open the temp file
|
// 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)) {
|
} else if (wxFileExists(filename+_("/")+file)) {
|
||||||
// a file in directory package
|
// a file in directory package
|
||||||
stream = new_shared1<wxFileInputStream>(filename+_("/")+file);
|
stream = new_shared1<BufferedFileInputStream>(filename+_("/")+file);
|
||||||
} else if (wxFileExists(filename) && it->second.zipEntry) {
|
} else if (wxFileExists(filename) && it->second.zipEntry) {
|
||||||
// a file in a zip archive
|
// a file in a zip archive
|
||||||
// somebody in wx thought seeking was no longer needed, it now only works with the 'compatability constructor'
|
// somebody in wx thought seeking was no longer needed, it now only works with the 'compatability constructor'
|
||||||
|
|||||||
Reference in New Issue
Block a user