Commit 7b11e13c authored by twanvl's avatar twanvl

combined_editor function, and improved dependency handling (removing...

combined_editor function, and improved dependency handling (removing duplicates), viewer refreshes on events from script manager
parent fe82334a
...@@ -69,7 +69,7 @@ String TextValueAction::getName(bool to_undo) const { return name; } ...@@ -69,7 +69,7 @@ String TextValueAction::getName(bool to_undo) const { return name; }
void TextValueAction::perform(bool to_undo) { void TextValueAction::perform(bool to_undo) {
swap(value().value, new_value); swap(value().value, new_value);
// if (value().value.age < new_value.age) value().value.age = Age(); value().last_update.update();
swap(selection_end, new_selection_end); swap(selection_end, new_selection_end);
} }
......
...@@ -48,7 +48,7 @@ void mark_dependency_member(const CardP& card, const String& name, const Depende ...@@ -48,7 +48,7 @@ void mark_dependency_member(const CardP& card, const String& name, const Depende
// Find field with that name // Find field with that name
IndexMap<FieldP,ValueP>::const_iterator it = card->data.find(name); IndexMap<FieldP,ValueP>::const_iterator it = card->data.find(name);
if (it != card->data.end()) { if (it != card->data.end()) {
(*it)->fieldP->dependent_scripts.push_back(dep); (*it)->fieldP->dependent_scripts.add(dep);
} }
} }
......
...@@ -50,7 +50,7 @@ class Field { ...@@ -50,7 +50,7 @@ class Field {
String card_list_name; ///< Alternate name to use in card list. String card_list_name; ///< Alternate name to use in card list.
Alignment card_list_align; ///< Alignment of the card list colummn. Alignment card_list_align; ///< Alignment of the card list colummn.
int tab_index; ///< Tab index in editor int tab_index; ///< Tab index in editor
vector<Dependency> dependent_scripts; ///< Scripts that depend on values of this field Dependencies dependent_scripts; ///< Scripts that depend on values of this field
/// Creates a new Value corresponding to this Field /// Creates a new Value corresponding to this Field
/** thisP is a smart pointer to this */ /** thisP is a smart pointer to this */
......
...@@ -95,8 +95,11 @@ String TextValue::toString() const { ...@@ -95,8 +95,11 @@ String TextValue::toString() const {
} }
bool TextValue::update(Context& ctx) { bool TextValue::update(Context& ctx) {
Value::update(ctx); Value::update(ctx);
return field().default_script.invokeOnDefault(ctx, value) WITH_DYNAMIC_ARG(last_update_age, last_update.get());
| field(). script.invokeOn(ctx, value); bool change = field().default_script.invokeOnDefault(ctx, value)
| field(). script.invokeOn(ctx, value);
if (change) last_update.update();
return change;
} }
IMPLEMENT_REFLECTION_NAMELESS(TextValue) { IMPLEMENT_REFLECTION_NAMELESS(TextValue) {
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <util/prec.hpp> #include <util/prec.hpp>
#include <util/defaultable.hpp> #include <util/defaultable.hpp>
#include <util/rotation.hpp> #include <util/rotation.hpp>
#include <util/age.hpp>
#include <data/field.hpp> #include <data/field.hpp>
#include <data/font.hpp> #include <data/font.hpp>
#include <data/symbol_font.hpp> #include <data/symbol_font.hpp>
...@@ -88,6 +89,7 @@ class TextValue : public Value { ...@@ -88,6 +89,7 @@ class TextValue : public Value {
typedef Defaultable<String> ValueType; typedef Defaultable<String> ValueType;
ValueType value; ///< The text of this value ValueType value; ///< The text of this value
Age last_update; ///< When was the text last changed?
virtual String toString() const; virtual String toString() const;
virtual bool update(Context&); virtual bool update(Context&);
......
...@@ -45,9 +45,9 @@ class Game : public Packaged { ...@@ -45,9 +45,9 @@ class Game : public Packaged {
vector<KeywordModeP> keyword_modes; ///< Modes of keywords vector<KeywordModeP> keyword_modes; ///< Modes of keywords
vector<KeywordP> keywords; ///< Keywords for use in text vector<KeywordP> keywords; ///< Keywords for use in text
vector<Dependency> dependent_scripts_cards; ///< scripts that depend on the card list Dependencies dependent_scripts_cards; ///< scripts that depend on the card list
vector<Dependency> dependent_scripts_keywords; ///< scripts that depend on the keywords Dependencies dependent_scripts_keywords; ///< scripts that depend on the keywords
bool dependencies_initialized; ///< are the script dependencies comming from this game all initialized? bool dependencies_initialized; ///< are the script dependencies comming from this game all initialized?
/// Loads the game with a particular name, for example "magic" /// Loads the game with a particular name, for example "magic"
static GameP byName(const String& name); static GameP byName(const String& name);
......
...@@ -135,18 +135,18 @@ ScriptValueP make_iterator(const Set& set) { ...@@ -135,18 +135,18 @@ ScriptValueP make_iterator(const Set& set) {
void mark_dependency_member(Set* value, const String& name, const Dependency& dep) { void mark_dependency_member(Set* value, const String& name, const Dependency& dep) {
// is it the card list? // is it the card list?
if (name == _("cards")) { if (name == _("cards")) {
value->game->dependent_scripts_cards.push_back(dep); value->game->dependent_scripts_cards.add(dep);
return; return;
} }
// is it the keywords? // is it the keywords?
if (name == _("keywords")) { if (name == _("keywords")) {
value->game->dependent_scripts_keywords.push_back(dep); value->game->dependent_scripts_keywords.add(dep);
return; return;
} }
// is it in the set data? // is it in the set data?
IndexMap<FieldP,ValueP>::const_iterator it = value->data.find(name); IndexMap<FieldP,ValueP>::const_iterator it = value->data.find(name);
if (it != value->data.end()) { if (it != value->data.end()) {
(*it)->fieldP->dependent_scripts.push_back(dep); (*it)->fieldP->dependent_scripts.add(dep);
} }
} }
void mark_dependency_member(const SetP& value, const String& name, const Dependency& dep) { void mark_dependency_member(const SetP& value, const String& name, const Dependency& dep) {
......
...@@ -261,7 +261,7 @@ void TextValueEditor::onValueChange() { ...@@ -261,7 +261,7 @@ void TextValueEditor::onValueChange() {
selection_start_i = selection_end_i = 0; selection_start_i = selection_end_i = 0;
} }
void TextValueEditor::onAction(const ValueAction& action, bool undone) { void TextValueEditor::onAction(const Action& action, bool undone) {
TextValueViewer::onAction(action, undone); TextValueViewer::onAction(action, undone);
TYPE_CASE(action, TextValueAction) { TYPE_CASE(action, TextValueAction) {
selection_start_i = action.selection_start; selection_start_i = action.selection_start;
......
...@@ -51,7 +51,7 @@ class TextValueEditor : public TextValueViewer, public ValueEditor { ...@@ -51,7 +51,7 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
// --------------------------------------------------- : Actions // --------------------------------------------------- : Actions
virtual void onValueChange(); virtual void onValueChange();
virtual void onAction(const ValueAction&, bool undone); virtual void onAction(const Action&, bool undone);
// --------------------------------------------------- : Clipboard // --------------------------------------------------- : Clipboard
......
...@@ -134,4 +134,16 @@ void DataViewer::onAction(const Action& action, bool undone) { ...@@ -134,4 +134,16 @@ void DataViewer::onAction(const Action& action, bool undone) {
} }
} }
} }
TYPE_CASE(action, ScriptValueEvent) {
if (action.card == card.get()) {
FOR_EACH(v, viewers) {
if (v->getValue().get() == action.value) {
// refresh the viewer
v->onAction(action, undone);
onChange();
return;
}
}
}
}
} }
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
class Set; class Set;
class DataViewer; class DataViewer;
class ValueAction; class Action;
DECLARE_POINTER_TYPE(Style); DECLARE_POINTER_TYPE(Style);
DECLARE_POINTER_TYPE(Value); DECLARE_POINTER_TYPE(Value);
...@@ -55,7 +55,7 @@ class ValueViewer { ...@@ -55,7 +55,7 @@ class ValueViewer {
/// Called when a (scripted) property of the associated style has changed /// Called when a (scripted) property of the associated style has changed
virtual void onStyleChange() {} virtual void onStyleChange() {}
/// Called when an action is performed on the associated value /// Called when an action is performed on the associated value
virtual void onAction(const ValueAction&, bool undone) { onValueChange(); } virtual void onAction(const Action&, bool undone) { onValueChange(); }
/// Convert this viewer to an editor, if possible /// Convert this viewer to an editor, if possible
virtual ValueEditor* getEditor() { return 0; } virtual ValueEditor* getEditor() { return 0; }
......
...@@ -168,7 +168,7 @@ void Context::setVariable(const String& name, const ScriptValueP& value) { ...@@ -168,7 +168,7 @@ void Context::setVariable(const String& name, const ScriptValueP& value) {
void Context::setVariable(int name, const ScriptValueP& value) { void Context::setVariable(int name, const ScriptValueP& value) {
Variable& var = variables[name]; Variable& var = variables[name];
if (var.value && var.level < level) { if (var.level < level) {
// keep shadow copy // keep shadow copy
Binding bind = {name, var}; Binding bind = {name, var};
shadowed.push_back(bind); shadowed.push_back(bind);
......
...@@ -60,6 +60,7 @@ class Context { ...@@ -60,6 +60,7 @@ class Context {
public:// public for FOR_EACH public:// public for FOR_EACH
/// Record of a variable /// Record of a variable
struct Variable { struct Variable {
Variable() : level(0) {}
unsigned int level; ///< Scope level on which this variable was set unsigned int level; ///< Scope level on which this variable was set
ScriptValueP value; ///< Value of this variable ScriptValueP value; ///< Value of this variable
}; };
......
...@@ -38,6 +38,25 @@ class Dependency { ...@@ -38,6 +38,25 @@ class Dependency {
inline Dependency makeCardIndependend() const { inline Dependency makeCardIndependend() const {
return Dependency(type == DEP_CARD_FIELD ? DEP_CARDS_FIELD : type, index, data); return Dependency(type == DEP_CARD_FIELD ? DEP_CARDS_FIELD : type, index, data);
} }
inline bool operator == (const Dependency& d) const {
return type == d.type && index == d.index && data == d.data;
}
};
// ----------------------------------------------------------------------------- : Dependencies
/// A list of dependencies
class Dependencies : public vector<Dependency> {
public:
/// Add a dependency, prevents duplicates
inline void add(const Dependency& d) {
if (find(begin(),end(),d) == end()) {
push_back(d);
}
}
private:
using vector<Dependency>::push_back;
}; };
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
......
...@@ -11,9 +11,14 @@ ...@@ -11,9 +11,14 @@
#include <script/dependency.hpp> #include <script/dependency.hpp>
#include <util/tagged_string.hpp> #include <util/tagged_string.hpp>
#include <data/set.hpp> #include <data/set.hpp>
#include <data/game.hpp>
#include <data/field/text.hpp>
#include <wx/regex.h> #include <wx/regex.h>
DECLARE_TYPEOF_COLLECTION(UInt); DECLARE_TYPEOF_COLLECTION(UInt);
DECLARE_TYPEOF_COLLECTION(FieldP);
DECLARE_TYPEOF_COLLECTION(TextValue*);
DECLARE_TYPEOF_COLLECTION(String);
/** @file script/functions.cpp /** @file script/functions.cpp
* *
...@@ -90,7 +95,7 @@ SCRIPT_FUNCTION(replace_rule) { ...@@ -90,7 +95,7 @@ SCRIPT_FUNCTION(replace_rule) {
ret->replacement = (String)*replace; ret->replacement = (String)*replace;
} }
// in_context // in_context
SCRIPT_OPTIONAL_PARAM_N(String, "in context", in_context) { SCRIPT_OPTIONAL_PARAM_N(String, _("in context"), in_context) {
if (!ret->context.Compile(in_context, wxRE_ADVANCED)) { if (!ret->context.Compile(in_context, wxRE_ADVANCED)) {
throw ScriptError(_("Error while compiling regular expression: '")+in_context+_("'")); throw ScriptError(_("Error while compiling regular expression: '")+in_context+_("'"));
} }
...@@ -453,6 +458,118 @@ SCRIPT_FUNCTION(number_of_items) { ...@@ -453,6 +458,118 @@ SCRIPT_FUNCTION(number_of_items) {
} }
// ----------------------------------------------------------------------------- : Combined editor
SCRIPT_FUNCTION_DEP(combined_editor) {
// read 'field#' arguments
vector<TextValue*> values;
for (int i = 0 ; ; ++i) {
String name = _("field"); if (i > 0) name = name << i;
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
TextValue* text_value = dynamic_cast<TextValue*>(value.get());
if (!text_value) throw ScriptError(_("Argument '")+name+_("' should be a text field"));
values.push_back(text_value);
} else if (i > 0) break;
}
if (values.empty()) {
throw ScriptError(_("No fields specified for combined_editor"));
}
// read 'separator#' arguments
vector<String> separators;
for (int i = 0 ; ; ++i) {
String name = _("separator"); if (i > 0) name = name << i;
SCRIPT_OPTIONAL_PARAM_N(String, name, separator) {
separators.push_back(separator);
} else if (i > 0) break;
}
if (separators.size() < values.size() - 1) {
throw ScriptError(String::Format(_("Not enough separators for combine_editor, expected %d"), values.size()-1));
}
// split the value
SCRIPT_PARAM(String, value);
vector<String> value_parts;
size_t pos = value.find(_("<sep"));
while (pos != String::npos) {
value_parts.push_back(value.substr(0, pos));
value = value.substr(min(skip_tag(value,match_close_tag(value,pos)), value.size()));
pos = value.find(_("<sep"));
}
value_parts.push_back(value);
if (value_parts.size() < values.size()) value_parts.resize(values.size());
// update the values if our input value is newer?
Age new_value_update = last_update_age();
FOR_EACH_2(v, values, nv, value_parts) {
if (v->value() != nv && v->last_update < new_value_update) {
// TODO : type over
v->value.assign(nv);
v->update(ctx);
}
nv = v->value();
}
// options
SCRIPT_PARAM_DEFAULT_N(bool, _("hide when empty"), hide_when_empty, false);
SCRIPT_PARAM_DEFAULT_N(bool, _("soft before empty"), soft_before_empty, false);
// recombine the parts
String new_value = value_parts.front();
for (size_t i = 1 ; i < value_parts.size() ; ++i) {
if (value_parts[i].empty() && new_value.empty() && hide_when_empty) {
// no separator
} else if (value_parts[i].empty() && soft_before_empty) {
// soft separator
new_value += _("<sep-soft>") + separators[i - 1] + _("</sep-soft>");
} else {
// normal separator
new_value += _("<sep>") + separators[i - 1] + _("</sep>");
new_value += value_parts[i];
}
}
SCRIPT_RETURN(new_value);
}
ScriptValueP ScriptBuildin_combined_editor::dependencies(Context& ctx, const Dependency& dep) const {
// read 'field#' arguments
vector<FieldP> fields;
for (int i = 0 ; ; ++i) {
String name = _("field"); if (i > 0) name = name << i;
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
fields.push_back(value->fieldP);
} else if (i > 0) break;
}
// Find the target field
SCRIPT_PARAM(Set*, set);
GameP game = set->game;
FieldP target_field;
if (dep.type == DEP_CARD_FIELD) target_field = game->card_fields[dep.index];
else if (dep.type == DEP_SET_FIELD) target_field = game->set_fields[dep.index];
else throw InternalError(_("Finding dependencies of combined error for non card/set field"));
// Add dependencies, from target_field on field#
// For card fields
size_t j = 0;
FOR_EACH(f, game->card_fields) {
Dependency dep(DEP_CARD_COPY_DEP, j++);
FOR_EACH(fn, fields) {
if (f == fn) {
target_field->dependent_scripts.add(dep);
break;
}
}
}
// For set fields
j = 0;
FOR_EACH(f, game->set_fields) {
Dependency dep(DEP_SET_COPY_DEP, j++);
FOR_EACH(fn, fields) {
if (f == fn) {
target_field->dependent_scripts.add(dep);
break;
}
}
}
SCRIPT_RETURN(dependency_dummy);
}
// ----------------------------------------------------------------------------- : Initialize functions // ----------------------------------------------------------------------------- : Initialize functions
void init_script_functions(Context& ctx) { void init_script_functions(Context& ctx) {
...@@ -471,5 +588,7 @@ void init_script_functions(Context& ctx) { ...@@ -471,5 +588,7 @@ void init_script_functions(Context& ctx) {
ctx.setVariable(_("tag remove rule"), script_tag_remove_rule); ctx.setVariable(_("tag remove rule"), script_tag_remove_rule);
ctx.setVariable(_("position"), script_position_of); ctx.setVariable(_("position"), script_position_of);
ctx.setVariable(_("number of items"), script_number_of_items); ctx.setVariable(_("number of items"), script_number_of_items);
ctx.setVariable(_("forward editor"), script_combined_editor);
ctx.setVariable(_("combined editor"), script_combined_editor);
} }
...@@ -20,11 +20,6 @@ ...@@ -20,11 +20,6 @@
DECLARE_TYPEOF_COLLECTION(SymbolStyle::VariationP); DECLARE_TYPEOF_COLLECTION(SymbolStyle::VariationP);
// image generating functions have two modes
// if last_update_age > 0 they return whether the image is still up to date
// if last_update_age == 0 they generate the image
DECLARE_DYNAMIC_ARG (long, last_update_age);
IMPLEMENT_DYNAMIC_ARG(long, last_update_age, 0);
IMPLEMENT_DYNAMIC_ARG(Package*, load_images_from, nullptr); IMPLEMENT_DYNAMIC_ARG(Package*, load_images_from, nullptr);
// ----------------------------------------------------------------------------- : ScriptImage // ----------------------------------------------------------------------------- : ScriptImage
......
...@@ -30,6 +30,8 @@ DECLARE_TYPEOF_NO_REV(IndexMap_FieldP_ValueP); ...@@ -30,6 +30,8 @@ DECLARE_TYPEOF_NO_REV(IndexMap_FieldP_ValueP);
void init_script_functions(Context& ctx); void init_script_functions(Context& ctx);
void init_script_image_functions(Context& ctx); void init_script_image_functions(Context& ctx);
#define LOG_UPDATES
// ----------------------------------------------------------------------------- : SetScriptContext : initialization // ----------------------------------------------------------------------------- : SetScriptContext : initialization
SetScriptContext::SetScriptContext(Set& set) SetScriptContext::SetScriptContext(Set& set)
...@@ -151,7 +153,13 @@ void SetScriptManager::onAction(const Action& action, bool undone) { ...@@ -151,7 +153,13 @@ void SetScriptManager::onAction(const Action& action, bool undone) {
// note: fallthrough // note: fallthrough
} }
TYPE_CASE_(action, CardListAction) { TYPE_CASE_(action, CardListAction) {
#ifdef LOG_UPDATES
wxLogDebug(_("Card dependencies"));
#endif
updateAllDependend(set.game->dependent_scripts_cards); updateAllDependend(set.game->dependent_scripts_cards);
#ifdef LOG_UPDATES
wxLogDebug(_("-------------------------------\n"));
#endif
} }
} }
...@@ -174,12 +182,21 @@ void SetScriptManager::updateValue(Value& value, const CardP& card) { ...@@ -174,12 +182,21 @@ void SetScriptManager::updateValue(Value& value, const CardP& card) {
deque<ToUpdate> to_update; deque<ToUpdate> to_update;
// execute script for initial changed value // execute script for initial changed value
value.update(getContext(card)); value.update(getContext(card));
#ifdef LOG_UPDATES
wxLogDebug(_("Start: %s"), value.fieldP->name);
#endif
// update dependent scripts // update dependent scripts
alsoUpdate(to_update, value.fieldP->dependent_scripts, card); alsoUpdate(to_update, value.fieldP->dependent_scripts, card);
updateRecursive(to_update, starting_age); updateRecursive(to_update, starting_age);
#ifdef LOG_UPDATES
wxLogDebug(_("-------------------------------\n"));
#endif
} }
void SetScriptManager::updateAll() { void SetScriptManager::updateAll() {
#ifdef LOG_UPDATES
wxLogDebug(_("Update all"));
#endif
// update set data // update set data
Context& ctx = getContext(set.stylesheet); Context& ctx = getContext(set.stylesheet);
FOR_EACH(v, set.data) { FOR_EACH(v, set.data) {
...@@ -194,6 +211,9 @@ void SetScriptManager::updateAll() { ...@@ -194,6 +211,9 @@ void SetScriptManager::updateAll() {
} }
// update things that depend on the card list // update things that depend on the card list
updateAllDependend(set.game->dependent_scripts_cards); updateAllDependend(set.game->dependent_scripts_cards);
#ifdef LOG_UPDATES
wxLogDebug(_("-------------------------------\n"));
#endif
} }
void SetScriptManager::updateAllDependend(const vector<Dependency>& dependent_scripts) { void SetScriptManager::updateAllDependend(const vector<Dependency>& dependent_scripts) {
...@@ -221,7 +241,14 @@ void SetScriptManager::updateToUpdate(const ToUpdate& u, deque<ToUpdate>& to_upd ...@@ -221,7 +241,14 @@ void SetScriptManager::updateToUpdate(const ToUpdate& u, deque<ToUpdate>& to_upd
set.actions.tellListeners(change, false); set.actions.tellListeners(change, false);
// u.value has changed, also update values with a dependency on u.value // u.value has changed, also update values with a dependency on u.value
alsoUpdate(to_update, u.value->fieldP->dependent_scripts, u.card); alsoUpdate(to_update, u.value->fieldP->dependent_scripts, u.card);
#ifdef LOG_UPDATES
wxLogDebug(_("Changed: %s"), u.value->fieldP->name);
#endif
} }
#ifdef LOG_UPDATES
else
wxLogDebug(_("Same: %s"), u.value->fieldP->name);
#endif
} }
void SetScriptManager::alsoUpdate(deque<ToUpdate>& to_update, const vector<Dependency>& deps, const CardP& card) { void SetScriptManager::alsoUpdate(deque<ToUpdate>& to_update, const vector<Dependency>& deps, const CardP& card) {
......
...@@ -355,6 +355,7 @@ template <> inline ScriptValueP getParam<ScriptValueP>(const ScriptValueP& value ...@@ -355,6 +355,7 @@ template <> inline ScriptValueP getParam<ScriptValueP>(const ScriptValueP& value
template <> inline String getParam<String> (const ScriptValueP& value) { return *value; } template <> inline String getParam<String> (const ScriptValueP& value) { return *value; }
template <> inline int getParam<int> (const ScriptValueP& value) { return *value; } template <> inline int getParam<int> (const ScriptValueP& value) { return *value; }
template <> inline double getParam<double> (const ScriptValueP& value) { return *value; } template <> inline double getParam<double> (const ScriptValueP& value) { return *value; }
template <> inline bool getParam<bool> (const ScriptValueP& value) { return (int)*value; }
/// Retrieve an optional parameter /// Retrieve an optional parameter
/** Usage: /** Usage:
...@@ -367,23 +368,25 @@ template <> inline double getParam<double> (const ScriptValueP& value ...@@ -367,23 +368,25 @@ template <> inline double getParam<double> (const ScriptValueP& value
* } * }
* @endcode * @endcode
*/ */
#define SCRIPT_OPTIONAL_PARAM(Type, name) SCRIPT_OPTIONAL_PARAM_N(Type, #name, name) #define SCRIPT_OPTIONAL_PARAM(Type, name) SCRIPT_OPTIONAL_PARAM_N(Type, _(#name), name)
#define SCRIPT_OPTIONAL_PARAM_N(Type, str, name) \ #define SCRIPT_OPTIONAL_PARAM_N(Type, str, name) \
ScriptValueP name##_ = ctx.getVariableOpt(_(str)); \ ScriptValueP name##_ = ctx.getVariableOpt(str); \
Type name = name##_ ? getParam<Type>(name##_) : Type(); \ Type name = name##_ ? getParam<Type>(name##_) : Type(); \
if (name##_) if (name##_)
/// Retrieve an optional parameter, can't be used as an if statement /// Retrieve an optional parameter, can't be used as an if statement
#define SCRIPT_OPTIONAL_PARAM_(Type, name) SCRIPT_OPTIONAL_PARAM_N_(Type, #name, name) #define SCRIPT_OPTIONAL_PARAM_(Type, name) SCRIPT_OPTIONAL_PARAM_N_(Type, _(#name), name)
#define SCRIPT_OPTIONAL_PARAM_N_(Type, str, name) \ #define SCRIPT_OPTIONAL_PARAM_N_(Type, str, name) \
ScriptValueP name##_ = ctx.getVariableOpt(_(str)); \ ScriptValueP name##_ = ctx.getVariableOpt(str); \
Type name = name##_ ? getParam<Type>(name##_) : Type(); Type name = name##_ ? getParam<Type>(name##_) : Type();
/// Retrieve an optional parameter with a default value /// Retrieve an optional parameter with a default value
#define SCRIPT_PARAM_DEFAULT(Type, name, def) \ #define SCRIPT_PARAM_DEFAULT(Type, name, def) SCRIPT_PARAM_DEFAULT_N(Type, _(#name), name, def)
ScriptValueP name##_ = ctx.getVariableOpt(_(#name)); \ /// Retrieve an optional parameter with a default value
#define SCRIPT_PARAM_DEFAULT_N(Type, str, name, def) \
ScriptValueP name##_ = ctx.getVariableOpt(str); \
Type name = name##_ ? getParam<Type>(name##_) : def Type name = name##_ ? getParam<Type>(name##_) : def
/// Return a value from a SCRIPT_FUNCTION /// Return a value from a SCRIPT_FUNCTION
......
...@@ -13,3 +13,5 @@ ...@@ -13,3 +13,5 @@
// what a waste of a source file... // what a waste of a source file...
volatile LONG Age::new_age; volatile LONG Age::new_age;
IMPLEMENT_DYNAMIC_ARG(long, last_update_age, 0);
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp> #include <util/prec.hpp>
#include <util/dynamic_arg.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
extern "C" { extern "C" {
...@@ -32,6 +33,7 @@ class Age { ...@@ -32,6 +33,7 @@ class Age {
Age() { Age() {
update(); update();
} }
Age(LONG age) : age(age) {}
/// Update the age to become the newest one /// Update the age to become the newest one
inline void update() { inline void update() {
...@@ -51,9 +53,14 @@ class Age { ...@@ -51,9 +53,14 @@ class Age {
static volatile LONG new_age; static volatile LONG new_age;
}; };
// ----------------------------------------------------------------------------- : Aged
/// Age the object currently being processed was last updated
/** NOTE:
* image generating functions have two modes
* if last_update_age > 0 they return whether the image is still up to date
* if last_update_age == 0 they generate the image
*/
DECLARE_DYNAMIC_ARG (long, last_update_age);
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
#endif #endif
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