Commit 9857a30b authored by twanvl's avatar twanvl

Experimental:

 * use ScriptValueP, wrapped in AnyValue, instead of the specialized value types
 * serialize these values using script syntax.
 * However: #ifdefed out for now, because I first wanted to commit the following change:

This requires a change to handling of last_change of MultipleChoiceValue. Instead of storing it in the field, it is now just part of the action. The action therefore has to be passed to Value::update.
parent 66091cd7
......@@ -39,8 +39,15 @@ void ValueAction::isOnCard(Card* card) {
// ----------------------------------------------------------------------------- : Simple
/// Swap the value in a Value object with a new one
#if !USE_SCRIPT_VALUE_CHOICE
inline void swap_value(ChoiceValue& a, ChoiceValue ::ValueType& b) { swap(a.value, b); }
#endif
#if !USE_SCRIPT_VALUE_COLOR
inline void swap_value(ColorValue& a, ColorValue ::ValueType& b) { swap(a.value, b); }
#endif
#if USE_SCRIPT_VALUE_VALUE
inline void swap_value(AnyValue& a, AnyValue ::ValueType& b) { swap(a.value, b); }
#endif
inline void swap_value(ImageValue& a, ImageValue ::ValueType& b) { swap(a.filename, b); a.last_update.update(); }
inline void swap_value(SymbolValue& a, SymbolValue ::ValueType& b) { swap(a.filename, b); a.last_update.update(); }
inline void swap_value(TextValue& a, TextValue ::ValueType& b) { swap(a.value, b); a.last_update.update(); }
......@@ -80,15 +87,40 @@ class SimpleValueAction : public ValueAction {
typename T::ValueType new_value;
};
#if !USE_SCRIPT_VALUE_CHOICE
ValueAction* value_action(const ChoiceValueP& value, const Defaultable<String>& new_value) { return new SimpleValueAction<ChoiceValue, true> (value, new_value); }
#endif
#if !USE_SCRIPT_VALUE_COLOR
ValueAction* value_action(const ColorValueP& value, const Defaultable<Color>& new_value) { return new SimpleValueAction<ColorValue, true> (value, new_value); }
#endif
#if USE_SCRIPT_VALUE_VALUE
ValueAction* value_action(const AnyValueP& value, const ScriptValueP& new_value) { return new SimpleValueAction<AnyValue, false>(value, new_value); }
#endif
ValueAction* value_action(const ImageValueP& value, const FileName& new_value) { return new SimpleValueAction<ImageValue, false>(value, new_value); }
ValueAction* value_action(const SymbolValueP& value, const FileName& new_value) { return new SimpleValueAction<SymbolValue, false>(value, new_value); }
ValueAction* value_action(const PackageChoiceValueP& value, const String& new_value) { return new SimpleValueAction<PackageChoiceValue, false>(value, new_value); }
// ----------------------------------------------------------------------------- : MultipleChoice
/*
ValueAction* value_action(const MultipleChoiceValueP& value, const Defaultable<String>& new_value, const String& last_change) {
MultipleChoiceValue::ValueType v = { new_value, last_change };
return new SimpleValueAction<MultipleChoiceValue, false>(value, v);
}
*/
ValueAction* value_action(const MultipleChoiceValueP& value, const Defaultable<String>& new_value, const String& last_change) {
return new MultipleChoiceValueAction(value,new_value,last_change);
}
// copy paste of SimpleValueAction :(
// TODO: do this in a better way
void MultipleChoiceValueAction::perform(bool to_undo) {
ValueAction::perform(to_undo);
swap_value(static_cast<MultipleChoiceValue&>(*valueP), new_value);
valueP->onAction(*this, to_undo); // notify value
}
// ----------------------------------------------------------------------------- : Text
......
......@@ -24,12 +24,17 @@ DECLARE_POINTER_TYPE(Set);
DECLARE_POINTER_TYPE(Value);
DECLARE_POINTER_TYPE(Style);
DECLARE_POINTER_TYPE(TextValue);
#if !USE_SCRIPT_VALUE_CHOICE
DECLARE_POINTER_TYPE(ChoiceValue);
#endif
DECLARE_POINTER_TYPE(MultipleChoiceValue);
#if !USE_SCRIPT_VALUE_COLOR
DECLARE_POINTER_TYPE(ColorValue);
#endif
DECLARE_POINTER_TYPE(ImageValue);
DECLARE_POINTER_TYPE(SymbolValue);
DECLARE_POINTER_TYPE(PackageChoiceValue);
DECLARE_POINTER_TYPE(AnyValue);
// ----------------------------------------------------------------------------- : ValueAction (based class)
......@@ -55,12 +60,34 @@ class ValueAction : public Action {
// ----------------------------------------------------------------------------- : Simple
/// Action that updates a Value to a new value
#if !USE_SCRIPT_VALUE_CHOICE
ValueAction* value_action(const ChoiceValueP& value, const Defaultable<String>& new_value);
ValueAction* value_action(const MultipleChoiceValueP& value, const Defaultable<String>& new_value, const String& last_change);
#endif
#if !USE_SCRIPT_VALUE_COLOR
ValueAction* value_action(const ColorValueP& value, const Defaultable<Color>& new_value);
#endif
ValueAction* value_action(const ImageValueP& value, const FileName& new_value);
ValueAction* value_action(const SymbolValueP& value, const FileName& new_value);
ValueAction* value_action(const PackageChoiceValueP& value, const String& new_value);
#if USE_SCRIPT_VALUE_VALUE
ValueAction* value_action(const AnyValueP& value, const ScriptValueP& new_value);
#endif
ValueAction* value_action(const MultipleChoiceValueP& value, const Defaultable<String>& new_value, const String& last_change);
// ----------------------------------------------------------------------------- : MultipleChoice
class MultipleChoiceValueAction : public ValueAction {
public:
inline MultipleChoiceValueAction(const ValueP& value, const Defaultable<String>& new_value, const String& changed_choice)
: ValueAction(value), new_value(new_value), changed_choice(changed_choice)
{}
virtual void perform(bool to_undo);
const String changed_choice; ///< What choice was toggled by this action (if any)
private:
Defaultable<String> new_value;
};
// ----------------------------------------------------------------------------- : Text
......
......@@ -275,7 +275,7 @@ bool Value::equals(const Value* that) {
return this == that;
}
bool Value::update(Context& ctx) {
bool Value::update(Context& ctx, const Action*) {
updateAge();
updateSortValue(ctx);
return false;
......@@ -304,23 +304,15 @@ void mark_dependency_member(const IndexMap<FieldP,ValueP>& value, const String&
}
}
// ----------------------------------------------------------------------------- : AnyValue
ValueP AnyValue::clone() const {
return intrusive(new AnyValue(fieldP,value));
}
String AnyValue::toString() const {
return value->toString();
}
void AnyValue::reflect(GetDefaultMember& reflector) {
reflector.handle(value);
}
void AnyValue::reflect(GetMember& reflector) {
// nothing
}
// ----------------------------------------------------------------------------- : AnyValue : reflecting ScriptValues
// TODO: move this to a more sensible location
ScriptValueP parse_script_value(String const& str) {
DECLARE_DYNAMIC_ARG(Field const*, field_for_reading);
IMPLEMENT_DYNAMIC_ARG(Field const*, field_for_reading, nullptr);
ScriptValueP parse_script_value(String::const_iterator& it, String::const_iterator const& end) {
// possible values:
// * "quoted string" # a string
// * 123.456 # a number
......@@ -328,54 +320,138 @@ ScriptValueP parse_script_value(String const& str) {
// * rgb(123,123,123) # a color
// * nil # nil
// * true/false # a boolean
return script_nil;
// * mark_default(value) # a value marked as being default
throw "TODO";
// reader.warning();
}
ScriptValueP parse_script_value(String const& str) {
String::const_iterator it = str.begin();
ScriptValueP val = parse_script_value(it, str.end());
// stuff after the value
while (it != str.end()) {
if (*it == _('#')) {
// comment until end of line
while (it != str.end() && *it != _('\n')) ++it;
} else if (isSpace(*it)) {
// ignore whitespace
++it;
} else {
//reader.warning(_(""));
break;
}
}
return val;
}
void parse_errors_to_reader_warnings(Reader& reader, vector<ScriptParseError> const& errors);
/// A filename in the current set
/// functions differently wrt. garbage collection
/*class ScriptLocalFileName : public ScriptString {
public:
ScriptLocalFileName(String const& filename) : ScriptString(filename) {}
// TODO!
};*/
void AnyValue::reflect(Reader& reflector) {
if (reflector.formatVersion() < 200001) {
void Reader::handle(ScriptValueP& value) {
Field const* field = field_for_reading();
if (formatVersion() < 20001 && field) {
// in older versions, the format was based on the type of the field
Field* field = fieldP.get();
if (dynamic_cast<BooleanField*>(field)) {
if (dynamic_cast<BooleanField const*>(field)) {
// boolean field: boolean "yes" or "no"
bool x;
reflector.handle(x);
handle(x);
value = to_script(x);
} else if (dynamic_cast<TextField*>(field) || dynamic_cast<ChoiceField*>(field)) {
} else if (dynamic_cast<TextField const*>(field) || dynamic_cast<ChoiceField const*>(field)) {
// text, choice fields: string
String str;
reflector.handle(str);
handle(str);
value = to_script(str);
} else if (dynamic_cast<ColorField*>(field)) {
} else if (dynamic_cast<ColorField const*>(field)) {
// color field: color
Color x;
reflector.handle(x);
handle(x);
value = to_script(x);
} else if (dynamic_cast<ImageField*>(field)) {
} else if (dynamic_cast<ImageField const*>(field)) {
// image, symbol fields: string that is a filename in the set
String str;
reflector.handle(str);
//value = intrusive(new ScriptLocalFileName(str));
handle(str);
//Packaged* package = package_for_reading();
Packaged* package = nullptr; // TODO
value = intrusive(new ScriptLocalFileName(package,str));
throw "TODO";
} else if (dynamic_cast<InfoField*>(field)) {
} else if (dynamic_cast<InfoField const*>(field)) {
// this should never happen, since info fields were not saved
String str;
handle(str);
}
} else {
// in the new system, the type is stored in the file.
String str;
reflector.handle(str);
value = parse_script_value(str);
String unparsed;
vector<ScriptParseError> errors;
handle(unparsed);
value = parse_value(unparsed, this->getPackage(), errors);
if (!value) {
value = script_nil;
}
parse_errors_to_reader_warnings(*this, errors);
}
}
void AnyValue::reflect(Writer& reflector) {
if (!fieldP->save_value) return;
// TODO
reflector.handle(value->toString());
void Writer::handle(ScriptValueP const& value) {
// TODO: Make a distinction in which values can be saved?
handle(value->toCode());
}
// ----------------------------------------------------------------------------- : AnyField
#if USE_SCRIPT_VALUE_VALUE
ScriptValueP script_default_nil() { static ScriptValueP x(new ScriptDefault(script_nil)); return x; }
AnyField::AnyField() : initial(script_default_nil()) {}
void AnyField::initDependencies(Context& ctx, const Dependency& dep) const {
Field ::initDependencies(ctx, dep);
script .initDependencies(ctx, dep);
default_script.initDependencies(ctx, dep);
}
IMPLEMENT_REFLECTION(AnyField) {
REFLECT_BASE(Field);
REFLECT(script);
REFLECT_N("default", default_script);
WITH_DYNAMIC_ARG(field_for_reading, this);
REFLECT(initial);
}
// ----------------------------------------------------------------------------- : AnyValue
AnyValue::AnyValue(AnyFieldP const& field)
: Value(field), value(field->initial)
{}
AnyValue::AnyValue(AnyFieldP const& field, ScriptValueP const& value)
: Value(field), value(value)
{}
/*// TODO: conflict with ColorValue::clone, from IMPLEMENT_FIELD
ValueP AnyValue::clone() const {
return intrusive(new AnyValue(*this));
}*/
String AnyValue::toString() const {
return value->toString();
}
bool AnyValue::update(Context& ctx, const Action* act) {
bool change = false;
if (ScriptDefault const* dv = dynamic_cast<ScriptDefault*>(value.get())) {
ScriptValueP dvv = dv->value;
change = field().default_script.invokeOn(ctx, dvv);
change |= field().script.invokeOn(ctx, dvv);
if (change) value = intrusive(new ScriptDefault(dvv));
} else {
change = field().script.invokeOn(ctx, value);
}
change |= Value::update(ctx, act);
return change;
}
IMPLEMENT_REFLECTION_NAMELESS(AnyValue) {
if (reflector.isWriting() && !fieldP->save_value) return;
if (reflector.isWriting() && is_default(value)) return;
WITH_DYNAMIC_ARG(field_for_reading, fieldP.get());
REFLECT_NAMELESS(value);
}
#endif
......@@ -34,6 +34,11 @@ DECLARE_POINTER_TYPE(ValueEditor);
// Value for which script updates are being run
DECLARE_DYNAMIC_ARG(Value*, value_being_updated);
// experimental: use ScriptValue to store any kind of value
#define USE_SCRIPT_VALUE_VALUE 0
#define USE_SCRIPT_VALUE_COLOR 0
#define USE_SCRIPT_VALUE_CHOICE 0
// ----------------------------------------------------------------------------- : Field
/// Information on how to store a value
......@@ -217,7 +222,9 @@ class Value : public IntrusivePtrVirtualBase {
/// Convert this value to a string for use in tables
virtual String toString() const = 0;
/// Apply scripts to this value, return true if the value has changed
virtual bool update(Context& ctx);
/** Optionally, the action that causes the update is also passed.
*/
virtual bool update(Context& ctx, const Action* = nullptr);
/// This value has been updated by an action
/** Does nothing for most Values, only FakeValues can update underlying data */
virtual void onAction(Action& a, bool undone) {}
......@@ -300,23 +307,43 @@ inline String type_name(const Value&) {
void mark_dependency_member(const IndexMap<FieldP,ValueP>& value, const String& name, const Dependency& dep);
#if USE_SCRIPT_VALUE_VALUE
// ----------------------------------------------------------------------------- : Value (new style)
/// Base class for fields whos values can be scripted
class AnyField : public Field {
public:
AnyField();
OptionalScript script; ///< Script to apply to all values
OptionalScript default_script; ///< Script that generates the default value
ScriptValueP initial; ///< Initial choice of a new value, if not set the first choice is used
virtual void initDependencies(Context&, const Dependency&) const;
DECLARE_REFLECTION_VIRTUAL();
};
DECLARE_POINTER_TYPE(AnyField)
/// A Value object that can hold something of 'any' type
class AnyValue : public Value {
public:
inline AnyValue(FieldP const& field, ScriptValueP const& value = script_nil)
: Value(field), value(value)
{}
AnyValue(AnyFieldP const& field);
AnyValue(AnyFieldP const& field, ScriptValueP const& value);
/// The actual value
typedef ScriptValueP ValueType;
ScriptValueP value;
virtual ValueP clone() const;
virtual String toString() const;
typedef ScriptValueP ValueType;
virtual bool update(Context& ctx, const Action* = nullptr);
DECLARE_HAS_FIELD(Any)
DECLARE_REFLECTION_VIRTUAL();
};
DECLARE_POINTER_TYPE(AnyValue)
#endif
// ----------------------------------------------------------------------------- : EOF
#endif
......@@ -19,23 +19,31 @@ DECLARE_TYPEOF(map<String COMMA ScriptableImage>);
ChoiceField::ChoiceField()
: choices((Choice*)new Choice)
#if !USE_SCRIPT_VALUE_CHOICE
, default_name(_("Default"))
#endif
{}
IMPLEMENT_FIELD_TYPE(Choice, "choice");
#if !USE_SCRIPT_VALUE_CHOICE
void ChoiceField::initDependencies(Context& ctx, const Dependency& dep) const {
Field ::initDependencies(ctx, dep);
script .initDependencies(ctx, dep);
default_script.initDependencies(ctx, dep);
}
#endif
IMPLEMENT_REFLECTION(ChoiceField) {
#if USE_SCRIPT_VALUE_CHOICE
REFLECT_BASE(AnyField);
#else
REFLECT_BASE(Field);
REFLECT_N("choices", choices->choices);
REFLECT(script);
REFLECT_N("default", default_script);
REFLECT(initial);
#endif
REFLECT_N("choices", choices->choices);
REFLECT(default_name);
REFLECT_IF_READING {
choices->initIds();
......@@ -283,6 +291,7 @@ IMPLEMENT_REFLECTION(ChoiceStyle) {
reflect_content(reflector, *this);
}
#if !USE_SCRIPT_VALUE_CHOICE
// ----------------------------------------------------------------------------- : ChoiceValue
ChoiceValue::ChoiceValue(const ChoiceFieldP& field, bool initial_first_choice)
......@@ -296,7 +305,7 @@ ChoiceValue::ChoiceValue(const ChoiceFieldP& field, bool initial_first_choice)
String ChoiceValue::toString() const {
return value();
}
bool ChoiceValue::update(Context& ctx) {
bool ChoiceValue::update(Context& ctx, const Action*) {
bool change = field().default_script.invokeOnDefault(ctx, value)
| field(). script.invokeOn(ctx, value);
Value::update(ctx);
......@@ -308,3 +317,4 @@ IMPLEMENT_REFLECTION_NAMELESS(ChoiceValue) {
}
INSTANTIATE_REFLECTION_NAMELESS(ChoiceValue)
#endif USE_SCRIPT_VALUE_CHOICE
......@@ -22,10 +22,16 @@
DECLARE_POINTER_TYPE(ChoiceField);
DECLARE_POINTER_TYPE(ChoiceStyle);
#if !USE_SCRIPT_VALUE_CHOICE
DECLARE_POINTER_TYPE(ChoiceValue);
#endif
/// A field that contains a list of choices
#if USE_SCRIPT_VALUE_CHOICE
class ChoiceField : public AnyField {
#else
class ChoiceField : public Field {
#endif
public:
ChoiceField();
DECLARE_FIELD_TYPE(Choice);
......@@ -34,14 +40,16 @@ class ChoiceField : public Field {
typedef intrusive_ptr<Choice> ChoiceP;
ChoiceP choices; ///< A choice group of possible choices
OptionalScript script; ///< Script to apply to all values
OptionalScript default_script; ///< Script that generates the default value
String initial; ///< Initial choice of a new value, or ""
String default_name; ///< Name of "default" value
map<String,Color> choice_colors; ///< Colors for the various choices (when color_cardlist)
map<String,Color> choice_colors_cardlist; ///< Colors for the various choices, for in the card list
#if !USE_SCRIPT_VALUE_CHOICE
virtual void initDependencies(Context&, const Dependency&) const;
OptionalScript script; ///< Script to apply to all values
OptionalScript default_script; ///< Script that generates the default value
String initial; ///< Initial choice of a new value, or ""
#endif
};
......@@ -164,6 +172,10 @@ class ChoiceStyle : public Style {
// ----------------------------------------------------------------------------- : ChoiceValue
#if USE_SCRIPT_VALUE_CHOICE
typedef AnyValue ChoiceValue;
typedef AnyValueP ChoiceValueP;
#else
/// The Value in a ChoiceField
class ChoiceValue : public Value {
public:
......@@ -176,8 +188,9 @@ class ChoiceValue : public Value {
ValueType value; /// The name of the selected choice
virtual bool update(Context&);
virtual bool update(Context&, const Action* = nullptr);
};
#endif
// ----------------------------------------------------------------------------- : EOF
#endif
......@@ -21,18 +21,23 @@ ColorField::ColorField()
IMPLEMENT_FIELD_TYPE(Color, "color");
#if !USE_SCRIPT_VALUE_COLOR
void ColorField::initDependencies(Context& ctx, const Dependency& dep) const {
Field ::initDependencies(ctx, dep);
script .initDependencies(ctx, dep);
default_script.initDependencies(ctx, dep);
}
#endif
IMPLEMENT_REFLECTION(ColorField) {
#if USE_SCRIPT_VALUE_COLOR
REFLECT_BASE(AnyField);
#else
REFLECT_BASE(Field);
REFLECT(script);
REFLECT_N("default", default_script);
REFLECT(initial);
#endif
REFLECT(default_name);
REFLECT(allow_custom);
REFLECT(choices);
......@@ -76,6 +81,8 @@ int ColorStyle::update(Context& ctx) {
// ----------------------------------------------------------------------------- : ColorValue
#if !USE_SCRIPT_VALUE_COLOR
ColorValue::ColorValue(const ColorFieldP& field)
: Value(field)
, value( !field->initial.isDefault() ? field->initial()
......@@ -92,7 +99,7 @@ String ColorValue::toString() const {
}
return _("<color>");
}
bool ColorValue::update(Context& ctx) {
bool ColorValue::update(Context& ctx, const Action*) {
bool change = field().default_script.invokeOnDefault(ctx, value)
| field(). script.invokeOn(ctx, value);
Value::update(ctx);
......@@ -102,3 +109,6 @@ bool ColorValue::update(Context& ctx) {
IMPLEMENT_REFLECTION_NAMELESS(ColorValue) {
if (fieldP->save_value || !reflector.isWriting()) REFLECT_NAMELESS(value);
}
#endif
......@@ -19,10 +19,16 @@
DECLARE_POINTER_TYPE(ColorField);
DECLARE_POINTER_TYPE(ColorStyle);
#if !USE_SCRIPT_VALUE_COLOR
DECLARE_POINTER_TYPE(ColorValue);
#endif
/// A field for color values, it contains a list of choices for colors
#if USE_SCRIPT_VALUE_COLOR
class ColorField : public AnyField {
#else
class ColorField : public Field {
#endif
public:
ColorField();
DECLARE_FIELD_TYPE(Color);
......@@ -30,14 +36,16 @@ class ColorField : public Field {
class Choice;
typedef intrusive_ptr<Choice> ChoiceP;
OptionalScript script; ///< Script to apply to all values
OptionalScript default_script; ///< Script that generates the default value
vector<ChoiceP> choices; ///< Color choices available
bool allow_custom; ///< Are colors not in the list of choices allowed?
Defaultable<Color> initial; ///< Initial choice of a new value, if not set the first choice is used
String default_name; ///< Name of "default" value
#if !USE_SCRIPT_VALUE_COLOR
virtual void initDependencies(Context&, const Dependency&) const;
OptionalScript script; ///< Script to apply to all values
OptionalScript default_script; ///< Script that generates the default value
Defaultable<Color> initial; ///< Initial choice of a new value, or ""
#endif
};
/// A color that can be chosen for this field
......@@ -69,6 +77,10 @@ class ColorStyle : public Style {
// ----------------------------------------------------------------------------- : ColorValue
#if USE_SCRIPT_VALUE_CHOICE
typedef AnyValue ColorValue;
typedef AnyValueP ColorValueP;
#else
/// The Value in a ColorField
class ColorValue : public Value {
public:
......@@ -77,9 +89,9 @@ class ColorValue : public Value {
ValueType value; ///< The value
virtual bool update(Context&);
virtual bool update(Context&, const Action* = nullptr);
};
#endif
// ----------------------------------------------------------------------------- : EOF
#endif
......@@ -62,7 +62,7 @@ IMPLEMENT_REFLECTION(InfoStyle) {
String InfoValue::toString() const {
return value;
}
bool InfoValue::update(Context& ctx) {
bool InfoValue::update(Context& ctx, const Action*) {
if (value.empty()) value = field().caption;
bool change = field().script.invokeOn(ctx, value);
Value::update(ctx);
......
......@@ -62,7 +62,7 @@ class InfoValue : public Value {
ValueType value;
virtual bool update(Context&);
virtual bool update(Context&, const Action* = nullptr);
};
// ----------------------------------------------------------------------------- : EOF
......
......@@ -8,6 +8,7 @@
#include <util/prec.hpp>
#include <data/field/multiple_choice.hpp>
#include <data/action/value.hpp>
// ----------------------------------------------------------------------------- : MultipleChoiceField
......@@ -51,10 +52,13 @@ IMPLEMENT_REFLECTION_NAMELESS(MultipleChoiceValue) {
REFLECT_BASE(ChoiceValue);
}
bool MultipleChoiceValue::update(Context& ctx) {
bool MultipleChoiceValue::update(Context& ctx, const Action* act) {
String old_value = value();
ctx.setVariable(_("last_change"), to_script(last_change));
ChoiceValue::update(ctx);
if (const MultipleChoiceValueAction* mvca = dynamic_cast<const MultipleChoiceValueAction*>(act)) {
ctx.setVariable(_("last_change"), to_script(mvca->changed_choice));
}
// ctx.setVariable(_("last_change"), to_script(last_change));
ChoiceValue::update(ctx,act);
normalForm();
return value() != old_value;
}
......
......@@ -65,7 +65,7 @@ class MultipleChoiceValue : public ChoiceValue {
/// Splits the value, stores the selected choices in the out parameter
void get(vector<String>& out) const;
virtual bool update(Context&);
virtual bool update(Context&, const Action* = nullptr);
private:
DECLARE_REFLECTION();
......
......@@ -61,9 +61,9 @@ PackagedP PackageChoiceValue::getPackage() const {
else return package_manager.openAny(package_name, true);
}
bool PackageChoiceValue::update(Context& ctx) {
bool PackageChoiceValue::update(Context& ctx, const Action* act) {
bool change = field().script.invokeOn(ctx, package_name);
Value::update(ctx);
Value::update(ctx,act);
return change;
}
......
......@@ -63,7 +63,7 @@ class PackageChoiceValue : public Value {
/// Get the package (if it is set)
PackagedP getPackage() const;
virtual bool update(Context&);
virtual bool update(Context&, const Action* = nullptr);
};
// ----------------------------------------------------------------------------- : EOF
......
......@@ -135,7 +135,7 @@ IMPLEMENT_REFLECTION(TextStyle) {
String TextValue::toString() const {
return untag_hide_sep(value());
}
bool TextValue::update(Context& ctx) {
bool TextValue::update(Context& ctx, const Action*) {
updateAge();
WITH_DYNAMIC_ARG(last_update_age, last_update.get());
WITH_DYNAMIC_ARG(value_being_updated, this);
......
......@@ -92,7 +92,7 @@ class TextValue : public Value {
ValueType value; ///< The text of this value
Age last_update; ///< When was the text last changed?
virtual bool update(Context&);
virtual bool update(Context&, const Action* = nullptr);
};
// ----------------------------------------------------------------------------- : TextValue
......
......@@ -25,7 +25,7 @@
DECLARE_TYPEOF_COLLECTION(CardP);
DECLARE_TYPEOF_COLLECTION(FieldP);
DECLARE_POINTER_TYPE(ChoiceValue);
//%DECLARE_POINTER_TYPE(ChoiceValue);
DECLARE_TYPEOF(map<int COMMA FieldP>);
DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA StyleP>);
DECLARE_TYPEOF_COLLECTION(CardListBase*);
......
......@@ -43,8 +43,14 @@ SCRIPT_FUNCTION(new_card) {
cvalue->value = v->toString();
} else if (PackageChoiceValue* pvalue = dynamic_cast<PackageChoiceValue*>(value)) {
pvalue->package_name = v->toString();
#if !USE_SCRIPT_VALUE_COLOR
} else if (ColorValue* cvalue = dynamic_cast<ColorValue*>(value)) {
cvalue->value = v->toColor();
#endif
#if USE_SCRIPT_VALUE_VALUE
} else if (AnyValue* avalue = dynamic_cast<AnyValue*>(value)) {
avalue->value = v;
#endif
} else {
throw ScriptError(format_string(_("Can not set value '%s', it is not of the right type"),name));
}
......
......@@ -155,7 +155,7 @@ void SetScriptManager::onAction(const Action& action, bool undone) {
TYPE_CASE(action, ValueAction) {
if (action.card) {
// we can just turn the Card* into a CardP
updateValue(*action.valueP, intrusive_from_existing(const_cast<Card*>(action.card)));
updateValue(*action.valueP, intrusive_from_existing(const_cast<Card*>(action.card)), &action);
return;
} else {
// is it a keyword's fake value?
......@@ -173,7 +173,7 @@ void SetScriptManager::onAction(const Action& action, bool undone) {
return;
}
// a set or styling value
updateValue(*action.valueP, CardP());
updateValue(*action.valueP, CardP(), &action);
}
}
TYPE_CASE_(action, ScriptValueEvent) {
......@@ -186,7 +186,7 @@ void SetScriptManager::onAction(const Action& action, bool undone) {
const CardP& card = step.item;
Context& ctx = getContext(card);
FOR_EACH(v, card->data) {
v->update(ctx);
v->update(ctx,&action);
}
}
}
......@@ -259,11 +259,11 @@ void SetScriptManager::updateDelayed() {
delay = 0;
}
void SetScriptManager::updateValue(Value& value, const CardP& card) {
void SetScriptManager::updateValue(Value& value, const CardP& card, Action const* action) {
Age starting_age; // the start of the update process
deque<ToUpdate> to_update;
// execute script for initial changed value
value.update(getContext(card));
value.update(getContext(card), action);
#ifdef LOG_UPDATES
wxLogDebug(_("Start: %s"), value.fieldP->name);
#endif
......
......@@ -81,8 +81,10 @@ class SetScriptManager : public SetScriptContext, public ActionListener {
/// Update a map of styles
void updateStyles(Context& ctx, const IndexMap<FieldP,StyleP>& styles, bool only_content_dependent);
/// Updates scripts, starting at some value
/** if the value changes any dependend values are updated as well */
void updateValue(Value& value, const CardP& card);
/** if the value changes any dependend values are updated as well
* optionally: action that causes this update
*/
void updateValue(Value& value, const CardP& card, const Action* action);
// Update all values with a specific dependency
void updateAllDependend(const vector<Dependency>& dependent_scripts, const CardP& card = CardP());
......
......@@ -52,9 +52,7 @@ ScriptValueP OptionalScript::invoke(Context& ctx, bool open_scope) const {
}
}
void OptionalScript::parse(Reader& reader, bool string_mode) {
vector<ScriptParseError> errors;
script = ::parse(unparsed, reader.getPackage(), string_mode, errors);
void parse_errors_to_reader_warnings(Reader& reader, vector<ScriptParseError> const& errors) {
// show parse errors as warnings
String include_warnings;
for (size_t i = 0 ; i < errors.size() ; ++i) {
......@@ -73,6 +71,12 @@ void OptionalScript::parse(Reader& reader, bool string_mode) {
}
}
void OptionalScript::parse(Reader& reader, bool string_mode) {
vector<ScriptParseError> errors;
script = ::parse(unparsed, reader.getPackage(), string_mode, errors);
parse_errors_to_reader_warnings(reader,errors);
}
void OptionalScript::initDependencies(Context& ctx, const Dependency& dep) const {
if (script) {
ctx.dependencies(dep, *script);
......
......@@ -16,6 +16,7 @@ template <typename T> class Defaultable;
template <typename T> class Scriptable;
DECLARE_POINTER_TYPE(Game);
DECLARE_POINTER_TYPE(StyleSheet);
DECLARE_POINTER_TYPE(ScriptValue);
class Packaged;
// ----------------------------------------------------------------------------- : Reader
......@@ -95,11 +96,10 @@ class Reader {
template <typename K, typename V> void handle(IndexMap<K,V>&);
template <typename K, typename V> void handle(DelayedIndexMaps<K,V>&);
template <typename K, typename V> void handle(DelayedIndexMapsData<K,V>&);
/// Reads a Defaultable from the input stream
template <typename T> void handle(Defaultable<T>&);
/// Reads a Scriptable from the input stream
template <typename T> void handle(Scriptable<T>&);
// special behaviour
void handle(ScriptValueP&);
// special behaviour: only write the name of the package
void handle(GameP&);
void handle(StyleSheetP&);
......
......@@ -61,10 +61,9 @@ class Writer {
template <typename K, typename V> void handle(const IndexMap<K,V>&);
template <typename K, typename V> void handle(const DelayedIndexMaps<K,V>&);
template <typename K, typename V> void handle(const DelayedIndexMapsData<K,V>&);
/// Write an object of type Defaultable<T> to the output stream
template <typename T> void handle(const Defaultable<T>&);
/// Write an object of type Scriptable<T> to the output stream
template <typename T> void handle(const Scriptable<T>&);
void handle(const ScriptValueP&);
// special behaviour
void handle(const GameP&);
void handle(const StyleSheetP&);
......
......@@ -81,14 +81,16 @@ const Char* version_suffix = _(" (ascii build)");
* - store time created,modified for cards -> changes set and clipboard format
* 0.3.9 : bugfix release mostly, a few new script functions
* 2.0.0 : bugfix release mostly, added error console
* 2.0.1 : values are stored as ScriptValues, i.e. as parsable code.
* previously they were stored as unescaped strings, where the field type determined how the value would be parsed.
*/
const Version file_version_locale = 20000; // 2.0.0
const Version file_version_set = 308; // 0.3.8
const Version file_version_game = 308; // 0.3.8
const Version file_version_stylesheet = 308; // 0.3.8
const Version file_version_symbol_font = 306; // 0.3.6
const Version file_version_set = 20001; // 2.0.1
const Version file_version_game = 20001; // 2.0.1
const Version file_version_stylesheet = 20001; // 2.0.1
const Version file_version_symbol_font = 20001; // 2.0.1
const Version file_version_export_template = 307; // 0.3.7
const Version file_version_installer = 307; // 0.3.7
const Version file_version_symbol = 305; // 0.3.5
const Version file_version_clipboard = 308; // 0.3.8
const Version file_version_script = 307; // 0.3.7
const Version file_version_script = 20001; // 2.0.1
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment