Commit 5fb8cafb authored by twanvl's avatar twanvl

Big change set:

* Use ScriptValueP for all Value types.
  All Value types now inherit from AnyValue, all Fields inherit from AnyField.
  Common properties, in particular scripting, are done by AnyValue/AnyField

* Repurposed ImageValueToImage as the representation for image values.

* Added LocalSymbolFile as the representation for symbol values.

* Moved FileName to package.hpp, and renamed it to LocalFileName.
  The notification of packages that was previously done by Reader/Writer is now done by LocalFileName.

* Added toFriendlyString to ScriptValue, it is used (primarily) for the card list.
  The idea is that this function strips tags and always returns something, for example "<image>" for images.

* Removed backwards compatibility with 0.2.7 style tags, since I was too lazy to update it.

Code is a bit messy right now, since cleanup will come in separate commits.
parent 70f7be2b
......@@ -6,8 +6,16 @@
-- trunk: new items added as changes are made
------------------------------------------------------------------------------
Program:
* Changed the way values are saved to files.
Instead of the representation depending on the type, all values now use script syntax, e.g. "strings" in quotes.
Older files can still be opened, but sets saved with 2.0.1 can not be opened with older versions of mse.
Templates:
* many changes
------------------------------------------------------------------------------
-- 2.0.0
-- 2.0.0, 2011-??-??
------------------------------------------------------------------------------
Program:
......
......@@ -25,7 +25,21 @@ The type of a value depends on the corresponding field:
| @"color"@ opaque [[type:color]] A color.
| @"info"@ [[type:string]] A label for the information box.
--Example--
--File syntax--
DOC_MSE_VERSION: since 2.0.1
Values are stored using script syntax. This makes means that a value can be parsed without knowing the field type.
Here are some examples
>some_text_value: "This is a string\nNext line."
>some_choice_value: "uncommon"
>some_image_value: local_image_file("image1.png")
>some_symbol_value: local_symbol_file("symbol1.mse-symbol")
--Example (old syntax)--
DOC_MSE_VERSION: before 2.0.1
For the field:
>field:
> type: choice
......
......@@ -64,7 +64,7 @@ void KeywordReminderTextValue::store() {
return;
}
// new value
String new_value = untag(value);
String new_value = untag(value->toString());
// Try to parse the script
vector<ScriptParseError> parse_errors;
ScriptP new_script = parse(new_value, nullptr, true, parse_errors);
......@@ -173,7 +173,7 @@ void KeywordReminderTextValue::highlight(const String& code, const vector<Script
}
}
// set
value = new_value;
value = to_script(new_value);
}
bool KeywordReminderTextValue::checkScript(const ScriptP& script) {
......
......@@ -48,10 +48,18 @@ inline void swap_value(ColorValue& a, ColorValue ::ValueType& b
#if USE_SCRIPT_VALUE_VALUE
inline void swap_value(AnyValue& a, AnyValue ::ValueType& b) { swap(a.value, b); }
#endif
#if !USE_SCRIPT_VALUE_IMAGE
inline void swap_value(ImageValue& a, ImageValue ::ValueType& b) { swap(a.filename, b); }
#endif
#if !USE_SCRIPT_VALUE_SYMBOL
inline void swap_value(SymbolValue& a, SymbolValue ::ValueType& b) { swap(a.filename, b); }
#endif
#if !USE_SCRIPT_VALUE_TEXT
inline void swap_value(TextValue& a, TextValue ::ValueType& b) { swap(a.value, b); }
#endif
#if !USE_SCRIPT_VALUE_PACKAGE
inline void swap_value(PackageChoiceValue& a, PackageChoiceValue ::ValueType& b) { swap(a.package_name, b); }
#endif
/// A ValueAction that swaps between old and new values
template <typename T, bool ALLOW_MERGE>
......@@ -92,9 +100,15 @@ ValueAction* value_action(const ColorValueP& value, const Defaultable<C
#if USE_SCRIPT_VALUE_VALUE
ValueAction* value_action(const AnyValueP& value, const ScriptValueP& new_value) { return new SimpleValueAction<AnyValue, false>(value, new_value); }
#endif
#if !USE_SCRIPT_VALUE_IMAGE
ValueAction* value_action(const ImageValueP& value, const FileName& new_value) { return new SimpleValueAction<ImageValue, false>(value, new_value); }
#endif
#if !USE_SCRIPT_VALUE_SYMBOL
ValueAction* value_action(const SymbolValueP& value, const FileName& new_value) { return new SimpleValueAction<SymbolValue, false>(value, new_value); }
#endif
#if !USE_SCRIPT_VALUE_PACKAGE
ValueAction* value_action(const PackageChoiceValueP& value, const String& new_value) { return new SimpleValueAction<PackageChoiceValue, false>(value, new_value); }
#endif
// ----------------------------------------------------------------------------- : MultipleChoice
......@@ -119,7 +133,11 @@ void MultipleChoiceValueAction::perform(bool to_undo) {
// ----------------------------------------------------------------------------- : Text
#if USE_SCRIPT_VALUE_TEXT
TextValueAction::TextValueAction(const TextValueP& value, size_t start, size_t end, size_t new_end, const ScriptValueP& new_value, const String& name)
#else
TextValueAction::TextValueAction(const TextValueP& value, size_t start, size_t end, size_t new_end, const Defaultable<String>& new_value, const String& name)
#endif
: ValueAction(value)
, selection_start(start), selection_end(end), new_selection_end(new_end)
, new_value(new_value)
......@@ -164,22 +182,22 @@ TextValueAction* toggle_format_action(const TextValueP& value, const String& tag
swap(start_i, end_i);
}
String new_value;
const String& str = value->value();
String old_value = value->value->toString();
// Are we inside the tag we are toggling?
if (!is_in_tag(str, _("<") + tag, start_i, end_i)) {
if (!is_in_tag(old_value, _("<") + tag, start_i, end_i)) {
// we are not inside this tag, add it
new_value = str.substr(0, start_i);
new_value = old_value.substr(0, start_i);
new_value += _("<") + tag + _(">");
new_value += str.substr(start_i, end_i - start_i);
new_value += old_value.substr(start_i, end_i - start_i);
new_value += _("</") + tag + _(">");
new_value += str.substr(end_i);
new_value += old_value.substr(end_i);
} else {
// we are inside this tag, 'remove' it
new_value = str.substr(0, start_i);
new_value = old_value.substr(0, start_i);
new_value += _("</") + tag + _(">");
new_value += str.substr(start_i, end_i - start_i);
new_value += old_value.substr(start_i, end_i - start_i);
new_value += _("<") + tag + _(">");
new_value += str.substr(end_i);
new_value += old_value.substr(end_i);
}
// Build action
if (start != end) {
......@@ -187,10 +205,10 @@ TextValueAction* toggle_format_action(const TextValueP& value, const String& tag
// user to press Ctrl+B and start typing bold text
new_value = simplify_tagged(new_value);
}
if (value->value() == new_value) {
if (new_value == old_value) {
return nullptr; // no changes
} else {
return new TextValueAction(value, start, end, end, new_value, action_name);
return new TextValueAction(value, start, end, end, to_script(new_value), action_name);
}
}
......@@ -200,15 +218,16 @@ TextValueAction* typing_action(const TextValueP& value, size_t start_i, size_t e
swap(start, end);
swap(start_i, end_i);
}
String new_value = tagged_substr_replace(value->value(), start_i, end_i, replacement);
if (value->value() == new_value) {
String old_value = value->value->toString();
String new_value = tagged_substr_replace(old_value, start_i, end_i, replacement);
if (new_value == old_value) {
// no change
return nullptr;
} else {
if (reverse) {
return new TextValueAction(value, end, start, start+untag(replacement).size(), new_value, action_name);
return new TextValueAction(value, end, start, start+untag(replacement).size(), to_script(new_value), action_name);
} else {
return new TextValueAction(value, start, end, start+untag(replacement).size(), new_value, action_name);
return new TextValueAction(value, start, end, start+untag(replacement).size(), to_script(new_value), action_name);
}
}
}
......@@ -218,11 +237,12 @@ TextValueAction* typing_action(const TextValueP& value, size_t start_i, size_t e
TextToggleReminderAction::TextToggleReminderAction(const TextValueP& value, size_t pos_in)
: ValueAction(value)
{
pos = in_tag(value->value(), _("<kw-"), pos_in, pos_in);
String old_value = value->value->toString();
pos = in_tag(old_value, _("<kw-"), pos_in, pos_in);
if (pos == String::npos) {
throw InternalError(_("TextToggleReminderAction: not in <kw- tag"));
}
Char c = value->value().GetChar(pos + 4);
Char c = old_value.GetChar(pos + 4);
enable = !(c == _('1') || c == _('A')); // if it was not enabled, then enable it
old = enable ? _('1') : _('0');
}
......@@ -233,7 +253,7 @@ String TextToggleReminderAction::getName(bool to_undo) const {
void TextToggleReminderAction::perform(bool to_undo) {
ValueAction::perform(to_undo);
TextValue& value = static_cast<TextValue&>(*valueP);
String& val = value.value.mutate();
String val = value.value->toString();
assert(pos + 4 < val.size());
size_t end = match_close_tag(val, pos);
Char& c = val[pos + 4];
......@@ -241,6 +261,7 @@ void TextToggleReminderAction::perform(bool to_undo) {
if (end != String::npos && end + 5 < val.size()) {
val[end + 5] = c; // </kw-c>
}
value.value = to_script(val);
value.onAction(*this, to_undo); // notify value
}
......
......@@ -21,6 +21,7 @@
class Card;
class StyleSheet;
class LocalFileName;
DECLARE_POINTER_TYPE(Set);
DECLARE_POINTER_TYPE(Value);
DECLARE_POINTER_TYPE(Style);
......@@ -81,9 +82,15 @@ ValueAction* value_action(const MultipleChoiceValueP& value, const ScriptValueP&
#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);
#if !USE_SCRIPT_VALUE_IMAGE
ValueAction* value_action(const ImageValueP& value, const LocalFileName& new_value);
#endif
#if !USE_SCRIPT_VALUE_SYMBOL
ValueAction* value_action(const SymbolValueP& value, const LocalFileName& new_value);
#endif
#if !USE_SCRIPT_VALUE_PACKAGE
ValueAction* value_action(const PackageChoiceValueP& value, const String& new_value);
#endif
#if USE_SCRIPT_VALUE_VALUE
ValueAction* value_action(const AnyValueP& value, const ScriptValueP& new_value);
#endif
......@@ -116,13 +123,21 @@ class MultipleChoiceValueAction : public ValueAction {
/// An action that changes a TextValue
class TextValueAction : public ValueAction {
public:
#if USE_SCRIPT_VALUE_TEXT
TextValueAction(const TextValueP& value, size_t start, size_t end, size_t new_end, const ScriptValueP& new_value, const String& name);
#else
TextValueAction(const TextValueP& value, size_t start, size_t end, size_t new_end, const Defaultable<String>& new_value, const String& name);
#endif
virtual String getName(bool to_undo) const;
virtual void perform(bool to_undo);
virtual bool merge(const Action& action);
#if USE_SCRIPT_VALUE_TEXT
inline String newValue() const { return new_value->toString(); }
#else
inline const String& newValue() const { return new_value(); }
#endif
/// The modified selection
size_t selection_start, selection_end;
......@@ -130,7 +145,11 @@ class TextValueAction : public ValueAction {
inline TextValue& value() const;
size_t new_selection_end;
#if USE_SCRIPT_VALUE_TEXT
ScriptValueP new_value;
#else
Defaultable<String> new_value;
#endif
String name;
};
......
......@@ -44,12 +44,12 @@ String Card::identification() const {
// an identifying field
FOR_EACH_CONST(v, data) {
if (v->fieldP->identifying) {
return v->toString();
return v->toFriendlyString();
}
}
// otherwise the first field
if (!data.empty()) {
return data.at(0)->toString();
return data.at(0)->toFriendlyString();
} else {
return wxEmptyString;
}
......@@ -57,7 +57,7 @@ String Card::identification() const {
bool Card::contains(String const& query) const {
FOR_EACH_CONST(v, data) {
if (find_i(v->toString(),query) != String::npos) return true;
if (find_i(v->toFriendlyString(),query) != String::npos) return true;
}
if (find_i(notes,query) != String::npos) return true;
return false;
......
......@@ -321,6 +321,8 @@ IMPLEMENT_DYNAMIC_ARG(Field const*, field_for_reading, nullptr);
// * mark_default(value) # a value marked as being default
void parse_errors_to_reader_warnings(Reader& reader, vector<ScriptParseError> const& errors);
ScriptValueP script_local_image_file(LocalFileName const& filename);
ScriptValueP script_local_symbol_file(LocalFileName const& filename);
void Reader::handle(ScriptValueP& value) {
Field const* field = field_for_reading();
......@@ -331,7 +333,7 @@ void Reader::handle(ScriptValueP& value) {
bool x;
handle(x);
value = to_script(x);
} else if (dynamic_cast<TextField const*>(field) || dynamic_cast<ChoiceField const*>(field)) {
} else if (dynamic_cast<TextField const*>(field) || dynamic_cast<ChoiceField const*>(field) || dynamic_cast<PackageChoiceField const*>(field)) {
// text, choice fields: string
String str;
handle(str);
......@@ -345,25 +347,33 @@ void Reader::handle(ScriptValueP& value) {
// image, symbol fields: string that is a filename in the set
String str;
handle(str);
//Packaged* package = package_for_reading();
Packaged* package = nullptr; // TODO
value = intrusive(new ScriptLocalFileName(package,str));
throw "TODO";
value = script_local_image_file(LocalFileName::fromReadString(str));
} else if (dynamic_cast<SymbolField const*>(field)) {
// image, symbol fields: string that is a filename in the set
String str;
handle(str);
value = script_local_symbol_file(LocalFileName::fromReadString(str));
} else if (dynamic_cast<InfoField const*>(field)) {
// this should never happen, since info fields were not saved
String str;
handle(str);
} else {
throw InternalError(_("Reader::handle(ScriptValueP)"));
}
} else {
// in the new system, the type is stored in the file.
String unparsed;
vector<ScriptParseError> errors;
handle(unparsed);
value = parse_value(unparsed, this->getPackage(), errors);
if (!value) {
if (unparsed.empty()) {
value = script_default_nil;
} else {
vector<ScriptParseError> errors;
value = parse_value(unparsed, this->getPackage(), errors);
if (!value) {
value = script_default_nil;
}
parse_errors_to_reader_warnings(*this, errors);
}
parse_errors_to_reader_warnings(*this, errors);
}
}
void Writer::handle(ScriptValueP const& value) {
......@@ -411,11 +421,17 @@ AnyValue::AnyValue(AnyFieldP const& field, ScriptValueP const& value)
ValueP AnyValue::clone() const {
return intrusive(new AnyValue(*this));
}
String AnyValue::toString() const {
return value->toString();
String AnyValue::toFriendlyString() const {
try {
return value->toFriendlyString();
} catch (...) {
return _("<") + value->typeName() + _(">");
}
}
bool AnyValue::update(Context& ctx, const Action* act) {
WITH_DYNAMIC_ARG(last_update_age, last_modified.get()); // TODO: this is redundant, since it can be got from value_being_updated
WITH_DYNAMIC_ARG(value_being_updated, this);
bool change = false;
if (ScriptDefault const* dv = dynamic_cast<ScriptDefault*>(value.get())) {
ScriptValueP dvv = dv->un_default;
......
......@@ -37,14 +37,14 @@ DECLARE_DYNAMIC_ARG(Value*, value_being_updated);
// experimental: use ScriptValue to store any kind of value
// TODO: get rid of the conditional stuff
// TODO2: mergre Any{Field,Value} into {Field,Value}
#define USE_SCRIPT_VALUE_VALUE 0
#define USE_SCRIPT_VALUE_COLOR 0
#define USE_SCRIPT_VALUE_CHOICE 0
#define USE_SCRIPT_VALUE_INFO 0
#define USE_SCRIPT_VALUE_TEXT 0
#define USE_SCRIPT_VALUE_SYMBOL 0
#define USE_SCRIPT_VALUE_IMAGE 0
#define USE_SCRIPT_VALUE_PACKAGE 0
#define USE_SCRIPT_VALUE_VALUE 1
#define USE_SCRIPT_VALUE_COLOR 1
#define USE_SCRIPT_VALUE_CHOICE 1
#define USE_SCRIPT_VALUE_INFO 1
#define USE_SCRIPT_VALUE_TEXT 1
#define USE_SCRIPT_VALUE_SYMBOL 1
#define USE_SCRIPT_VALUE_IMAGE 1
#define USE_SCRIPT_VALUE_PACKAGE 1
// ----------------------------------------------------------------------------- : Field
......@@ -83,9 +83,10 @@ class Field : public IntrusivePtrVirtualBase {
/// Add the given dependency to the dependet_scripts list for the variables this field depends on
virtual void initDependencies(Context& ctx, const Dependency& dep) const;
virtual void after_reading(Version ver);
private:
DECLARE_REFLECTION_VIRTUAL();
virtual void after_reading(Version ver);
friend void after_reading(Field& s, Version ver);
};
template <>
......@@ -176,6 +177,8 @@ class Style : public IntrusivePtrVirtualBase {
private:
DECLARE_REFLECTION_VIRTUAL();
virtual void after_reading(Version ver) {}
friend void after_reading(Style& s, Version ver);
/// Things that are listening to changes in this style
vector<StyleListener*> listeners;
};
......@@ -199,6 +202,10 @@ inline String type_name(const Style&) {
return _TYPE_("style");
}
inline void after_reading(Style& s, Version ver) {
s.after_reading(ver);
}
void mark_dependency_member(const Style& style, const String& name, const Dependency& dep);
// ----------------------------------------------------------------------------- : StyleListener
......@@ -232,8 +239,8 @@ class Value : public IntrusivePtrVirtualBase {
/// Get a copy of this value
virtual ValueP clone() const = 0;
/// Convert this value to a string for use in tables
virtual String toString() const = 0;
/// Convert this value to a string, should be human readable, so no <tags>
virtual String toFriendlyString() const = 0;
/// Apply scripts to this value, return true if the value has changed
/** Optionally, the action that causes the update is also passed.
*/
......@@ -250,7 +257,7 @@ class Value : public IntrusivePtrVirtualBase {
/// Get the key to use for sorting this value
inline String getSortKey() const {
return fieldP->sort_script ? sort_value : toString();
return fieldP->sort_script ? sort_value : toFriendlyString();
}
protected:
......@@ -309,7 +316,7 @@ inline String type_name(const Value&) {
DECLARE_REFLECTION(); public: \
DECLARE_HAS_FIELD(Type) \
virtual ValueP clone() const; \
virtual String toString() const; \
virtual String toFriendlyString() const; \
typedef ValueType_ ValueType
// implement field() which returns a field with the right (derived) type
......@@ -346,12 +353,17 @@ class AnyValue : public Value {
/// The actual value
typedef ScriptValueP ValueType;
ScriptValueP value;
ScriptValueP value; // never null
virtual ValueP clone() const;
virtual String toString() const;
virtual String toFriendlyString() const;
virtual bool update(Context& ctx, const Action* = nullptr);
// Convenience functions
inline void operator = (ScriptValueP const& value) {
this->value = value;
}
DECLARE_HAS_FIELD(Any)
DECLARE_REFLECTION_VIRTUAL();
};
......
......@@ -12,8 +12,8 @@
// ----------------------------------------------------------------------------- : BooleanField
BooleanField::BooleanField() {
choices->choices.push_back(intrusive(new Choice(_("yes"))));
choices->choices.push_back(intrusive(new Choice(_("no"))));
choices->choices.push_back(intrusive(new Choice(_("true"),_("yes"))));
choices->choices.push_back(intrusive(new Choice(_("false"),_("no"))));
choices->initIds();
#if USE_SCRIPT_VALUE_CHOICE
initial = script_true;
......@@ -39,12 +39,21 @@ BooleanStyle::BooleanStyle(const ChoiceFieldP& field)
: ChoiceStyle(field)
{
render_style = RENDER_BOTH;
//choice_images[_("yes")] = ScriptableImage(_("buildin_image(\"bool_yes\")"));
//choice_images[_("no")] = ScriptableImage(_("buildin_image(\"bool_no\")"));
choice_images[_("yes")] = ScriptableImage(intrusive(new BuiltInImage(_("bool_yes"))));
choice_images[_("no")] = ScriptableImage(intrusive(new BuiltInImage(_("bool_no"))));
choice_images[_("true")] = ScriptableImage(intrusive(new BuiltInImage(_("bool_yes"))));
choice_images[_("false")] = ScriptableImage(intrusive(new BuiltInImage(_("bool_no"))));
}
IMPLEMENT_REFLECTION(BooleanStyle) {
REFLECT_BASE(ChoiceStyle);
}
void BooleanStyle::after_reading(Version ver) {
// Prior to 2.0.1, the choices were called "yes" and "no"
if (!choice_images[_("true")].isScripted() && choice_images.find(_("yes")) != choice_images.end()) {
choice_images[_("true")] = choice_images[_("yes")];
}
if (!choice_images[_("false")].isScripted() && choice_images.find(_("no")) != choice_images.end()) {
choice_images[_("false")] = choice_images[_("no")];
}
}
......@@ -39,6 +39,7 @@ class BooleanStyle : public ChoiceStyle {
private:
DECLARE_REFLECTION();
virtual void after_reading(Version ver);
};
// ----------------------------------------------------------------------------- : BooleanValue
......
......@@ -70,8 +70,8 @@ ChoiceField::Choice::Choice()
: line_below(false), enabled(true), type(CHOICE_TYPE_CHECK)
, first_id(0)
{}
ChoiceField::Choice::Choice(const String& name)
: name(name)
ChoiceField::Choice::Choice(const String& name, const String& caption)
: name(name), caption(caption)
, line_below(false), enabled(true), type(CHOICE_TYPE_CHECK)
, first_id(0)
{}
......@@ -316,7 +316,7 @@ ChoiceValue::ChoiceValue(const ChoiceFieldP& field, bool initial_first_choice)
, true)
{}
String ChoiceValue::toString() const {
String ChoiceValue::toFriendlyString() const {
return value();
}
bool ChoiceValue::update(Context& ctx, const Action*) {
......
......@@ -64,9 +64,10 @@ enum ChoiceChoiceType {
class ChoiceField::Choice : public IntrusivePtrBase<ChoiceField::Choice> {
public:
Choice();
Choice(const String& name);
Choice(const String& name, const String& caption);
String name; ///< Name/value of the item
String caption; ///< Caption that is shown in menus etc.
String default_name; ///< A default item, if this is a group and default_name.empty() there is no default
vector<ChoiceP> choices; ///< Choices and sub groups in this group
bool line_below; ///< Show a line after this item?
......
......@@ -95,7 +95,7 @@ ColorValue::ColorValue(const ColorFieldP& field)
, true)
{}
String ColorValue::toString() const {
String ColorValue::toFriendlyString() const {
if (value.isDefault()) return field().default_name;
// is this a named color?
FOR_EACH(c, field().choices) {
......
......@@ -33,9 +33,11 @@ int ImageStyle::update(Context& ctx) {
// ----------------------------------------------------------------------------- : ImageValue
#if !USE_SCRIPT_VALUE_IMAGE
IMPLEMENT_VALUE_CLONE(Image);
String ImageValue::toString() const {
String ImageValue::toFriendlyString() const {
return filename.empty() ? wxEmptyString : _("<image>");
}
......@@ -52,3 +54,4 @@ void ImageValue::reflect(GetDefaultMember& reflector) {
// convert to ScriptImageP for scripting
reflector.handle( (ScriptValueP)intrusive(new ImageValueToImage(filename)) );
}
#endif
......@@ -17,7 +17,11 @@ IMPLEMENT_FIELD_TYPE(Info, "info");
#if USE_SCRIPT_VALUE_INFO
IMPLEMENT_REFLECTION(InfoField) {
REFLECT_BASE(AnyField);
REFLECT_IF_READING if(initial == script_default_nil) initial = to_script(caption);
}
void InfoField::after_reading(Version ver) {
AnyField::after_reading(ver);
if (initial == script_default_nil) initial = to_script(caption);
initial = make_default(initial);
}
#else
void InfoField::initDependencies(Context& ctx, const Dependency& dep) const {
......@@ -69,7 +73,7 @@ IMPLEMENT_REFLECTION(InfoStyle) {
IMPLEMENT_VALUE_CLONE(Info);
String InfoValue::toString() const {
String InfoValue::toFriendlyString() const {
return value;
}
bool InfoValue::update(Context& ctx, const Action*) {
......
......@@ -31,6 +31,7 @@ class InfoField : public AnyField {
public:
InfoField() { editable = false; }
DECLARE_FIELD_TYPE();
virtual void after_reading(Version ver);
};
#else
class InfoField : public Field {
......
......@@ -55,20 +55,20 @@ IMPLEMENT_REFLECTION_NAMELESS(MultipleChoiceValue) {
}
bool MultipleChoiceValue::update(Context& ctx, const Action* act) {
String old_value = toString();
String old_value = value->toString();
if (const MultipleChoiceValueAction* mvca = dynamic_cast<const MultipleChoiceValueAction*>(act)) {
ctx.setVariable(_("last_change"), to_script(mvca->changed_choice));
}
ChoiceValue::update(ctx,act);
normalForm();
return toString() != old_value;
return value->toString() != old_value;
}
void MultipleChoiceValue::get(vector<String>& out) const {
// split the value
out.clear();
bool is_new = true;
String val = toString();
String val = value->toString();
FOR_EACH_CONST(c, val) {
if (c == _(',')) {
is_new = true;
......@@ -85,7 +85,7 @@ void MultipleChoiceValue::get(vector<String>& out) const {
}
void MultipleChoiceValue::normalForm() {
String val = toString();
String val = value->toString();
// which choices are active?
vector<bool> seen(field().choices->lastId());
for (size_t pos = 0 ; pos < val.size() ; ) {
......
......@@ -14,16 +14,22 @@
IMPLEMENT_FIELD_TYPE(PackageChoice, "package choice");
#if !USE_SCRIPT_VALUE_PACKAGE
void PackageChoiceField::initDependencies(Context& ctx, const Dependency& dep) const {
Field ::initDependencies(ctx, dep);
script. initDependencies(ctx, dep);
}
#endif
IMPLEMENT_REFLECTION(PackageChoiceField) {
#if USE_SCRIPT_VALUE_CHOICE
REFLECT_BASE(AnyField);
#else
REFLECT_BASE(Field);
REFLECT(script);
REFLECT(match);
REFLECT(initial);
#endif
REFLECT(match);
REFLECT(required);
REFLECT(empty_name);
}
......@@ -49,13 +55,14 @@ IMPLEMENT_REFLECTION(PackageChoiceStyle) {
}
// ----------------------------------------------------------------------------- : PackageChoiceValue
#if !USE_SCRIPT_VALUE_PACKAGE
IMPLEMENT_VALUE_CLONE(PackageChoice);
String PackageChoiceValue::toString() const {
String PackageChoiceValue::toFriendlyString() const {
PackagedP pack = getPackage();
if (pack.get()) return pack->short_name;
else return _("");
else return _("");
}
PackagedP PackageChoiceValue::getPackage() const {
......@@ -87,3 +94,4 @@ void PackageChoiceValue::reflect(GetDefaultMember& reflector) {
}
}
void PackageChoiceValue::reflect(GetMember& reflector) {}
#endif
......@@ -47,12 +47,39 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(SymbolVariation) {
// ----------------------------------------------------------------------------- : SymbolValue
#if USE_SCRIPT_VALUE_SYMBOL
ScriptValueP script_local_symbol_file(LocalFileName const& filename) {
return intrusive(new LocalSymbolFile(filename));
}
String quote_string(String const& str);
String LocalSymbolFile::toCode() const {
return _("local_symbol_file(") + quote_string(filename.toStringForWriting()) + _(")");
}
String LocalSymbolFile::typeName() const {
return _("symbol");
}
GeneratedImageP LocalSymbolFile::toImage() const {
SymbolVariationP variation(new SymbolVariation);
variation->filter = intrusive(new SolidFillSymbolFilter);
return intrusive(new SymbolToImage(true, filename, variation));
}
String LocalSymbolFile::toFriendlyString() const {
return _("<") + _TYPE_("symbol") + _(">");
}
#else
IMPLEMENT_VALUE_CLONE(Symbol);
String SymbolValue::toString() const {
String SymbolValue::toFriendlyString() const {
return filename.empty() ? wxEmptyString : _("<symbol>");
}
IMPLEMENT_REFLECTION_NAMELESS(SymbolValue) {
IMPLEMENT_REFLECTION_NO_GET_MEMBER(SymbolValue) {
if (fieldP->save_value || !reflector.isWriting()) REFLECT_NAMELESS(filename);
}
void SymbolValue::reflect(GetMember&) {}
void SymbolValue::reflect(GetDefaultMember&) {}
#endif
......@@ -20,7 +20,9 @@ DECLARE_POINTER_TYPE(SymbolVariation);
DECLARE_POINTER_TYPE(SymbolField);
DECLARE_POINTER_TYPE(SymbolStyle);
#if !USE_SCRIPT_VALUE_SYMBOL
#if USE_SCRIPT_VALUE_SYMBOL
DECLARE_POINTER_TYPE(LocalSymbolFile);
#else
DECLARE_POINTER_TYPE(SymbolValue);
#endif
......@@ -71,6 +73,21 @@ class SymbolVariation : public IntrusivePtrBase<SymbolVariation> {
#if USE_SCRIPT_VALUE_SYMBOL
typedef AnyValue SymbolValue;
typedef AnyValueP SymbolValueP;
// A file that refers to a symbol
class LocalSymbolFile : public ScriptValue {
public:
LocalSymbolFile(LocalFileName const& filename) : filename(filename) {}
virtual String toCode() const;
virtual String typeName() const;
virtual ScriptType type() const { return SCRIPT_FILENAME; }
virtual GeneratedImageP toImage() const;
virtual String toFriendlyString() const;
LocalFileName filename; // not empty
};
#else
/// The Value in a SymbolField, i.e. a symbol
class SymbolValue : public Value {
......
......@@ -15,24 +15,32 @@
TextField::TextField()
: multi_line(false)
#if !USE_SCRIPT_VALUE_TEXT
, default_name(_("Default"))
#endif
{}
IMPLEMENT_FIELD_TYPE(Text, "text");
#if !USE_SCRIPT_VALUE_TEXT
void TextField::initDependencies(Context& ctx, const Dependency& dep) const {
Field ::initDependencies(ctx, dep);
script .initDependencies(ctx, dep);
default_script.initDependencies(ctx, dep);
}
#endif
IMPLEMENT_REFLECTION(TextField) {
#if USE_SCRIPT_VALUE_TEXT
REFLECT_BASE(AnyField);
#else
REFLECT_BASE(Field);
REFLECT(multi_line);
REFLECT(script);
REFLECT_N("default", default_script);
REFLECT(default_name);
#endif
REFLECT(multi_line);
}
// ----------------------------------------------------------------------------- : TextStyle
......@@ -132,9 +140,11 @@ IMPLEMENT_REFLECTION(TextStyle) {
// ----------------------------------------------------------------------------- : TextValue
#if !USE_SCRIPT_VALUE_TEXT
IMPLEMENT_VALUE_CLONE(Text);
String TextValue::toString() const {
String TextValue::toFriendlyString() const {
return untag_hide_sep(value());
}
bool TextValue::update(Context& ctx, const Action*) {
......@@ -150,6 +160,8 @@ IMPLEMENT_REFLECTION_NAMELESS(TextValue) {
if (fieldP->save_value || !reflector.isWriting()) REFLECT_NAMELESS(value);
}
#endif
// ----------------------------------------------------------------------------- : FakeTextValue
FakeTextValue::FakeTextValue(const TextFieldP& field, String* underlying, bool editable, bool untagged)
......@@ -160,7 +172,7 @@ FakeTextValue::FakeTextValue(const TextFieldP& field, String* underlying, bool e
void FakeTextValue::store() {
if (underlying) {
if (editable) {
*underlying = untagged ? untag(value) : value();
*underlying = untagged ? untag(value->toString()) : value->toString();
} else {
retrieve();
}
......@@ -168,9 +180,9 @@ void FakeTextValue::store() {
}
void FakeTextValue::retrieve() {
if (underlying) {
value.assign(untagged ? escape(*underlying) : *underlying);
value = to_script(untagged ? escape(*underlying) : *underlying);
} else {
value.assign(wxEmptyString);
value = script_default_nil;
}
}
......
......@@ -42,8 +42,6 @@ class TextField : public Field {
#if !USE_SCRIPT_VALUE_TEXT
OptionalScript script; ///< Script to apply to all values
OptionalScript default_script; ///< Script that generates the default value
//%OptionalScript view_script; ///< Script to apply before viewing
//%OptionalScript unview_script; ///< Script to apply after changes to the view
String default_name; ///< Name of "default" value
virtual void initDependencies(Context&, const Dependency&) const;
......
......@@ -360,6 +360,9 @@ void ApprDistro::writeD(wxTextOutputStream& tout, const String& name, int c, int
String untag_appr(const String& s) {
return replace_all(untag(curly_quotes(s,false)), _("\n"), _("\r\n"));
}
inline String untag_appr(const ScriptValueP& str) {
return untag_appr(str->toString());
}
DECLARE_POINTER_TYPE(ApprCardRecord);
DECLARE_TYPEOF_COLLECTION(ApprCardRecordP);
......@@ -422,10 +425,10 @@ class ApprCardRecord : public IntrusivePtrBase<ApprCardRecord> {
// conversion from MSE2 card
ApprCardRecord::ApprCardRecord(const Card& card, const String& sets_) {
name = untag_appr(card.value<TextValue>(_("name")).value);
sets = sets_ + _("-") + card_rarity_code(card.value<ChoiceValue>(_("rarity")).value);
sets = sets_ + _("-") + card_rarity_code(card.value<ChoiceValue>(_("rarity")).value->toString());
cc = untag_appr(card.value<TextValue>(_("casting_cost")).value);
type = untag_appr(card.value<TextValue>(_("super_type")).value);
String subType = untag(card.value<TextValue>(_("sub_type")).value);
String subType = untag_appr(card.value<TextValue>(_("sub_type")).value);
if (!subType.empty()) type += _(" - ") + subType;
text = untag_appr(card.value<TextValue>(_("rule_text")).value);
flavor = untag_appr(card.value<TextValue>(_("flavor_text")).value);
......@@ -725,7 +728,7 @@ bool ApprenticeExportWindow::exportSet() {
if (res == wxNO) return false; // abort export
}
// add our set
expan.expansions[set->apprentice_code] = set->value<TextValue>(_("title")).value;
expan.expansions[set->apprentice_code] = set->value<TextValue>(_("title")).value->toString();
expan.write();
// Format database
......
......@@ -17,6 +17,8 @@
#include <data/field/image.hpp>
#include <wx/wfstream.h>
ScriptValueP script_local_image_file(LocalFileName const& filename);
// ----------------------------------------------------------------------------- : MSE1FileFormat
/// The file format of MSE1 files
......@@ -54,9 +56,9 @@ SetP MSE1FileFormat::importSet(const String& filename) {
throw ParseError(_("Expected MSE format version 8\nTo convert files made with older versions of Magic Set Editor:\n 1. Download the latest version 1 from http:;//magicsetedtitor.sourceforge.net\n 2. Open the set, then save the set\n 3. Try to open them again in this program."));
}
// read general info
set->value<TextValue>(_("title")) .value = file.ReadLine();
set->value<TextValue>(_("artist")) .value = file.ReadLine();
set->value<TextValue>(_("copyright")).value = file.ReadLine();
set->value<TextValue>(_("title")) .value = to_script(file.ReadLine());
set->value<TextValue>(_("artist")) .value = to_script(file.ReadLine());
set->value<TextValue>(_("copyright")).value = to_script(file.ReadLine());
file.ReadLine(); // border color, ignored
String stylesheet = file.ReadLine();
set->apprentice_code = file.ReadLine(); // apprentice prefix
......@@ -70,7 +72,7 @@ SetP MSE1FileFormat::importSet(const String& filename) {
if (line == _("\xFF")) break;
desc += line;
}
set->value<TextValue>(_("description")).value = desc;
set->value<TextValue>(_("description")).value = to_script(desc);
// load stylesheet
if (stylesheet.substr(0,3) == _("old")) {
......@@ -95,6 +97,13 @@ SetP MSE1FileFormat::importSet(const String& filename) {
return set;
}
// append a line to a ScriptString, this is a bit inefficient, since we keep copying the string
void append_line(ScriptValueP& target, String const& line) {
String old_value = target->toString();
if (!is_default(target)) old_value += _("\n");
target = to_script(old_value + line);
}
void read_mse1_card(Set& set, wxFileInputStream& f, wxTextInputStream& file) {
CardP card(new Card(*set.game));
while (!f.Eof()) {
......@@ -109,46 +118,42 @@ void read_mse1_card(Set& set, wxFileInputStream& f, wxTextInputStream& file) {
set.cards.push_back(card);
return;
} case 'B': { // name
card->value<TextValue>(_("name")) .value.assign(line);
card->value<TextValue>(_("name")) .value = to_script(line);
break;
} case 'C': case 'D': { // image filename
String image_file = set.newFileName(_("image"),_("")); // a new unique name in the package
LocalFileName image_file = set.newFileName(_("image"),_("")); // a new unique name in the package
if (wxCopyFile(line, set.nameOut(image_file), true)) {
card->value<ImageValue>(_("image")) .filename = image_file;
card->value<ImageValue>(_("image")) = script_local_image_file(image_file);
}
break;
} case 'E': { // super type
card->value<TextValue>(_("super type")) .value.assign(line);
card->value<TextValue>(_("super type")) .value = to_script(line);
break;
} case 'F': { // sub type
card->value<TextValue>(_("sub type")) .value.assign(line);
card->value<TextValue>(_("sub type")) .value = to_script(line);
break;
} case 'G': { // casting cost
card->value<TextValue>(_("casting cost")).value.assign(line);
card->value<TextValue>(_("casting cost")).value = to_script(line);
break;
} case 'H': { // rarity
String rarity;
if (line == _("(U)")) rarity = _("uncommon");
else if (line == _("(R)")) rarity = _("rare");
else rarity = _("common");
card->value<ChoiceValue>(_("rarity")) .value.assign(rarity);
card->value<ChoiceValue>(_("rarity")) .value = to_script(rarity);
break;
} case 'I': { // power/thoughness
size_t pos = line.find_first_of(_('/'));
if (pos != String::npos) {
card->value<TextValue>(_("power")) .value.assign(line.substr(0, pos));
card->value<TextValue>(_("toughness")) .value.assign(line.substr(pos+1));
card->value<TextValue>(_("power")) .value = to_script(line.substr(0, pos));
card->value<TextValue>(_("toughness")) .value = to_script(line.substr(pos+1));
}
break;
} case 'J': { // rule text or part of text
Defaultable<String>& text = card->value<TextValue>(_("rule text")).value;
if (!text().empty()) text.mutate() += _('\n');
text.mutate() += line;
append_line(card->value<TextValue>(_("rule text")).value, line);
break;
} case 'K': { // flavor text or part of text
Defaultable<String>& text = card->value<TextValue>(_("flavor text")).value;
if (!text().empty()) text.mutate() += _('\n');
text.mutate() += line;
append_line(card->value<TextValue>(_("flavor text")).value, line);
break;
} case 'L': { // card color (if not default)
// decode color
......@@ -162,7 +167,7 @@ void read_mse1_card(Set& set, wxFileInputStream& f, wxTextInputStream& file) {
else if (line == _("7")) color = _("land");
else if (line == _("9")) color = _("multicolor");
else color = _("colorless");
card->value<ChoiceValue>(_("card color")).value.assign(color);
card->value<ChoiceValue>(_("card color")).value = to_script(color);
break;
} default: {
throw ParseError(_("Not a valid MSE1 file"));
......
......@@ -19,6 +19,7 @@
#include <wx/wfstream.h>
DECLARE_TYPEOF_COLLECTION(CardP);
ScriptValueP script_local_image_file(LocalFileName const& filename);
// ----------------------------------------------------------------------------- : MtgEditorFileFormat
......@@ -31,7 +32,7 @@ class MtgEditorFileFormat : public FileFormat {
virtual bool canExport(const Game&) { return false; }
virtual SetP importSet(const String& filename);
private:
// Filter: se filename -> image directory
// Filter: set filename -> image directory
// based on MtgEditor's: CardSet.getImageFolder
String filter1(const String& str);
// Filter: card name -> image name
......@@ -41,6 +42,7 @@ class MtgEditorFileFormat : public FileFormat {
void untag(const CardP& card, const String& field);
// Translate all tags, mana tags get converted to <sym>, other tags are removed
void translateTags(String& value);
void translateTags(ScriptValueP& value);
};
FileFormatP mtg_editor_file_format() {
......@@ -49,6 +51,8 @@ FileFormatP mtg_editor_file_format() {
// ----------------------------------------------------------------------------- : Importing
void append_line(ScriptValueP& target, String const& line);
SetP MtgEditorFileFormat::importSet(const String& filename) {
wxFileInputStream f(filename);
#ifdef UNICODE
......@@ -61,7 +65,7 @@ SetP MtgEditorFileFormat::importSet(const String& filename) {
// parsing state
CardP current_card;
Defaultable<String>* target = nullptr; // value we are currently reading
ScriptValueP* target = nullptr; // value we are currently reading
String layout = _("8e");
String set_date, card_date;
bool first = true;
......@@ -99,7 +103,7 @@ SetP MtgEditorFileFormat::importSet(const String& filename) {
untag(current_card, _("power"));
untag(current_card, _("toughness"));
// translate mtg editor tags to mse2 tags
translateTags(current_card->value<TextValue>(_("rule text")).value.mutate());
translateTags(current_card->value<TextValue>(_("rule text")).value);
// add the card to the set
set->cards.push_back(current_card);
}
......@@ -119,18 +123,18 @@ SetP MtgEditorFileFormat::importSet(const String& filename) {
} else if (line == _("#RARITY########") || line == _("#FREQUENCY#####")) { // rarity
target = 0;
line = file.ReadLine();
if (line == _("0")) current_card->value<ChoiceValue>(_("rarity")).value.assign(_("common"));
else if (line == _("1")) current_card->value<ChoiceValue>(_("rarity")).value.assign(_("uncommon"));
else current_card->value<ChoiceValue>(_("rarity")).value.assign(_("rare"));
if (line == _("0")) current_card->value<ChoiceValue>(_("rarity")).value = to_script(_("common"));
else if (line == _("1")) current_card->value<ChoiceValue>(_("rarity")).value = to_script(_("uncommon"));
else current_card->value<ChoiceValue>(_("rarity")).value = to_script(_("rare"));
} else if (line == _("#COLOR#########")) { // card color
target = 0;
line = file.ReadLine();
current_card->value<ChoiceValue>(_("card color")).value.assign(line);
current_card->value<ChoiceValue>(_("card color")).value = to_script(line);
} else if (line == _("#AUTOBG########")) { // card color.isDefault
target = 0;
line = file.ReadLine();
if (line == _("TRUE")) {
current_card->value<ChoiceValue>(_("card color")).value.makeDefault();
current_card->value<ChoiceValue>(_("card color")).value = script_default_nil;
}
} else if (line == _("#RULETEXT######")) { // rule text
target = &current_card->value<TextValue>(_("rule text")).value;
......@@ -150,26 +154,25 @@ SetP MtgEditorFileFormat::importSet(const String& filename) {
if (!wxFileExists(line)) {
// based on card name and date
line = filter1(filename) + set_date + _("/") +
filter2(current_card->value<TextValue>(_("name")).value) + card_date + _(".jpg");
filter2(current_card->value<TextValue>(_("name")).value->toString()) + card_date + _(".jpg");
}
// copy image into set
if (wxFileExists(line)) {
String image_file = set->newFileName(_("image"),_(""));
FileName image_file = set->newFileName(_("image"),_(""));
if (wxCopyFile(line, set->nameOut(image_file), true)) {
current_card->value<ImageValue>(_("image")).filename = image_file;
current_card->value<ImageValue>(_("image")).value = script_local_image_file(image_file);
}
}
} else if (line == _("#TOMBSTONE#####")) { // tombstone
target = 0;
line = file.ReadLine();
current_card->value<ChoiceValue>(_("card symbol")).value.assign(
current_card->value<ChoiceValue>(_("card symbol")).value = to_script(
line==_("TRUE") ? _("tombstone") : _("none")
);
} else {
// normal text
if (target != 0) { // value of a text field
if (!target->isDefault()) target->mutate() += _("\n");
target->mutate() += line;
append_line(*target, line);
} else {
throw ParseError(_("Error in Mtg Editor file, unexpected text:\n") + line);
}
......@@ -178,16 +181,16 @@ SetP MtgEditorFileFormat::importSet(const String& filename) {
// set defaults for artist and copyright to that of the first card
if (!set->cards.empty()) {
String artist = set->cards[0]->value<TextValue>(_("illustrator")).value;
String copyright = set->cards[0]->value<TextValue>(_("copyright")) .value;
set->value<TextValue>(_("artist")) .value.assign(artist);
set->value<TextValue>(_("copyright")).value.assign(copyright);
ScriptValueP& artist = set->cards[0]->value<TextValue>(_("illustrator")).value;
ScriptValueP& copyright = set->cards[0]->value<TextValue>(_("copyright")) .value;
set->value<TextValue>(_("artist")) .value = artist;
set->value<TextValue>(_("copyright")).value = copyright;
// which cards have this value?
FOR_EACH(card, set->cards) {
Defaultable<String>& card_artist = card->value<TextValue>(_("illustrator")).value;
Defaultable<String>& card_copyright = card->value<TextValue>(_("copyright")) .value;
if (card_artist == artist) card_artist.makeDefault();
if (card_copyright == copyright) card_copyright.makeDefault();
ScriptValueP& card_artist = card->value<TextValue>(_("illustrator")).value;
ScriptValueP& card_copyright = card->value<TextValue>(_("copyright")) .value;
if (equal(card_artist , artist)) card_artist = make_default(artist);
if (equal(card_copyright, copyright)) card_copyright = make_default(card_copyright);
}
}
......@@ -237,8 +240,8 @@ String MtgEditorFileFormat::filter2(const String& str) {
}
void MtgEditorFileFormat::untag(const CardP& card, const String& field) {
Defaultable<String>& value = card->value<TextValue>(field).value;
value.assignDontChangeDefault(untag_no_escape(value));
ScriptValueP& value = card->value<TextValue>(field).value;
value = with_defaultness_of(value, to_script(untag_no_escape(value->toString())));
}
......@@ -275,3 +278,8 @@ void MtgEditorFileFormat::translateTags(String& value) {
// Join adjecent symbol sections
value = replace_all(ret, _("</sym><sym>"), _(""));
}
void MtgEditorFileFormat::translateTags(ScriptValueP& value) {
String val = value->toString();
translateTags(val);
value = to_script(val);
}
......@@ -26,6 +26,9 @@ String untag_mws(const String& str) {
// TODO : em dashes?
return replace_all(untag(curly_quotes(str,false)), _("\n"), _("\n\t\t") );
}
inline String untag_mws(const ScriptValueP& str) {
return untag_mws(str->toString());
}
//String untag_mws(const Defaultable<String>& str) {
// str.
//}
......@@ -72,7 +75,7 @@ void export_mws(Window* parent, const SetP& set) {
wxTextOutputStream file(f, wxEOL_DOS);
// Write header
file.WriteString(set->value<TextValue>(_("title")).value + _(" Spoiler List\n"));
file.WriteString(set->value<TextValue>(_("title")).value->toString() + _(" Spoiler List\n"));
file.WriteString(_("Set exported using Magic Set Editor 2, version ") + app_version.toString() + _("\n\n"));
wxDateTime now = wxDateTime::Now();
file.WriteString(_("Spoiler List created on ") + now.FormatISODate() + _(" ") + now.FormatISOTime());
......@@ -83,7 +86,7 @@ void export_mws(Window* parent, const SetP& set) {
file.WriteString(_("Card Name:\t"));
file.WriteString(untag_mws(card->value<TextValue>(_("name")).value));
file.WriteString(_("\nCard Color:\t"));
file.WriteString(card_color_mws(card->value<ChoiceValue>(_("card color")).value));
file.WriteString(card_color_mws(card->value<ChoiceValue>(_("card color")).value->toString()));
file.WriteString(_("\nMana Cost:\t"));
file.WriteString(untag_mws(card->value<TextValue>(_("casting cost")).value));
file.WriteString(_("\nType & Class:\t"));
......@@ -103,7 +106,7 @@ void export_mws(Window* parent, const SetP& set) {
file.WriteString(_("\nArtist:\t\t"));
file.WriteString(untag_mws(card->value<TextValue>(_("illustrator")).value));
file.WriteString(_("\nRarity:\t\t"));
file.WriteString(card_rarity_code(card->value<ChoiceValue>(_("rarity")).value));
file.WriteString(card_rarity_code(card->value<ChoiceValue>(_("rarity")).value->toString()));
file.WriteString(_("\nCard #:\t\t"));
file.WriteString(untag_mws(card->value<TextValue>(_("card number")).value));
file.WriteString(_("\n\n"));
......
......@@ -111,13 +111,13 @@ String Set::identification() const {
// an identifying field
FOR_EACH_CONST(v, data) {
if (v->fieldP->identifying) {
return v->toString();
return v->toFriendlyString();
}
}
// otherwise the first non-information field
FOR_EACH_CONST(v, data) {
if (!dynamic_pointer_cast<InfoValue>(v)) {
return v->toString();
return v->toFriendlyString();
}
}
return wxEmptyString;
......@@ -127,16 +127,6 @@ String Set::identification() const {
String Set::typeName() const { return _("set"); }
Version Set::fileVersion() const { return file_version_set; }
// fix values for versions < 0.2.7
void fix_value_207(const ValueP& value) {
if (TextValue* v = dynamic_cast<TextValue*>(value.get())) {
// text value -> fix it
v->value.assignDontChangeDefault( // don't change defaultness
fix_old_tags(v->value()) // remove tags
);
}
}
void Set::validate(Version file_app_version) {
Packaged::validate(file_app_version);
// are the
......@@ -150,19 +140,7 @@ void Set::validate(Version file_app_version) {
if (stylesheet->game != game) {
throw Error(_ERROR_("stylesheet and set refer to different game"));
}
// This is our chance to fix version incompatabilities
if (file_app_version < 207) {
// Since 0.2.7 we use </tag> style close tags, in older versions it was </>
// Walk over all fields and fix...
FOR_EACH(c, cards) {
FOR_EACH(v, c->data) fix_value_207(v);
}
FOR_EACH(v, data) fix_value_207(v);
/* FOR_EACH(s, styleData) {
FOR_EACH(v, s.second->data) fix_value_207(v);
}
*/ }
// we want at least one card
if (cards.empty()) cards.push_back(intrusive(new Card(*game)));
// update scripts
......
......@@ -19,6 +19,7 @@
ScriptType GeneratedImage::type() const { return SCRIPT_IMAGE; }
String GeneratedImage::typeName() const { return _TYPE_("image"); }
String GeneratedImage::toFriendlyString() const { return _("<") + _TYPE_("image") + _(">"); }
GeneratedImageP GeneratedImage::toImage() const {
return intrusive_from_existing(const_cast<GeneratedImage*>(this));
}
......@@ -448,9 +449,12 @@ bool BuiltInImage::operator == (const GeneratedImage& that) const {
// ----------------------------------------------------------------------------- : SymbolToImage
SymbolToImage::SymbolToImage(bool is_local, const String& filename, Age age, const SymbolVariationP& variation)
: is_local(is_local), filename(filename), age(age), variation(variation)
{}
SymbolToImage::SymbolToImage(bool is_local, const LocalFileName& filename, const SymbolVariationP& variation)
: is_local(is_local), filename(filename), variation(variation)
{
assert(variation);
assert(variation->filter);
}
SymbolToImage::~SymbolToImage() {}
Image SymbolToImage::generate(const Options& opt) const {
......@@ -464,27 +468,32 @@ Image SymbolToImage::generate(const Options& opt) const {
the_symbol = package->readFile<SymbolP>(filename);
}
int size = max(100, 3*max(opt.width,opt.height));
int width = size * opt.width / max(opt.width,opt.height);
int height = size * opt.height / max(opt.width,opt.height);
bool allow_smaller = true;
if (opt.width <= 1 || opt.height <= 1) {
return render_symbol(the_symbol, *variation->filter, variation->border_radius, size, size);
} else {
int width = size * opt.width / max(opt.width,opt.height);
int height = size * opt.height / max(opt.width,opt.height);
return render_symbol(the_symbol, *variation->filter, variation->border_radius, width, height, false, true);
allow_smaller = false;
width = height = size;
}
return render_symbol(the_symbol, *variation->filter, variation->border_radius, width, height, false, allow_smaller);
}
bool SymbolToImage::operator == (const GeneratedImage& that) const {
const SymbolToImage* that2 = dynamic_cast<const SymbolToImage*>(&that);
return that2 && is_local == that2->is_local
&& filename == that2->filename
&& age == that2->age
&& (variation == that2->variation ||
*variation == *that2->variation // custom variation
);
}
// ----------------------------------------------------------------------------- : ImageValueToImage
ImageValueToImage::ImageValueToImage(const String& filename)
ScriptValueP script_local_image_file(LocalFileName const& filename) {
return intrusive(new ImageValueToImage(filename));
}
ImageValueToImage::ImageValueToImage(const LocalFileName& filename)
: filename(filename)
{}
ImageValueToImage::~ImageValueToImage() {}
......@@ -506,3 +515,8 @@ bool ImageValueToImage::operator == (const GeneratedImage& that) const {
const ImageValueToImage* that2 = dynamic_cast<const ImageValueToImage*>(&that);
return that2 && filename == that2->filename;
}
String quote_string(String const& str);
String ImageValueToImage::toCode() const {
return _("local_image_file(") + quote_string(filename.toStringForWriting()) + _(")");
}
......@@ -11,6 +11,7 @@
#include <util/prec.hpp>
#include <util/age.hpp>
#include <util/io/package.hpp>
#include <gfx/gfx.hpp>
#include <script/value.hpp>
......@@ -63,6 +64,7 @@ class GeneratedImage : public ScriptValue {
virtual ScriptType type() const;
virtual String typeName() const;
virtual GeneratedImageP toImage() const;
virtual String toFriendlyString() const;
};
/// Resize an image to conform to the options
......@@ -353,7 +355,8 @@ class BuiltInImage : public GeneratedImage {
/// Use a symbol as an image
class SymbolToImage : public GeneratedImage {
public:
SymbolToImage(bool is_local, const String& filename, Age age, const SymbolVariationP& variation);
SymbolToImage(const SymbolToImage& symbol, const SymbolVariationP& variation);
SymbolToImage(bool is_local, const LocalFileName& filename, const SymbolVariationP& variation = SymbolVariationP());
~SymbolToImage();
virtual Image generate(const Options& opt) const;
virtual bool operator == (const GeneratedImage& that) const;
......@@ -365,24 +368,28 @@ class SymbolToImage : public GeneratedImage {
private:
SymbolToImage(const SymbolToImage&); // copy ctor
bool is_local; ///< Use local package?
String filename;
Age age; ///< Age the symbol was last updated
LocalFileName filename;
SymbolVariationP variation;
};
// ----------------------------------------------------------------------------- : ImageValueToImage
/// Use an image from an ImageValue as an image
// Also used as representation for script_local_image_file
// TODO: rename this
class ImageValueToImage : public GeneratedImage {
public:
ImageValueToImage(const String& filename);
ImageValueToImage(const LocalFileName& filename);
~ImageValueToImage();
virtual Image generate(const Options& opt) const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return true; }
virtual String toCode() const;
private:
ImageValueToImage(const ImageValueToImage&); // copy ctor
String filename;
LocalFileName filename;
};
// ----------------------------------------------------------------------------- : EOF
......
......@@ -312,7 +312,7 @@ String CardListBase::OnGetItemText(long pos, long col) const {
return wxEmptyString;
}
ValueP val = getCard(pos)->data[column_fields[col]];
if (val) return val->toString();
if (val) return val->toFriendlyString();
else return wxEmptyString;
}
......
......@@ -12,6 +12,8 @@
#include <data/field/image.hpp>
#include <data/game.hpp>
#include <data/card.hpp>
#include <script/image.hpp>
#include <gfx/generated_image.hpp>
#include <gfx/gfx.hpp>
#include <wx/imaglist.h>
......@@ -51,24 +53,23 @@ ImageFieldP ImageCardList::findImageField() {
/// A request for a thumbnail of a card image
class CardThumbnailRequest : public ThumbnailRequest {
public:
CardThumbnailRequest(ImageCardList* parent, const String& filename)
CardThumbnailRequest(ImageCardList* parent, const String& key, const GeneratedImageP& imgen)
: ThumbnailRequest(
parent,
_("card") + parent->set->absoluteFilename() + _("-") + filename,
_("card") + parent->set->absoluteFilename() + _("-") + key,
wxDateTime::Now()) // TODO: Find mofication time of card image
, filename(filename)
, key(key)
, imgen(imgen)
{}
virtual Image generate() {
try {
ImageCardList* parent = (ImageCardList*)owner;
Image image;
if (image.LoadFile(*parent->set->openIn(filename))) {
// two step anti aliased resampling
image.Rescale(36, 28); // step 1: no anti aliassing
return resample(image, 18, 14); // step 2: with anti aliassing
} else {
return Image();
}
GeneratedImage::Options opts;
opts.local_package = parent->set.get();
Image image = imgen->generate(opts);
// two step anti aliased resampling
image.Rescale(36, 28); // step 1: no anti aliassing
return resample(image, 18, 14); // step 2: with anti aliassing
} catch (...) {
return Image();
}
......@@ -79,28 +80,36 @@ class CardThumbnailRequest : public ThumbnailRequest {
if (img.Ok()) {
wxImageList* il = parent->GetImageList(wxIMAGE_LIST_SMALL);
int id = il->Add(wxBitmap(img));
parent->thumbnails.insert(make_pair(filename, id));
parent->thumbnails.insert(make_pair(key, id));
parent->Refresh(false);
}
}
virtual bool threadSafe() const {return true;}
private:
String filename;
String key;
GeneratedImageP imgen;
};
int ImageCardList::OnGetItemImage(long pos) const {
if (image_field) {
// Image = thumbnail of first image field of card
ImageValue& val = static_cast<ImageValue&>(*getCard(pos)->data[image_field]);
if (!val.filename) return -1; // no image
const ImageValue& val = static_cast<const ImageValue&>(*getCard(pos)->data[image_field]);
if (val.value->isNil()) return -1;
GeneratedImageP image = val.value->toImage();
// is there already a thumbnail?
map<String,int>::const_iterator it = thumbnails.find(val.filename);
String key;
try {
key = image->toCode();
} catch (...) {
return -1; // nothing that can be used as a key
}
map<String,int>::const_iterator it = thumbnails.find(key);
if (it != thumbnails.end()) {
return it->second;
} else {
// request a thumbnail
thumbnail_thread.request(intrusive(new CardThumbnailRequest(const_cast<ImageCardList*>(this), val.filename)));
thumbnail_thread.request(intrusive(new CardThumbnailRequest(const_cast<ImageCardList*>(this), key, image)));
}
}
return -1;
......
......@@ -48,11 +48,12 @@ SymbolWindow::SymbolWindow(Window* parent, ValueActionPerformer* performer)
// attempt to load symbol
SymbolP symbol;
SymbolValueP value = static_pointer_cast<SymbolValue>(performer->value);
if (!value->filename.empty()) {
LocalSymbolFileP symbol_file = dynamic_pointer_cast<LocalSymbolFile>(value->value);
if (symbol_file) {
try {
// load symbol
Package& package = performer->getLocalPackage();
symbol = package.readFile<SymbolP>(value->filename);
symbol = package.readFile<SymbolP>(symbol_file->filename);
} catch (const Error& e) {
handle_error(e);
}
......@@ -251,11 +252,11 @@ void SymbolWindow::onFileStore(wxCommandEvent& ev) {
if (performer) {
SymbolValueP value = static_pointer_cast<SymbolValue>(performer->value);
Package& package = performer->getLocalPackage();
FileName new_filename = package.newFileName(value->field().name,_(".mse-symbol")); // a new unique name in the package
LocalFileName new_filename = package.newFileName(value->field().name,_(".mse-symbol")); // a new unique name in the package
OutputStreamP stream = package.openOut(new_filename);
Writer writer(*stream, file_version_symbol);
writer.handle(control->getSymbol());
performer->addAction(value_action(value, new_filename));
performer->addAction(value_action(value, intrusive(new LocalSymbolFile(new_filename))));
}
}
......
......@@ -236,7 +236,7 @@ void DropDownChoiceList::onShow() {
void DropDownChoiceList::select(size_t item) {
if (isFieldDefault(item)) {
dynamic_cast<ChoiceValueEditor&>(cve).change( Defaultable<String>() );
dynamic_cast<ChoiceValueEditor&>(cve).change( script_default_nil );
} else {
ChoiceField::ChoiceP choice = getChoice(item);
dynamic_cast<ChoiceValueEditor&>(cve).change( field().choices->choiceName(choice->first_id) );
......@@ -245,11 +245,11 @@ void DropDownChoiceList::select(size_t item) {
size_t DropDownChoiceList::selection() const {
// selected item
const Defaultable<String>& value = dynamic_cast<ChoiceValueEditor&>(cve).value().value();
int id = field().choices->choiceId(value);
ScriptValueP value = dynamic_cast<ChoiceValueEditor&>(cve).value().value;
int id = field().choices->choiceId(value->toString());
// id of default item
if (hasFieldDefault()) {
if (value.isDefault()) {
if (is_default(value)) {
// default is selected
default_id = id;
return 0;
......@@ -304,6 +304,9 @@ void ChoiceValueEditor::determineSize(bool) {
style().height = max(style().height(), 16.);
}
void ChoiceValueEditor::change(const Defaultable<String>& c) {
addAction(value_action(valueP(), c));
void ChoiceValueEditor::change(ScriptValueP const& v) {
addAction(value_action(valueP(), v));
}
void ChoiceValueEditor::change(const String& c) {
change(to_script(c));
}
......@@ -37,7 +37,8 @@ class ChoiceValueEditor : public ChoiceValueViewer, public ValueEditor {
DropDownListP drop_down;
friend class DropDownChoiceList;
/// Change the choice
void change(const Defaultable<String>& c);
void change(const ScriptValueP& c);
void change(const String& c);
};
// ----------------------------------------------------------------------------- : DropDownChoiceList
......
......@@ -80,7 +80,7 @@ void DropDownColorList::drawIcon(DC& dc, int x, int y, size_t item, bool selecte
if (isDefault(item)) {
col = default_color;
} else if (isCustom(item)) {
col = cve.value().value();
col = cve.value().value->toColor();
} else {
col = field().choices[item - hasDefault()]->color;
}
......@@ -96,16 +96,16 @@ size_t DropDownColorList::selection() const {
size_t selection = hasCustom() ? itemCount() - 1 : NO_SELECTION;
size_t i = 0;
FOR_EACH_CONST(c, field().choices) {
if (c->color == cve.value().value()) {
if (c->color == cve.value().value->toColor()) {
selection = i + hasDefault();
break;
}
i++;
}
// has default item?
if (hasDefault() && cve.value().value.isDefault()) {
if (hasDefault() && is_default(cve.value().value)) {
// default is selected
default_color = cve.value().value();
default_color = cve.value().value->toColor();
return 0;
} else if (hasDefault()) {
// evaluate script to find default color
......@@ -115,7 +115,7 @@ size_t DropDownColorList::selection() const {
}
void DropDownColorList::select(size_t item) {
if (isDefault(item)) {
cve.change( Defaultable<Color>());
cve.change(script_default_nil);
} else if (isCustom(item)) {
cve.changeCustom();
} else {
......@@ -149,10 +149,13 @@ void ColorValueEditor::determineSize(bool) {
style().height = 20;
}
void ColorValueEditor::change(const Defaultable<Color>& c) {
void ColorValueEditor::change(Color c) {
change(to_script(c));
}
void ColorValueEditor::change(ScriptValueP const& c) {
addAction(value_action(valueP(), c));
}
void ColorValueEditor::changeCustom() {
Color c = wxGetColourFromUser(0, value().value());
Color c = wxGetColourFromUser(0, value().value->toColor());
if (c.Ok()) change(c);
}
......@@ -34,7 +34,8 @@ class ColorValueEditor : public ColorValueViewer, public ValueEditor {
DropDownListP drop_down;
friend class DropDownColorList;
/// Change the color
void change(const Defaultable<Color>& c);
void change(const ScriptValueP& c);
void change(Color c);
/// Change to a custom color
void changeCustom();
};
......
......@@ -13,6 +13,8 @@
#include <data/action/value.hpp>
#include <wx/clipbrd.h>
ScriptValueP script_local_image_file(LocalFileName const& filename);
// ----------------------------------------------------------------------------- : ImageValueEditor
IMPLEMENT_VALUE_EDITOR(Image) {}
......@@ -39,17 +41,17 @@ void ImageValueEditor::sliceImage(const Image& image) {
// clicked ok?
if (s.ShowModal() == wxID_OK) {
// store the image into the set
FileName new_image_file = getLocalPackage().newFileName(field().name,_("")); // a new unique name in the package
LocalFileName new_image_file = getLocalPackage().newFileName(field().name,_("")); // a new unique name in the package
Image img = s.getImage();
img.SaveFile(getLocalPackage().nameOut(new_image_file), wxBITMAP_TYPE_PNG); // always use PNG images, see #69. Disk space is cheap anyway.
addAction(value_action(valueP(), new_image_file));
addAction(value_action(valueP(), script_local_image_file(new_image_file)));
}
}
// ----------------------------------------------------------------------------- : Clipboard
bool ImageValueEditor::canCopy() const {
return !value().filename.empty();
return !value().value->isNil();
}
bool ImageValueEditor::canPaste() const {
......@@ -58,10 +60,12 @@ bool ImageValueEditor::canPaste() const {
}
bool ImageValueEditor::doCopy() {
// load image
InputStreamP image_file = getLocalPackage().openIn(value().filename);
Image image;
if (!image.LoadFile(*image_file)) return false;
// load/generate image
GeneratedImage::Options opts;
opts.package = &getStylePackage();
opts.local_package = &getLocalPackage();
Image image = value().value->toImage()->generate(opts);
if (!image.Ok()) return false;
// set data
if (!wxTheClipboard->Open()) return false;
bool ok = wxTheClipboard->SetData(new wxBitmapDataObject(image));
......@@ -82,7 +86,7 @@ bool ImageValueEditor::doPaste() {
}
bool ImageValueEditor::doDelete() {
addAction(value_action(valueP(), FileName()));
addAction(value_action(valueP(), script_nil));
return true;
}
......
......@@ -56,7 +56,7 @@ void DropDownMultipleChoiceList::drawIcon(DC& dc, int x, int y, size_t item, boo
active = dynamic_cast<MultipleChoiceValueEditor&>(cve).active[choice->first_id];
radio = choice->type == CHOICE_TYPE_RADIO;
} else {
active = dynamic_cast<MultipleChoiceValueEditor&>(cve).value().value.isDefault();
active = is_default(dynamic_cast<MultipleChoiceValueEditor&>(cve).value().value);
}
// draw checkbox
dc.SetPen(*wxTRANSPARENT_PEN);
......@@ -177,9 +177,13 @@ void MultipleChoiceValueEditor::toggle(int id) {
if (i == id) toggled_choice = choice;
}
// store value
addAction(value_action(valueP(), new_value, toggled_choice));
addAction(value_action(valueP(), to_script(new_value), toggled_choice));
}
void MultipleChoiceValueEditor::toggleDefault() {
addAction(value_action(valueP(), Defaultable<String>(value().value(), !value().value.isDefault()), _("")));
if (ScriptDefault const* dv = is_default(value().value)) {
addAction(value_action(valueP(), dv->un_default));
} else {
addAction(value_action(valueP(), make_default(value().value)));
}
}
......@@ -75,8 +75,9 @@ void DropDownPackageChoiceList::select(size_t item) {
size_t DropDownPackageChoiceList::selection() const {
size_t n = 0;
String package_name = editor.value().value->toString();
FOR_EACH(i, editor.items) {
if (editor.value().package_name == i.package_name) {
if (package_name == i.package_name) {
return n + !editor.field().required;
}
++n;
......@@ -111,7 +112,7 @@ void PackageChoiceValueEditor::determineSize(bool) {
}
void PackageChoiceValueEditor::change(const String& c) {
addAction(value_action(valueP(), c));
addAction(value_action(valueP(), to_script(c)));
}
void PackageChoiceValueEditor::initDropDown() {
......
This diff is collapsed.
......@@ -59,7 +59,9 @@ intrusive_ptr<SymbolFilter> read_new<SymbolFilter>(Reader& reader);
/// Symbol filter that returns solid colors
class SolidFillSymbolFilter : public SymbolFilter {
public:
inline SolidFillSymbolFilter() {}
inline SolidFillSymbolFilter()
: fill_color(AColor(0,0,0,255)), border_color(AColor(255,255,255,255))
{}
inline SolidFillSymbolFilter(const AColor& fill_color, const AColor& border_color)
: fill_color(fill_color), border_color(border_color)
{}
......
......@@ -17,12 +17,12 @@ IMPLEMENT_VALUE_VIEWER(Choice);
void get_options(Rotation& rot, ValueViewer& viewer, const ChoiceStyle& style, GeneratedImage::Options& opts);
bool ChoiceValueViewer::prepare(RotatedDC& dc) {
return prepare_choice_viewer(dc, *this, style(), value().value());
return prepare_choice_viewer(dc, *this, style(), value().value->toString());
}
void ChoiceValueViewer::draw(RotatedDC& dc) {
drawFieldBorder(dc);
if (style().render_style & RENDER_HIDDEN) return;
draw_choice_viewer(dc, *this, style(), value().value());
draw_choice_viewer(dc, *this, style(), value().value->toString());
}
void ChoiceValueViewer::onStyleChange(int changes) {
......
......@@ -19,16 +19,16 @@ IMPLEMENT_VALUE_VIEWER(Color);
void ColorValueViewer::draw(RotatedDC& dc) {
// draw in the value color
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(value().value());
dc.SetBrush(value().value->toColor());
if (nativeLook()) {
// native look
// find name of color
String color_name = _("Custom");
if (field().default_script && value().value.isDefault()) {
if (field().default_script && is_default(value().value)) {
color_name = field().default_name;
} else {
FOR_EACH_CONST(c, field().choices) {
if (value().value() == c->color) {
if (value().value->toColor() == c->color) {
color_name = capitalize(c->name);
break;
}
......@@ -45,7 +45,7 @@ void ColorValueViewer::draw(RotatedDC& dc) {
// is there a mask?
const AlphaMask& alpha_mask = getMask(dc);
if (alpha_mask.isLoaded()) {
dc.DrawImage(alpha_mask.colorImage(value().value()), RealPoint(0,0), style().combine);
dc.DrawImage(alpha_mask.colorImage(value().value->toColor()), RealPoint(0,0), style().combine);
} else {
// do we need clipping?
bool clip = style().left_width < style().width && style().right_width < style().width &&
......
......@@ -28,8 +28,22 @@ void ImageValueViewer::draw(RotatedDC& dc) {
if (!bitmap.Ok()) {
angle = a;
is_default = false;
// load/generate image
GeneratedImage::Options opts;
opts.package = &getStylePackage();
opts.local_package = &getLocalPackage();
opts.angle = a;
opts.width = (int)dc.trX(style().width);
opts.height = (int)dc.trY(style().height);
opts.preserve_aspect = ASPECT_STRETCH;
// TODO: use CachecScriptableImage
Image image;
// load from file
try {
if (!value().value->isNil()) {
image = value().value->toImage()->generate(opts);
}
} CATCH_ALL_ERRORS(false);
/*
if (!value().filename.empty()) {
try {
InputStreamP image_file = getLocalPackage().openIn(value().filename);
......@@ -37,7 +51,7 @@ void ImageValueViewer::draw(RotatedDC& dc) {
image.Rescale(w, h);
}
} CATCH_ALL_ERRORS(false);
}
}*/
// nice placeholder
if (!image.Ok() && style().default_image.isReady()) {
image = style().default_image.generate(GeneratedImage::Options(w, h, &getStylePackage(), &getLocalPackage()));
......
......@@ -35,6 +35,7 @@ void InfoValueViewer::draw(RotatedDC& dc) {
-style().padding_left - style().padding_right,
-style().padding_top - style().padding_bottom
);
RealSize size = dc.GetTextExtent(value().value);
dc.DrawText(value().value, align_in_rect(style().alignment, size, rect));
String val = value().value->toString();
RealSize size = dc.GetTextExtent(val);
dc.DrawText(val, align_in_rect(style().alignment, size, rect));
}
......@@ -20,7 +20,7 @@ IMPLEMENT_VALUE_VIEWER(MultipleChoice);
bool MultipleChoiceValueViewer::prepare(RotatedDC& dc) {
if (style().render_style & (RENDER_CHECKLIST | RENDER_LIST)) return false;
return prepare_choice_viewer(dc, *this, style(), value().value());
return prepare_choice_viewer(dc, *this, style(), value().value->toString());
}
void MultipleChoiceValueViewer::draw(RotatedDC& dc) {
......@@ -46,7 +46,7 @@ void MultipleChoiceValueViewer::draw(RotatedDC& dc) {
drawChoice(dc, pos, choice);
}
} else {
draw_choice_viewer(dc, *this, style(), value().value());
draw_choice_viewer(dc, *this, style(), value().value->toString());
}
}
......
......@@ -47,15 +47,16 @@ void PackageChoiceValueViewer::initItems() {
void PackageChoiceValueViewer::draw(RotatedDC& dc) {
drawFieldBorder(dc);
// find item
String text = value().package_name;
String text = value().value->toString();
Bitmap image;
if (value().package_name.empty()) {
if (text.empty()) {
text = field().empty_name;
} else {
FOR_EACH(i, items) {
if (i.package_name == value().package_name) {
if (i.package_name == text) {
text = i.name;
image = i.image;
break;
}
}
}
......
......@@ -26,10 +26,11 @@ void SymbolValueViewer::draw(RotatedDC& dc) {
draw_checker(dc, style().getInternalRect());
double wh = min(dc.getWidth(), dc.getHeight());
// try to load symbol
if (symbols.empty() && !value().filename.empty()) {
LocalSymbolFileP symbol_file = dynamic_pointer_cast<LocalSymbolFile>(value().value);
if (symbols.empty() && symbol_file) {
try {
// load symbol
SymbolP symbol = getLocalPackage().readFile<SymbolP>(value().filename);
SymbolP symbol = getLocalPackage().readFile<SymbolP>(symbol_file->filename);
// aspect ratio
double ar = symbol->aspectRatio();
ar = min(style().max_aspect_ratio, max(style().min_aspect_ratio, ar));
......
......@@ -16,13 +16,13 @@ IMPLEMENT_VALUE_VIEWER(Text);
bool TextValueViewer::prepare(RotatedDC& dc) {
getMask(dc); // ensure alpha/contour mask is loaded
return v.prepare(dc, value().value(), style(), viewer.getContext());
return v.prepare(dc, value().value->toString(), style(), viewer.getContext());
}
void TextValueViewer::draw(RotatedDC& dc) {
drawFieldBorder(dc);
if (!v.prepared()) {
v.prepare(dc, value().value(), style(), viewer.getContext());
v.prepare(dc, value().value->toString(), style(), viewer.getContext());
dc.setStretch(getStretch());
}
DrawWhat what = viewer.drawWhat(this);
......
......@@ -37,23 +37,32 @@ SCRIPT_FUNCTION(new_card) {
}
Value* value = value_it->get();
// set the value
#if !USE_SCRIPT_VALUE_TEXT
if (TextValue* tvalue = dynamic_cast<TextValue*>(value)) {
tvalue->value = v->toString();
} else
#endif
#if !USE_SCRIPT_VALUE_CHOICE
} else if (ChoiceValue* cvalue = dynamic_cast<ChoiceValue*>(value)) {
if (ChoiceValue* cvalue = dynamic_cast<ChoiceValue*>(value)) {
cvalue->value = v->toString();
} else
#endif
} else if (PackageChoiceValue* pvalue = dynamic_cast<PackageChoiceValue*>(value)) {
#if !USE_SCRIPT_VALUE_PACKAGE
if (PackageChoiceValue* pvalue = dynamic_cast<PackageChoiceValue*>(value)) {
pvalue->package_name = v->toString();
} else
#endif
#if !USE_SCRIPT_VALUE_COLOR
} else if (ColorValue* cvalue = dynamic_cast<ColorValue*>(value)) {
if (ColorValue* cvalue = dynamic_cast<ColorValue*>(value)) {
cvalue->value = v->toColor();
} else
#endif
#if USE_SCRIPT_VALUE_VALUE
} else if (AnyValue* avalue = dynamic_cast<AnyValue*>(value)) {
if (AnyValue* avalue = dynamic_cast<AnyValue*>(value)) {
avalue->value = v;
} else
#endif
} else {
{
throw ScriptError(format_string(_("Can not set value '%s', it is not of the right type"),name));
}
}
......
......@@ -83,8 +83,8 @@ SCRIPT_FUNCTION_WITH_DEP(combined_editor) {
Age new_value_update = last_update_age();
FOR_EACH_2(v, values, nv, value_parts) {
if (v->last_modified < new_value_update) {
bool changed = v->value() != nv.first;
v->value.assign(nv.first);
bool changed = v->value->toString() != nv.first;
if (changed) v->value = to_script(nv.first);
v->last_modified = new_value_update;
changed |= v->update(ctx);
if (changed) { // notify of change
......@@ -94,7 +94,7 @@ SCRIPT_FUNCTION_WITH_DEP(combined_editor) {
set->actions.tellListeners(change, false);
}
}
nv.first = v->value();
nv.first = v->value->toString();
nv.second = index_to_untagged(nv.first, nv.first.size()) == 0;
}
// options
......@@ -208,7 +208,7 @@ SCRIPT_FUNCTION(primary_choice) {
throw ScriptError(_("Argument to 'primary_choice' should be a choice value"));
}
// determine choice
int id = field->choices->choiceId(value->toString());
int id = field->choices->choiceId(value->value->toString());
// find the last group that still contains id
const vector<ChoiceField::ChoiceP>& choices = field->choices->choices;
FOR_EACH_CONST_REVERSE(c, choices) {
......
......@@ -146,13 +146,16 @@ SCRIPT_FUNCTION(symbol_variation) {
SCRIPT_PARAM(ScriptValueP, symbol); // TODO: change to input?
ScriptObject<ValueP>* valueO = dynamic_cast<ScriptObject<ValueP>*>(symbol.get());
SymbolValue* value = valueO ? dynamic_cast<SymbolValue*>(valueO->getValue().get()) : nullptr;
String filename;
if (value) {
filename = value->filename;
} else if (valueO) {
throw ScriptErrorConversion(valueO->typeName(), _TYPE_("symbol" ));
LocalSymbolFileP symbol_file;
LocalFileName filename;
if (value && value->value->isNil()) {
// empty filename
} else if(value && (symbol_file = dynamic_pointer_cast<LocalSymbolFile>(value->value))) {
filename = symbol_file->filename;
} else if (!valueO) {
filename = LocalFileName::fromReadString(symbol->toString());
} else {
filename = symbol->toString();
throw ScriptErrorConversion(valueO->typeName(), _TYPE_("symbol"));
}
// known variation?
SCRIPT_OPTIONAL_PARAM_(String, variation)
......@@ -166,7 +169,7 @@ SCRIPT_FUNCTION(symbol_variation) {
FOR_EACH(v, style->variations) {
if (v->name == variation) {
// found it
return intrusive(new SymbolToImage(value, filename, value->last_modified, v));
return intrusive(new SymbolToImage(value, filename, v));
}
}
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
......@@ -200,7 +203,7 @@ SCRIPT_FUNCTION(symbol_variation) {
} else {
throw ScriptError(_("Unknown fill type for symbol_variation: ") + fill_type);
}
return intrusive(new SymbolToImage(value, filename, value ? value->last_modified : Age(), var));
return intrusive(new SymbolToImage(value, filename, var));
}
}
......
......@@ -448,8 +448,9 @@ ExprType parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
Token token = input.read();
if (token == _("(")) {
// Parentheses = grouping for precedence of expressions
parseOper(input, script, PREC_ALL);
ExprType type = parseOper(input, script, PREC_ALL);
expectToken(input, _(")"), &token);
return type;
} else if (token == _("{")) {
// {} = function block. Parse a new Script
intrusive_ptr<Script> subScript(new Script);
......@@ -500,19 +501,19 @@ ExprType parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
parseOper(input, script, PREC_AND); // AAA
unsigned jmpElse = script.addInstruction(I_JUMP_IF_NOT); // jnz lbl_else
expectToken(input, _("then")); // then
parseOper(input, script, PREC_SET); // BBB
ExprType type1 = parseOper(input, script, PREC_SET); // BBB
unsigned jmpEnd = script.addInstruction(I_JUMP); // jump lbl_end
script.comeFrom(jmpElse); // lbl_else:
bool has_else = input.peek() == _("else"); //else
ExprType type = EXPR_STATEMENT;
ExprType type2 = EXPR_STATEMENT;
if (has_else) {
input.read();
type = parseOper(input, script, PREC_SET); // CCC
type2 = parseOper(input, script, PREC_SET); // CCC
} else {
script.addInstruction(I_PUSH_CONST, script_nil);
}
script.comeFrom(jmpEnd); // lbl_end:
return type == EXPR_STATEMENT ? EXPR_STATEMENT : EXPR_OTHER;
return type1 == EXPR_STATEMENT || type2 == EXPR_STATEMENT ? EXPR_STATEMENT : EXPR_OTHER;
} else if (token == _("for")) {
// the loop body should have a net stack effect of 0, but the entire expression of +1
// solution: add all results from the body, start with nil
......@@ -724,7 +725,7 @@ ExprType parseOper(TokenIterator& input, Script& script, Precedence minPrec, Ins
else if (minPrec <= PREC_AND && token==_("xor")) parseOper(input, script, PREC_CMP, I_BINARY, I_XOR);
else if (minPrec <= PREC_CMP && token==_("=")) {
if (minPrec <= PREC_SET) {
input.add_error(_("Use of '=', did you mean ':=' or '=='?"));
input.add_error(_("Use of '=', did you mean ':=' or '=='? I will assume '=='"));
}
parseOper(input, script, PREC_ADD, I_BINARY, I_EQ);
}
......@@ -851,6 +852,9 @@ void parseCallArguments(TokenIterator& input, Script& script, vector<Variable>&
// ----------------------------------------------------------------------------- : Parsing values
ScriptValueP script_local_image_file(LocalFileName const& filename);
ScriptValueP script_local_symbol_file(LocalFileName const& filename);
ScriptValueP parse_value(TokenIterator& input, Packaged* package) {
Token token = input.read();
if (token == _("(")) {
......@@ -884,9 +888,6 @@ ScriptValueP parse_value(TokenIterator& input, Packaged* package) {
}
expectToken(input, _("]"), &token);
return col;
} else if (token == _("-")) {
// TODO?
throw "TODO";
} else if (token == TOK_NAME) {
if (token == _("true")) {
return script_true;
......@@ -920,16 +921,22 @@ ScriptValueP parse_value(TokenIterator& input, Packaged* package) {
return to_script(AColor(r->toInt(),g->toInt(),b->toInt(),a->toInt()));
} else if (token == _("mark_default")) {
expectToken(input, _("("));
ScriptValueP a = parse_value(input, package);
ScriptValueP x = parse_value(input, package);
expectToken(input, _(")"));
if (!a) return ScriptValueP();
return intrusive(new ScriptDefault(a));
} else if (token == _("local_filename")) {
if (!x) return ScriptValueP();
return intrusive(new ScriptDefault(x));
} else if (token == _("local_image_file")) {
expectToken(input, _("("));
ScriptValueP a = parse_value(input, package);
ScriptValueP x = parse_value(input, package);
expectToken(input, _(")"));
if (!a) return ScriptValueP();
return intrusive(new ScriptLocalFileName(package,a->toString()));
if (!x) return ScriptValueP();
return script_local_image_file(LocalFileName::fromReadString(x->toString()));
} else if (token == _("local_symbol_file")) {
expectToken(input, _("("));
ScriptValueP x = parse_value(input, package);
expectToken(input, _(")"));
if (!x) return ScriptValueP();
return script_local_symbol_file(LocalFileName::fromReadString(x->toString()));
}
} else if (token == TOK_INT) {
long l = 0;
......@@ -941,6 +948,9 @@ ScriptValueP parse_value(TokenIterator& input, Packaged* package) {
return to_script(d);
} else if (token == TOK_STRING) {
return to_script(token.value);
/*} else if (token == _("-")) {
// TODO?
throw InternalError("TODO");*/
}
// parse error
input.expected(_("value (string/number/boolean/color/list)"));
......
......@@ -111,6 +111,7 @@ class ScriptDefault : public ScriptValue {
virtual ScriptType type() const { return un_default->type(); }
virtual String typeName() const { return un_default->typeName(); }
virtual String toString() const { return un_default->toString(); }
virtual String toFriendlyString() const { return un_default->toFriendlyString(); }
virtual String toCode() const { return _("mark_default(") + un_default->toCode() + _(")"); }
virtual double toDouble() const { return un_default->toDouble(); }
virtual int toInt() const { return un_default->toInt(); }
......@@ -130,13 +131,14 @@ inline ScriptDefault const* is_default(ScriptValueP const& x) {
return is_default(x.get());
}
inline ScriptValueP make_default(ScriptValueP const& x) {
return intrusive(new ScriptDefault(x));
return is_default(x) ? x : intrusive(new ScriptDefault(x));
}
inline ScriptValueP with_defaultness_of(ScriptValueP const& of, ScriptValueP const& x) {
return is_default(of) ? make_default(x) : x;
}
extern ScriptValueP script_default_nil;
/*
// ----------------------------------------------------------------------------- : File names
class Packaged;
......@@ -156,6 +158,7 @@ class ScriptLocalFileName : public ScriptValue {
String fn; //< The filename
Type file_type;
};
*/
// ----------------------------------------------------------------------------- : Iterators
......
......@@ -12,6 +12,7 @@
#include <script/context.hpp>
#include <gfx/generated_image.hpp>
#include <util/error.hpp>
#include <util/tagged_string.hpp>
#include <boost/pool/singleton_pool.hpp>
DECLARE_TYPEOF_COLLECTION(pair<Variable COMMA ScriptValueP>);
......@@ -27,6 +28,7 @@ AColor ScriptValue::toColor() const { throw Script
wxDateTime ScriptValue::toDateTime() const { throw ScriptErrorConversion(typeName(), _TYPE_("date" )); }
GeneratedImageP ScriptValue::toImage() const { throw ScriptErrorConversion(typeName(), _TYPE_("image" )); }
String ScriptValue::toCode() const { return toString(); }
String ScriptValue::toFriendlyString() const { return toString(); }
ScriptValueP ScriptValue::do_eval(Context&, bool) const { return delay_error(ScriptErrorConversion(typeName(), _TYPE_("function"))); }
ScriptValueP ScriptValue::next(ScriptValueP* key_out) { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); }
ScriptValueP ScriptValue::makeIterator() const { return delay_error(ScriptErrorConversion(typeName(), _TYPE_("collection"))); }
......@@ -250,6 +252,11 @@ class ScriptString : public ScriptValue {
virtual String toCode() const {
return quote_string(value);
}
virtual String toFriendlyString() const {
// assume that the string can contain tags
// TODO: distinguish between strings with tags and strings without
return untag(value);
}
virtual double toDouble() const {
double d;
if (value.ToDouble(&d)) {
......
......@@ -63,6 +63,8 @@ class ScriptValue : public IntrusivePtrBaseWithDelete {
virtual String toString() const;
/// Script code to generate this value
virtual String toCode() const;
/// A string that can be shown to a user (i.e. not a template developer), should not contains tags
virtual String toFriendlyString() const;
/// Convert this value to a double
virtual double toDouble() const;
/// Convert this value to an integer
......@@ -75,7 +77,9 @@ class ScriptValue : public IntrusivePtrBaseWithDelete {
virtual wxDateTime toDateTime() const;
/// Convert this value to an image
virtual GeneratedImageP toImage() const;
/// Is the value equal to script_nil?
inline bool isNil() const { return type() == SCRIPT_NIL; }
/// Get a member variable from this value
virtual ScriptValueP getMember(const String& name) const;
......
......@@ -33,8 +33,10 @@ class Age {
}
/// Compare two ages, smaller means earlier
inline bool operator < (Age a) const { return age < a.age; }
/// Compare two ages
inline bool operator < (Age a) const { return age < a.age; }
inline bool operator <= (Age a) const { return age <= a.age; }
inline bool operator > (Age a) const { return age > a.age; }
inline bool operator >= (Age a) const { return age >= a.age; }
inline bool operator == (Age a) const { return age == a.age; }
/// A number corresponding to the age
......
......@@ -10,10 +10,10 @@
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <data/field/text.hpp>
#include <wx/fdrepdlg.h>
DECLARE_POINTER_TYPE(Card);
DECLARE_POINTER_TYPE(TextValue);
// ----------------------------------------------------------------------------- : Search/replace
......
......@@ -18,7 +18,7 @@ using boost::tribool;
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 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); }
......
......@@ -259,7 +259,7 @@ String Package::nameOut(const String& file) {
}
}
FileName Package::newFileName(const String& prefix, const String& suffix) {
LocalFileName Package::newFileName(const String& prefix, const String& suffix) {
assert(wxThread::IsMain()); // Writing should only be done from the main thread
String name;
UInt infix = 0;
......@@ -287,6 +287,8 @@ void Package::referenceFile(const String& file) {
it->second.keep = true;
}
// ----------------------------------------------------------------------------- : LocalFileNames and absolute file references
String Package::absoluteName(const String& file) {
assert(wxThread::IsMain());
FileInfos::iterator it = files.find(normalize_internal_filename(file));
......@@ -301,9 +303,10 @@ String Package::absoluteName(const String& file) {
return filename+_("/")+file;
} else {
// assume zip package
return filename+_("\1")+file;
return filename + _("\1") + file;
}
}
// Open a file that is in some package
InputStreamP Package::openAbsoluteFile(const String& name) {
size_t pos = name.find_first_of(_('\1'));
......@@ -320,6 +323,42 @@ InputStreamP Package::openAbsoluteFile(const String& name) {
}
}
String LocalFileName::toStringForWriting() const {
if (!fn.empty() && clipboard_package()) {
// use absolute names on clipboard
try {
return clipboard_package()->absoluteName(fn);
} catch (const Error&) {
// ignore errors
return _("");
}
} else if (!fn.empty() && writing_package()) {
writing_package()->referenceFile(fn);
return fn;
} else {
return fn;
}
}
LocalFileName LocalFileName::fromReadString(String const& fn, String const& prefix, String const& suffix) {
if (!fn.empty() && clipboard_package()) {
// copy file into current package
try {
LocalFileName local_name = clipboard_package()->newFileName(prefix,_("")); // a new unique name in the package, assume it's an image
OutputStreamP out = clipboard_package()->openOut(local_name);
InputStreamP in = Package::openAbsoluteFile(fn);
out->Write(*in); // copy
return local_name;
} catch (Error) {
// ignore errors
return _("");
}
} else {
return LocalFileName(fn);
}
}
// ----------------------------------------------------------------------------- : Package : private
Package::FileInfo::FileInfo()
......
......@@ -21,15 +21,51 @@ class wxZipInputStream;
class wxZipEntry;
DECLARE_POINTER_TYPE(PackageDependency);
/// The package that is currently being written to
/// The package that is currently being written to.
/// When writing a filename, the writing_package should be notified that this file is still in use.
DECLARE_DYNAMIC_ARG(Package*, writing_package);
/// The package that is being put onto/read from the clipboard
/// The package that contains the thing being written to the clipboard, or the package that will contain the thing being read from the clipboard.
/// When writing a filename, it should be converted to a global name referencing clipboard_package.
/// When reading a global name, the file should be copied into the clipboard_package.
DECLARE_DYNAMIC_ARG(Package*, clipboard_package);
typedef shared_ptr<wxOutputStream> OutputStreamP;
// ----------------------------------------------------------------------------- : FileName
/// A string standing for a filename, has different behaviour when reading/writing
/// Behaviour is controled by dynamic args:
/// * clipboard_package
/// * writing_package
class LocalFileName {
public:
LocalFileName() {}
// Convert to a string that can be written to a package.
// notifies the package that the underlying file is in use.
// when writing to the clipboard, instead returns a global file reference.
String toStringForWriting() const;
// Construct a LocalFileName based on a string read from a package.
// when reading from the clipboard, this will instead be a global file reference, and it is converted at this point.
static LocalFileName fromReadString(const String&, const String& prefix = _("image"), String const& suffix = _(""));
inline bool empty() const {
return fn.empty();
}
inline bool operator == (LocalFileName const& that) const {
return this->fn == that.fn;
}
private:
LocalFileName(const wxString& fn) : fn(fn) {}
String fn;
friend class Package;
};
// TODO: rename to LocalFileName
typedef LocalFileName FileName;
// ----------------------------------------------------------------------------- : Package
/// A package is a container for files. On disk it is either a directory or a zip file.
......@@ -105,14 +141,23 @@ class Package : public IntrusivePtrVirtualBase {
/// Open an input stream for a file in the package.
InputStreamP openIn(const String& file);
inline InputStreamP openIn(const LocalFileName& file) {
return openIn(file.fn);
}
/// Open an output stream for a file in the package.
/// (changes are only committed with save())
OutputStreamP openOut(const String& file);
inline OutputStreamP openOut(const LocalFileName& file) {
return openOut(file.fn);
}
/// Get a filename that can be written to to modfify a file in the package
/// (changes are only committed with save())
String nameOut(const String& file);
inline String nameOut(const LocalFileName& file) {
return nameOut(file.fn);
}
/// Creates a new, unique, filename with the specified prefix and suffix
/// for example newFileName("image/",".jpg") -> "image/1.jpg"
......@@ -124,13 +169,6 @@ class Package : public IntrusivePtrVirtualBase {
/// If they are to be kept in the package.
void referenceFile(const String& file);
/// Get an 'absolute filename' for a file in the package.
/// This file can later be opened from anywhere (other process) using openAbsoluteFile()
String absoluteName(const String& file);
/// Open a file given an absolute filename
static InputStreamP openAbsoluteFile(const String& name);
// --------------------------------------------------- : Managing the inside of the package : Reader/writer
template <typename T>
......@@ -142,6 +180,10 @@ class Package : public IntrusivePtrVirtualBase {
readFile(file, obj);
return obj;
}
template <typename T>
inline T readFile(const LocalFileName& file) {
return readFile<T>(file.fn);
}
template <typename T>
void writeFile(const String& file, const T& obj, Version file_version) {
......@@ -149,6 +191,10 @@ class Package : public IntrusivePtrVirtualBase {
Writer writer(*stream, file_version);
writer.handle(obj);
}
template <typename T>
inline void writeFile(const LocalFileName& file, const T& obj, Version file_version) {
return readFile(file.fn, obj, file_version);
}
protected:
// TODO: I dislike putting this here very much. There ought to be a better way.
......@@ -202,6 +248,13 @@ class Package : public IntrusivePtrVirtualBase {
void saveToZipfile(const String&, bool remove_unused, bool is_copy);
void saveToDirectory(const String&, bool remove_unused, bool is_copy);
FileInfos::iterator addFile(const String& file);
/// Get an 'absolute filename' for a file in the package.
/// This file can later be opened from anywhere (other process) using openAbsoluteFile()
String absoluteName(const String& file);
/// Open a file given an absolute filename
static InputStreamP openAbsoluteFile(const String& name);
friend class LocalFileName;
};
// ----------------------------------------------------------------------------- : Packaged
......
......@@ -56,6 +56,9 @@ PackagedP PackageManager::openAny(const String& name_, bool just_header) {
// global data dir
filename = normalize_filename(global.name(name));
}
if (!wxFileExists(filename) && !wxDirExists(filename)) {
throw PackageNotFoundError(_("Package not found: '") + name + _("'"));
}
} else { // Absolute filename
filename = normalize_filename(name);
}
......
......@@ -371,26 +371,8 @@ template <> void Reader::handle(Vector2D& vec) {
}
}
template <> void Reader::handle(FileName& f) {
if (clipboard_package()) {
String str = getValue();
if (!str.empty()) {
// copy file into current package
try {
String packaged_name = clipboard_package()->newFileName(_("image"),_("")); // a new unique name in the package, assume it's an image
OutputStreamP out = clipboard_package()->openOut(packaged_name);
InputStreamP in = Package::openAbsoluteFile(str);
out->Write(*in); // copy
f.assign(packaged_name);
} catch (Error) {
// ignore errors
}
} else {
f.assign(str);
}
} else {
handle(static_cast<String&>(f));
}
template <> void Reader::handle(LocalFileName& f) {
f = LocalFileName::fromReadString(this->getValue());
}
// ----------------------------------------------------------------------------- : EnumReader
......
......@@ -133,18 +133,6 @@ template <> void Writer::handle(const Color& col) {
handle(String::Format(_("rgb(%u,%u,%u)"), col.Red(), col.Green(), col.Blue()));
}
template <> void Writer::handle(const FileName& value) {
if (clipboard_package() && !value.empty()) {
// use absolute names on clipboard
try {
handle(clipboard_package()->absoluteName(value));
} catch (const Error&) {
// ignore errors
}
} else {
handle(static_cast<const String&>(value));
if (writing_package()) {
writing_package()->referenceFile(value);
}
}
template <> void Writer::handle(const LocalFileName& value) {
handle(value.toStringForWriting());
}
......@@ -89,13 +89,6 @@ typedef unsigned int UInt;
/// Null pointer
#define nullptr 0
/// A string standing for a filename, has different behaviour when reading/writing
class FileName : public wxString {
public:
FileName() {}
FileName(const wxString& s) : wxString(s) {}
};
// ----------------------------------------------------------------------------- : MSE Headers
// MSE utility headers (ones unlikely to change and used everywhere)
......
......@@ -89,8 +89,8 @@ 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_export_template = 20001; // 2.0.1
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_clipboard = 20001; // 2.0.1
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