mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
Split script/functions.cpp into multiple files in new script/functions/ directory.
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@217 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+5
-1
@@ -89,13 +89,17 @@ magicseteditor_SOURCES += ./src/gui/drop_down_list.cpp
|
||||
magicseteditor_SOURCES += ./src/gui/image_slice_window.cpp
|
||||
magicseteditor_SOURCES += ./src/script/script_manager.cpp
|
||||
magicseteditor_SOURCES += ./src/script/script.cpp
|
||||
magicseteditor_SOURCES += ./src/script/functions.cpp
|
||||
magicseteditor_SOURCES += ./src/script/value.cpp
|
||||
magicseteditor_SOURCES += ./src/script/dependency.cpp
|
||||
magicseteditor_SOURCES += ./src/script/image.cpp
|
||||
magicseteditor_SOURCES += ./src/script/context.cpp
|
||||
magicseteditor_SOURCES += ./src/script/scriptable.cpp
|
||||
magicseteditor_SOURCES += ./src/script/parser.cpp
|
||||
magicseteditor_SOURCES += ./src/script/functions/basic.cpp
|
||||
magicseteditor_SOURCES += ./src/script/functions/image.cpp
|
||||
magicseteditor_SOURCES += ./src/script/functions/editor.cpp
|
||||
magicseteditor_SOURCES += ./src/script/functions/export.cpp
|
||||
magicseteditor_SOURCES += ./src/script/functions/english.cpp
|
||||
magicseteditor_SOURCES += ./src/data/field/color.cpp
|
||||
magicseteditor_SOURCES += ./src/data/field/boolean.cpp
|
||||
magicseteditor_SOURCES += ./src/data/field/image.cpp
|
||||
|
||||
@@ -92,7 +92,7 @@ void export_image(const SetP& set, const CardP& card, const String& filename);
|
||||
Bitmap export_bitmap(const SetP& set, const CardP& card);
|
||||
|
||||
/// Export a set to Magic Workstation format
|
||||
void export_mws(const SetP& set);
|
||||
void export_mws(Window* parent, const SetP& set);
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
|
||||
@@ -52,7 +52,7 @@ String card_rarity_code(const String& rarity) {
|
||||
|
||||
// ----------------------------------------------------------------------------- : export_mws
|
||||
|
||||
void export_mws(const SetP& set) {
|
||||
void export_mws(Window* parent, const SetP& set) {
|
||||
if (!set->game->isMagic()) {
|
||||
throw Error(_("Can only export Magic sets to Magic Workstation"));
|
||||
}
|
||||
@@ -60,7 +60,7 @@ void export_mws(const SetP& set) {
|
||||
// Select filename
|
||||
String name = wxFileSelector(_("Export to file"),_(""),_(""),_(""),
|
||||
_("Text files (*.txt)|*.txt|All Files|*.*"),
|
||||
wxSAVE | wxOVERWRITE_PROMPT);
|
||||
wxSAVE | wxOVERWRITE_PROMPT, parent);
|
||||
if (name.empty()) return;
|
||||
wxBusyCursor busy;
|
||||
// Open file
|
||||
|
||||
@@ -389,17 +389,17 @@ String KeywordDatabase::expand(const String& text,
|
||||
part = part + param; // keep tags
|
||||
} else if (kw->parameters[j/2-1]->script) {
|
||||
// apply parameter script
|
||||
ctx.setVariable(_("input"), toScript(part));
|
||||
ctx.setVariable(_("input"), to_script(part));
|
||||
part = kw->parameters[j/2-1]->script.invoke(ctx)->toString();
|
||||
ctx.setVariable(_("input"), toScript(part));
|
||||
ctx.setVariable(_("input"), to_script(part));
|
||||
param = kw->parameters[j/2-1]->script.invoke(ctx)->toString();
|
||||
}
|
||||
ctx.setVariable(String(_("param")) << (int)(j/2), toScript(param));
|
||||
ctx.setVariable(String(_("param")) << (int)(j/2), to_script(param));
|
||||
}
|
||||
total += part;
|
||||
start = part_end;
|
||||
}
|
||||
ctx.setVariable(_("mode"), toScript(kw->mode));
|
||||
ctx.setVariable(_("mode"), to_script(kw->mode));
|
||||
|
||||
// Show reminder text?
|
||||
bool expand = expand_type == _('1');
|
||||
@@ -412,8 +412,8 @@ String KeywordDatabase::expand(const String& text,
|
||||
// Combine keyword & reminder with result
|
||||
if (expand) {
|
||||
String reminder = kw->reminder.invoke(ctx)->toString();
|
||||
ctx.setVariable(_("keyword"), toScript(total));
|
||||
ctx.setVariable(_("reminder"), toScript(reminder));
|
||||
ctx.setVariable(_("keyword"), to_script(total));
|
||||
ctx.setVariable(_("reminder"), to_script(reminder));
|
||||
result += _("<kw-"); result += expand_type; result += _(">");
|
||||
result += combine_script->eval(ctx)->toString();
|
||||
result += _("</kw-"); result += expand_type; result += _(">");
|
||||
|
||||
@@ -33,7 +33,7 @@ ColumnSettings::ColumnSettings()
|
||||
{}
|
||||
|
||||
// dummy for ColumnSettings reflection
|
||||
ScriptValueP toScript(const ColumnSettings&) { return script_nil; }
|
||||
ScriptValueP to_script(const ColumnSettings&) { return script_nil; }
|
||||
|
||||
IMPLEMENT_REFLECTION(ColumnSettings) {
|
||||
REFLECT(width);
|
||||
|
||||
@@ -457,7 +457,7 @@ void SetWindow::onFileExportApprentice(wxCommandEvent&) {
|
||||
}
|
||||
|
||||
void SetWindow::onFileExportMWS(wxCommandEvent&) {
|
||||
export_mws(set);
|
||||
export_mws(this, set);
|
||||
}
|
||||
|
||||
void SetWindow::onFilePrint(wxCommandEvent&) {
|
||||
|
||||
+97
-3
@@ -2120,9 +2120,6 @@
|
||||
<File
|
||||
RelativePath=".\script\dependency.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\script\functions.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\script\image.cpp">
|
||||
<FileConfiguration
|
||||
@@ -2198,6 +2195,103 @@
|
||||
<File
|
||||
RelativePath=".\script\value.hpp">
|
||||
</File>
|
||||
<Filter
|
||||
Name="functions"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\script\functions\basic.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\script\functions\editor.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)2.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)2.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug Unicode|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)2.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release Unicode|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)2.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release Profile Unicode|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)2.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release Unicode fast build|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)2.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\script\functions\english.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\script\functions\export.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\script\functions\functions.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\script\functions\image.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)5.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)5.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug Unicode|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)5.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release Unicode|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)5.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release Profile Unicode|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)5.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release Unicode fast build|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)5.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\script\functions\util.hpp">
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="render"
|
||||
|
||||
+15
-15
@@ -212,10 +212,10 @@ void instrUnary (UnaryInstructionType i, ScriptValueP& a) {
|
||||
a = a->makeIterator();
|
||||
break;
|
||||
case I_NEGATE:
|
||||
a = toScript(-(int)*a);
|
||||
a = to_script(-(int)*a);
|
||||
break;
|
||||
case I_NOT:
|
||||
a = toScript(!(bool)*a);
|
||||
a = to_script(!(bool)*a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -224,26 +224,26 @@ void instrUnary (UnaryInstructionType i, ScriptValueP& a) {
|
||||
|
||||
// operator on ints
|
||||
#define OPERATOR_I(OP) \
|
||||
a = toScript((int)*a OP (int)*b); \
|
||||
a = to_script((int)*a OP (int)*b); \
|
||||
break
|
||||
|
||||
// operator on doubles or ints
|
||||
#define OPERATOR_DI(OP) \
|
||||
if (at == SCRIPT_DOUBLE || bt == SCRIPT_DOUBLE) { \
|
||||
a = toScript((double)*a OP (double)*b); \
|
||||
a = to_script((double)*a OP (double)*b); \
|
||||
} else { \
|
||||
a = toScript((int)*a OP (int)*b); \
|
||||
a = to_script((int)*a OP (int)*b); \
|
||||
} \
|
||||
break
|
||||
|
||||
// operator on strings or doubles or ints
|
||||
#define OPERATOR_SDI(OP) \
|
||||
if (at == SCRIPT_STRING || bt == SCRIPT_STRING) { \
|
||||
a = toScript(a->toString() OP b->toString()); \
|
||||
a = to_script(a->toString() OP b->toString()); \
|
||||
} else if (at == SCRIPT_DOUBLE || bt == SCRIPT_DOUBLE) { \
|
||||
a = toScript((double)*a OP (double)*b); \
|
||||
a = to_script((double)*a OP (double)*b); \
|
||||
} else { \
|
||||
a = toScript((int)*a OP (int)*b); \
|
||||
a = to_script((int)*a OP (int)*b); \
|
||||
} \
|
||||
break
|
||||
|
||||
@@ -283,13 +283,13 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP&
|
||||
} else if (at == SCRIPT_FUNCTION && bt == SCRIPT_FUNCTION) {
|
||||
a = new_intrusive2<ScriptCompose>(a, b);
|
||||
} else if (at == SCRIPT_STRING || bt == SCRIPT_STRING) {
|
||||
a = toScript(a->toString() + b->toString());
|
||||
a = to_script(a->toString() + b->toString());
|
||||
} else if (at == SCRIPT_DOUBLE || bt == SCRIPT_DOUBLE) {
|
||||
a = toScript((double)*a + (double)*b);
|
||||
a = to_script((double)*a + (double)*b);
|
||||
} else if (at == SCRIPT_INT || bt == SCRIPT_INT) {
|
||||
a = toScript((int)*a + (int)*b);
|
||||
a = to_script((int)*a + (int)*b);
|
||||
} else {
|
||||
a = toScript(a->toString() + b->toString());
|
||||
a = to_script(a->toString() + b->toString());
|
||||
}
|
||||
break;
|
||||
case I_SUB: OPERATOR_DI(-);
|
||||
@@ -297,9 +297,9 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP&
|
||||
case I_DIV: OPERATOR_DI(/);
|
||||
case I_MOD:
|
||||
if (at == SCRIPT_DOUBLE || bt == SCRIPT_DOUBLE) {
|
||||
a = toScript(fmod((double)*a, (double)*b));
|
||||
a = to_script(fmod((double)*a, (double)*b));
|
||||
} else {
|
||||
a = toScript((int)*a % (int)*b);
|
||||
a = to_script((int)*a % (int)*b);
|
||||
}
|
||||
break;
|
||||
case I_AND: OPERATOR_I(&&);
|
||||
@@ -318,7 +318,7 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP&
|
||||
void instrTernary(TernaryInstructionType i, ScriptValueP& a, const ScriptValueP& b, const ScriptValueP& c) {
|
||||
switch (i) {
|
||||
case I_RGB:
|
||||
a = toScript(Color((int)*a, (int)*b, (int)*c));
|
||||
a = to_script(Color((int)*a, (int)*b, (int)*c));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,25 +6,203 @@
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <script/to_value.hpp>
|
||||
#include <script/context.hpp>
|
||||
#include <script/dependency.hpp>
|
||||
#include <script/functions/functions.hpp>
|
||||
#include <script/functions/util.hpp>
|
||||
#include <util/tagged_string.hpp>
|
||||
#include <data/set.hpp>
|
||||
#include <data/game.hpp>
|
||||
#include <data/keyword.hpp>
|
||||
#include <data/field/text.hpp>
|
||||
#include <wx/regex.h>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(UInt);
|
||||
DECLARE_TYPEOF_COLLECTION(FieldP);
|
||||
DECLARE_TYPEOF_COLLECTION(TextValue*);
|
||||
DECLARE_TYPEOF_COLLECTION(String);
|
||||
// ----------------------------------------------------------------------------- : String stuff
|
||||
|
||||
// convert a string to upper case
|
||||
SCRIPT_FUNCTION(to_upper) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_RETURN(input.Upper());
|
||||
}
|
||||
|
||||
// convert a string to lower case
|
||||
SCRIPT_FUNCTION(to_lower) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_RETURN(input.Lower());
|
||||
}
|
||||
|
||||
// convert a string to title case
|
||||
SCRIPT_FUNCTION(to_title) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_RETURN(capitalize(input));
|
||||
}
|
||||
|
||||
// extract a substring
|
||||
SCRIPT_FUNCTION(substring) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_PARAM_DEFAULT(int, begin, 0);
|
||||
SCRIPT_PARAM_DEFAULT(int, end, INT_MAX);
|
||||
if (begin < 0) begin = 0;
|
||||
if (end < 0) end = 0;
|
||||
if (begin >= end || (size_t)begin >= input.size()) {
|
||||
SCRIPT_RETURN(wxEmptyString);
|
||||
} else if ((size_t)end >= input.size()) {
|
||||
SCRIPT_RETURN(input.substr(begin));
|
||||
} else {
|
||||
SCRIPT_RETURN(input.substr(begin, end - begin));
|
||||
}
|
||||
}
|
||||
|
||||
// does a string contain a substring?
|
||||
SCRIPT_FUNCTION(contains) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_PARAM(String, match);
|
||||
SCRIPT_RETURN(input.find(match) != String::npos);
|
||||
}
|
||||
|
||||
SCRIPT_RULE_1(format, String, format) {
|
||||
String fmt = _("%") + replace_all(format, _("%"), _(""));
|
||||
// determine type expected by format string
|
||||
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 string
|
||||
|
||||
/// Replace the contents of a specific tag with the value of a script function
|
||||
String replace_tag_contents(String input, const String& tag, const ScriptValueP& contents, Context& ctx) {
|
||||
String ret;
|
||||
size_t pos = input.find(tag);
|
||||
while (pos != String::npos) {
|
||||
// find end of tag and contents
|
||||
size_t end = match_close_tag(input, pos);
|
||||
if (end == String::npos) break; // missing close tag
|
||||
// prepare for call
|
||||
String old_contents = input.substr(pos + tag.size(), end - (pos + tag.size()));
|
||||
ctx.setVariable(_("contents"), to_script(old_contents));
|
||||
// replace
|
||||
ret += input.substr(0, pos); // before tag
|
||||
ret += tag;
|
||||
ret += contents->eval(ctx)->toString();// new contents (call)
|
||||
ret += close_tag(tag);
|
||||
// next
|
||||
input = input.substr(skip_tag(input,end));
|
||||
pos = input.find(tag);
|
||||
}
|
||||
return ret + input;
|
||||
}
|
||||
|
||||
// Replace the contents of a specific tag
|
||||
SCRIPT_RULE_2(tag_contents, String, tag, ScriptValueP, contents) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_RETURN(replace_tag_contents(input, tag, contents, ctx));
|
||||
}
|
||||
|
||||
SCRIPT_RULE_1(tag_remove, String, tag) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_RETURN(remove_tag(input, tag));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Collection stuff
|
||||
|
||||
/// compare script values for equallity
|
||||
bool equal(const ScriptValue& a, const ScriptValue& b) {
|
||||
if (&a == &b) return true;
|
||||
ScriptType at = a.type(), bt = b.type();
|
||||
if (at != bt) {
|
||||
return false;
|
||||
} else if (at == SCRIPT_INT) {
|
||||
return (int)a == (int)b;
|
||||
} else if (at == SCRIPT_DOUBLE) {
|
||||
return (double)a == (double)b;
|
||||
} else if (at == SCRIPT_STRING) {
|
||||
return a.toString() == b.toString();
|
||||
} else {
|
||||
// compare pointers, must be equal and not null
|
||||
const void *ap = a.comparePointer(), *bp = b.comparePointer();
|
||||
return (ap && ap == bp);
|
||||
}
|
||||
}
|
||||
|
||||
/// position of some element in a vector
|
||||
/** 0 based index, -1 if not found */
|
||||
int position_in_vector(const ScriptValueP& of, const ScriptValueP& in, const ScriptValueP& order_by) {
|
||||
ScriptType of_t = of->type(), in_t = in->type();
|
||||
if (of_t == SCRIPT_STRING || in_t == SCRIPT_STRING) {
|
||||
// string finding
|
||||
return (int)of->toString().find(in->toString()); // (int)npos == -1
|
||||
} else if (order_by) {
|
||||
ScriptObject<Set*>* s = dynamic_cast<ScriptObject<Set*>* >(in.get());
|
||||
ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(of.get());
|
||||
if (s && c) {
|
||||
return s->getValue()->positionOfCard(c->getValue(), order_by);
|
||||
} else {
|
||||
throw ScriptError(_("position: using 'order_by' is only supported for finding cards in the set"));
|
||||
}
|
||||
} else {
|
||||
// unordered position
|
||||
ScriptValueP it = in->makeIterator();
|
||||
int i = 0;
|
||||
while (ScriptValueP v = it->next()) {
|
||||
if (equal(*of, *v)) return i;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return -1; // TODO?
|
||||
}
|
||||
|
||||
// finding positions, also of substrings
|
||||
SCRIPT_FUNCTION_WITH_DEP(position_of) {
|
||||
ScriptValueP of = ctx.getVariable(_("of"));
|
||||
ScriptValueP in = ctx.getVariable(_("in"));
|
||||
ScriptValueP order_by = ctx.getVariableOpt(_("order by"));
|
||||
SCRIPT_RETURN(position_in_vector(of, in, order_by));
|
||||
}
|
||||
SCRIPT_FUNCTION_DEPENDENCIES(position_of) {
|
||||
ScriptValueP of = ctx.getVariable(_("of"));
|
||||
ScriptValueP in = ctx.getVariable(_("in"));
|
||||
ScriptValueP order_by = ctx.getVariableOpt(_("order by"));
|
||||
ScriptObject<Set*>* s = dynamic_cast<ScriptObject<Set*>* >(in.get());
|
||||
ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(of.get());
|
||||
if (s && c) {
|
||||
// dependency on cards
|
||||
mark_dependency_member(s->getValue(), _("cards"), dep);
|
||||
if (order_by) {
|
||||
// dependency on order_by function
|
||||
order_by->dependencies(ctx, dep.makeCardIndependend());
|
||||
}
|
||||
}
|
||||
return dependency_dummy;
|
||||
};
|
||||
|
||||
// finding sizes
|
||||
SCRIPT_FUNCTION(number_of_items) {
|
||||
SCRIPT_RETURN(ctx.getVariable(_("in"))->itemCount());
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : 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));
|
||||
}
|
||||
|
||||
/** @file script/functions.cpp
|
||||
*
|
||||
* @brief Functions used in scripts
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rules : regex replace
|
||||
|
||||
@@ -54,7 +232,7 @@ class ScriptReplaceRule : public ScriptValue {
|
||||
regex.GetMatch(&start, &len, m);
|
||||
String name = m == 0 ? _("input") : String(_("_")) << m;
|
||||
String value = input.substr(start, len);
|
||||
ctx.setVariable(name, toScript(value));
|
||||
ctx.setVariable(name, to_script(value));
|
||||
}
|
||||
// call
|
||||
inside = replacement_function->eval(ctx)->toString();
|
||||
@@ -81,7 +259,7 @@ class ScriptReplaceRule : public ScriptValue {
|
||||
};
|
||||
|
||||
// Create a regular expression rule for replacing in strings
|
||||
SCRIPT_FUNCTION(replace_rule) {
|
||||
ScriptValueP replace_rule(Context& ctx) {
|
||||
intrusive_ptr<ScriptReplaceRule> ret(new ScriptReplaceRule);
|
||||
// match
|
||||
SCRIPT_PARAM(String, match);
|
||||
@@ -104,6 +282,13 @@ SCRIPT_FUNCTION(replace_rule) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(replace_rule) {
|
||||
return replace_rule(ctx);
|
||||
}
|
||||
SCRIPT_FUNCTION(replace) {
|
||||
return replace_rule(ctx)->eval(ctx);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rules : regex filter
|
||||
|
||||
class ScriptFilterRule : public ScriptValue {
|
||||
@@ -128,7 +313,7 @@ class ScriptFilterRule : public ScriptValue {
|
||||
};
|
||||
|
||||
// Create a regular expression rule for filtering strings
|
||||
SCRIPT_FUNCTION(filter_rule) {
|
||||
ScriptValueP filter_rule(Context& ctx) {
|
||||
intrusive_ptr<ScriptFilterRule> ret(new ScriptFilterRule);
|
||||
// match
|
||||
SCRIPT_PARAM(String, match);
|
||||
@@ -138,6 +323,13 @@ SCRIPT_FUNCTION(filter_rule) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(filter_rule) {
|
||||
return filter_rule(ctx);
|
||||
}
|
||||
SCRIPT_FUNCTION(filter) {
|
||||
return filter_rule(ctx)->eval(ctx);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rules : sort
|
||||
|
||||
/// Sort a string using a specification using the shortest cycle metric, see spec_sort
|
||||
@@ -244,390 +436,40 @@ String spec_sort(const String& spec, const String& input) {
|
||||
}
|
||||
|
||||
|
||||
// Utility for defining a script rule with a single parameter
|
||||
#define SCRIPT_RULE_1(funname, type1, name1) \
|
||||
class ScriptRule_##funname: public ScriptValue { \
|
||||
public: \
|
||||
inline ScriptRule_##funname(const type1& name1) : name1(name1) {} \
|
||||
virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
|
||||
virtual String typeName() const { return _(#funname)_("_rule"); } \
|
||||
virtual ScriptValueP eval(Context& ctx) const; \
|
||||
private: \
|
||||
type1 name1; \
|
||||
}; \
|
||||
SCRIPT_FUNCTION(funname##_rule) { \
|
||||
SCRIPT_PARAM(type1, name1); \
|
||||
return new_intrusive1<ScriptRule_##funname>(name1); \
|
||||
} \
|
||||
SCRIPT_FUNCTION(funname) { \
|
||||
SCRIPT_PARAM(type1, name1); \
|
||||
return ScriptRule_##funname(name1).eval(ctx); \
|
||||
} \
|
||||
ScriptValueP ScriptRule_##funname::eval(Context& ctx) const
|
||||
|
||||
// Utility for defining a script rule with two parameters
|
||||
#define SCRIPT_RULE_2_N(funname, type1, str1, name1, type2, str2, name2) \
|
||||
class ScriptRule_##funname: public ScriptValue { \
|
||||
public: \
|
||||
inline ScriptRule_##funname(const type1& name1, const type2& name2) \
|
||||
: name1(name1), name2(name2) {} \
|
||||
virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
|
||||
virtual String typeName() const { return _(#funname)_("_rule"); } \
|
||||
virtual ScriptValueP eval(Context& ctx) const; \
|
||||
private: \
|
||||
type1 name1; \
|
||||
type2 name2; \
|
||||
}; \
|
||||
SCRIPT_FUNCTION(funname##_rule) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
SCRIPT_PARAM_N(type2, str2, name2); \
|
||||
return new_intrusive2<ScriptRule_##funname>(name1, name2); \
|
||||
} \
|
||||
SCRIPT_FUNCTION(funname) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
SCRIPT_PARAM_N(type2, str2, name2); \
|
||||
return ScriptRule_##funname(name1, name2).eval(ctx); \
|
||||
} \
|
||||
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
|
||||
SCRIPT_RULE_1(sort, String, order) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_RETURN(spec_sort(order, input));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : String stuff
|
||||
|
||||
// convert a string to upper case
|
||||
SCRIPT_FUNCTION(to_upper) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_RETURN(input.Upper());
|
||||
}
|
||||
// ----------------------------------------------------------------------------- : Init
|
||||
|
||||
// convert a string to lower case
|
||||
SCRIPT_FUNCTION(to_lower) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_RETURN(input.Lower());
|
||||
}
|
||||
|
||||
// convert a string to title case
|
||||
SCRIPT_FUNCTION(to_title) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_RETURN(capitalize(input));
|
||||
}
|
||||
|
||||
// extract a substring
|
||||
SCRIPT_FUNCTION(substring) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_PARAM_DEFAULT(int, begin, 0);
|
||||
SCRIPT_PARAM_DEFAULT(int, end, INT_MAX);
|
||||
if (begin < 0) begin = 0;
|
||||
if (end < 0) end = 0;
|
||||
if (begin >= end || (size_t)begin >= input.size()) {
|
||||
SCRIPT_RETURN(wxEmptyString);
|
||||
} else if ((size_t)end >= input.size()) {
|
||||
SCRIPT_RETURN(input.substr(begin));
|
||||
} else {
|
||||
SCRIPT_RETURN(input.substr(begin, end - begin));
|
||||
}
|
||||
}
|
||||
|
||||
// does a string contain a substring?
|
||||
SCRIPT_FUNCTION(contains) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_PARAM(String, match);
|
||||
SCRIPT_RETURN(input.find(match) != String::npos);
|
||||
}
|
||||
|
||||
SCRIPT_RULE_1(format, String, format) {
|
||||
String fmt = _("%") + replace_all(format, _("%"), _(""));
|
||||
// determine type expected by format string
|
||||
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
|
||||
|
||||
String replace_tag_contents(String input, const String& tag, const ScriptValueP& contents, Context& ctx) {
|
||||
String ret;
|
||||
size_t pos = input.find(tag);
|
||||
while (pos != String::npos) {
|
||||
// find end of tag and contents
|
||||
size_t end = match_close_tag(input, pos);
|
||||
if (end == String::npos) break; // missing close tag
|
||||
// prepare for call
|
||||
String old_contents = input.substr(pos + tag.size(), end - (pos + tag.size()));
|
||||
ctx.setVariable(_("contents"), toScript(old_contents));
|
||||
// replace
|
||||
ret += input.substr(0, pos); // before tag
|
||||
ret += tag;
|
||||
ret += contents->eval(ctx)->toString();// new contents (call)
|
||||
ret += close_tag(tag);
|
||||
// next
|
||||
input = input.substr(skip_tag(input,end));
|
||||
pos = input.find(tag);
|
||||
}
|
||||
return ret + input;
|
||||
}
|
||||
|
||||
|
||||
// Replace the contents of a specific tag
|
||||
SCRIPT_RULE_2(tag_contents, String, tag, ScriptValueP, contents) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_RETURN(replace_tag_contents(input, tag, contents, ctx));
|
||||
}
|
||||
|
||||
SCRIPT_RULE_1(tag_remove, String, tag) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
SCRIPT_RETURN(remove_tag(input, tag));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : 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
|
||||
bool equal(const ScriptValue& a, const ScriptValue& b) {
|
||||
ScriptType at = a.type(), bt = b.type();
|
||||
if (at != bt) {
|
||||
return false;
|
||||
} else if (at == SCRIPT_INT) {
|
||||
return (int)a == (int)b;
|
||||
} else if (at == SCRIPT_DOUBLE) {
|
||||
return (double)a == (double)b;
|
||||
} else if (at == SCRIPT_STRING) {
|
||||
return a.toString() == b.toString();
|
||||
} else if (at == SCRIPT_OBJECT) {
|
||||
// HACK for ScriptObject<shared_ptr<X> >
|
||||
// assumes different types are layed out the same, and that
|
||||
// should be void*, but then we need getMember for void
|
||||
const ScriptObject<int*>& av = dynamic_cast<const ScriptObject<int*>&>(a);
|
||||
const ScriptObject<int*>& bv = dynamic_cast<const ScriptObject<int*>&>(b);
|
||||
return av.getValue() == bv.getValue();
|
||||
}
|
||||
return &a == &b;
|
||||
}
|
||||
|
||||
/// position of some element in a vector
|
||||
/** 0 based index, -1 if not found */
|
||||
int position_in_vector(const ScriptValueP& of, const ScriptValueP& in, const ScriptValueP& order_by) {
|
||||
ScriptType of_t = of->type(), in_t = in->type();
|
||||
if (of_t == SCRIPT_STRING || in_t == SCRIPT_STRING) {
|
||||
// string finding
|
||||
return (int)of->toString().find(in->toString()); // (int)npos == -1
|
||||
} else if (order_by) {
|
||||
ScriptObject<Set*>* s = dynamic_cast<ScriptObject<Set*>* >(in.get());
|
||||
ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(of.get());
|
||||
if (s && c) {
|
||||
return s->getValue()->positionOfCard(c->getValue(), order_by);
|
||||
} else {
|
||||
throw ScriptError(_("position: using 'order_by' is only supported for finding cards in the set"));
|
||||
}
|
||||
} else {
|
||||
// unordered position
|
||||
ScriptValueP it = in->makeIterator();
|
||||
int i = 0;
|
||||
while (ScriptValueP v = it->next()) {
|
||||
if (equal(*of, *v)) return i;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return -1; // TODO?
|
||||
}
|
||||
|
||||
// finding positions, also of substrings
|
||||
SCRIPT_FUNCTION_DEP(position_of) {
|
||||
ScriptValueP of = ctx.getVariable(_("of"));
|
||||
ScriptValueP in = ctx.getVariable(_("in"));
|
||||
ScriptValueP order_by = ctx.getVariableOpt(_("order by"));
|
||||
SCRIPT_RETURN(position_in_vector(of, in, order_by));
|
||||
}
|
||||
|
||||
ScriptValueP ScriptBuildin_position_of::dependencies(Context& ctx, const Dependency& dep) const {
|
||||
ScriptValueP of = ctx.getVariable(_("of"));
|
||||
ScriptValueP in = ctx.getVariable(_("in"));
|
||||
ScriptValueP order_by = ctx.getVariableOpt(_("order by"));
|
||||
ScriptObject<Set*>* s = dynamic_cast<ScriptObject<Set*>* >(in.get());
|
||||
ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(of.get());
|
||||
if (s && c) {
|
||||
// dependency on cards
|
||||
mark_dependency_member(s->getValue(), _("cards"), dep);
|
||||
if (order_by) {
|
||||
// dependency on order_by function
|
||||
order_by->dependencies(ctx, dep.makeCardIndependend());
|
||||
}
|
||||
}
|
||||
return dependency_dummy;
|
||||
};
|
||||
|
||||
|
||||
// finding sizes
|
||||
SCRIPT_FUNCTION(number_of_items) {
|
||||
SCRIPT_RETURN(ctx.getVariable(_("in"))->itemCount());
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Combined editor
|
||||
|
||||
SCRIPT_FUNCTION_DEP(combined_editor) {
|
||||
// read 'field#' arguments
|
||||
vector<TextValue*> values;
|
||||
for (int i = 0 ; ; ++i) {
|
||||
String name = _("field"); if (i > 0) name = name << i;
|
||||
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
|
||||
TextValue* text_value = dynamic_cast<TextValue*>(value.get());
|
||||
if (!text_value) throw ScriptError(_("Argument '")+name+_("' should be a text field"));
|
||||
values.push_back(text_value);
|
||||
} else if (i > 0) break;
|
||||
}
|
||||
if (values.empty()) {
|
||||
throw ScriptError(_("No fields specified for combined_editor"));
|
||||
}
|
||||
// read 'separator#' arguments
|
||||
vector<String> separators;
|
||||
for (int i = 0 ; ; ++i) {
|
||||
String name = _("separator"); if (i > 0) name = name << i;
|
||||
SCRIPT_OPTIONAL_PARAM_N(String, name, separator) {
|
||||
separators.push_back(separator);
|
||||
} else if (i > 0) break;
|
||||
}
|
||||
if (separators.size() < values.size() - 1) {
|
||||
throw ScriptError(String::Format(_("Not enough separators for combine_editor, expected %d"), values.size()-1));
|
||||
}
|
||||
// split the value
|
||||
SCRIPT_PARAM(String, value);
|
||||
vector<String> value_parts;
|
||||
size_t pos = value.find(_("<sep"));
|
||||
while (pos != String::npos) {
|
||||
value_parts.push_back(value.substr(0, pos));
|
||||
value = value.substr(min(match_close_tag_end(value,pos), value.size()));
|
||||
pos = value.find(_("<sep"));
|
||||
}
|
||||
value_parts.push_back(value);
|
||||
value_parts.resize(values.size()); // TODO: what if there are more value_parts than values?
|
||||
// update the values if our input value is newer?
|
||||
Age new_value_update = last_update_age();
|
||||
FOR_EACH_2(v, values, nv, value_parts) {
|
||||
if (v->value() != nv && v->last_update < new_value_update) {
|
||||
// TODO : type over
|
||||
v->value.assign(nv);
|
||||
v->update(ctx);
|
||||
}
|
||||
nv = v->value();
|
||||
}
|
||||
// options
|
||||
SCRIPT_PARAM_DEFAULT_N(bool, _("hide when empty"), hide_when_empty, false);
|
||||
SCRIPT_PARAM_DEFAULT_N(bool, _("soft before empty"), soft_before_empty, false);
|
||||
// recombine the parts
|
||||
String new_value = value_parts.front();
|
||||
for (size_t i = 1 ; i < value_parts.size() ; ++i) {
|
||||
if (value_parts[i].empty() && new_value.empty() && hide_when_empty) {
|
||||
// no separator
|
||||
} else if (value_parts[i].empty() && soft_before_empty) {
|
||||
// soft separator
|
||||
new_value += _("<sep-soft>") + separators[i - 1] + _("</sep-soft>");
|
||||
} else {
|
||||
// normal separator
|
||||
new_value += _("<sep>") + separators[i - 1] + _("</sep>");
|
||||
new_value += value_parts[i];
|
||||
}
|
||||
}
|
||||
SCRIPT_RETURN(new_value);
|
||||
}
|
||||
|
||||
ScriptValueP ScriptBuildin_combined_editor::dependencies(Context& ctx, const Dependency& dep) const {
|
||||
// read 'field#' arguments
|
||||
vector<FieldP> fields;
|
||||
for (int i = 0 ; ; ++i) {
|
||||
String name = _("field"); if (i > 0) name = name << i;
|
||||
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
|
||||
fields.push_back(value->fieldP);
|
||||
} else if (i > 0) break;
|
||||
}
|
||||
// Find the target field
|
||||
SCRIPT_PARAM(Set*, set);
|
||||
GameP game = set->game;
|
||||
FieldP target_field;
|
||||
if (dep.type == DEP_CARD_FIELD) target_field = game->card_fields[dep.index];
|
||||
else if (dep.type == DEP_SET_FIELD) target_field = game->set_fields[dep.index];
|
||||
else throw InternalError(_("Finding dependencies of combined error for non card/set field"));
|
||||
// Add dependencies, from target_field on field#
|
||||
// For card fields
|
||||
size_t j = 0;
|
||||
FOR_EACH(f, game->card_fields) {
|
||||
Dependency dep(DEP_CARD_COPY_DEP, j++);
|
||||
FOR_EACH(fn, fields) {
|
||||
if (f == fn) {
|
||||
target_field->dependent_scripts.add(dep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// For set fields
|
||||
j = 0;
|
||||
FOR_EACH(f, game->set_fields) {
|
||||
Dependency dep(DEP_SET_COPY_DEP, j++);
|
||||
FOR_EACH(fn, fields) {
|
||||
if (f == fn) {
|
||||
target_field->dependent_scripts.add(dep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dependency_dummy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Initialize functions
|
||||
|
||||
void init_script_functions(Context& ctx) {
|
||||
ctx.setVariable(_("replace rule"), script_replace_rule);
|
||||
ctx.setVariable(_("filter rule"), script_filter_rule);
|
||||
ctx.setVariable(_("sort"), script_sort);
|
||||
ctx.setVariable(_("sort rule"), script_sort_rule);
|
||||
void init_script_basic_functions(Context& ctx) {
|
||||
// string
|
||||
ctx.setVariable(_("to upper"), script_to_upper);
|
||||
ctx.setVariable(_("to lower"), script_to_lower);
|
||||
ctx.setVariable(_("to title"), script_to_title);
|
||||
ctx.setVariable(_("substring"), script_substring);
|
||||
ctx.setVariable(_("contains"), script_contains);
|
||||
ctx.setVariable(_("format"), script_format);
|
||||
ctx.setVariable(_("format rule"), script_format_rule);
|
||||
// tagged string
|
||||
ctx.setVariable(_("tag contents"), script_tag_contents);
|
||||
ctx.setVariable(_("remove tag"), script_tag_remove);
|
||||
ctx.setVariable(_("tag contents rule"), script_tag_contents_rule);
|
||||
ctx.setVariable(_("tag remove rule"), script_tag_remove_rule);
|
||||
ctx.setVariable(_("expand keywords rule"), script_expand_keywords_rule);
|
||||
ctx.setVariable(_("expand keywords"), script_expand_keywords);
|
||||
// collection
|
||||
ctx.setVariable(_("position"), script_position_of);
|
||||
ctx.setVariable(_("number of items"), script_number_of_items);
|
||||
ctx.setVariable(_("forward editor"), script_combined_editor);
|
||||
ctx.setVariable(_("combined editor"), script_combined_editor);
|
||||
// keyword
|
||||
ctx.setVariable(_("expand keywords"), script_expand_keywords);
|
||||
ctx.setVariable(_("expand keywords rule"), script_expand_keywords_rule);
|
||||
// advanced string rules
|
||||
ctx.setVariable(_("replace"), script_replace);
|
||||
ctx.setVariable(_("filter"), script_filter);
|
||||
ctx.setVariable(_("sort"), script_sort);
|
||||
ctx.setVariable(_("replace rule"), script_replace_rule);
|
||||
ctx.setVariable(_("filter rule"), script_filter_rule);
|
||||
ctx.setVariable(_("sort rule"), script_sort_rule);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <script/functions/functions.hpp>
|
||||
#include <script/functions/util.hpp>
|
||||
#include <util/tagged_string.hpp>
|
||||
#include <data/set.hpp>
|
||||
#include <data/game.hpp>
|
||||
#include <data/field/text.hpp>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(FieldP);
|
||||
DECLARE_TYPEOF_COLLECTION(TextValue*);
|
||||
DECLARE_TYPEOF_COLLECTION(String);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Combined editor
|
||||
|
||||
// Combining multiple (text) values into a single one
|
||||
// The combined value is value1 <sep>something</sep> value2 <sep>something</sep> value3
|
||||
//
|
||||
|
||||
SCRIPT_FUNCTION_WITH_DEP(combined_editor) {
|
||||
// read 'field#' arguments
|
||||
vector<TextValue*> values;
|
||||
for (int i = 0 ; ; ++i) {
|
||||
String name = _("field"); if (i > 0) name = name << i;
|
||||
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
|
||||
TextValue* text_value = dynamic_cast<TextValue*>(value.get());
|
||||
if (!text_value) throw ScriptError(_("Argument '")+name+_("' should be a text field"));
|
||||
values.push_back(text_value);
|
||||
} else if (i > 0) break;
|
||||
}
|
||||
if (values.empty()) {
|
||||
throw ScriptError(_("No fields specified for combined_editor"));
|
||||
}
|
||||
// read 'separator#' arguments
|
||||
vector<String> separators;
|
||||
for (int i = 0 ; ; ++i) {
|
||||
String name = _("separator"); if (i > 0) name = name << i;
|
||||
SCRIPT_OPTIONAL_PARAM_N(String, name, separator) {
|
||||
separators.push_back(separator);
|
||||
} else if (i > 0) break;
|
||||
}
|
||||
if (separators.size() < values.size() - 1) {
|
||||
throw ScriptError(String::Format(_("Not enough separators for combine_editor, expected %d"), values.size()-1));
|
||||
}
|
||||
// split the value
|
||||
SCRIPT_PARAM(String, value);
|
||||
vector<String> value_parts;
|
||||
size_t pos = value.find(_("<sep"));
|
||||
while (pos != String::npos) {
|
||||
value_parts.push_back(value.substr(0, pos));
|
||||
value = value.substr(min(match_close_tag_end(value,pos), value.size()));
|
||||
pos = value.find(_("<sep"));
|
||||
}
|
||||
value_parts.push_back(value);
|
||||
value_parts.resize(values.size()); // TODO: what if there are more value_parts than values?
|
||||
// update the values if our input value is newer?
|
||||
Age new_value_update = last_update_age();
|
||||
FOR_EACH_2(v, values, nv, value_parts) {
|
||||
if (v->value() != nv && v->last_update < new_value_update) {
|
||||
// TODO : type over
|
||||
v->value.assign(nv);
|
||||
v->update(ctx);
|
||||
}
|
||||
nv = v->value();
|
||||
}
|
||||
// options
|
||||
SCRIPT_PARAM_DEFAULT_N(bool, _("hide when empty"), hide_when_empty, false);
|
||||
SCRIPT_PARAM_DEFAULT_N(bool, _("soft before empty"), soft_before_empty, false);
|
||||
// recombine the parts
|
||||
String new_value = value_parts.front();
|
||||
for (size_t i = 1 ; i < value_parts.size() ; ++i) {
|
||||
if (value_parts[i].empty() && new_value.empty() && hide_when_empty) {
|
||||
// no separator
|
||||
} else if (value_parts[i].empty() && soft_before_empty) {
|
||||
// soft separator
|
||||
new_value += _("<sep-soft>") + separators[i - 1] + _("</sep-soft>");
|
||||
} else {
|
||||
// normal separator
|
||||
new_value += _("<sep>") + separators[i - 1] + _("</sep>");
|
||||
new_value += value_parts[i];
|
||||
}
|
||||
}
|
||||
SCRIPT_RETURN(new_value);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION_DEPENDENCIES(combined_editor) {
|
||||
// read 'field#' arguments
|
||||
vector<FieldP> fields;
|
||||
for (int i = 0 ; ; ++i) {
|
||||
String name = _("field"); if (i > 0) name = name << i;
|
||||
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
|
||||
fields.push_back(value->fieldP);
|
||||
} else if (i > 0) break;
|
||||
}
|
||||
// Find the target field
|
||||
SCRIPT_PARAM(Set*, set);
|
||||
GameP game = set->game;
|
||||
FieldP target_field;
|
||||
if (dep.type == DEP_CARD_FIELD) target_field = game->card_fields[dep.index];
|
||||
else if (dep.type == DEP_SET_FIELD) target_field = game->set_fields[dep.index];
|
||||
else throw InternalError(_("Finding dependencies of combined error for non card/set field"));
|
||||
// Add dependencies, from target_field on field#
|
||||
// For card fields
|
||||
size_t j = 0;
|
||||
FOR_EACH(f, game->card_fields) {
|
||||
Dependency dep(DEP_CARD_COPY_DEP, j++);
|
||||
FOR_EACH(fn, fields) {
|
||||
if (f == fn) {
|
||||
target_field->dependent_scripts.add(dep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// For set fields
|
||||
j = 0;
|
||||
FOR_EACH(f, game->set_fields) {
|
||||
Dependency dep(DEP_SET_COPY_DEP, j++);
|
||||
FOR_EACH(fn, fields) {
|
||||
if (f == fn) {
|
||||
target_field->dependent_scripts.add(dep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dependency_dummy;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Init
|
||||
|
||||
void init_script_editor_functions(Context& ctx) {
|
||||
ctx.setVariable(_("forward editor"), script_combined_editor); // combatability
|
||||
ctx.setVariable(_("combined editor"), script_combined_editor);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <script/functions/functions.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- : Numbers
|
||||
|
||||
// ----------------------------------------------------------------------------- : Init
|
||||
|
||||
void init_script_english_functions(Context& ctx) {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <script/functions/functions.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- :
|
||||
|
||||
// ----------------------------------------------------------------------------- : Init
|
||||
|
||||
void init_script_export_functions(Context& ctx) {
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
#ifndef HEADER_SCRIPT_FUNCTIONS_FUNCTIONS
|
||||
#define HEADER_SCRIPT_FUNCTIONS_FUNCTIONS
|
||||
|
||||
/** @file script/functions/functions.cpp
|
||||
*
|
||||
* @brief Header for buildin script functions.
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <util/prec.hpp>
|
||||
|
||||
class Context;
|
||||
|
||||
// ----------------------------------------------------------------------------- : Script functions
|
||||
|
||||
void init_script_basic_functions(Context& ctx);
|
||||
void init_script_image_functions(Context& ctx);
|
||||
void init_script_editor_functions(Context& ctx);
|
||||
void init_script_export_functions(Context& ctx);
|
||||
void init_script_english_functions(Context& ctx);
|
||||
|
||||
/// Initialize all build in functions for a context
|
||||
inline void init_script_functions(Context& ctx) {
|
||||
init_script_basic_functions(ctx);
|
||||
init_script_image_functions(ctx);
|
||||
init_script_editor_functions(ctx);
|
||||
init_script_export_functions(ctx);
|
||||
init_script_english_functions(ctx);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
@@ -0,0 +1,143 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <script/functions/functions.hpp>
|
||||
#include <script/functions/util.hpp>
|
||||
#include <script/image.hpp>
|
||||
// used by the functions
|
||||
#include <data/set.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <data/symbol.hpp>
|
||||
#include <data/field/symbol.hpp>
|
||||
#include <render/symbol/filter.hpp>
|
||||
#include <gui/util.hpp> // load_resource_image
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(SymbolStyle::VariationP);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Macros
|
||||
|
||||
#define SCRIPT_IMAGE_FUNCTION(name) \
|
||||
SCRIPT_FUNCTION(name) { \
|
||||
if (last_update_age() == 0)
|
||||
#define SCRIPT_IMAGE_FUNCTION_UP_TO_DATE }
|
||||
|
||||
template <> inline ScriptImageP from_script<ScriptImageP>(const ScriptValueP& value) {
|
||||
return to_script_image(value);
|
||||
}
|
||||
|
||||
#define SCRIPT_IMAGE_PARAM_UP_TO_DATE(name) script_image_up_to_date(ctx.getVariable(_(#name)))
|
||||
|
||||
// ----------------------------------------------------------------------------- : Image functions
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(linear_blend) {
|
||||
SCRIPT_PARAM(ScriptImageP, image1);
|
||||
SCRIPT_PARAM(ScriptImageP, image2);
|
||||
SCRIPT_PARAM(double, x1); SCRIPT_PARAM(double, y1);
|
||||
SCRIPT_PARAM(double, x2); SCRIPT_PARAM(double, y2);
|
||||
linear_blend(image1->image, image2->image, x1, y1, x2, y2);
|
||||
return image1;
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
SCRIPT_RETURN(
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image1) &&
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image2)
|
||||
);
|
||||
}
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(masked_blend) {
|
||||
SCRIPT_PARAM(ScriptImageP, light);
|
||||
SCRIPT_PARAM(ScriptImageP, dark);
|
||||
SCRIPT_PARAM(ScriptImageP, mask);
|
||||
mask_blend(light->image, dark->image, mask->image);
|
||||
return light;
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
SCRIPT_RETURN(
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(light) &&
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(dark) &&
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(mask)
|
||||
);
|
||||
}
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(set_mask) {
|
||||
SCRIPT_PARAM(ScriptImageP, image);
|
||||
SCRIPT_PARAM(ScriptImageP, mask);
|
||||
set_alpha(image->image, mask->image);
|
||||
return image;
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
SCRIPT_RETURN(
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image) &&
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(mask)
|
||||
);
|
||||
}
|
||||
|
||||
bool parse_enum(const String&, ImageCombine& out);
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(set_combine) {
|
||||
SCRIPT_PARAM(String, combine);
|
||||
SCRIPT_PARAM(ScriptImageP, input);
|
||||
// parse and set combine
|
||||
if (!parse_enum(combine, input->combine)) {
|
||||
throw ScriptError(_("Not a valid combine mode: '") + combine + _("'"));
|
||||
}
|
||||
return input;
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
SCRIPT_RETURN(
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(input)
|
||||
);
|
||||
}
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(symbol_variation) {
|
||||
SCRIPT_PARAM(ValueP, symbol);
|
||||
SymbolValueP value = dynamic_pointer_cast<SymbolValue>(symbol);
|
||||
SCRIPT_PARAM(String, variation);
|
||||
// find set & style
|
||||
SCRIPT_PARAM(Set*, set);
|
||||
SCRIPT_OPTIONAL_PARAM_(CardP, card);
|
||||
SymbolStyleP style = dynamic_pointer_cast<SymbolStyle>(set->stylesheetFor(card)->styleFor(value->fieldP));
|
||||
if (!style) throw InternalError(_("Symbol value has a style of the wrong type"));
|
||||
// load symbol
|
||||
SymbolP the_symbol;
|
||||
if (value->filename.empty()) {
|
||||
the_symbol = default_symbol();
|
||||
} else {
|
||||
the_symbol = set->readFile<SymbolP>(value->filename);
|
||||
}
|
||||
// determine filter & render
|
||||
FOR_EACH(v, style->variations) {
|
||||
if (v->name == variation) {
|
||||
// render & filter
|
||||
return new_intrusive1<ScriptImage>(render_symbol(the_symbol, *v->filter, v->border_radius));
|
||||
}
|
||||
}
|
||||
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
// SCRIPT_RETURN(last_update_age() >= value->filename.last_update_age);
|
||||
SCRIPT_RETURN(last_update_age() > 1); // the symbol was created/loaded after program start,
|
||||
// don't use cached images
|
||||
}
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(buildin_image) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
Image img = load_resource_image(input);
|
||||
if (!img.Ok()) {
|
||||
throw ScriptError(_("There is no build in image '") + input + _("'"));
|
||||
}
|
||||
return new_intrusive1<ScriptImage>(img);
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
SCRIPT_RETURN(true); // always up to date
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Init
|
||||
|
||||
void init_script_image_functions(Context& ctx) {
|
||||
ctx.setVariable(_("linear blend"), script_linear_blend);
|
||||
ctx.setVariable(_("masked blend"), script_masked_blend);
|
||||
ctx.setVariable(_("set mask"), script_set_mask);
|
||||
ctx.setVariable(_("set combine"), script_set_combine);
|
||||
ctx.setVariable(_("symbol variation"), script_symbol_variation);
|
||||
ctx.setVariable(_("buildin image"), script_buildin_image);
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
#ifndef HEADER_SCRIPT_FUNCTIONS_UTIL
|
||||
#define HEADER_SCRIPT_FUNCTIONS_UTIL
|
||||
|
||||
/** @file script/functions/util.cpp
|
||||
*
|
||||
* @brief Utility macros for defining script functions.
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <util/error.hpp>
|
||||
#include <script/to_value.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- : Functions
|
||||
|
||||
/// Macro to declare a new script function
|
||||
/** Usage:
|
||||
* @code
|
||||
* SCRIPT_FUNCTION(my_function) {
|
||||
* // function code goes here
|
||||
* }
|
||||
* @endcode
|
||||
* This declares a value 'script_my_function' which can be added as a variable to a context
|
||||
* using:
|
||||
* @code
|
||||
* extern ScriptValueP script_my_function;
|
||||
* context.setVariable("my_function", script_my_function);
|
||||
* @endcode
|
||||
*/
|
||||
#define SCRIPT_FUNCTION(name) SCRIPT_FUNCTION_AUX(name,;)
|
||||
|
||||
/// Macro to declare a new script function with custom dependency handling
|
||||
#define SCRIPT_FUNCTION_WITH_DEP(name) \
|
||||
SCRIPT_FUNCTION_AUX(name, virtual ScriptValueP dependencies(Context&, const Dependency&) const;)
|
||||
|
||||
#define SCRIPT_FUNCTION_DEPENDENCIES(name) \
|
||||
ScriptValueP ScriptBuildin_##name::dependencies(Context& ctx, const Dependency& dep) const
|
||||
|
||||
// helper for SCRIPT_FUNCTION and SCRIPT_FUNCTION_DEP
|
||||
#define SCRIPT_FUNCTION_AUX(name,dep) \
|
||||
class ScriptBuildin_##name : public ScriptValue { \
|
||||
dep \
|
||||
virtual ScriptType type() const \
|
||||
{ return SCRIPT_FUNCTION; } \
|
||||
virtual String typeName() const \
|
||||
{ return _("build in function '") _(#name) _("'"); } \
|
||||
virtual ScriptValueP eval(Context&) const; \
|
||||
}; \
|
||||
ScriptValueP script_##name(new ScriptBuildin_##name); \
|
||||
ScriptValueP ScriptBuildin_##name::eval(Context& ctx) const
|
||||
|
||||
/// Return a value from a SCRIPT_FUNCTION
|
||||
#define SCRIPT_RETURN(value) return to_script(value)
|
||||
|
||||
// ----------------------------------------------------------------------------- : Parameters
|
||||
|
||||
/// Retrieve a parameter to a SCRIPT_FUNCTION with the given name and type
|
||||
/** Usage:
|
||||
* @code
|
||||
* SCRIPT_FUNCTION(my_function) {
|
||||
* SCRIPT_PARAM(String, my_string_param);
|
||||
* ... my_string_param ...
|
||||
* }
|
||||
* @endcode
|
||||
* Throws an error if the parameter is not found.
|
||||
*/
|
||||
#define SCRIPT_PARAM(Type, name) \
|
||||
SCRIPT_PARAM_N(Type, _(#name), name)
|
||||
#define SCRIPT_PARAM_N(Type, str, name) \
|
||||
Type name = from_script<Type>(ctx.getVariable(str))
|
||||
|
||||
/// Retrieve an optional parameter
|
||||
/** Usage:
|
||||
* @code
|
||||
* SCRIPT_FUNCTION(my_function) {
|
||||
* SCRIPT_OPTIONAL_PARAM(String, my_string_param) {
|
||||
* ... my_string_param ...
|
||||
* }
|
||||
* ...
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
#define SCRIPT_OPTIONAL_PARAM(Type, name) \
|
||||
SCRIPT_OPTIONAL_PARAM_N(Type, _(#name), name)
|
||||
/// Retrieve a named optional parameter
|
||||
#define SCRIPT_OPTIONAL_PARAM_N(Type, str, name) \
|
||||
ScriptValueP name##_ = ctx.getVariableOpt(str); \
|
||||
Type name = name##_ ? from_script<Type>(name##_) : Type(); \
|
||||
if (name##_)
|
||||
|
||||
/// Retrieve an optional parameter, can't be used as an if statement
|
||||
#define SCRIPT_OPTIONAL_PARAM_(Type, name) \
|
||||
SCRIPT_OPTIONAL_PARAM_N_(Type, _(#name), name)
|
||||
/// Retrieve a named optional parameter, can't be used as an if statement
|
||||
#define SCRIPT_OPTIONAL_PARAM_N_(Type, str, name) \
|
||||
ScriptValueP name##_ = ctx.getVariableOpt(str); \
|
||||
Type name = name##_ ? from_script<Type>(name##_) : Type();
|
||||
|
||||
/// Retrieve an optional parameter with a default value
|
||||
#define SCRIPT_PARAM_DEFAULT(Type, name, def) \
|
||||
SCRIPT_PARAM_DEFAULT_N(Type, _(#name), name, def)
|
||||
/// Retrieve a named optional parameter with a default value
|
||||
#define SCRIPT_PARAM_DEFAULT_N(Type, str, name, def) \
|
||||
ScriptValueP name##_ = ctx.getVariableOpt(str); \
|
||||
Type name = name##_ ? from_script<Type>(name##_) : def
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rules
|
||||
|
||||
/// Utility for defining a script rule with a single parameter
|
||||
#define SCRIPT_RULE_1(funname, type1, name1) \
|
||||
SCRIPT_RULE_1_N(funname, type1, _(#name1), name1)
|
||||
/// Utility for defining a script rule with a single named parameter
|
||||
#define SCRIPT_RULE_1_N(funname, type1, str1, name1) \
|
||||
class ScriptRule_##funname: public ScriptValue { \
|
||||
public: \
|
||||
inline ScriptRule_##funname(const type1& name1) : name1(name1) {} \
|
||||
virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
|
||||
virtual String typeName() const { return _(#funname)_("_rule"); } \
|
||||
virtual ScriptValueP eval(Context& ctx) const; \
|
||||
private: \
|
||||
type1 name1; \
|
||||
}; \
|
||||
SCRIPT_FUNCTION(funname##_rule) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
return new_intrusive1<ScriptRule_##funname>(name1); \
|
||||
} \
|
||||
SCRIPT_FUNCTION(funname) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
return ScriptRule_##funname(name1).eval(ctx); \
|
||||
} \
|
||||
ScriptValueP ScriptRule_##funname::eval(Context& ctx) const
|
||||
|
||||
/// Utility for defining a script rule with two parameters
|
||||
#define SCRIPT_RULE_2(funname, type1, name1, type2, name2) \
|
||||
SCRIPT_RULE_2_N(funname, type1, _(#name1), name1, type2, _(#name2), name2)
|
||||
/// Utility for defining a script rule with two named parameters
|
||||
#define SCRIPT_RULE_2_N(funname, type1, str1, name1, type2, str2, name2) \
|
||||
class ScriptRule_##funname: public ScriptValue { \
|
||||
public: \
|
||||
inline ScriptRule_##funname(const type1& name1, const type2& name2) \
|
||||
: name1(name1), name2(name2) {} \
|
||||
virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
|
||||
virtual String typeName() const { return _(#funname)_("_rule"); } \
|
||||
virtual ScriptValueP eval(Context& ctx) const; \
|
||||
private: \
|
||||
type1 name1; \
|
||||
type2 name2; \
|
||||
}; \
|
||||
SCRIPT_FUNCTION(funname##_rule) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
SCRIPT_PARAM_N(type2, str2, name2); \
|
||||
return new_intrusive2<ScriptRule_##funname>(name1, name2); \
|
||||
} \
|
||||
SCRIPT_FUNCTION(funname) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
SCRIPT_PARAM_N(type2, str2, name2); \
|
||||
return ScriptRule_##funname(name1, name2).eval(ctx); \
|
||||
} \
|
||||
ScriptValueP ScriptRule_##funname::eval(Context& ctx) const
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
@@ -11,15 +11,6 @@
|
||||
#include <script/to_value.hpp>
|
||||
#include <util/dynamic_arg.hpp>
|
||||
#include <util/io/package.hpp>
|
||||
// for functions:
|
||||
#include <data/set.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <data/symbol.hpp>
|
||||
#include <data/field/symbol.hpp>
|
||||
#include <render/symbol/filter.hpp>
|
||||
#include <gui/util.hpp> // load_resource_image
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(SymbolStyle::VariationP);
|
||||
|
||||
IMPLEMENT_DYNAMIC_ARG(Package*, load_images_from, nullptr);
|
||||
|
||||
@@ -169,123 +160,3 @@ template <> void Writer::handle(const ScriptableImage& s) {
|
||||
template <> void GetDefaultMember::handle(const ScriptableImage& s) {
|
||||
handle(s.script.unparsed);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Functions
|
||||
|
||||
SCRIPT_FUNCTION(linear_blend) {
|
||||
if (last_update_age() == 0) {
|
||||
ScriptImageP image1 = to_script_image(ctx.getVariable(_("image1")));
|
||||
ScriptImageP image2 = to_script_image(ctx.getVariable(_("image2")));
|
||||
SCRIPT_PARAM(double, x1); SCRIPT_PARAM(double, y1);
|
||||
SCRIPT_PARAM(double, x2); SCRIPT_PARAM(double, y2);
|
||||
linear_blend(image1->image, image2->image, x1, y1, x2, y2);
|
||||
return image1;
|
||||
} else {
|
||||
SCRIPT_RETURN(
|
||||
script_image_up_to_date(ctx.getVariable(_("image1"))) &&
|
||||
script_image_up_to_date(ctx.getVariable(_("image2")))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(masked_blend) {
|
||||
if (last_update_age() == 0) {
|
||||
ScriptImageP light = to_script_image(ctx.getVariable(_("light")));
|
||||
ScriptImageP dark = to_script_image(ctx.getVariable(_("dark")));
|
||||
ScriptImageP mask = to_script_image(ctx.getVariable(_("mask")));
|
||||
mask_blend(light->image, dark->image, mask->image);
|
||||
return light;
|
||||
} else {
|
||||
SCRIPT_RETURN(
|
||||
script_image_up_to_date(ctx.getVariable(_("light"))) &&
|
||||
script_image_up_to_date(ctx.getVariable(_("dark" ))) &&
|
||||
script_image_up_to_date(ctx.getVariable(_("mask" )))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(set_mask) {
|
||||
if (last_update_age() == 0) {
|
||||
ScriptImageP image = to_script_image(ctx.getVariable(_("image")));
|
||||
ScriptImageP mask = to_script_image(ctx.getVariable(_("mask")));
|
||||
set_alpha(image->image, mask->image);
|
||||
return image;
|
||||
} else {
|
||||
SCRIPT_RETURN(
|
||||
script_image_up_to_date(ctx.getVariable(_("image"))) &&
|
||||
script_image_up_to_date(ctx.getVariable(_("mask")))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool parse_enum(const String&, ImageCombine& out);
|
||||
|
||||
SCRIPT_FUNCTION(set_combine) {
|
||||
if (last_update_age() == 0) {
|
||||
SCRIPT_PARAM(String, combine);
|
||||
ScriptImageP image = to_script_image(ctx.getVariable(_("input")));
|
||||
// parse and set combine
|
||||
if (!parse_enum(combine, image->combine)) {
|
||||
throw ScriptError(_("Not a valid combine mode: '") + combine + _("'"));
|
||||
}
|
||||
return image;
|
||||
} else {
|
||||
SCRIPT_RETURN(
|
||||
script_image_up_to_date(ctx.getVariable(_("input")))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(symbol_variation) {
|
||||
SCRIPT_PARAM(ValueP, symbol);
|
||||
SymbolValueP value = dynamic_pointer_cast<SymbolValue>(symbol);
|
||||
if (last_update_age() == 0) {
|
||||
SCRIPT_PARAM(String, variation);
|
||||
// find set & style
|
||||
SCRIPT_PARAM(Set*, set);
|
||||
SCRIPT_OPTIONAL_PARAM_(CardP, card);
|
||||
SymbolStyleP style = dynamic_pointer_cast<SymbolStyle>(set->stylesheetFor(card)->styleFor(value->fieldP));
|
||||
if (!style) throw InternalError(_("Symbol value has a style of the wrong type"));
|
||||
// load symbol
|
||||
SymbolP symbol;
|
||||
if (value->filename.empty()) {
|
||||
symbol = default_symbol();
|
||||
} else {
|
||||
symbol = set->readFile<SymbolP>(value->filename);
|
||||
}
|
||||
// determine filter & render
|
||||
FOR_EACH(v, style->variations) {
|
||||
if (v->name == variation) {
|
||||
// render & filter
|
||||
return new_intrusive1<ScriptImage>(render_symbol(symbol, *v->filter, v->border_radius));
|
||||
}
|
||||
}
|
||||
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
|
||||
} else {
|
||||
// SCRIPT_RETURN(last_update_age() >= value->filename.last_update_age);
|
||||
SCRIPT_RETURN(last_update_age() > 1); // the symbol was created/loaded after program start,
|
||||
// don't use cached images
|
||||
// SCRIPT_RETURN(true);
|
||||
}
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(buildin_image) {
|
||||
if (last_update_age() == 0) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
Image img = load_resource_image(input);
|
||||
if (!img.Ok()) throw ScriptError(_("There is no build in image '") + input + _("'"));
|
||||
return new_intrusive1<ScriptImage>(img);
|
||||
} else {
|
||||
SCRIPT_RETURN(true); // always up to date
|
||||
}
|
||||
}
|
||||
|
||||
void init_script_image_functions(Context& ctx) {
|
||||
ctx.setVariable(_("linear blend"), script_linear_blend);
|
||||
ctx.setVariable(_("masked blend"), script_masked_blend);
|
||||
ctx.setVariable(_("set mask"), script_set_mask);
|
||||
ctx.setVariable(_("set combine"), script_set_combine);
|
||||
ctx.setVariable(_("symbol variation"), script_symbol_variation);
|
||||
ctx.setVariable(_("buildin image"), script_buildin_image);
|
||||
}
|
||||
|
||||
@@ -85,7 +85,13 @@ class ScriptableImage {
|
||||
};
|
||||
|
||||
/// Missing for now
|
||||
inline ScriptValueP toScript(const ScriptableImage&) { return script_nil; }
|
||||
inline ScriptValueP to_script(const ScriptableImage&) { return script_nil; }
|
||||
|
||||
/// Convert a script value to an image
|
||||
ScriptImageP to_script_image(const ScriptValueP& value);
|
||||
|
||||
/// Is the given image up to date?
|
||||
bool script_image_up_to_date(const ScriptValueP& value);
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
|
||||
@@ -419,14 +419,14 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
|
||||
long l = 0;
|
||||
//l = lexical_cast<long>(token.value);
|
||||
token.value.ToLong(&l);
|
||||
script.addInstruction(I_PUSH_CONST, toScript(l));
|
||||
script.addInstruction(I_PUSH_CONST, to_script(l));
|
||||
} else if (token == TOK_DOUBLE) {
|
||||
double d = 0;
|
||||
//d = lexical_cast<double>(token.value);
|
||||
token.value.ToDouble(&d);
|
||||
script.addInstruction(I_PUSH_CONST, toScript(d));
|
||||
script.addInstruction(I_PUSH_CONST, to_script(d));
|
||||
} else if (token == TOK_STRING) {
|
||||
script.addInstruction(I_PUSH_CONST, toScript(token.value));
|
||||
script.addInstruction(I_PUSH_CONST, to_script(token.value));
|
||||
} else {
|
||||
throw ScriptParseError(_("Unexpected token '") + token.value + _("'"));
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ void Script::addInstruction(InstructionType t, const ScriptValueP& c) {
|
||||
instructions.push_back(i);
|
||||
}
|
||||
void Script::addInstruction(InstructionType t, const String& s) {
|
||||
constants.push_back(toScript(s));
|
||||
constants.push_back(to_script(s));
|
||||
Instruction i = {t, {(unsigned int)constants.size() - 1}};
|
||||
instructions.push_back(i);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <script/script_manager.hpp>
|
||||
#include <script/to_value.hpp>
|
||||
#include <script/functions/functions.hpp>
|
||||
#include <data/set.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <data/game.hpp>
|
||||
@@ -25,10 +26,6 @@ DECLARE_TYPEOF_COLLECTION(Dependency);
|
||||
DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA StyleP>);
|
||||
DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA ValueP>);
|
||||
|
||||
// initialize functions, from functions.cpp
|
||||
void init_script_functions(Context& ctx);
|
||||
void init_script_image_functions(Context& ctx);
|
||||
|
||||
//#define LOG_UPDATES
|
||||
|
||||
// ----------------------------------------------------------------------------- : SetScriptContext : initialization
|
||||
@@ -56,12 +53,11 @@ Context& SetScriptContext::getContext(const StyleSheetP& stylesheet) {
|
||||
// NOTE: do not use a smart pointer for the pointer to the set, because the set owns this
|
||||
// which would lead to a reference cycle.
|
||||
init_script_functions(*ctx);
|
||||
init_script_image_functions(*ctx);
|
||||
ctx->setVariable(_("set"), new_intrusive1<ScriptObject<Set*> >(&set));
|
||||
ctx->setVariable(_("game"), toScript(set.game));
|
||||
ctx->setVariable(_("stylesheet"), toScript(stylesheet));
|
||||
ctx->setVariable(_("card"), set.cards.empty() ? script_nil : toScript(set.cards.front())); // dummy value
|
||||
ctx->setVariable(_("styling"), toScript(&set.stylingDataFor(*stylesheet)));
|
||||
ctx->setVariable(_("game"), to_script(set.game));
|
||||
ctx->setVariable(_("stylesheet"), to_script(stylesheet));
|
||||
ctx->setVariable(_("card"), set.cards.empty() ? script_nil : to_script(set.cards.front())); // dummy value
|
||||
ctx->setVariable(_("styling"), to_script(&set.stylingDataFor(*stylesheet)));
|
||||
try {
|
||||
// perform init scripts, don't use a scope, variables stay bound in the context
|
||||
set.game ->init_script.invoke(*ctx, false);
|
||||
@@ -76,7 +72,7 @@ Context& SetScriptContext::getContext(const StyleSheetP& stylesheet) {
|
||||
Context& SetScriptContext::getContext(const CardP& card) {
|
||||
Context& ctx = getContext(set.stylesheetFor(card));
|
||||
if (card) {
|
||||
ctx.setVariable(_("card"), toScript(card));
|
||||
ctx.setVariable(_("card"), to_script(card));
|
||||
} else {
|
||||
ctx.setVariable(_("card"), script_nil);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ class OptionalScript {
|
||||
bool invokeOn(Context& ctx, T& value) const {
|
||||
if (script) {
|
||||
T new_value;
|
||||
ctx.setVariable(_("value"), toScript(value));
|
||||
ctx.setVariable(_("value"), to_script(value));
|
||||
store(ctx.eval(*script), new_value);
|
||||
if (value != new_value) {
|
||||
value = new_value;
|
||||
|
||||
+35
-109
@@ -37,7 +37,7 @@ class ScriptCollectionIterator : public ScriptIterator {
|
||||
ScriptCollectionIterator(const Collection* col) : pos(0), col(col) {}
|
||||
virtual ScriptValueP next() {
|
||||
if (pos < col->size()) {
|
||||
return toScript(col->at(pos++));
|
||||
return to_script(col->at(pos++));
|
||||
} else {
|
||||
return ScriptValueP();
|
||||
}
|
||||
@@ -57,7 +57,7 @@ class ScriptCollection : public ScriptValue {
|
||||
virtual ScriptValueP getMember(const String& name) const {
|
||||
long index;
|
||||
if (name.ToLong(&index) && index >= 0 && (size_t)index < value->size()) {
|
||||
return toScript(value->at(index));
|
||||
return to_script(value->at(index));
|
||||
} else {
|
||||
return ScriptValue::getMember(name);
|
||||
}
|
||||
@@ -66,6 +66,8 @@ class ScriptCollection : public ScriptValue {
|
||||
return new_intrusive1<ScriptCollectionIterator<Collection> >(value);
|
||||
}
|
||||
virtual int itemCount() const { return (int)value->size(); }
|
||||
/// Collections can be compared by comparing pointers
|
||||
virtual const void* comparePointer() const { return value; }
|
||||
private:
|
||||
/// Store a pointer to a collection, collections are only ever used for structures owned outside the script
|
||||
const Collection* value;
|
||||
@@ -77,7 +79,7 @@ template <typename V>
|
||||
ScriptValueP get_member(const map<String,V>& m, const String& name) {
|
||||
typename map<String,V>::const_iterator it = m.find(name);
|
||||
if (it != m.end()) {
|
||||
return toScript(it->second);
|
||||
return to_script(it->second);
|
||||
} else {
|
||||
throw ScriptError(_ERROR_2_("has no member", _TYPE_("collection"), name));
|
||||
}
|
||||
@@ -87,7 +89,7 @@ template <typename K, typename V>
|
||||
ScriptValueP get_member(const IndexMap<K,V>& m, const String& name) {
|
||||
typename IndexMap<K,V>::const_iterator it = m.find(name);
|
||||
if (it != m.end()) {
|
||||
return toScript(*it);
|
||||
return to_script(*it);
|
||||
} else {
|
||||
throw ScriptError(_ERROR_2_("has no member", _TYPE_("collection"), name));
|
||||
}
|
||||
@@ -104,6 +106,8 @@ class ScriptMap : public ScriptValue {
|
||||
return get_member(*value, name);
|
||||
}
|
||||
virtual int itemCount() const { return (int)value->size(); }
|
||||
/// Collections can be compared by comparing pointers
|
||||
virtual const void* comparePointer() const { return value; }
|
||||
private:
|
||||
/// Store a pointer to a collection, collections are only ever used for structures owned outside the script
|
||||
const Collection* value;
|
||||
@@ -163,6 +167,8 @@ class ScriptObject : public ScriptValue {
|
||||
int i = item_count(*value);
|
||||
return i >= 0 ? i : ScriptValue::itemCount();
|
||||
}
|
||||
/// Objects can be compared by comparing pointers
|
||||
virtual const void* comparePointer() const { return &*value; }
|
||||
/// Get access to the value
|
||||
inline T getValue() const { return value; }
|
||||
private:
|
||||
@@ -177,118 +183,38 @@ class ScriptObject : public ScriptValue {
|
||||
// ----------------------------------------------------------------------------- : Creating
|
||||
|
||||
/// Convert a value to a script value
|
||||
ScriptValueP toScript(int v);
|
||||
inline ScriptValueP toScript(long v) { return toScript((int) v); }
|
||||
ScriptValueP toScript(double v);
|
||||
ScriptValueP toScript(const String& v);
|
||||
ScriptValueP toScript(const Color& v);
|
||||
inline ScriptValueP toScript(bool v) { return v ? script_true : script_false; }
|
||||
ScriptValueP to_script(int v);
|
||||
inline ScriptValueP to_script(long v) { return to_script((int) v); }
|
||||
ScriptValueP to_script(double v);
|
||||
ScriptValueP to_script(const String& v);
|
||||
ScriptValueP to_script(const Color& v);
|
||||
inline ScriptValueP to_script(bool v) { return v ? script_true : script_false; }
|
||||
template <typename T>
|
||||
inline ScriptValueP toScript(const vector<T>* v) { return new_intrusive1<ScriptCollection<vector<T> > >(v); }
|
||||
inline ScriptValueP to_script(const vector<T>* v) { return new_intrusive1<ScriptCollection<vector<T> > >(v); }
|
||||
template <typename K, typename V>
|
||||
inline ScriptValueP toScript(const map<K,V>* v) { return new_intrusive1<ScriptMap<map<K,V> > >(v); }
|
||||
inline ScriptValueP to_script(const map<K,V>* v) { return new_intrusive1<ScriptMap<map<K,V> > >(v); }
|
||||
template <typename K, typename V>
|
||||
inline ScriptValueP toScript(const IndexMap<K,V>* v) { return new_intrusive1<ScriptMap<IndexMap<K,V> > >(v); }
|
||||
inline ScriptValueP to_script(const IndexMap<K,V>* v) { return new_intrusive1<ScriptMap<IndexMap<K,V> > >(v); }
|
||||
template <typename T>
|
||||
inline ScriptValueP toScript(const shared_ptr<T>& v) { return new_intrusive1<ScriptObject<shared_ptr<T> > >(v); }
|
||||
inline ScriptValueP to_script(const shared_ptr<T>& v) { return new_intrusive1<ScriptObject<shared_ptr<T> > >(v); }
|
||||
template <typename T>
|
||||
inline ScriptValueP toScript(const Defaultable<T>& v) { return toScript(v()); }
|
||||
inline ScriptValueP to_script(const Defaultable<T>& v) { return to_script(v()); }
|
||||
|
||||
// ----------------------------------------------------------------------------- : Buildin functions
|
||||
// ----------------------------------------------------------------------------- : Destructing
|
||||
|
||||
/// Macro to declare a new script function
|
||||
/** Usage:
|
||||
* @code
|
||||
* SCRIPT_FUNCTION(my_function) {
|
||||
* // function code goes here
|
||||
* }
|
||||
* @endcode
|
||||
* This declares a value 'script_my_function' which can be added as a variable to a context
|
||||
* using:
|
||||
* @code
|
||||
* extern ScriptValueP script_my_function;
|
||||
* context.setVariable("my_function", script_my_function);
|
||||
* @endcode
|
||||
*/
|
||||
#define SCRIPT_FUNCTION(name) SCRIPT_FUNCTION_AUX(name,;)
|
||||
|
||||
/// Macro to declare a new script function with custom dependency handling
|
||||
#define SCRIPT_FUNCTION_DEP(name) SCRIPT_FUNCTION_AUX(name, virtual ScriptValueP dependencies(Context&, const Dependency&) const;)
|
||||
|
||||
// helper for SCRIPT_FUNCTION and SCRIPT_FUNCTION_DEP
|
||||
#define SCRIPT_FUNCTION_AUX(name,dep) \
|
||||
class ScriptBuildin_##name : public ScriptValue { \
|
||||
dep \
|
||||
virtual ScriptType type() const \
|
||||
{ return SCRIPT_FUNCTION; } \
|
||||
virtual String typeName() const \
|
||||
{ return _("build in function '") _(#name) _("'"); } \
|
||||
virtual ScriptValueP eval(Context&) const; \
|
||||
}; \
|
||||
ScriptValueP script_##name(new ScriptBuildin_##name); \
|
||||
ScriptValueP ScriptBuildin_##name::eval(Context& ctx) const
|
||||
|
||||
/// Retrieve a parameter to a SCRIPT_FUNCTION with the given name and type
|
||||
/** Usage:
|
||||
* @code
|
||||
* SCRIPT_FUNCTION(my_function) {
|
||||
* SCRIPT_PARAM(String, my_string_param);
|
||||
* ... my_string_param ...
|
||||
* }
|
||||
* @endcode
|
||||
* Throws an error if the parameter is not found.
|
||||
*/
|
||||
#define SCRIPT_PARAM(Type, name) \
|
||||
SCRIPT_PARAM_N(Type, _(#name), name)
|
||||
#define SCRIPT_PARAM_N(Type, str, name) \
|
||||
Type name = getParam<Type>(ctx.getVariable(str))
|
||||
|
||||
template <typename T>
|
||||
inline T getParam (const ScriptValueP& value) {
|
||||
ScriptObject<T>* o = dynamic_cast<ScriptObject<T>*>(value.get());
|
||||
if (!o) throw ScriptError(_("Can't convert from ")+value->typeName()+_(" to object"));
|
||||
return o->getValue();
|
||||
}
|
||||
template <> inline ScriptValueP getParam<ScriptValueP>(const ScriptValueP& value) { return value; }
|
||||
template <> inline String getParam<String> (const ScriptValueP& value) { return *value; }
|
||||
template <> inline int getParam<int> (const ScriptValueP& value) { return *value; }
|
||||
template <> inline double getParam<double> (const ScriptValueP& value) { return *value; }
|
||||
template <> inline bool getParam<bool> (const ScriptValueP& value) { return (int)*value; }
|
||||
|
||||
/// Retrieve an optional parameter
|
||||
/** Usage:
|
||||
* @code
|
||||
* SCRIPT_FUNCTION(my_function) {
|
||||
* SCRIPT_OPTIONAL_PARAM(String, my_string_param) {
|
||||
* ... my_string_param ...
|
||||
* }
|
||||
* ...
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
#define SCRIPT_OPTIONAL_PARAM(Type, name) SCRIPT_OPTIONAL_PARAM_N(Type, _(#name), name)
|
||||
|
||||
#define SCRIPT_OPTIONAL_PARAM_N(Type, str, name) \
|
||||
ScriptValueP name##_ = ctx.getVariableOpt(str); \
|
||||
Type name = name##_ ? getParam<Type>(name##_) : Type(); \
|
||||
if (name##_)
|
||||
|
||||
/// Retrieve an optional parameter, can't be used as an if statement
|
||||
#define SCRIPT_OPTIONAL_PARAM_(Type, name) SCRIPT_OPTIONAL_PARAM_N_(Type, _(#name), name)
|
||||
|
||||
#define SCRIPT_OPTIONAL_PARAM_N_(Type, str, name) \
|
||||
ScriptValueP name##_ = ctx.getVariableOpt(str); \
|
||||
Type name = name##_ ? getParam<Type>(name##_) : Type();
|
||||
|
||||
/// Retrieve an optional parameter with a default value
|
||||
#define SCRIPT_PARAM_DEFAULT(Type, name, def) SCRIPT_PARAM_DEFAULT_N(Type, _(#name), name, def)
|
||||
/// Retrieve an optional parameter with a default value
|
||||
#define SCRIPT_PARAM_DEFAULT_N(Type, str, name, def) \
|
||||
ScriptValueP name##_ = ctx.getVariableOpt(str); \
|
||||
Type name = name##_ ? getParam<Type>(name##_) : def
|
||||
|
||||
/// Return a value from a SCRIPT_FUNCTION
|
||||
#define SCRIPT_RETURN(value) return toScript(value)
|
||||
/// Convert a value from a script value to a normal value
|
||||
template <typename T> inline T from_script (const ScriptValueP& value) {
|
||||
ScriptObject<T>* o = dynamic_cast<ScriptObject<T>*>(value.get());
|
||||
if (!o) {
|
||||
throw ScriptError(_ERROR_2_("can't convert", value->typeName(), _TYPE_("object" )));
|
||||
}
|
||||
return o->getValue();
|
||||
}
|
||||
template <> inline ScriptValueP from_script<ScriptValueP>(const ScriptValueP& value) { return value; }
|
||||
template <> inline String from_script<String> (const ScriptValueP& value) { return *value; }
|
||||
template <> inline int from_script<int> (const ScriptValueP& value) { return *value; }
|
||||
template <> inline double from_script<double> (const ScriptValueP& value) { return *value; }
|
||||
template <> inline bool from_script<bool> (const ScriptValueP& value) { return *value; }
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
|
||||
@@ -23,6 +23,7 @@ ScriptValueP ScriptValue::getMember(const String& name) const { throw ScriptErro
|
||||
ScriptValueP ScriptValue::next() { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); }
|
||||
ScriptValueP ScriptValue::makeIterator() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("collection"))); }
|
||||
int ScriptValue::itemCount() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("collection"))); }
|
||||
const void* ScriptValue::comparePointer() const { return nullptr; }
|
||||
|
||||
ScriptValueP ScriptValue::dependencyMember(const String& name, const Dependency&) const { return dependency_dummy; }
|
||||
ScriptValueP ScriptValue::dependencies(Context&, const Dependency&) const { return dependency_dummy; }
|
||||
@@ -41,7 +42,7 @@ class ScriptRangeIterator : public ScriptIterator {
|
||||
: pos(start), end(end) {}
|
||||
virtual ScriptValueP next() {
|
||||
if (pos <= end) {
|
||||
return toScript(pos++);
|
||||
return to_script(pos++);
|
||||
} else {
|
||||
return ScriptValueP();
|
||||
}
|
||||
@@ -84,7 +85,7 @@ class ScriptInt : public ScriptValue {
|
||||
}
|
||||
#endif
|
||||
|
||||
ScriptValueP toScript(int v) {
|
||||
ScriptValueP to_script(int v) {
|
||||
#ifdef USE_POOL_ALLOCATOR
|
||||
#ifdef USE_INTRUSIVE_PTR
|
||||
return ScriptValueP(
|
||||
@@ -138,7 +139,7 @@ class ScriptDouble : public ScriptValue {
|
||||
double value;
|
||||
};
|
||||
|
||||
ScriptValueP toScript(double v) {
|
||||
ScriptValueP to_script(double v) {
|
||||
return new_intrusive1<ScriptDouble>(v);
|
||||
}
|
||||
|
||||
@@ -184,7 +185,7 @@ class ScriptString : public ScriptValue {
|
||||
// get member returns characters
|
||||
long index;
|
||||
if (name.ToLong(&index) && index >= 0 && (size_t)index < value.size()) {
|
||||
return toScript(String(1,value[index]));
|
||||
return to_script(String(1,value[index]));
|
||||
} else {
|
||||
throw ScriptError(_ERROR_2_("has no member value", value, name));
|
||||
}
|
||||
@@ -193,7 +194,7 @@ class ScriptString : public ScriptValue {
|
||||
String value;
|
||||
};
|
||||
|
||||
ScriptValueP toScript(const String& v) {
|
||||
ScriptValueP to_script(const String& v) {
|
||||
return new_intrusive1<ScriptString>(v);
|
||||
}
|
||||
|
||||
@@ -214,7 +215,7 @@ class ScriptColor : public ScriptValue {
|
||||
Color value;
|
||||
};
|
||||
|
||||
ScriptValueP toScript(const Color& v) {
|
||||
ScriptValueP to_script(const Color& v) {
|
||||
return new_intrusive1<ScriptColor>(v);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,9 @@ class ScriptValue : public IntrusivePtrBase {
|
||||
virtual ScriptType type() const = 0;
|
||||
/// Name of the type of value
|
||||
virtual String typeName() const = 0;
|
||||
/// A pointer that uniquely identifies the value, used for comparing.
|
||||
/** If implementation is not possible, should return nullptr. */
|
||||
virtual const void* comparePointer() const;
|
||||
|
||||
/// Convert this value to a string
|
||||
virtual operator String() const;
|
||||
|
||||
@@ -13,15 +13,15 @@
|
||||
|
||||
// ---------------------------------------------------------------------------- : GetDefaultMember
|
||||
|
||||
void GetDefaultMember::handle(const Char* v) { value = toScript(v); }
|
||||
template <> void GetDefaultMember::handle(const String& v) { value = toScript(v); }
|
||||
template <> void GetDefaultMember::handle(const FileName& v) { value = toScript(v); }
|
||||
template <> void GetDefaultMember::handle(const int& v) { value = toScript(v); }
|
||||
template <> void GetDefaultMember::handle(const unsigned int& v) { value = toScript((int)v); }
|
||||
template <> void GetDefaultMember::handle(const double& v) { value = toScript(v); }
|
||||
template <> void GetDefaultMember::handle(const bool& v) { value = toScript(v); }
|
||||
template <> void GetDefaultMember::handle(const Vector2D& v) { value = toScript(String::Format(_("(%.10lf,%.10lf)"), v.x, v.y)); }
|
||||
template <> void GetDefaultMember::handle(const Color& v) { value = toScript(v); }
|
||||
void GetDefaultMember::handle(const Char* v) { value = to_script(v); }
|
||||
template <> void GetDefaultMember::handle(const String& v) { value = to_script(v); }
|
||||
template <> void GetDefaultMember::handle(const FileName& v) { value = to_script(v); }
|
||||
template <> void GetDefaultMember::handle(const int& v) { value = to_script(v); }
|
||||
template <> void GetDefaultMember::handle(const unsigned int& v) { value = to_script((int)v); }
|
||||
template <> void GetDefaultMember::handle(const double& v) { value = to_script(v); }
|
||||
template <> void GetDefaultMember::handle(const bool& v) { value = to_script(v); }
|
||||
template <> void GetDefaultMember::handle(const Vector2D& v) { value = to_script(String::Format(_("(%.10lf,%.10lf)"), v.x, v.y)); }
|
||||
template <> void GetDefaultMember::handle(const Color& v) { value = to_script(v); }
|
||||
void GetDefaultMember::handle(const ScriptValueP& v) { value = v; }
|
||||
void GetDefaultMember::handle(const ScriptP& v) { value = v; }
|
||||
|
||||
|
||||
@@ -47,10 +47,10 @@ class GetDefaultMember {
|
||||
/// Handle a Defaultable: investigate children
|
||||
template <typename T> void handle(const Defaultable<T>&);
|
||||
template <typename T> void handle(const Scriptable<T>& );
|
||||
template <typename T> void handle(const vector<T>& c) { value = toScript(&c); }
|
||||
template <typename K, typename V> void handle(const map<K,V>& c) { value = toScript(&c); }
|
||||
template <typename K, typename V> void handle(const IndexMap<K,V>& c) { value = toScript(&c); }
|
||||
template <typename T> void handle(const shared_ptr<T>& p) { value = toScript(p); }
|
||||
template <typename T> void handle(const vector<T>& c) { value = to_script(&c); }
|
||||
template <typename K, typename V> void handle(const map<K,V>& c) { value = to_script(&c); }
|
||||
template <typename K, typename V> void handle(const IndexMap<K,V>& c) { value = to_script(&c); }
|
||||
template <typename T> void handle(const shared_ptr<T>& p) { value = to_script(p); }
|
||||
void handle(const ScriptValueP&);
|
||||
void handle(const ScriptP&);
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user