mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-12 05:36:59 -04:00
The DECLARE_TYPEOF(()) calls don't work in MSVC, I changed it to use a COMMA macro instead of ,
If this doesn't work in GCC, the COMMA definition could be made only for MSVC, then GCC sees DECLARE_TYPEOF(map<int COMMA string>). GCC doesn't need DECLARE_TYPEOF anyway. Keyword expansion now works, still todo: - marking parameters, e.g. "Cycling 2W" -> "Cycling <param-mana>2W</param-mana>" - user interface for toggling reminder text - user interface for keywords git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@210 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -260,8 +260,11 @@ error:
|
|||||||
unable to store file: Error while saving, unable to store file
|
unable to store file: Error while saving, unable to store file
|
||||||
|
|
||||||
# Script stuff
|
# Script stuff
|
||||||
collection has no member: Collection has no member '%s'
|
has no member: %s has no member '%s'
|
||||||
object has no member: Object has no member '%s'
|
can't convert: Can't convert from %s to %s
|
||||||
|
has no member value: String "%s" has no member '%s'
|
||||||
|
can't convert value: Can't convert "%s" from %s to %s
|
||||||
|
unsupported format: Invalid string format: '%s'
|
||||||
|
|
||||||
# Image stuff
|
# Image stuff
|
||||||
coordinates for blending overlap: Coordinates for blending overlap
|
coordinates for blending overlap: Coordinates for blending overlap
|
||||||
@@ -287,9 +290,15 @@ error:
|
|||||||
|
|
||||||
############################################################## Types used in scripts
|
############################################################## Types used in scripts
|
||||||
type:
|
type:
|
||||||
real: Real number
|
function: function
|
||||||
integer: Integer number
|
collection: collection
|
||||||
string: String
|
object: object
|
||||||
|
real: real number
|
||||||
|
integer: integer number
|
||||||
|
string: string
|
||||||
|
boolean: boolean
|
||||||
|
color: color
|
||||||
|
nil: nothing
|
||||||
|
|
||||||
############################################################## Magic
|
############################################################## Magic
|
||||||
game:
|
game:
|
||||||
|
|||||||
@@ -161,18 +161,22 @@ init script:
|
|||||||
# after: ")",
|
# after: ")",
|
||||||
# fix_english: true
|
# fix_english: true
|
||||||
# ) +
|
# ) +
|
||||||
# step 3 : expand shortcut words ~ and CARDNAME
|
expand_keywords_rule(
|
||||||
|
default_expand: { set.automatic_reminder_text == "yes" },
|
||||||
|
combine: { "{keyword}<atom-reminder><i> ({reminder})</i></atom-reminder>" }
|
||||||
|
) +
|
||||||
|
# step 3a : expand shortcut words ~ and CARDNAME
|
||||||
replace_rule(
|
replace_rule(
|
||||||
match: "~|~THIS~|CARDNAME",
|
match: "~|~THIS~|CARDNAME",
|
||||||
in_context: "(^|[[:space:]]|\\()<match>", # TODO: Allow any punctuation before
|
in_context: "(^|[[:space:]]|\\()<match>", # TODO: Allow any punctuation before
|
||||||
replace: "<atom-cardname></atom-cardname>"
|
replace: "<atom-cardname></atom-cardname>"
|
||||||
) +
|
) +
|
||||||
# step 4 : fill in atom fields
|
# step 3b : fill in atom fields
|
||||||
tag_contents_rule(
|
tag_contents_rule(
|
||||||
tag: "<atom-cardname>",
|
tag: "<atom-cardname>",
|
||||||
contents: { if card_name=="" then "CARDNAME" else card_name }
|
contents: { if card_name=="" then "CARDNAME" else card_name }
|
||||||
) +
|
) +
|
||||||
# step 4.5 : explict non mana symbols
|
# step 4 : explict non mana symbols
|
||||||
replace_rule(
|
replace_rule(
|
||||||
match: "\\][STXYZWUBRG0-9/|]+\\[",
|
match: "\\][STXYZWUBRG0-9/|]+\\[",
|
||||||
replace: {"<nosym>" + mana_filter_t() + "</nosym>"} ) +
|
replace: {"<nosym>" + mana_filter_t() + "</nosym>"} ) +
|
||||||
@@ -802,7 +806,7 @@ keyword parameter type:
|
|||||||
keyword parameter type:
|
keyword parameter type:
|
||||||
name: cost
|
name: cost
|
||||||
#insert as: word
|
#insert as: word
|
||||||
match: ***:[XYZ0-9WUBRGS/]+|[^(.,\n]|([XYZ0-9WUBRGS/]+,)?[^(.,\n]*
|
match: [XYZ0-9WUBRGS/]+|[^(.,\n]|([XYZ0-9WUBRGS/]+,)?[^(.,\n]*
|
||||||
keyword parameter type:
|
keyword parameter type:
|
||||||
name: number
|
name: number
|
||||||
match: [XYZ0-9]+
|
match: [XYZ0-9]+
|
||||||
@@ -821,11 +825,11 @@ keyword parameter type:
|
|||||||
keyword parameter type:
|
keyword parameter type:
|
||||||
name: action
|
name: action
|
||||||
#insert as: word
|
#insert as: word
|
||||||
match: ***:[^(.,\n]+
|
match: [^(.,\n]+
|
||||||
keyword parameter type:
|
keyword parameter type:
|
||||||
name: name
|
name: name
|
||||||
#insert as: word
|
#insert as: word
|
||||||
match: ***:[^(.,\n]+
|
match: [^(.,\n]+
|
||||||
|
|
||||||
############################# All Magic keywords
|
############################# All Magic keywords
|
||||||
# By JrEye and Neko_Asakami
|
# By JrEye and Neko_Asakami
|
||||||
@@ -851,7 +855,7 @@ keyword:
|
|||||||
keyword: Cycling
|
keyword: Cycling
|
||||||
separator: whitespace [ ]
|
separator: whitespace [ ]
|
||||||
parameter: cost
|
parameter: cost
|
||||||
reminder: <param>, Discard this card: Draw a card.
|
reminder: {param1}, Discard this card: Draw a card.
|
||||||
keyword:
|
keyword:
|
||||||
keyword: Trample
|
keyword: Trample
|
||||||
reminder: If this creature would deal enough combat damage to its blockers to destroy them, you may have it deal the rest of its damage to defending player.
|
reminder: If this creature would deal enough combat damage to its blockers to destroy them, you may have it deal the rest of its damage to defending player.
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
#include <data/action/symbol.hpp>
|
#include <data/action/symbol.hpp>
|
||||||
#include <data/action/symbol_part.hpp>
|
#include <data/action/symbol_part.hpp>
|
||||||
|
|
||||||
DECLARE_TYPEOF_COLLECTION((pair<SymbolPartP,SymbolPartCombine>));
|
DECLARE_TYPEOF_COLLECTION(pair<SymbolPartP COMMA SymbolPartCombine>);
|
||||||
DECLARE_TYPEOF_COLLECTION((pair<SymbolPartP,size_t >));
|
DECLARE_TYPEOF_COLLECTION(pair<SymbolPartP COMMA size_t >);
|
||||||
DECLARE_TYPEOF_COLLECTION(SymbolPartP);
|
DECLARE_TYPEOF_COLLECTION(SymbolPartP);
|
||||||
DECLARE_TYPEOF_COLLECTION(ControlPointP);
|
DECLARE_TYPEOF_COLLECTION(ControlPointP);
|
||||||
|
|
||||||
@@ -204,11 +204,11 @@ void SymbolPartScaleAction::update() {
|
|||||||
// the size after the move
|
// the size after the move
|
||||||
newMin = newRealMin; newSize = newRealSize;
|
newMin = newRealMin; newSize = newRealSize;
|
||||||
if (constrain && scaleX != 0 && scaleY != 0) {
|
if (constrain && scaleX != 0 && scaleY != 0) {
|
||||||
// TODO : snapping
|
|
||||||
Vector2D scale = newSize.div(tmpSize);
|
Vector2D scale = newSize.div(tmpSize);
|
||||||
scale = constrain_vector(scale, true, true);
|
scale = constrain_vector(scale, true, true);
|
||||||
newSize = tmpSize.mul(scale);
|
newSize = tmpSize.mul(scale);
|
||||||
newMin += (newRealSize - newSize).mul(Vector2D(scaleX == -1 ? 1 : 0, scaleY == -1 ? 1 : 0));
|
newMin += (newRealSize - newSize).mul(Vector2D(scaleX == -1 ? 1 : 0, scaleY == -1 ? 1 : 0));
|
||||||
|
// TODO : snapping
|
||||||
} else if (snap >= 0) {
|
} else if (snap >= 0) {
|
||||||
if (scaleX + scaleY < 0) {
|
if (scaleX + scaleY < 0) {
|
||||||
newMin = snap_vector(newMin, snap);
|
newMin = snap_vector(newMin, snap);
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@
|
|||||||
#include <util/reflect.hpp>
|
#include <util/reflect.hpp>
|
||||||
|
|
||||||
DECLARE_TYPEOF_COLLECTION(FieldP);
|
DECLARE_TYPEOF_COLLECTION(FieldP);
|
||||||
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,ValueP>));
|
DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA ValueP>);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Card
|
// ----------------------------------------------------------------------------- : Card
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include <util/io/package.hpp>
|
#include <util/io/package.hpp>
|
||||||
|
|
||||||
DECLARE_TYPEOF_COLLECTION(ChoiceField::ChoiceP);
|
DECLARE_TYPEOF_COLLECTION(ChoiceField::ChoiceP);
|
||||||
DECLARE_TYPEOF((map<String,ScriptableImage>));
|
DECLARE_TYPEOF(map<String COMMA ScriptableImage>);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : ChoiceField
|
// ----------------------------------------------------------------------------- : ChoiceField
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <data/format/image_to_symbol.hpp>
|
#include <data/format/image_to_symbol.hpp>
|
||||||
#include <gfx/bezier.hpp>
|
#include <gfx/bezier.hpp>
|
||||||
#include <util/error.hpp>
|
#include <util/error.hpp>
|
||||||
|
#include <util/platform.hpp>
|
||||||
|
|
||||||
DECLARE_TYPEOF_COLLECTION(ControlPointP);
|
DECLARE_TYPEOF_COLLECTION(ControlPointP);
|
||||||
DECLARE_TYPEOF_COLLECTION(SymbolPartP);
|
DECLARE_TYPEOF_COLLECTION(SymbolPartP);
|
||||||
@@ -99,7 +100,7 @@ bool is_mse1_symbol(const Image& img) {
|
|||||||
int r = *d++;
|
int r = *d++;
|
||||||
int g = *d++;
|
int g = *d++;
|
||||||
int b = *d++;
|
int b = *d++;
|
||||||
delta += fabs(r - b) + fabs(r - g) + fabs(b - g);
|
delta += abs(r - b) + abs(r - g) + abs(b - g);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (delta > 5000) return false; // not black & white enough
|
if (delta > 5000) return false; // not black & white enough
|
||||||
@@ -357,7 +358,7 @@ void straighten(SymbolPart& part) {
|
|||||||
Vector2D bb = next.delta_before.normalized();
|
Vector2D bb = next.delta_before.normalized();
|
||||||
// if the area beneath the polygon formed by the handles is small
|
// if the area beneath the polygon formed by the handles is small
|
||||||
// then it is a straight line
|
// then it is a straight line
|
||||||
double cpDot = fabs(aa.cross(ab)) + fabs(bb.cross(ab));
|
double cpDot = abs(aa.cross(ab)) + abs(bb.cross(ab));
|
||||||
if (cpDot < treshold) {
|
if (cpDot < treshold) {
|
||||||
cur.segment_after = next.segment_before = SEGMENT_LINE;
|
cur.segment_after = next.segment_before = SEGMENT_LINE;
|
||||||
cur.delta_after = next.delta_before = Vector2D();
|
cur.delta_after = next.delta_before = Vector2D();
|
||||||
@@ -374,7 +375,7 @@ void merge_lines(SymbolPart& part) {
|
|||||||
Vector2D a = part.getPoint(i-1)->pos, b = cur.pos, c = part.getPoint(i+1)->pos;
|
Vector2D a = part.getPoint(i-1)->pos, b = cur.pos, c = part.getPoint(i+1)->pos;
|
||||||
Vector2D ab = (a-b).normalized();
|
Vector2D ab = (a-b).normalized();
|
||||||
Vector2D bc = (b-c).normalized();
|
Vector2D bc = (b-c).normalized();
|
||||||
double angle_len = fabs( atan2(ab.x,ab.y) - atan2(bc.x,bc.y)) * (a-c).lengthSqr();
|
double angle_len = abs( atan2(ab.x,ab.y) - atan2(bc.x,bc.y)) * (a-c).lengthSqr();
|
||||||
bool keep = angle_len >= .0001;
|
bool keep = angle_len >= .0001;
|
||||||
if (!keep) {
|
if (!keep) {
|
||||||
part.points.erase(part.points.begin() + i);
|
part.points.erase(part.points.begin() + i);
|
||||||
|
|||||||
+313
-52
@@ -10,7 +10,12 @@
|
|||||||
#include <util/tagged_string.hpp>
|
#include <util/tagged_string.hpp>
|
||||||
|
|
||||||
class KeywordTrie;
|
class KeywordTrie;
|
||||||
DECLARE_TYPEOF((map<Char, KeywordTrie*>));
|
DECLARE_TYPEOF(map<Char COMMA KeywordTrie*>);
|
||||||
|
DECLARE_TYPEOF_COLLECTION(KeywordTrie*);
|
||||||
|
DECLARE_TYPEOF_COLLECTION(KeywordP);
|
||||||
|
DECLARE_TYPEOF_COLLECTION(KeywordParamP);
|
||||||
|
DECLARE_TYPEOF_COLLECTION(KeywordExpansionP);
|
||||||
|
DECLARE_TYPEOF_COLLECTION(const KeywordExpansion*);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Reflection
|
// ----------------------------------------------------------------------------- : Reflection
|
||||||
|
|
||||||
@@ -58,10 +63,91 @@ IMPLEMENT_REFLECTION(Keyword) {
|
|||||||
read_compat(tag, this);
|
read_compat(tag, this);
|
||||||
REFLECT(expansions);
|
REFLECT(expansions);
|
||||||
REFLECT(rules);
|
REFLECT(rules);
|
||||||
REFLECT(mode);
|
// REFLECT(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Regex stuff
|
||||||
|
|
||||||
|
/// Make sure the given regex does no capturing
|
||||||
|
/** Basicly replaces "(" with "(?:" */
|
||||||
|
String make_non_capturing(const String& re) {
|
||||||
|
String ret;
|
||||||
|
bool escape = false, bracket = false, capture = false;
|
||||||
|
FOR_EACH_CONST(c, re) {
|
||||||
|
if (capture && c != _('?')) {
|
||||||
|
// change this capture into a non-capturing "(" by appending "?:"
|
||||||
|
ret += _("?:");
|
||||||
|
capture = false;
|
||||||
|
}
|
||||||
|
if (escape) { // second char of escape sequence
|
||||||
|
escape = false;
|
||||||
|
} else if (c == _('\\')) { // start of escape sequence
|
||||||
|
escape = true;
|
||||||
|
} else if (c == _('[')) { // start of [...]
|
||||||
|
bracket = true;
|
||||||
|
} else if (c == _(']')) { // end of [...]
|
||||||
|
bracket = false;
|
||||||
|
} else if (bracket && c == _('(')) {
|
||||||
|
// wx has a bug, it counts the '(' in "[(]" as a matching group
|
||||||
|
// escape it so wx doesn't see it
|
||||||
|
ret += _('\\');
|
||||||
|
} else if (c == _('(')) { // start of capture?
|
||||||
|
capture = true;
|
||||||
|
}
|
||||||
|
ret += c;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Escape a single character for use in regular expressions
|
||||||
|
String regex_escape(Char c) {
|
||||||
|
if (c == _('(') || c == _(')') || c == _('[') || c == _(']') || c == _('{') ||
|
||||||
|
c == _('.') || c == _('^') || c == _('$') || c == _('#') || c == _('\\') ||
|
||||||
|
c == _('|') || c == _('+') || c == _('*') || c == _('?')) {
|
||||||
|
// c needs to be escaped
|
||||||
|
return _("\\") + String(1,c);
|
||||||
|
} else {
|
||||||
|
return String(1,c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeywordExpansion::prepare(const vector<KeywordParamP>& param_types, bool force) {
|
||||||
|
if (!force && matchRe.IsValid()) return;
|
||||||
|
parameters.clear();
|
||||||
|
// Prepare regex
|
||||||
|
// String regex;
|
||||||
|
vector<KeywordParamP>::const_iterator param = parameters.begin();
|
||||||
|
// Parse the 'match' string
|
||||||
|
for (size_t i = 0 ; i < match.size() ;) {
|
||||||
|
Char c = match.GetChar(i);
|
||||||
|
if (is_substr(match, i, _("<param"))) {
|
||||||
|
// parameter, determine type...
|
||||||
|
size_t start = skip_tag(match, i), end = match_close_tag(match, i);
|
||||||
|
String type = match.substr(start, end-start);
|
||||||
|
// find parameter type 'type'
|
||||||
|
KeywordParam* p = nullptr;
|
||||||
|
FOR_EACH_CONST(pt, param_types) {
|
||||||
|
if (pt->name == type) {
|
||||||
|
p = pt.get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!p) {
|
||||||
|
throw InternalError(_("Unknown keyword parameter type: ") + type);
|
||||||
|
}
|
||||||
|
// modify regex
|
||||||
|
regex += _("(") + make_non_capturing(p->match) + _(")");
|
||||||
|
i = skip_tag(match, end);
|
||||||
|
} else {
|
||||||
|
regex += regex_escape(c);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!matchRe.Compile(regex, wxRE_ADVANCED)) {
|
||||||
|
throw InternalError(_("Error creating match regex"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : KeywordTrie
|
// ----------------------------------------------------------------------------- : KeywordTrie
|
||||||
|
|
||||||
@@ -71,10 +157,13 @@ class KeywordTrie {
|
|||||||
KeywordTrie();
|
KeywordTrie();
|
||||||
~KeywordTrie();
|
~KeywordTrie();
|
||||||
|
|
||||||
map<Char, KeywordTrie*> children; ///< children after a given character (owned)
|
map<Char, KeywordTrie*> children; ///< children after a given character (owned)
|
||||||
KeywordTrie* on_any_star; ///< children on /.*/ (owned)
|
KeywordTrie* on_any_star; ///< children on /.*/ (owned or this)
|
||||||
Keyword* finished; ///< keywords that end in this node
|
vector<const KeywordExpansion*> finished; ///< keywords expansions that end in this node
|
||||||
|
|
||||||
|
/// Insert nodes representing the given character
|
||||||
|
/** return the node where the evaluation will be after matching the character */
|
||||||
|
KeywordTrie* insert(Char match);
|
||||||
/// Insert nodes representing the given string
|
/// Insert nodes representing the given string
|
||||||
/** return the node where the evaluation will be after matching the string */
|
/** return the node where the evaluation will be after matching the string */
|
||||||
KeywordTrie* insert(const String& match);
|
KeywordTrie* insert(const String& match);
|
||||||
@@ -94,73 +183,245 @@ KeywordTrie::~KeywordTrie() {
|
|||||||
FOR_EACH(c, children) {
|
FOR_EACH(c, children) {
|
||||||
delete c.second;
|
delete c.second;
|
||||||
}
|
}
|
||||||
delete on_any_star;
|
if (on_any_star != this) delete on_any_star;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeywordTrie* KeywordTrie::insert(Char c) {
|
||||||
|
KeywordTrie*& child = children[c];
|
||||||
|
if (!child) child = new KeywordTrie;
|
||||||
|
return child;
|
||||||
|
}
|
||||||
KeywordTrie* KeywordTrie::insert(const String& match) {
|
KeywordTrie* KeywordTrie::insert(const String& match) {
|
||||||
KeywordTrie* cur = this;
|
KeywordTrie* cur = this;
|
||||||
FOR_EACH_CONST(c, match) {
|
FOR_EACH_CONST(c, match) {
|
||||||
KeywordTrie*& child = cur->children[c];
|
cur = cur->insert(c);
|
||||||
if (!child) child = new KeywordTrie;
|
|
||||||
cur = child;
|
|
||||||
}
|
}
|
||||||
return cur;
|
return cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeywordTrie* KeywordTrie::insertAnyStar() {
|
KeywordTrie* KeywordTrie::insertAnyStar() {
|
||||||
if (!on_any_star) on_any_star = new KeywordTrie;
|
if (!on_any_star) on_any_star = new KeywordTrie;
|
||||||
|
on_any_star->on_any_star = on_any_star; // circular reference to itself
|
||||||
return on_any_star;
|
return on_any_star;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : KeywordMatcher
|
|
||||||
|
|
||||||
/// State of the matching algorithm
|
|
||||||
class KeywordMatcher {
|
|
||||||
public:
|
|
||||||
KeywordMatcher(const String& s);
|
|
||||||
private:
|
|
||||||
String str;
|
|
||||||
size_t pos;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : KeywordDatabase
|
// ----------------------------------------------------------------------------- : KeywordDatabase
|
||||||
|
|
||||||
/// A database of keywords to allow for fast matching
|
KeywordDatabase::KeywordDatabase()
|
||||||
/** NOTE: keywords may not be altered after they are added to the database,
|
: root(nullptr)
|
||||||
* The database should be rebuild.
|
{}
|
||||||
*/
|
|
||||||
class KeywordDatabase {
|
|
||||||
public:
|
|
||||||
/// Add a keyword to be matched
|
|
||||||
void addKeyword(const Keyword&);
|
|
||||||
|
|
||||||
/// Find the first matching keyword, return its position
|
KeywordDatabase::~KeywordDatabase() {
|
||||||
size_t firstMatch(const String& input, Keyword* keyword);
|
clear();
|
||||||
|
|
||||||
private:
|
|
||||||
KeywordTrie root;
|
|
||||||
};
|
|
||||||
|
|
||||||
void KeywordDatabase::addKeyword(const Keyword& kw) {
|
|
||||||
// TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Using keywords
|
void KeywordDatabase::clear() {
|
||||||
|
delete root;
|
||||||
KeywordDatabaseP new_keyword_database() {
|
root = nullptr;
|
||||||
return new_shared<KeywordDatabase>();
|
|
||||||
}
|
|
||||||
void add_keyword(KeywordDatabase& db, const Keyword& kw) {
|
|
||||||
db.addKeyword(kw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KeywordDatabase::add(const vector<KeywordP>& kws) {
|
||||||
String expand_keywords(const KeywordDatabase& db, const String& text) {
|
FOR_EACH_CONST(kw, kws) {
|
||||||
// 1. Remove all old reminder texts
|
add(*kw);
|
||||||
String s = remove_tag_contents(text, _("<atom-keyword>"));
|
}
|
||||||
// 2. Process keywords
|
}
|
||||||
|
void KeywordDatabase::add(const Keyword& kw) {
|
||||||
// TODO
|
FOR_EACH_CONST(e, kw.expansions) {
|
||||||
|
add(*e);
|
||||||
return s;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeywordDatabase::add(const KeywordExpansion& e) {
|
||||||
|
if (!root) {
|
||||||
|
root = new KeywordTrie;
|
||||||
|
root->on_any_star = root;
|
||||||
|
}
|
||||||
|
KeywordTrie* cur = root->insertAnyStar();
|
||||||
|
for (size_t i = 0 ; i < e.match.size() ;) {
|
||||||
|
Char c = e.match.GetChar(i);
|
||||||
|
if (is_substr(e.match, i, _("<param"))) {
|
||||||
|
// tag, parameter, match anything
|
||||||
|
cur = cur->insertAnyStar();
|
||||||
|
i = match_close_tag_end(e.match, i);
|
||||||
|
} else {
|
||||||
|
cur = cur->insert(c);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// now cur is the trie after matching the keyword anywhere in the input text
|
||||||
|
cur->finished.push_back(&e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeywordDatabase::prepare_parameters(const vector<KeywordParamP>& ps, const vector<KeywordP>& kws) {
|
||||||
|
FOR_EACH_CONST(kw, kws) {
|
||||||
|
prepare_parameters(ps, *kw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void KeywordDatabase::prepare_parameters(const vector<KeywordParamP>& ps, const Keyword& kw) {
|
||||||
|
FOR_EACH_CONST(e, kw.expansions) {
|
||||||
|
e->prepare(ps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : KeywordDatabase : matching
|
||||||
|
|
||||||
|
// transitive closure of a state, follow all on_any_star links
|
||||||
|
void closure(vector<KeywordTrie*>& state) {
|
||||||
|
for (size_t j = 0 ; j < state.size() ; ++j) {
|
||||||
|
if (state[j]->on_any_star && state[j]->on_any_star != state[j]) {
|
||||||
|
state.push_back(state[j]->on_any_star);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//DEBUG
|
||||||
|
void dump(int i, KeywordTrie* t) {
|
||||||
|
FOR_EACH(c, t->children) {
|
||||||
|
wxLogDebug(String(i,_(' ')) + c.first + _(" ") + String::Format(_("%p"),c.second));
|
||||||
|
dump(i+2, c.second);
|
||||||
|
}
|
||||||
|
if (t->on_any_star) {
|
||||||
|
wxLogDebug(String(i,_(' ')) + _(".*") + _(" ") + String::Format(_("%p"),t->on_any_star));
|
||||||
|
if (t->on_any_star != t) dump(i+2, t->on_any_star);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String KeywordDatabase::expand(const String& text,
|
||||||
|
const ScriptValueP& expand_default,
|
||||||
|
const ScriptValueP& combine_script,
|
||||||
|
Context& ctx) const {
|
||||||
|
// DEBUG: dump db
|
||||||
|
//dump(0, root);
|
||||||
|
|
||||||
|
assert(combine_script);
|
||||||
|
|
||||||
|
// Remove all old reminder texts
|
||||||
|
String s = remove_tag_contents(text, _("<atom-reminder>"));
|
||||||
|
s = remove_tag_contents(s, _("<atom-keyword>")); // OLD, TODO: REMOVEME
|
||||||
|
s = remove_tag(s, _("<keyword-param"));
|
||||||
|
String untagged = untag_no_escape(s);
|
||||||
|
|
||||||
|
if (!root) return s;
|
||||||
|
|
||||||
|
String result;
|
||||||
|
|
||||||
|
// Find keywords
|
||||||
|
while (!s.empty()) {
|
||||||
|
vector<KeywordTrie*> current; // current location(s) in the trie
|
||||||
|
vector<KeywordTrie*> next; // location(s) after this step
|
||||||
|
set<const KeywordExpansion*> used; // keywords already investigated
|
||||||
|
current.push_back(root);
|
||||||
|
closure(current);
|
||||||
|
char expand_type = 'a'; // is the keyword expanded? From <kw-?> tag
|
||||||
|
// Possible values are:
|
||||||
|
// - '0' = reminder text explicitly hidden
|
||||||
|
// - '1' = reminder text explicitly shown
|
||||||
|
// - 'a' = reminder text in default state, hidden
|
||||||
|
// - 'A' = reminder text in default state, shown
|
||||||
|
|
||||||
|
for (size_t i = 0 ; i < s.size() ;) {
|
||||||
|
Char c = s.GetChar(i);
|
||||||
|
// tag?
|
||||||
|
if (c == _('<')) {
|
||||||
|
if (is_substr(s, i, _("<kw-")) && i + 4 < s.size()) {
|
||||||
|
expand_type = s.GetChar(i + 4); // <kw-?>
|
||||||
|
s = s.erase(i, skip_tag(s,i)-i); // remove the tag from the string
|
||||||
|
} else if (is_substr(s, i, _("</kw-"))) {
|
||||||
|
expand_type = 'a';
|
||||||
|
s = s.erase(i, skip_tag(s,i)-i); // remove the tag from the string
|
||||||
|
} else {
|
||||||
|
i = skip_tag(s, i);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
// find 'next' trie node set matching c
|
||||||
|
FOR_EACH(kt, current) {
|
||||||
|
if (kt->on_any_star) {
|
||||||
|
next.push_back(kt->on_any_star);
|
||||||
|
}
|
||||||
|
map<Char,KeywordTrie*>::const_iterator it = kt->children.find(c);
|
||||||
|
if (it != kt->children.end()) {
|
||||||
|
next.push_back(it->second);
|
||||||
|
wxLogDebug(c + String(_(" -> ")) + String::Format(_("%p"), it->second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// next becomes current
|
||||||
|
swap(current, next);
|
||||||
|
next.clear();
|
||||||
|
closure(current);
|
||||||
|
// are we done?
|
||||||
|
FOR_EACH(n, current) {
|
||||||
|
FOR_EACH(f, n->finished) {
|
||||||
|
const KeywordExpansion* kw = f;
|
||||||
|
if (used.insert(kw).second) {
|
||||||
|
// we have found a possible match, which we have not seen before
|
||||||
|
assert(kw->matchRe.IsValid());
|
||||||
|
|
||||||
|
// try to match it against the *untagged* string
|
||||||
|
if (kw->matchRe.Matches(untagged)) {
|
||||||
|
// Everything before the keyword
|
||||||
|
size_t start_u, len_u;
|
||||||
|
kw->matchRe.GetMatch(&start_u, &len_u, 0);
|
||||||
|
size_t start = untagged_to_index(s, start_u, true),
|
||||||
|
end = untagged_to_index(s, start_u + len_u, true);
|
||||||
|
result += s.substr(0, start);
|
||||||
|
|
||||||
|
// Set parameters in context
|
||||||
|
size_t match_count = kw->matchRe.GetMatchCount();
|
||||||
|
for (size_t j = 1 ; j < match_count ; ++j) {
|
||||||
|
size_t start_u, len_u;
|
||||||
|
kw->matchRe.GetMatch(&start_u, &len_u, j);
|
||||||
|
String param = untagged.substr(start_u, len_u);
|
||||||
|
if (j-1 < kw->parameters.size() && kw->parameters[j-1]->script) {
|
||||||
|
// apply parameter script
|
||||||
|
param = kw->parameters[j-1]->script.invoke(ctx)->toString();
|
||||||
|
}
|
||||||
|
ctx.setVariable(String(_("param")) << (int)j, toScript(param));
|
||||||
|
}
|
||||||
|
ctx.setVariable(_("mode"), toScript(kw->mode));
|
||||||
|
|
||||||
|
// Show reminder text?
|
||||||
|
bool expand = expand_type == _('1');
|
||||||
|
if (!expand && expand_type != _('0')) {
|
||||||
|
// default expand, determined by script
|
||||||
|
expand = expand_default && (bool)*expand_default->eval(ctx);
|
||||||
|
expand_type = expand ? _('A') : _('a');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine keyword & reminder with result
|
||||||
|
if (expand) {
|
||||||
|
String reminder = kw->reminder.invoke(ctx)->toString();
|
||||||
|
ctx.setVariable(_("keyword"), toScript(s.substr(start, end - start)));
|
||||||
|
ctx.setVariable(_("reminder"), toScript(reminder));
|
||||||
|
result += _("<kw-"); result += expand_type; result += _(">");
|
||||||
|
result += combine_script->eval(ctx)->toString();
|
||||||
|
result += _("</kw-"); result += expand_type; result += _(">");
|
||||||
|
} else {
|
||||||
|
result += _("<kw-"); result += expand_type; result += _(">");
|
||||||
|
result += s.substr(start, end - start);
|
||||||
|
result += _("</kw-"); result += expand_type; result += _(">");
|
||||||
|
}
|
||||||
|
|
||||||
|
// After keyword
|
||||||
|
s = s.substr(end);
|
||||||
|
untagged = untagged.substr(start_u + len_u);
|
||||||
|
used.clear();
|
||||||
|
expand_type = _('a');
|
||||||
|
goto matched_keyword;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remainder of the string
|
||||||
|
result += s; s.clear();
|
||||||
|
|
||||||
|
matched_keyword:;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-16
@@ -16,6 +16,8 @@
|
|||||||
DECLARE_POINTER_TYPE(KeywordParam);
|
DECLARE_POINTER_TYPE(KeywordParam);
|
||||||
DECLARE_POINTER_TYPE(KeywordExpansion);
|
DECLARE_POINTER_TYPE(KeywordExpansion);
|
||||||
DECLARE_POINTER_TYPE(KeywordMode);
|
DECLARE_POINTER_TYPE(KeywordMode);
|
||||||
|
DECLARE_POINTER_TYPE(Keyword);
|
||||||
|
class KeywordTrie;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Keyword components
|
// ----------------------------------------------------------------------------- : Keyword components
|
||||||
|
|
||||||
@@ -24,8 +26,7 @@ class KeywordParam {
|
|||||||
public:
|
public:
|
||||||
String name; ///< Name of the parameter type
|
String name; ///< Name of the parameter type
|
||||||
String description; ///< Description of the type
|
String description; ///< Description of the type
|
||||||
String match; ///< Uncompiled regex
|
String match; ///< Regular expression to match
|
||||||
wxRegEx matchRe; ///< Regular expression to match
|
|
||||||
OptionalScript script; ///< Transformation of the value for showing in the reminder text
|
OptionalScript script; ///< Transformation of the value for showing in the reminder text
|
||||||
String example; ///< Example for preview dialog
|
String example; ///< Example for preview dialog
|
||||||
|
|
||||||
@@ -49,9 +50,18 @@ class KeywordExpansion {
|
|||||||
public:
|
public:
|
||||||
String match; ///< String to match, <param> tags are used for parameters
|
String match; ///< String to match, <param> tags are used for parameters
|
||||||
vector<KeywordParamP> parameters; ///< The types of parameters
|
vector<KeywordParamP> parameters; ///< The types of parameters
|
||||||
// wxRegEx splitter; ///< Regular expression to split/match the components, automatically generated
|
wxRegEx matchRe; ///< Regular expression to match and split parameters, automatically generated
|
||||||
StringScript reminder; ///< Reminder text of the keyword
|
StringScript reminder; ///< Reminder text of the keyword
|
||||||
String mode; ///< Mode of use, can be used by scripts (only gives the name). Default is the mode of the Keyword.
|
String mode; ///< Mode of use, can be used by scripts (only gives the name)
|
||||||
|
// . Default is the mode of the Keyword.
|
||||||
|
String regex;//TODO REMOVE
|
||||||
|
|
||||||
|
/// Prepare the expansion: (re)generate matchRe and the list of parameters.
|
||||||
|
/** Throws when there is an error in the input
|
||||||
|
* @param param_types A list of all parameter types.
|
||||||
|
* @param force Re-prepare even if the regex¶meters are okay
|
||||||
|
*/
|
||||||
|
void prepare(const vector<KeywordParamP>& param_types, bool force = false);
|
||||||
|
|
||||||
DECLARE_REFLECTION();
|
DECLARE_REFLECTION();
|
||||||
};
|
};
|
||||||
@@ -64,7 +74,7 @@ class Keyword {
|
|||||||
String keyword; ///< The keyword
|
String keyword; ///< The keyword
|
||||||
vector<KeywordExpansionP> expansions; ///< Expansions, i.e. ways to use this keyword
|
vector<KeywordExpansionP> expansions; ///< Expansions, i.e. ways to use this keyword
|
||||||
String rules; ///< Rules/explanation
|
String rules; ///< Rules/explanation
|
||||||
String mode; ///< Mode of use, can be used by scripts (only gives the name)
|
// String mode; ///< Mode of use, can be used by scripts (only gives the name)
|
||||||
|
|
||||||
DECLARE_REFLECTION();
|
DECLARE_REFLECTION();
|
||||||
};
|
};
|
||||||
@@ -72,21 +82,41 @@ class Keyword {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Using keywords
|
// ----------------------------------------------------------------------------- : Using keywords
|
||||||
|
|
||||||
/// A class that allows for fast matching of keywords
|
/// A database of keywords to allow for fast matching
|
||||||
class KeywordDatabase;
|
|
||||||
DECLARE_POINTER_TYPE(KeywordDatabase);
|
|
||||||
|
|
||||||
/// Create a new keyword database
|
|
||||||
KeywordDatabaseP new_keyword_database();
|
|
||||||
|
|
||||||
/// Add a keyword to a KeywordDatabase
|
|
||||||
/** NOTE: keywords may not be altered after they are added to the database,
|
/** NOTE: keywords may not be altered after they are added to the database,
|
||||||
* The database should be rebuild.
|
* The database should be rebuild.
|
||||||
*/
|
*/
|
||||||
void add_keyword(KeywordDatabase& db, const Keyword& kw);
|
class KeywordDatabase {
|
||||||
|
public:
|
||||||
|
KeywordDatabase();
|
||||||
|
~KeywordDatabase();
|
||||||
|
|
||||||
/// Expand/update all keywords in the given string
|
/// Add a list of keywords to be matched
|
||||||
String expand_keywords(const KeywordDatabase& db, const String& text);
|
void add(const vector<KeywordP>&);
|
||||||
|
/// Add a keyword to be matched
|
||||||
|
void add(const Keyword&);
|
||||||
|
/// Add an expansion of a keyword to be matched
|
||||||
|
void add(const KeywordExpansion&);
|
||||||
|
|
||||||
|
/// Prepare the parameters and match regex for a list of keywords
|
||||||
|
static void prepare_parameters(const vector<KeywordParamP>&, const vector<KeywordP>&);
|
||||||
|
static void prepare_parameters(const vector<KeywordParamP>&, const Keyword&);
|
||||||
|
|
||||||
|
/// Clear the database
|
||||||
|
void clear();
|
||||||
|
/// Is the database empty?
|
||||||
|
inline bool empty() const { return !root; }
|
||||||
|
|
||||||
|
/// Expand/update all keywords in the given string.
|
||||||
|
/** @param expand_default script function indicating whether reminder text should be shown by default
|
||||||
|
* @param combine_script script function to combine keyword and reminder text in some way
|
||||||
|
* @param ctx context for evaluation of scripts
|
||||||
|
*/
|
||||||
|
String expand(const String& text, const ScriptValueP& expand_default, const ScriptValueP& combine_script, Context& ctx) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
KeywordTrie* root; ///< Data structure for finding keywords
|
||||||
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : EOF
|
// ----------------------------------------------------------------------------- : EOF
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@
|
|||||||
#include <wx/sstream.h>
|
#include <wx/sstream.h>
|
||||||
|
|
||||||
DECLARE_TYPEOF_COLLECTION(CardP);
|
DECLARE_TYPEOF_COLLECTION(CardP);
|
||||||
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,ValueP>));
|
DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA ValueP>);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Set
|
// ----------------------------------------------------------------------------- : Set
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <util/action_stack.hpp>
|
#include <util/action_stack.hpp>
|
||||||
#include <util/io/package.hpp>
|
#include <util/io/package.hpp>
|
||||||
#include <data/field.hpp> // for Set::value
|
#include <data/field.hpp> // for Set::value
|
||||||
|
#include <data/keyword.hpp>
|
||||||
#include <boost/scoped_ptr.hpp>
|
#include <boost/scoped_ptr.hpp>
|
||||||
|
|
||||||
DECLARE_POINTER_TYPE(Card);
|
DECLARE_POINTER_TYPE(Card);
|
||||||
@@ -57,6 +58,7 @@ class Set : public Packaged {
|
|||||||
vector<KeywordP> keywords; ///< Additional keywords used in this set
|
vector<KeywordP> keywords; ///< Additional keywords used in this set
|
||||||
String apprentice_code; ///< Code to use for apprentice (Magic only)
|
String apprentice_code; ///< Code to use for apprentice (Magic only)
|
||||||
ActionStack actions; ///< Actions performed on this set and the cards in it
|
ActionStack actions; ///< Actions performed on this set and the cards in it
|
||||||
|
KeywordDatabase keyword_db; ///< Database for matching keywords, must be cleared when keywords change
|
||||||
|
|
||||||
/// A context for performing scripts
|
/// A context for performing scripts
|
||||||
/** Should only be used from the main thread! */
|
/** Should only be used from the main thread! */
|
||||||
|
|||||||
@@ -26,8 +26,8 @@
|
|||||||
DECLARE_TYPEOF_COLLECTION(CardP);
|
DECLARE_TYPEOF_COLLECTION(CardP);
|
||||||
DECLARE_TYPEOF_COLLECTION(FieldP);
|
DECLARE_TYPEOF_COLLECTION(FieldP);
|
||||||
DECLARE_POINTER_TYPE(ChoiceValue);
|
DECLARE_POINTER_TYPE(ChoiceValue);
|
||||||
DECLARE_TYPEOF((map<int,FieldP>));
|
DECLARE_TYPEOF(map<int COMMA FieldP>);
|
||||||
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,StyleP>));
|
DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA StyleP>);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Events
|
// ----------------------------------------------------------------------------- : Events
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ DECLARE_TYPEOF_COLLECTION(GraphAxisP);
|
|||||||
DECLARE_TYPEOF_COLLECTION(GraphElementP);
|
DECLARE_TYPEOF_COLLECTION(GraphElementP);
|
||||||
DECLARE_TYPEOF_COLLECTION(GraphGroup);
|
DECLARE_TYPEOF_COLLECTION(GraphGroup);
|
||||||
DECLARE_TYPEOF_COLLECTION(int);
|
DECLARE_TYPEOF_COLLECTION(int);
|
||||||
DECLARE_TYPEOF((map<String,UInt>));
|
DECLARE_TYPEOF(map<String COMMA UInt>);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Events
|
// ----------------------------------------------------------------------------- : Events
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#include <data/stylesheet.hpp>
|
#include <data/stylesheet.hpp>
|
||||||
|
|
||||||
DECLARE_TYPEOF_COLLECTION(ValueViewerP);
|
DECLARE_TYPEOF_COLLECTION(ValueViewerP);
|
||||||
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,StyleP>));
|
DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA StyleP>);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : NativeLookEditor
|
// ----------------------------------------------------------------------------- : NativeLookEditor
|
||||||
|
|
||||||
|
|||||||
@@ -570,7 +570,7 @@ void TextValueEditor::fixSelection(IndexType t, Movement dir) {
|
|||||||
// start and end must be on the same side of separators
|
// start and end must be on the same side of separators
|
||||||
size_t seppos = val.find(_("<sep"));
|
size_t seppos = val.find(_("<sep"));
|
||||||
while (seppos != String::npos) {
|
while (seppos != String::npos) {
|
||||||
size_t sepend = skip_tag(val,match_close_tag(val, seppos));
|
size_t sepend = match_close_tag_end(val, seppos);
|
||||||
if (selection_start_i <= seppos && selection_end_i > seppos) {
|
if (selection_start_i <= seppos && selection_end_i > seppos) {
|
||||||
// not on same side, move selection end before sep
|
// not on same side, move selection end before sep
|
||||||
selection_end = index_to_cursor(val, seppos, dir);
|
selection_end = index_to_cursor(val, seppos, dir);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#include <gui/util.hpp> // clearDC
|
#include <gui/util.hpp> // clearDC
|
||||||
|
|
||||||
DECLARE_TYPEOF_COLLECTION(ValueViewerP);
|
DECLARE_TYPEOF_COLLECTION(ValueViewerP);
|
||||||
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,StyleP>));
|
DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA StyleP>);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : DataViewer
|
// ----------------------------------------------------------------------------- : DataViewer
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ bool_no IMAGE "../common/bool_no.png"
|
|||||||
//help_page BITMAP "help_page.png"
|
//help_page BITMAP "help_page.png"
|
||||||
|
|
||||||
about IMAGE "../common/about.png"
|
about IMAGE "../common/about.png"
|
||||||
two_beta IMAGE "../common/two_beta.png"
|
two_beta IMAGE "../common/two_beta.png"
|
||||||
btn_normal IMAGE "../common/btn_normal.png"
|
btn_normal IMAGE "../common/btn_normal.png"
|
||||||
btn_hover IMAGE "../common/btn_hover.png"
|
btn_hover IMAGE "../common/btn_hover.png"
|
||||||
btn_focus IMAGE "../common/btn_focus.png"
|
btn_focus IMAGE "../common/btn_focus.png"
|
||||||
@@ -155,7 +155,7 @@ FILETYPE VFT_APP
|
|||||||
VALUE "License", "GNU General Public License 2 or later; This is free software, and you are welcome to redistribute it under certain conditions; See the help file for details"
|
VALUE "License", "GNU General Public License 2 or later; This is free software, and you are welcome to redistribute it under certain conditions; See the help file for details"
|
||||||
VALUE "FileDescription", "Magic Set Editor"
|
VALUE "FileDescription", "Magic Set Editor"
|
||||||
VALUE "InternalName", "mse2/8"
|
VALUE "InternalName", "mse2/8"
|
||||||
VALUE "LegalCopyright", " 2001-2006 Twan van Laarhoven"
|
VALUE "LegalCopyright", "© 2001-2006 Twan van Laarhoven"
|
||||||
VALUE "ProductName", "Magic Set Editor"
|
VALUE "ProductName", "Magic Set Editor"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ void instrUnary (UnaryInstructionType i, ScriptValueP& a) {
|
|||||||
a = toScript(-(int)*a);
|
a = toScript(-(int)*a);
|
||||||
break;
|
break;
|
||||||
case I_NOT:
|
case I_NOT:
|
||||||
a = toScript(!(int)*a);
|
a = toScript(!(bool)*a);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+61
-29
@@ -12,6 +12,7 @@
|
|||||||
#include <util/tagged_string.hpp>
|
#include <util/tagged_string.hpp>
|
||||||
#include <data/set.hpp>
|
#include <data/set.hpp>
|
||||||
#include <data/game.hpp>
|
#include <data/game.hpp>
|
||||||
|
#include <data/keyword.hpp>
|
||||||
#include <data/field/text.hpp>
|
#include <data/field/text.hpp>
|
||||||
#include <wx/regex.h>
|
#include <wx/regex.h>
|
||||||
|
|
||||||
@@ -265,7 +266,7 @@ String spec_sort(const String& spec, const String& input) {
|
|||||||
ScriptValueP ScriptRule_##funname::eval(Context& ctx) const
|
ScriptValueP ScriptRule_##funname::eval(Context& ctx) const
|
||||||
|
|
||||||
// Utility for defining a script rule with two parameters
|
// Utility for defining a script rule with two parameters
|
||||||
#define SCRIPT_RULE_2(funname, type1, name1, type2, name2) \
|
#define SCRIPT_RULE_2_N(funname, type1, str1, name1, type2, str2, name2) \
|
||||||
class ScriptRule_##funname: public ScriptValue { \
|
class ScriptRule_##funname: public ScriptValue { \
|
||||||
public: \
|
public: \
|
||||||
inline ScriptRule_##funname(const type1& name1, const type2& name2) \
|
inline ScriptRule_##funname(const type1& name1, const type2& name2) \
|
||||||
@@ -278,16 +279,18 @@ String spec_sort(const String& spec, const String& input) {
|
|||||||
type2 name2; \
|
type2 name2; \
|
||||||
}; \
|
}; \
|
||||||
SCRIPT_FUNCTION(funname##_rule) { \
|
SCRIPT_FUNCTION(funname##_rule) { \
|
||||||
SCRIPT_PARAM(type1, name1); \
|
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||||
SCRIPT_PARAM(type2, name2); \
|
SCRIPT_PARAM_N(type2, str2, name2); \
|
||||||
return new_intrusive2<ScriptRule_##funname>(name1, name2); \
|
return new_intrusive2<ScriptRule_##funname>(name1, name2); \
|
||||||
} \
|
} \
|
||||||
SCRIPT_FUNCTION(funname) { \
|
SCRIPT_FUNCTION(funname) { \
|
||||||
SCRIPT_PARAM(type1, name1); \
|
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||||
SCRIPT_PARAM(type2, name2); \
|
SCRIPT_PARAM_N(type2, str2, name2); \
|
||||||
return ScriptRule_##funname(name1, name2).eval(ctx); \
|
return ScriptRule_##funname(name1, name2).eval(ctx); \
|
||||||
} \
|
} \
|
||||||
ScriptValueP ScriptRule_##funname::eval(Context& ctx) const
|
ScriptValueP ScriptRule_##funname::eval(Context& ctx) const
|
||||||
|
#define SCRIPT_RULE_2(funname, type1, name1, type2, name2) \
|
||||||
|
SCRIPT_RULE_2_N(funname, type1, _(#name1), name1, type2, _(#name2), name2)
|
||||||
|
|
||||||
|
|
||||||
// Create a rule for spec_sorting strings
|
// Create a rule for spec_sorting strings
|
||||||
@@ -339,10 +342,21 @@ SCRIPT_FUNCTION(contains) {
|
|||||||
SCRIPT_RETURN(input.find(match) != String::npos);
|
SCRIPT_RETURN(input.find(match) != String::npos);
|
||||||
}
|
}
|
||||||
|
|
||||||
SCRIPT_FUNCTION(format) {
|
SCRIPT_RULE_1(format, String, format) {
|
||||||
SCRIPT_PARAM(String, format);
|
String fmt = _("%") + replace_all(format, _("%"), _(""));
|
||||||
SCRIPT_PARAM(String, input);
|
// determine type expected by format string
|
||||||
SCRIPT_RETURN(format_string(_("%") + replace_all(format, _("%"), _("")), input));
|
if (format.find_first_of(_("DdIiOoXx")) != String.npos) {
|
||||||
|
SCRIPT_PARAM(int, input);
|
||||||
|
SCRIPT_RETURN(String::Format(fmt, input));
|
||||||
|
} else if (format.find_first_of(_("EeFfGg")) != String.npos) {
|
||||||
|
SCRIPT_PARAM(double, input);
|
||||||
|
SCRIPT_RETURN(String::Format(fmt, input));
|
||||||
|
} else if (format.find_first_of(_("Ss")) != String.npos) {
|
||||||
|
SCRIPT_PARAM(String, input);
|
||||||
|
SCRIPT_RETURN(format_string(fmt, input));
|
||||||
|
} else {
|
||||||
|
throw ScriptError(_ERROR_1_("unsupported format", format));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Tagged stuff
|
// ----------------------------------------------------------------------------- : Tagged stuff
|
||||||
@@ -381,7 +395,23 @@ SCRIPT_RULE_1(tag_remove, String, tag) {
|
|||||||
SCRIPT_RETURN(remove_tag(input, tag));
|
SCRIPT_RETURN(remove_tag(input, tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Vector stuff
|
// ----------------------------------------------------------------------------- : Keywords
|
||||||
|
|
||||||
|
SCRIPT_RULE_2_N(expand_keywords, ScriptValueP, _("default expand"), default_expand,
|
||||||
|
ScriptValueP, _("combine"), combine) {
|
||||||
|
SCRIPT_PARAM(String, input);
|
||||||
|
SCRIPT_PARAM(Set*, set);
|
||||||
|
KeywordDatabase& db = set->keyword_db;
|
||||||
|
if (db.empty()) {
|
||||||
|
db.add(set->game->keywords);
|
||||||
|
db.add(set->keywords);
|
||||||
|
db.prepare_parameters(set->game->keyword_parameter_types, set->game->keywords);
|
||||||
|
db.prepare_parameters(set->game->keyword_parameter_types, set->keywords);
|
||||||
|
}
|
||||||
|
SCRIPT_RETURN(db.expand(input, default_expand, combine, ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Collection stuff
|
||||||
|
|
||||||
/// compare script values for equallity
|
/// compare script values for equallity
|
||||||
bool equal(const ScriptValue& a, const ScriptValue& b) {
|
bool equal(const ScriptValue& a, const ScriptValue& b) {
|
||||||
@@ -497,7 +527,7 @@ SCRIPT_FUNCTION_DEP(combined_editor) {
|
|||||||
size_t pos = value.find(_("<sep"));
|
size_t pos = value.find(_("<sep"));
|
||||||
while (pos != String::npos) {
|
while (pos != String::npos) {
|
||||||
value_parts.push_back(value.substr(0, pos));
|
value_parts.push_back(value.substr(0, pos));
|
||||||
value = value.substr(min(skip_tag(value,match_close_tag(value,pos)), value.size()));
|
value = value.substr(min(match_close_tag_end(value,pos), value.size()));
|
||||||
pos = value.find(_("<sep"));
|
pos = value.find(_("<sep"));
|
||||||
}
|
}
|
||||||
value_parts.push_back(value);
|
value_parts.push_back(value);
|
||||||
@@ -579,23 +609,25 @@ ScriptValueP ScriptBuildin_combined_editor::dependencies(Context& ctx, const Dep
|
|||||||
// ----------------------------------------------------------------------------- : Initialize functions
|
// ----------------------------------------------------------------------------- : Initialize functions
|
||||||
|
|
||||||
void init_script_functions(Context& ctx) {
|
void init_script_functions(Context& ctx) {
|
||||||
ctx.setVariable(_("replace rule"), script_replace_rule);
|
ctx.setVariable(_("replace rule"), script_replace_rule);
|
||||||
ctx.setVariable(_("filter rule"), script_filter_rule);
|
ctx.setVariable(_("filter rule"), script_filter_rule);
|
||||||
ctx.setVariable(_("sort"), script_sort);
|
ctx.setVariable(_("sort"), script_sort);
|
||||||
ctx.setVariable(_("sort rule"), script_sort_rule);
|
ctx.setVariable(_("sort rule"), script_sort_rule);
|
||||||
ctx.setVariable(_("to upper"), script_to_upper);
|
ctx.setVariable(_("to upper"), script_to_upper);
|
||||||
ctx.setVariable(_("to lower"), script_to_lower);
|
ctx.setVariable(_("to lower"), script_to_lower);
|
||||||
ctx.setVariable(_("to title"), script_to_title);
|
ctx.setVariable(_("to title"), script_to_title);
|
||||||
ctx.setVariable(_("substring"), script_substring);
|
ctx.setVariable(_("substring"), script_substring);
|
||||||
ctx.setVariable(_("contains"), script_contains);
|
ctx.setVariable(_("contains"), script_contains);
|
||||||
ctx.setVariable(_("format"), script_format);
|
ctx.setVariable(_("format"), script_format);
|
||||||
ctx.setVariable(_("tag contents"), script_tag_contents);
|
ctx.setVariable(_("tag contents"), script_tag_contents);
|
||||||
ctx.setVariable(_("remove tag"), script_tag_remove);
|
ctx.setVariable(_("remove tag"), script_tag_remove);
|
||||||
ctx.setVariable(_("tag contents rule"), script_tag_contents_rule);
|
ctx.setVariable(_("tag contents rule"), script_tag_contents_rule);
|
||||||
ctx.setVariable(_("tag remove rule"), script_tag_remove_rule);
|
ctx.setVariable(_("tag remove rule"), script_tag_remove_rule);
|
||||||
ctx.setVariable(_("position"), script_position_of);
|
ctx.setVariable(_("expand keywords rule"), script_expand_keywords_rule);
|
||||||
ctx.setVariable(_("number of items"), script_number_of_items);
|
ctx.setVariable(_("expand keywords"), script_expand_keywords);
|
||||||
ctx.setVariable(_("forward editor"), script_combined_editor);
|
ctx.setVariable(_("position"), script_position_of);
|
||||||
ctx.setVariable(_("combined editor"), script_combined_editor);
|
ctx.setVariable(_("number of items"), script_number_of_items);
|
||||||
|
ctx.setVariable(_("forward editor"), script_combined_editor);
|
||||||
|
ctx.setVariable(_("combined editor"), script_combined_editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ ScriptImageP to_script_image(const ScriptValueP& value) {
|
|||||||
/// Is the given image up to date?
|
/// Is the given image up to date?
|
||||||
bool script_image_up_to_date(const ScriptValueP& value) {
|
bool script_image_up_to_date(const ScriptValueP& value) {
|
||||||
if (value->type() == SCRIPT_INT) {
|
if (value->type() == SCRIPT_INT) {
|
||||||
return (int)*value; // boolean up-to-dateness from parameter
|
return (bool)*value; // boolean up-to-dateness from parameter
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ DECLARE_TYPEOF(Contexts);
|
|||||||
DECLARE_TYPEOF_COLLECTION(CardP);
|
DECLARE_TYPEOF_COLLECTION(CardP);
|
||||||
DECLARE_TYPEOF_COLLECTION(FieldP);
|
DECLARE_TYPEOF_COLLECTION(FieldP);
|
||||||
DECLARE_TYPEOF_COLLECTION(Dependency);
|
DECLARE_TYPEOF_COLLECTION(Dependency);
|
||||||
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,StyleP>));
|
DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA StyleP>);
|
||||||
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,ValueP>));
|
DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA ValueP>);
|
||||||
|
|
||||||
// initialize functions, from functions.cpp
|
// initialize functions, from functions.cpp
|
||||||
void init_script_functions(Context& ctx);
|
void init_script_functions(Context& ctx);
|
||||||
|
|||||||
+10
-8
@@ -53,13 +53,13 @@ class ScriptCollection : public ScriptValue {
|
|||||||
public:
|
public:
|
||||||
inline ScriptCollection(const Collection* v) : value(v) {}
|
inline ScriptCollection(const Collection* v) : value(v) {}
|
||||||
virtual ScriptType type() const { return SCRIPT_COLLECTION; }
|
virtual ScriptType type() const { return SCRIPT_COLLECTION; }
|
||||||
virtual String typeName() const { return _("collection"); }
|
virtual String typeName() const { return _TYPE_("collection"); }
|
||||||
virtual ScriptValueP getMember(const String& name) const {
|
virtual ScriptValueP getMember(const String& name) const {
|
||||||
long index;
|
long index;
|
||||||
if (name.ToLong(&index) && index >= 0 && (size_t)index < value->size()) {
|
if (name.ToLong(&index) && index >= 0 && (size_t)index < value->size()) {
|
||||||
return toScript(value->at(index));
|
return toScript(value->at(index));
|
||||||
} else {
|
} else {
|
||||||
throw ScriptError(_("Collection has no member ") + name);
|
return ScriptValue::getMember(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual ScriptValueP makeIterator() const {
|
virtual ScriptValueP makeIterator() const {
|
||||||
@@ -79,7 +79,7 @@ ScriptValueP get_member(const map<String,V>& m, const String& name) {
|
|||||||
if (it != m.end()) {
|
if (it != m.end()) {
|
||||||
return toScript(it->second);
|
return toScript(it->second);
|
||||||
} else {
|
} else {
|
||||||
throw ScriptError(_ERROR_1_("collection has no member", name));
|
throw ScriptError(_ERROR_2_("has no member", _TYPE_("collection"), name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ ScriptValueP get_member(const IndexMap<K,V>& m, const String& name) {
|
|||||||
if (it != m.end()) {
|
if (it != m.end()) {
|
||||||
return toScript(*it);
|
return toScript(*it);
|
||||||
} else {
|
} else {
|
||||||
throw ScriptError(_ERROR_1_("collection has no member", name));
|
throw ScriptError(_ERROR_2_("has no member", _TYPE_("collection"), name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ class ScriptMap : public ScriptValue {
|
|||||||
public:
|
public:
|
||||||
inline ScriptMap(const Collection* v) : value(v) {}
|
inline ScriptMap(const Collection* v) : value(v) {}
|
||||||
virtual ScriptType type() const { return SCRIPT_COLLECTION; }
|
virtual ScriptType type() const { return SCRIPT_COLLECTION; }
|
||||||
virtual String typeName() const { return _("collection"); }
|
virtual String typeName() const { return _TYPE_("collection"); }
|
||||||
virtual ScriptValueP getMember(const String& name) const {
|
virtual ScriptValueP getMember(const String& name) const {
|
||||||
return get_member(*value, name);
|
return get_member(*value, name);
|
||||||
}
|
}
|
||||||
@@ -132,7 +132,7 @@ class ScriptObject : public ScriptValue {
|
|||||||
public:
|
public:
|
||||||
inline ScriptObject(const T& v) : value(v) {}
|
inline ScriptObject(const T& v) : value(v) {}
|
||||||
virtual ScriptType type() const { return SCRIPT_OBJECT; }
|
virtual ScriptType type() const { return SCRIPT_OBJECT; }
|
||||||
virtual String typeName() const { return _("object"); }
|
virtual String typeName() const { return _TYPE_("object"); }
|
||||||
virtual operator String() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator String(); }
|
virtual operator String() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator String(); }
|
||||||
virtual operator double() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator double(); }
|
virtual operator double() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator double(); }
|
||||||
virtual operator int() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator int(); }
|
virtual operator int() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator int(); }
|
||||||
@@ -147,7 +147,7 @@ class ScriptObject : public ScriptValue {
|
|||||||
if (d) {
|
if (d) {
|
||||||
return d->getMember(name);
|
return d->getMember(name);
|
||||||
} else {
|
} else {
|
||||||
throw ScriptError(_ERROR_1_("object has no member", name));
|
throw ScriptValue::getMember(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,7 +239,9 @@ inline ScriptValueP toScript(const Defaultable<T>& v) { return toScript(v()); }
|
|||||||
* Throws an error if the parameter is not found.
|
* Throws an error if the parameter is not found.
|
||||||
*/
|
*/
|
||||||
#define SCRIPT_PARAM(Type, name) \
|
#define SCRIPT_PARAM(Type, name) \
|
||||||
Type name = getParam<Type>(ctx.getVariable(_(#name)))
|
SCRIPT_PARAM_N(Type, _(#name), name)
|
||||||
|
#define SCRIPT_PARAM_N(Type, str, name) \
|
||||||
|
Type name = getParam<Type>(ctx.getVariable(str))
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline T getParam (const ScriptValueP& value) {
|
inline T getParam (const ScriptValueP& value) {
|
||||||
|
|||||||
+17
-17
@@ -15,14 +15,14 @@
|
|||||||
// Base cases
|
// Base cases
|
||||||
|
|
||||||
ScriptValue::operator String() const { return _("[[") + typeName() + _("]]"); }
|
ScriptValue::operator String() const { return _("[[") + typeName() + _("]]"); }
|
||||||
ScriptValue::operator int() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to integer number")); }
|
ScriptValue::operator int() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("integer" ))); }
|
||||||
ScriptValue::operator double() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to real number" )); }
|
ScriptValue::operator double() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("real" ))); }
|
||||||
ScriptValue::operator Color() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to color" )); }
|
ScriptValue::operator Color() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("color" ))); }
|
||||||
ScriptValueP ScriptValue::eval(Context&) const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to function" )); }
|
ScriptValueP ScriptValue::eval(Context&) const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("function"))); }
|
||||||
ScriptValueP ScriptValue::getMember(const String& name) const { throw ScriptError(typeName() + _(" has no member '") + name + _("'")); }
|
ScriptValueP ScriptValue::getMember(const String& name) const { throw ScriptError(_ERROR_2_("has no member", typeName(), name)); }
|
||||||
ScriptValueP ScriptValue::next() { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); }
|
ScriptValueP ScriptValue::next() { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); }
|
||||||
ScriptValueP ScriptValue::makeIterator() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to collection")); }
|
ScriptValueP ScriptValue::makeIterator() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("collection"))); }
|
||||||
int ScriptValue::itemCount() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to collection")); }
|
int ScriptValue::itemCount() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("collection"))); }
|
||||||
|
|
||||||
ScriptValueP ScriptValue::dependencyMember(const String& name, const Dependency&) const { return dependency_dummy; }
|
ScriptValueP ScriptValue::dependencyMember(const String& name, const Dependency&) const { return dependency_dummy; }
|
||||||
ScriptValueP ScriptValue::dependencies(Context&, const Dependency&) const { return dependency_dummy; }
|
ScriptValueP ScriptValue::dependencies(Context&, const Dependency&) const { return dependency_dummy; }
|
||||||
@@ -63,7 +63,7 @@ class ScriptInt : public ScriptValue {
|
|||||||
public:
|
public:
|
||||||
ScriptInt(int v) : value(v) {}
|
ScriptInt(int v) : value(v) {}
|
||||||
virtual ScriptType type() const { return SCRIPT_INT; }
|
virtual ScriptType type() const { return SCRIPT_INT; }
|
||||||
virtual String typeName() const { return _("integer number"); }
|
virtual String typeName() const { return _TYPE_("integer"); }
|
||||||
virtual operator String() const { return String() << value; }
|
virtual operator String() const { return String() << value; }
|
||||||
virtual operator double() const { return value; }
|
virtual operator double() const { return value; }
|
||||||
virtual operator int() const { return value; }
|
virtual operator int() const { return value; }
|
||||||
@@ -108,7 +108,7 @@ class ScriptBool : public ScriptValue {
|
|||||||
public:
|
public:
|
||||||
ScriptBool(bool v) : value(v) {}
|
ScriptBool(bool v) : value(v) {}
|
||||||
virtual ScriptType type() const { return SCRIPT_INT; }
|
virtual ScriptType type() const { return SCRIPT_INT; }
|
||||||
virtual String typeName() const { return _("boolean"); }
|
virtual String typeName() const { return _TYPE_("boolean"); }
|
||||||
virtual operator String() const { return value ? _("true") : _("false"); }
|
virtual operator String() const { return value ? _("true") : _("false"); }
|
||||||
virtual operator int() const { return value; }
|
virtual operator int() const { return value; }
|
||||||
private:
|
private:
|
||||||
@@ -130,7 +130,7 @@ class ScriptDouble : public ScriptValue {
|
|||||||
public:
|
public:
|
||||||
ScriptDouble(double v) : value(v) {}
|
ScriptDouble(double v) : value(v) {}
|
||||||
virtual ScriptType type() const { return SCRIPT_DOUBLE; }
|
virtual ScriptType type() const { return SCRIPT_DOUBLE; }
|
||||||
virtual String typeName() const { return _("real number"); }
|
virtual String typeName() const { return _TYPE_("real"); }
|
||||||
virtual operator String() const { return String() << value; }
|
virtual operator String() const { return String() << value; }
|
||||||
virtual operator double() const { return value; }
|
virtual operator double() const { return value; }
|
||||||
virtual operator int() const { return (int)value; }
|
virtual operator int() const { return (int)value; }
|
||||||
@@ -149,14 +149,14 @@ class ScriptString : public ScriptValue {
|
|||||||
public:
|
public:
|
||||||
ScriptString(const String& v) : value(v) {}
|
ScriptString(const String& v) : value(v) {}
|
||||||
virtual ScriptType type() const { return SCRIPT_STRING; }
|
virtual ScriptType type() const { return SCRIPT_STRING; }
|
||||||
virtual String typeName() const { return _("string"); }
|
virtual String typeName() const { return _TYPE_("string"); }
|
||||||
virtual operator String() const { return value; }
|
virtual operator String() const { return value; }
|
||||||
virtual operator double() const {
|
virtual operator double() const {
|
||||||
double d;
|
double d;
|
||||||
if (value.ToDouble(&d)) {
|
if (value.ToDouble(&d)) {
|
||||||
return d;
|
return d;
|
||||||
} else {
|
} else {
|
||||||
throw ScriptError(_("Not a number: '") + value + _("'"));
|
throw ScriptError(_ERROR_3_("can't convert value", value, typeName(), _TYPE_("double")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual operator int() const {
|
virtual operator int() const {
|
||||||
@@ -168,7 +168,7 @@ class ScriptString : public ScriptValue {
|
|||||||
} else if (value == _("no") || value == _("false") || value.empty()) {
|
} else if (value == _("no") || value == _("false") || value.empty()) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
throw ScriptError(_("Not a number: '") + value + _("'"));
|
throw ScriptError(_ERROR_3_("can't convert value", value, typeName(), _TYPE_("integer")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual operator Color() const {
|
virtual operator Color() const {
|
||||||
@@ -176,7 +176,7 @@ class ScriptString : public ScriptValue {
|
|||||||
if (wxSscanf(value.c_str(),_("rgb(%u,%u,%u)"),&r,&g,&b)) {
|
if (wxSscanf(value.c_str(),_("rgb(%u,%u,%u)"),&r,&g,&b)) {
|
||||||
return Color(r, g, b);
|
return Color(r, g, b);
|
||||||
} else {
|
} else {
|
||||||
throw ScriptError(_("Not a color: '") + value + _("'"));
|
throw ScriptError(_ERROR_3_("can't convert value", value, typeName(), _TYPE_("color")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual int itemCount() const { return (int)value.size(); }
|
virtual int itemCount() const { return (int)value.size(); }
|
||||||
@@ -186,7 +186,7 @@ class ScriptString : public ScriptValue {
|
|||||||
if (name.ToLong(&index) && index >= 0 && (size_t)index < value.size()) {
|
if (name.ToLong(&index) && index >= 0 && (size_t)index < value.size()) {
|
||||||
return toScript(String(1,value[index]));
|
return toScript(String(1,value[index]));
|
||||||
} else {
|
} else {
|
||||||
throw ScriptError(_("String \"") + value + _("\" has no member ") + name);
|
throw ScriptError(_ERROR_2_("has no member value", value, name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
@@ -205,7 +205,7 @@ class ScriptColor : public ScriptValue {
|
|||||||
public:
|
public:
|
||||||
ScriptColor(const Color& v) : value(v) {}
|
ScriptColor(const Color& v) : value(v) {}
|
||||||
virtual ScriptType type() const { return SCRIPT_COLOR; }
|
virtual ScriptType type() const { return SCRIPT_COLOR; }
|
||||||
virtual String typeName() const { return _("color"); }
|
virtual String typeName() const { return _TYPE_("color"); }
|
||||||
virtual operator Color() const { return value; }
|
virtual operator Color() const { return value; }
|
||||||
virtual operator String() const {
|
virtual operator String() const {
|
||||||
return String::Format(_("rgb(%u,%u,%u)"), value.Red(), value.Green(), value.Blue());
|
return String::Format(_("rgb(%u,%u,%u)"), value.Red(), value.Green(), value.Blue());
|
||||||
@@ -225,7 +225,7 @@ ScriptValueP toScript(const Color& v) {
|
|||||||
class ScriptNil : public ScriptValue {
|
class ScriptNil : public ScriptValue {
|
||||||
public:
|
public:
|
||||||
virtual ScriptType type() const { return SCRIPT_NIL; }
|
virtual ScriptType type() const { return SCRIPT_NIL; }
|
||||||
virtual String typeName() const { return _("nil"); }
|
virtual String typeName() const { return _TYPE_("nil"); }
|
||||||
virtual operator String() const { return wxEmptyString; }
|
virtual operator String() const { return wxEmptyString; }
|
||||||
virtual operator double() const { return 0.0; }
|
virtual operator double() const { return 0.0; }
|
||||||
virtual operator int() const { return 0; }
|
virtual operator int() const { return 0; }
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ class ScriptValue : public IntrusivePtrBase {
|
|||||||
virtual operator double() const;
|
virtual operator double() const;
|
||||||
/// Convert this value to an integer
|
/// Convert this value to an integer
|
||||||
virtual operator int() const;
|
virtual operator int() const;
|
||||||
|
/// Convert this value to a boolean
|
||||||
|
inline operator bool() const { return (int)*this; }
|
||||||
/// Convert this value to a color
|
/// Convert this value to a color
|
||||||
virtual operator Color() const;
|
virtual operator Color() const;
|
||||||
|
|
||||||
|
|||||||
@@ -85,11 +85,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Declare typeof magic for a specific std::vector type
|
/// Declare typeof magic for a specific std::vector type
|
||||||
#define DECLARE_TYPEOF_COLLECTION(T) DECLARE_TYPEOF(vector<T>); \
|
#define DECLARE_TYPEOF_COLLECTION(T) DECLARE_TYPEOF(vector< T >); \
|
||||||
// DECLARE_TYPEOF_CONST(set<T>)
|
DECLARE_TYPEOF_CONST(set< T >)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Use for template classes
|
||||||
|
/** i.e.
|
||||||
|
* DECLARE_TYPEOF(pair<a COMMA b>);
|
||||||
|
* instead of
|
||||||
|
* DECLARE_TYPEOF(pair<a,b>);
|
||||||
|
*/
|
||||||
|
#define COMMA ,
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Looping macros with iterators
|
// ----------------------------------------------------------------------------- : Looping macros with iterators
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -97,8 +97,9 @@ String tr(const SymbolFont&, const String& key, const String& def);
|
|||||||
inline String format_string(const String& format, ...) {
|
inline String format_string(const String& format, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
return String::Format(format, args);
|
String res = String::Format(format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
inline String format_string(const String& format, const String& a0) {
|
inline String format_string(const String& format, const String& a0) {
|
||||||
return String::Format(format, a0.c_str());
|
return String::Format(format, a0.c_str());
|
||||||
|
|||||||
+12
-1
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
/** @file util/platform.hpp
|
/** @file util/platform.hpp
|
||||||
*
|
*
|
||||||
* @brief Platform specific hacks
|
* @brief Platform and compiler specific hacks.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Includes
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
@@ -23,11 +23,22 @@
|
|||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
|
||||||
|
/// wxMkDir as documented
|
||||||
inline void wxMkDir(const String& dir) {
|
inline void wxMkDir(const String& dir) {
|
||||||
wxMkDir(wxConvLocal.cWX2MB(dir), 0777);
|
wxMkDir(wxConvLocal.cWX2MB(dir), 0777);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : GCC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
|
||||||
|
/// Absolute value of integers
|
||||||
|
template <typename T>
|
||||||
|
inline T abs(T a) { return a < 0 ? -a : a; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : EOF
|
// ----------------------------------------------------------------------------- : EOF
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+2
-1
@@ -113,7 +113,8 @@ String capitalize_sentence(const String&);
|
|||||||
String cannocial_name_form(const String&);
|
String cannocial_name_form(const String&);
|
||||||
|
|
||||||
/// Returns the singular form of a string
|
/// Returns the singular form of a string
|
||||||
/** Used for reflection, for example "vector<T> apples" is written with keys "apple"
|
/** Used for reflection, for example "vector<T> apples" is written with keys
|
||||||
|
* singular_form("apples"), which is "apple"
|
||||||
*/
|
*/
|
||||||
String singular_form(const String&);
|
String singular_form(const String&);
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,10 @@ size_t match_close_tag(const String& str, size_t start) {
|
|||||||
return String::npos;
|
return String::npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t match_close_tag_end(const String& str, size_t start) {
|
||||||
|
return skip_tag(str, match_close_tag(str, start));
|
||||||
|
}
|
||||||
|
|
||||||
size_t last_start_tag_before(const String& str, const String& tag, size_t start) {
|
size_t last_start_tag_before(const String& str, const String& tag, size_t start) {
|
||||||
start = min(str.size(), start);
|
start = min(str.size(), start);
|
||||||
for (size_t pos = start ; pos > 0 ; --pos) {
|
for (size_t pos = start ; pos > 0 ; --pos) {
|
||||||
@@ -178,7 +182,7 @@ size_t index_to_cursor(const String& str, size_t index, Movement dir) {
|
|||||||
if (is_substr(str, i, _("<atom")) || is_substr(str, i, _("<sep"))) {
|
if (is_substr(str, i, _("<atom")) || is_substr(str, i, _("<sep"))) {
|
||||||
// skip tag contents, tag counts as a single 'character'
|
// skip tag contents, tag counts as a single 'character'
|
||||||
size_t before = i;
|
size_t before = i;
|
||||||
size_t after = skip_tag(str, match_close_tag(str, i));
|
size_t after = match_close_tag_end(str, i);
|
||||||
if (index > before && index < after) {
|
if (index > before && index < after) {
|
||||||
// index is inside an atom, determine on which side we want the cursor
|
// index is inside an atom, determine on which side we want the cursor
|
||||||
if (dir == MOVE_RIGHT) {
|
if (dir == MOVE_RIGHT) {
|
||||||
@@ -215,7 +219,7 @@ void cursor_to_index_range(const String& str, size_t cursor, size_t& start, size
|
|||||||
// a tag
|
// a tag
|
||||||
if (is_substr(str, i, _("<atom")) || is_substr(str, i, _("<sep"))) {
|
if (is_substr(str, i, _("<atom")) || is_substr(str, i, _("<sep"))) {
|
||||||
// skip tag contents, tag counts as a single 'character'
|
// skip tag contents, tag counts as a single 'character'
|
||||||
i = skip_tag(str, match_close_tag(str, i));
|
i = match_close_tag_end(str, i);
|
||||||
} else {
|
} else {
|
||||||
i = skip_tag(str, i);
|
i = skip_tag(str, i);
|
||||||
has_width = false;
|
has_width = false;
|
||||||
@@ -259,6 +263,24 @@ size_t cursor_to_index(const String& str, size_t cursor, Movement dir) {
|
|||||||
return dir == MOVE_RIGHT ? end - 1 : start;
|
return dir == MOVE_RIGHT ? end - 1 : start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Untagged position
|
||||||
|
|
||||||
|
size_t untagged_to_index(const String& str, size_t pos, bool inside) {
|
||||||
|
size_t i = 0, p = 0;
|
||||||
|
while (i < str.size()) {
|
||||||
|
Char c = str.GetChar(i);
|
||||||
|
if (c == _('<')) {
|
||||||
|
bool is_close = is_substr(str, i, _("</"));
|
||||||
|
if (p == pos && is_close == inside) break;
|
||||||
|
i = skip_tag(str, i);
|
||||||
|
} else {
|
||||||
|
if (p == pos) break;
|
||||||
|
i++;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Global operations
|
// ----------------------------------------------------------------------------- : Global operations
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,12 @@ size_t skip_tag(const String& str, size_t start);
|
|||||||
/** If not found returns String::npos */
|
/** If not found returns String::npos */
|
||||||
size_t match_close_tag(const String& str, size_t start);
|
size_t match_close_tag(const String& str, size_t start);
|
||||||
|
|
||||||
|
/// Find the position of the closing tag matching the tag at start
|
||||||
|
/** Returns the position just after that tag.
|
||||||
|
* match_close_tag_end(s,i) == skip_tag(s, match_close_tag(s,i) )
|
||||||
|
* If not found returns String::npos */
|
||||||
|
size_t match_close_tag_end(const String& str, size_t start);
|
||||||
|
|
||||||
/// Find the last start tag before position start
|
/// Find the last start tag before position start
|
||||||
/** If not found returns String::npos */
|
/** If not found returns String::npos */
|
||||||
size_t last_start_tag_before(const String& str, const String& tag, size_t start);
|
size_t last_start_tag_before(const String& str, const String& tag, size_t start);
|
||||||
@@ -103,6 +109,14 @@ void cursor_to_index_range(const String& str, size_t cursor, size_t& begin, size
|
|||||||
/// Find the character index corresponding to the given cursor position
|
/// Find the character index corresponding to the given cursor position
|
||||||
size_t cursor_to_index(const String& str, size_t cursor, Movement dir = MOVE_MID);
|
size_t cursor_to_index(const String& str, size_t cursor, Movement dir = MOVE_MID);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Untagged position
|
||||||
|
|
||||||
|
/// Find the tagged position corresponding to the given untagged position.
|
||||||
|
/** An untagged position in str is a position in untag(str).
|
||||||
|
* @param inside if inside then it prefers to find positions inside tags (after open tags, before close tags)
|
||||||
|
*/
|
||||||
|
size_t untagged_to_index(const String& str, size_t pos, bool inside);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Global operations
|
// ----------------------------------------------------------------------------- : Global operations
|
||||||
|
|
||||||
/// Remove all instances of a tag and its close tag, but keep the contents.
|
/// Remove all instances of a tag and its close tag, but keep the contents.
|
||||||
|
|||||||
Reference in New Issue
Block a user