mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 13:06:59 -04:00
ScriptObject now looks for a default member for everything that it can not handle, meaning that scripts based on values now work.
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@72 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -25,8 +25,6 @@ class DependencyDummy : public ScriptIterator {
|
||||
virtual ScriptType type() const { return SCRIPT_DUMMY; }
|
||||
virtual String typeName() const { return _("dummy"); }
|
||||
virtual ScriptValueP next() { return ScriptValueP(); }
|
||||
virtual ScriptValueP eval(Context&) const { return dependency_dummy; } // dummy() == dummy
|
||||
virtual ScriptValueP getMember(const String&) const { return dependency_dummy; } // dummy.* = dummy
|
||||
};
|
||||
|
||||
ScriptValueP dependency_dummy(new DependencyDummy);
|
||||
@@ -52,6 +50,9 @@ class DependencyUnion : public ScriptValue {
|
||||
virtual ScriptValueP makeIterator() const {
|
||||
return unified(a->makeIterator(), b->makeIterator());
|
||||
}
|
||||
virtual ScriptValueP dependencyMember(const String& name, const Dependency& dep) const {
|
||||
return unified(a->dependencyMember(name,dep), b->dependencyMember(name,dep));
|
||||
}
|
||||
private:
|
||||
ScriptValueP a, b;
|
||||
};
|
||||
@@ -212,8 +213,7 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
|
||||
// Get an object member (almost as normal)
|
||||
case I_MEMBER_C: {
|
||||
String name = *script.constants[i.data];
|
||||
stack.back()->signalDependent(*this, dep, name); // dependency on member
|
||||
stack.back() = stack.back()->getMember(name);
|
||||
stack.back() = stack.back()->dependencyMember(name, dep); // dependency on member
|
||||
break;
|
||||
}
|
||||
// Loop over a container, push next value or jump (almost as normal)
|
||||
@@ -295,8 +295,7 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
|
||||
break;
|
||||
case I_MEMBER: {
|
||||
String name = *b;
|
||||
a->signalDependent(*this, dep, name); // dependency on member
|
||||
a = a->getMember(name);
|
||||
a = a->dependencyMember(name, dep); // dependency on member
|
||||
break;
|
||||
} case I_ADD:
|
||||
unify(a, b); // may be function composition
|
||||
|
||||
@@ -123,7 +123,7 @@ ScriptImageP ScriptableImage::update(Context& ctx, Package& pkg, UInt width, UIn
|
||||
bool ScriptableImage::upToDate(Context& ctx, Age age) const {
|
||||
try {
|
||||
WITH_DYNAMIC_ARG(last_update_age, age.get());
|
||||
return (int)*script.invoke(ctx);
|
||||
return script_image_up_to_date(script.invoke(ctx));
|
||||
} catch (Error e) {
|
||||
return true; // script gives errors, don't update
|
||||
}
|
||||
|
||||
@@ -78,6 +78,15 @@ Context& ScriptManager::getContext(const StyleSheetP& stylesheet) {
|
||||
return *ctx;
|
||||
}
|
||||
}
|
||||
Context& ScriptManager::getContext(const CardP& card) {
|
||||
Context& ctx = getContext(set.stylesheetFor(card));
|
||||
if (card) {
|
||||
ctx.setVariable(_("card"), toScript(card));
|
||||
} else {
|
||||
ctx.setVariable(_("card"), script_nil);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void ScriptManager::initDependencies(Context& ctx, Game& game) {
|
||||
if (game.dependencies_initialized) return;
|
||||
@@ -115,7 +124,7 @@ void ScriptManager::onAction(const Action& action, bool undone) {
|
||||
void ScriptManager::updateStyles(const CardP& card) {
|
||||
// lastUpdatedCard = card;
|
||||
StyleSheetP stylesheet = set.stylesheetFor(card);
|
||||
Context& ctx = getContext(stylesheet);
|
||||
Context& ctx = getContext(card);
|
||||
// update all styles
|
||||
FOR_EACH(s, stylesheet->card_style) {
|
||||
if (s->update(ctx)) {
|
||||
@@ -130,7 +139,7 @@ void ScriptManager::updateValue(Value& value, const CardP& card) {
|
||||
Age starting_age; // the start of the update process
|
||||
deque<ToUpdate> to_update;
|
||||
// execute script for initial changed value
|
||||
value.update(getContext(set.stylesheetFor(card)));
|
||||
value.update(getContext(card));
|
||||
// update dependent scripts
|
||||
alsoUpdate(to_update, value.fieldP->dependent_scripts, card);
|
||||
updateRecursive(to_update, starting_age);
|
||||
@@ -144,7 +153,7 @@ void ScriptManager::updateAll() {
|
||||
}
|
||||
// update card data of all cards
|
||||
FOR_EACH(card, set.cards) {
|
||||
Context& ctx = getContext(set.stylesheetFor(card));
|
||||
Context& ctx = getContext(card);
|
||||
FOR_EACH(v, card->data) {
|
||||
v->update(ctx);
|
||||
}
|
||||
@@ -171,7 +180,7 @@ void ScriptManager::updateRecursive(deque<ToUpdate>& to_update, Age starting_age
|
||||
void ScriptManager::updateToUpdate(const ToUpdate& u, deque<ToUpdate>& to_update, Age starting_age) {
|
||||
Age age = u.value->last_script_update;
|
||||
if (starting_age < age) return; // this value was already updated
|
||||
Context& ctx = getContext(set.stylesheetFor(u.card));
|
||||
Context& ctx = getContext(u.card);
|
||||
if (u.value->update(ctx)) {
|
||||
// changed, send event
|
||||
// ScriptValueEvent change(&*u.card, u.value);
|
||||
|
||||
@@ -41,7 +41,9 @@ class ScriptManager : public ActionListener {
|
||||
~ScriptManager();
|
||||
|
||||
/// Get a context to use for the set, for a given stylesheet
|
||||
Context& getContext(const StyleSheetP& s);
|
||||
Context& getContext(const StyleSheetP&);
|
||||
/// Get a context to use for the set, for a given card
|
||||
Context& getContext(const CardP&);
|
||||
|
||||
// Update all styles for a particular card
|
||||
void updateStyles(const CardP& card);
|
||||
@@ -66,8 +68,8 @@ class ScriptManager : public ActionListener {
|
||||
|
||||
// Something that needs to be updated
|
||||
struct ToUpdate {
|
||||
Value* value; // value to update
|
||||
CardP card; // card the value is in, or 0 if it is not a card field
|
||||
Value* value; ///< value to update
|
||||
CardP card; ///< card the value is in, or CadP() if it is not a card field
|
||||
};
|
||||
/// Update all things in to_update, and things that depent on them, etc.
|
||||
/** Only update things that are older than starting_age. */
|
||||
|
||||
+11
-2
@@ -23,8 +23,8 @@ ScriptValueP ScriptValue::next() { throw InternalEr
|
||||
ScriptValueP ScriptValue::makeIterator() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to collection")); }
|
||||
int ScriptValue::itemCount() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to collection")); }
|
||||
|
||||
void ScriptValue::signalDependent(Context&, const Dependency&, const String& name) {}
|
||||
ScriptValueP ScriptValue::dependencies(Context&, 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; }
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Iterators
|
||||
@@ -167,6 +167,15 @@ class ScriptString : public ScriptValue {
|
||||
}
|
||||
}
|
||||
virtual int itemCount() const { return (int)value.size(); }
|
||||
virtual ScriptValueP getMember(const String& name) const {
|
||||
// get member returns characters
|
||||
long index;
|
||||
if (name.ToLong(&index) && index >= 0 && (size_t)index < value.size()) {
|
||||
return toScript(String(1,value[index]));
|
||||
} else {
|
||||
throw ScriptError(_("String \"") + value + _("\" has no member ") + name);
|
||||
}
|
||||
}
|
||||
private:
|
||||
String value;
|
||||
};
|
||||
|
||||
+25
-7
@@ -68,9 +68,15 @@ class ScriptValue {
|
||||
|
||||
/// Get a member variable from this value
|
||||
virtual ScriptValueP getMember(const String& name) const;
|
||||
/// Signal that a script depends on a member of this value
|
||||
/** It is the abstract version of getMember*/
|
||||
virtual ScriptValueP dependencyMember(const String& name, const Dependency&) const;
|
||||
|
||||
/// Evaluate this value (if it is a function)
|
||||
virtual ScriptValueP eval(Context&) const;
|
||||
/// Mark the scripts that this function depends on
|
||||
/** Return value is an abstract version of the return value of eval */
|
||||
virtual ScriptValueP dependencies(Context&, const Dependency&) const;
|
||||
|
||||
/// Return an iterator for the current collection, an iterator is a value that has next()
|
||||
virtual ScriptValueP makeIterator() const;
|
||||
@@ -79,11 +85,6 @@ class ScriptValue {
|
||||
/// Return the number of items in this value (assuming it is a collection)
|
||||
virtual int itemCount() const;
|
||||
|
||||
/// Signal that a script depends on a member of this value
|
||||
virtual void signalDependent(Context&, const Dependency&, const String& name);
|
||||
/// Mark the scripts that this function depends on
|
||||
/** Return value is an abstract version of the return value of eval */
|
||||
virtual ScriptValueP dependencies(Context&, const Dependency&) const;
|
||||
|
||||
protected:
|
||||
/// Delete this object
|
||||
@@ -158,7 +159,7 @@ class ScriptCollection : public ScriptValue {
|
||||
virtual String typeName() const { return _("collection"); }
|
||||
virtual ScriptValueP getMember(const String& name) const {
|
||||
long index;
|
||||
if (name.ToLong(&index)) {
|
||||
if (name.ToLong(&index) && index >= 0 && (size_t)index < value->size()) {
|
||||
return toScript(value->at(index));
|
||||
} else {
|
||||
throw ScriptError(_("Collection has no member ") + name);
|
||||
@@ -220,14 +221,31 @@ class ScriptObject : public ScriptValue {
|
||||
inline ScriptObject(const T& v) : value(v) {}
|
||||
virtual ScriptType type() const { return SCRIPT_OBJECT; }
|
||||
virtual String typeName() const { return _("object"); }
|
||||
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 int() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator int(); }
|
||||
virtual operator Color() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator Color(); }
|
||||
virtual ScriptValueP getMember(const String& name) const {
|
||||
GetMember gm(name);
|
||||
gm.handle(*value);
|
||||
if (gm.result()) return gm.result();
|
||||
else throw ScriptError(_("Object has no member '") + name + _("'"));
|
||||
else {
|
||||
// try nameless member
|
||||
ScriptValueP d = getDefault();
|
||||
if (d) {
|
||||
return d->getMember(name);
|
||||
} else {
|
||||
throw ScriptError(_("Object has no member '") + name + _("'"));
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
T value; ///< The object
|
||||
ScriptValueP getDefault() const {
|
||||
GetDefaultMember gdm;
|
||||
gdm.handle(*value);
|
||||
return gdm.result();
|
||||
}
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Creating
|
||||
|
||||
@@ -79,7 +79,9 @@ class GetMember : private GetDefaultMember {
|
||||
/// Handle an object: we are done if the name matches
|
||||
template <typename T>
|
||||
void handle(const Char* name, const T& object) {
|
||||
if (!gdm.result() && name == target_name) gdm.handle(object);
|
||||
if (!gdm.result() && cannocial_name_compare(target_name, name)) {
|
||||
gdm.handle(object);
|
||||
}
|
||||
}
|
||||
/// Handle an object: investigate children
|
||||
template <typename T> void handle(const T&);
|
||||
|
||||
Reference in New Issue
Block a user