From 087af8360d402f84456bed1b05d111f9d96146ad Mon Sep 17 00:00:00 2001 From: twanvl Date: Tue, 28 Aug 2007 20:49:25 +0000 Subject: [PATCH] Added tag that takes up no space for alignment purposes; used this tag for magic creature types; Added correct handling of Tribal sub types; Fixed sort_index use by spoiler export template git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@637 0fc631ac-6414-0410-93d0-97cfa31319b6 --- .../export-template | 23 ++++---- data/magic.mse-game/game | 54 +++++++++++-------- doc/type/tagged_string.txt | 1 + src/gui/value/text.cpp | 2 +- src/render/text/element.cpp | 6 ++- src/render/text/element.hpp | 14 +++-- src/render/text/font.cpp | 8 +-- src/render/text/viewer.cpp | 40 ++++++++------ src/script/parser.cpp | 2 +- src/util/rotation.cpp | 8 +-- src/util/string.cpp | 2 +- 11 files changed, 94 insertions(+), 66 deletions(-) diff --git a/data/magic-spoiler.mse-export-template/export-template b/data/magic-spoiler.mse-export-template/export-template index a350d9c8..e3e97c99 100644 --- a/data/magic-spoiler.mse-export-template/export-template +++ b/data/magic-spoiler.mse-export-template/export-template @@ -147,7 +147,7 @@ script: }" } write_group := { - cards := filter_list(set.cards, filter: { sort_index(card:input) == code } ) + cards := filter_list(set.cards, filter: { contains(match:sort_index(card:input), code } ) count := number_of_items(in:cards) if count > 0 then "

{title} ({count} {if count == 1 then "card" else "cards"})

" + @@ -194,16 +194,17 @@ script:
{ to_html(set.description) }
{ if options.grouping == "group by color" then # Codes as by sort_index - write_group(title: "White", code:"A") + - write_group(title: "Blue", code:"B") + - write_group(title: "Black", code:"C") + - write_group(title: "Red", code:"D") + - write_group(title: "Green", code:"E") + - write_group(title: "Multicolor", code:"F") + - write_group(title: "Hybrids", code:"G") + - write_group(title: "Colorless", code:"I") + - write_group(title: "Non-basic lands", code:"J") + - write_group(title: "Basic lands", code:"K") + write_group(title: "White", code:"A") + + write_group(title: "Blue", code:"B") + + write_group(title: "Black", code:"C") + + write_group(title: "Red", code:"D") + + write_group(title: "Green", code:"E") + + write_group(title: "Multicolor", code:"F") + + write_group(title: "Hybrids", code:"G") + + write_group(title: "Multicolor split cards", code:"H") + + write_group(title: "Colorless", code:"I") + + write_group(title: "Non-basic lands", code:"K") + + write_group(title: "Basic lands", code:"LMNOPQ") else write_cards(cards: set.cards) } diff --git a/data/magic.mse-game/game b/data/magic.mse-game/game index 74493d96..658cdee2 100644 --- a/data/magic.mse-game/game +++ b/data/magic.mse-game/game @@ -1,8 +1,8 @@ -mse version: 0.3.4 +mse version: 0.3.5 short name: Magic full name: Magic the Gathering icon: card-back.png -version: 2007-07-01 +version: 2007-08-28 position hint: 01 ############################################################## Functions & filters @@ -126,7 +126,8 @@ init script: } # The color of a card - is_creature := match_rule(match: "(?i)Creature|Tribal") + is_creature := match_rule(match: "(?i)Creature") + is_tribal := match_rule(match: "(?i)Tribal") is_artifact := match_rule(match: "(?i)Artifact") is_land := match_rule(match: "(?i)Land") is_enchantment := match_rule(match: "(?i)Enchantment") @@ -176,17 +177,17 @@ init script: card_color := card.card_color casting_cost := card.casting_cost if card.casting_cost_2 != "" and - card_color != card.card_color_2 then "H" # multicolor splits + card_color != card.card_color_2 then "H" # multicolor splits else if chosen(choice: "land", card_color) then ( # land - if card.rarity != "basic land" then "K" # nonbasic land + if card.rarity != "basic land" then "K" # nonbasic land else ( if contains(card.name, match:"Plains") then "M" else if contains(card.name, match:"Island") then "N" else if contains(card.name, match:"Swamp") then "O" else if contains(card.name, match:"Mountain") then "P" else if contains(card.name, match:"Forest") then "Q" - else "L" # other basic land + else "L" # other basic land ) ) else if is_null_cost(casting_cost) then ( # no casting cost; use frame @@ -368,24 +369,31 @@ init script: type_over_type + { "{input}" } - space_to_wlclass := replace_rule(match:" +", replace:" ") + space_to_wltags := replace_rule(match:"( +| )", + replace:{"{_1}"}) sub_type_filter := tag_remove_rule(tag: "" - else ( - first := only_first(input); - next := trim(only_next(input)); - if next != "" then next := next + " "; - "{first} " + - "" + space_to_wlclass(next) + "" - ) + replace_rule(match: "
$", replace: "") + # remove trailing soft space + tag_remove_rule(tag: " " + else first := first + " " + input := next + ) else ( + first := "" ) - else if is_land(type) then "{ input}" - else if is_artifact(type) then "{ input}" - else if is_enchantment(type) then "{input}" - else if is_spell(type) then "{ input}" - else input + if list_type != "" then ( + if input != "" then input := input + " " # Add a new box at the end + first + "{ space_to_wltags(input) }" + ) else first + input } # all sub types, for word list @@ -398,7 +406,7 @@ init script: } all_races := { for each card in set do - if contains(card.super_type, match:"Creature") then + if is_creature(card.super_type) or is_tribal(card.super_type) then "," + only_first(to_text(card.sub_type)) } all_classes := { @@ -1247,7 +1255,9 @@ word list: script: all_classes() line below: true word: Cleric + word: Druid word: Lord + word: Shaman word: Soldier word: Warrior word: diff --git a/doc/type/tagged_string.txt b/doc/type/tagged_string.txt index e1ae225b..fbc569b0 100644 --- a/doc/type/tagged_string.txt +++ b/doc/type/tagged_string.txt @@ -37,6 +37,7 @@ This is written as the character with code 1 in files. Inserting this tag manually will confuse that function!
This tag can never be selected, and its contents can not be edited. | @""@ Like @""@, only hidden. This is inserted by [[fun:combined_editor]] +| @""@ Text who's width is ignored for alignment, similair to @""@, but not a separator. | @""@ Indicate that the text inside the tag should be selected from a [[type:word list]]. The ? must be the name of a word list in the game. | any other tag Other tags are ignored. diff --git a/src/gui/value/text.cpp b/src/gui/value/text.cpp index 29a24e0a..ad646d30 100644 --- a/src/gui/value/text.cpp +++ b/src/gui/value/text.cpp @@ -1297,7 +1297,7 @@ void TextValueEditor::clearWordListIndicators(RotatedDC& dc) { } // restore background if (wl->behind.Ok()) { - dc.DrawBitmap(wl->behind, wl->rect.topRight() + RealSize(0,-1)); + dc.DrawPreRotatedBitmap(wl->behind, wl->rect.topRight() + RealSize(0,-1)); } } } diff --git a/src/render/text/element.cpp b/src/render/text/element.cpp index 59c8fabc..5a6ff19f 100644 --- a/src/render/text/element.cpp +++ b/src/render/text/element.cpp @@ -33,12 +33,12 @@ void TextElements::getCharInfo(RotatedDC& dc, double scale, size_t start, size_t FOR_EACH_CONST(e, elements) { // characters before this element, after the previous while (out.size() < e->start) { - out.push_back(CharInfo(RealSize(0,0), BREAK_NO)); + out.push_back(CharInfo()); } e->getCharInfo(dc, scale, out); } while (out.size() < end) { - out.push_back(CharInfo(RealSize(0,0), BREAK_NO)); + out.push_back(CharInfo()); } } @@ -100,6 +100,8 @@ struct TextElementsFromString { else if (is_substr(text, tag_start, _(" { // ----------------------------------------------------------------------------- : TextElements /// A list of text elements -class TextElements : public vector { +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; diff --git a/src/render/text/font.cpp b/src/render/text/font.cpp index 097c6898..2f7233a8 100644 --- a/src/render/text/font.cpp +++ b/src/render/text/font.cpp @@ -37,13 +37,15 @@ void FontTextElement::getCharInfo(RotatedDC& dc, double scale, vector& 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)); + 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 + out.push_back(CharInfo( + RealSize(s.width - prev_width, s.height), + c == _(' ') ? BREAK_SPACE : BREAK_MAYBE, + draw_as == DRAW_ACTIVE // from tag )); prev_width = s.width; } diff --git a/src/render/text/viewer.cpp b/src/render/text/viewer.cpp index 4b4d1994..a3206699 100644 --- a/src/render/text/viewer.cpp +++ b/src/render/text/viewer.cpp @@ -16,6 +16,7 @@ DECLARE_TYPEOF_COLLECTION(double); struct TextViewer::Line { size_t start; ///< Index of the first character in this line + size_t end_or_soft; ///< Index just beyond the last non-soft character vector 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 @@ -23,13 +24,13 @@ struct TextViewer::Line { //% Alignment alignment; ///< Alignment of this line Line() - : start(0), top(0), line_height(0), break_after(BREAK_NO) + : start(0), end_or_soft(0), top(0), line_height(0), break_after(BREAK_NO) {} /// 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(); } + double width() const { return positions[end_or_soft-start] - 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 @@ -158,7 +159,7 @@ bool TextViewer::prepare(RotatedDC& dc, const String& text, TextStyle& style, Co } } void TextViewer::reset(bool related) { - elements.clear(); + elements.elements.clear(); lines.clear(); if (!related) scale = 1.0; } @@ -169,6 +170,7 @@ bool TextViewer::prepared() const { // ----------------------------------------------------------------------------- : Positions const TextViewer::Line& TextViewer::findLine(size_t index) const { + assert(!lines.empty()); FOR_EACH_CONST(l, lines) { if (l.end() >= index) return l; } @@ -295,6 +297,7 @@ void TextViewer::scrollBy(double delta) { } bool TextViewer::ensureVisible(double height, size_t char_id) { + if (lines.empty()) return true; const Line& line = findLine(char_id); if (line.top < 0) { // scroll up @@ -511,6 +514,7 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector& chars, // The word we are currently reading RealSize word_size; vector positions_word; // positios for this word + size_t word_end_or_soft = 0; size_t word_start = 0; // For each character ... for(size_t i = 0 ; i < chars.size() ; ++i) { @@ -539,6 +543,7 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector& chars, word_size = add_horizontal(word_size, c.size); } positions_word.push_back(word_size.width); + if (!c.soft) word_end_or_soft = i + 1; // Did the word become too long? if (style.field().multi_line && !break_now) { double max_width = lineRight(dc, style, line.top); @@ -565,11 +570,13 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector& chars, FOR_EACH(p, positions_word) { line.positions.push_back(line_size.width + p); } - // add size; next word + if (word_end_or_soft != 0) line.end_or_soft = word_end_or_soft; line_size = add_horizontal(line_size, word_size); + // next word word_size = RealSize(0, 0); word_start = i + 1; positions_word.clear(); + word_end_or_soft = 0; } // Breaking (ending the current line) if (break_now) { @@ -583,10 +590,7 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector& chars, } else { line.line_height = line_size.height; } -// // too low? -// if (stop_if_too_long && line.bottom() > dc.getInternalSize().height - style.padding_bottom) { -// return false; -// } + line.end_or_soft = max(line.start, min(line.end_or_soft, line.end())); // push lines.push_back(line); // reset line object for next line @@ -612,6 +616,7 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector& chars, FOR_EACH(p, positions_word) { line.positions.push_back(line_size.width + p); } + if (word_end_or_soft != 0) line.end_or_soft = word_end_or_soft; line_size = add_horizontal(line_size, word_size); // the last line if (line_size.height < 0.01 && !lines.empty()) { @@ -619,6 +624,7 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector& chars, } else { line.line_height = line_size.height; } + line.end_or_soft = max(line.start, min(line.end_or_soft, line.end())); lines.push_back(line); // does it fit vertically? return lines.empty() || @@ -688,14 +694,14 @@ void TextViewer::alignLines(RotatedDC& dc, const vector& chars, const FOR_EACH(l, lines) { l.top += vdelta; // amount to shift all characters horizontally - double width = l.positions.back(); + double width = l.positions[l.end_or_soft - l.start]; if ((style.alignment & ALIGN_JUSTIFY) || (style.alignment & ALIGN_JUSTIFY_OVERFLOW && width > s.width)) { // justify text justifying = true; - double hdelta = s.width - width; // amount of space to distribute - int count = (int)l.positions.size() - 1; // distribute it among this many characters - if (count == 0) count = 1; // prevent div by 0 + double hdelta = s.width - width; // amount of space to distribute + int count = (int)(l.end_or_soft - l.start); // distribute it among this many characters + if (count <= 0) count = 1; // prevent div by 0 int i = 0; FOR_EACH(c, l.positions) { c += hdelta * i++ / count; @@ -703,16 +709,16 @@ void TextViewer::alignLines(RotatedDC& dc, const vector& chars, const } else if (style.alignment & ALIGN_JUSTIFY_WORDS) { // justify text, by words justifying = true; - double hdelta = s.width - width; // amount of space to distribute - int count = 0; // distribute it among this many words - for (size_t k = l.start + 1 ; k < l.end() - 1 ; ++k) { + double hdelta = s.width - width; // amount of space to distribute + int count = 0; // distribute it among this many words + for (size_t k = l.start + 1 ; k < l.end_or_soft - 1 ; ++k) { if (chars[k].break_after == BREAK_SPACE) ++count; } - if (count == 0) count = 1; // prevent div by 0 + if (count == 0) count = 1; // prevent div by 0 int i = 0; size_t j = l.start; FOR_EACH(c, l.positions) { c += hdelta * i / count; - if (j < l.end() && chars[j++].break_after == BREAK_SPACE) i++; + if (j < l.end_or_soft && chars[j++].break_after == BREAK_SPACE) i++; } } else { // simple alignment diff --git a/src/script/parser.cpp b/src/script/parser.cpp index eea9bf46..7ff312d4 100644 --- a/src/script/parser.cpp +++ b/src/script/parser.cpp @@ -190,7 +190,7 @@ void TokenIterator::readToken() { filename = include_file; InputStreamP is = packages.openFileFromPackage(include_file); input = read_utf8_line(*is, true, true); - } else if (isAlpha(c)) { + } else if (isAlpha(c) || c == _('_')) { // name size_t start = pos - 1; while (pos < input.size() && isAlnum_(input.GetChar(pos))) ++pos; diff --git a/src/util/rotation.cpp b/src/util/rotation.cpp index 9a6ef6d0..dadee2a0 100644 --- a/src/util/rotation.cpp +++ b/src/util/rotation.cpp @@ -153,7 +153,7 @@ void RotatedDC::DrawText (const String& text, const RealPoint& pos, int blur_ra void RotatedDC::DrawBitmap(const Bitmap& bitmap, const RealPoint& pos) { if (angle == 0) { RealPoint p_ext = tr(pos); - dc.DrawBitmap(bitmap, (int) p_ext.x, (int) p_ext.y, true); + dc.DrawBitmap(bitmap, to_int(p_ext.x), to_int(p_ext.y), true); } else { DrawImage(bitmap.ConvertToImage(), pos); } @@ -161,15 +161,15 @@ void RotatedDC::DrawBitmap(const Bitmap& bitmap, const RealPoint& pos) { void RotatedDC::DrawImage (const Image& image, const RealPoint& pos, ImageCombine combine, int angle) { Image rotated = rotate_image(image, angle + this->angle); wxRect r = trNoNegNoZoom(RealRect(pos, RealSize(image))); - draw_combine_image(dc, r.x, r.y, rotated, combine); + draw_combine_image(dc, to_int(r.x), to_int(r.y), rotated, combine); } void RotatedDC::DrawPreRotatedBitmap(const Bitmap& bitmap, const RealPoint& pos) { RealPoint p_ext = tr(pos) - RealSize(revX()?bitmap.GetWidth():0, revY()?bitmap.GetHeight():0); - dc.DrawBitmap(bitmap, (int) p_ext.x, (int) p_ext.y, true); + dc.DrawBitmap(bitmap, to_int(p_ext.x), to_int(p_ext.y), true); } void RotatedDC::DrawPreRotatedImage (const Image& image, const RealPoint& pos, ImageCombine combine) { RealPoint p_ext = tr(pos) - RealSize(revX()?image.GetWidth():0, revY()?image.GetHeight():0); - draw_combine_image(dc, p_ext.x, p_ext.y, image, combine); + draw_combine_image(dc, to_int(p_ext.x), to_int(p_ext.y), image, combine); } void RotatedDC::DrawLine (const RealPoint& p1, const RealPoint& p2) { diff --git a/src/util/string.cpp b/src/util/string.cpp index 38def722..f6cdb300 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -166,7 +166,7 @@ String cannocial_name_form(const String& str) { bool leading = true; FOR_EACH_CONST(c, str) { if ((c == _('_') || c == _(' '))) { - if (!leading) ret += _(' '); + ret += leading ? c : _(' '); } else { ret += c; leading = false;