mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 13:06:59 -04:00
Conversion to new ScriptableImage complete, this affected quite a bit, including the evil thumbnail thread;
Added StyleListener, so style changes are only propagated to interested viewers. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@329 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -14,39 +14,21 @@
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <data/symbol.hpp>
|
||||
#include <data/field/symbol.hpp>
|
||||
#include <render/symbol/filter.hpp>
|
||||
#include <gui/util.hpp> // load_resource_image
|
||||
|
||||
#include <gfx/generated_image.hpp>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(SymbolVariationP);
|
||||
|
||||
bool parse_enum(const String&, ImageCombine& out);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Macros
|
||||
|
||||
#define SCRIPT_IMAGE_FUNCTION(name) \
|
||||
SCRIPT_FUNCTION(name) { \
|
||||
if (last_update_age() == 0)
|
||||
#define SCRIPT_IMAGE_FUNCTION_UP_TO_DATE }
|
||||
|
||||
template <> inline ScriptImageP from_script<ScriptImageP>(const ScriptValueP& value) {
|
||||
return to_script_image(value);
|
||||
}
|
||||
|
||||
#define SCRIPT_IMAGE_PARAM_UP_TO_DATE(name) script_image_up_to_date(ctx.getVariable(_(#name)))
|
||||
|
||||
// ----------------------------------------------------------------------------- : Utility
|
||||
|
||||
// TODO : use this system
|
||||
|
||||
template <> inline GeneratedImageP from_script<GeneratedImageP>(const ScriptValueP& value) {
|
||||
return image_from_script(value);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Image functions
|
||||
|
||||
SCRIPT_FUNCTION(linear_blend2) {
|
||||
SCRIPT_FUNCTION(linear_blend) {
|
||||
SCRIPT_PARAM(GeneratedImageP, image1);
|
||||
SCRIPT_PARAM(GeneratedImageP, image2);
|
||||
SCRIPT_PARAM(double, x1); SCRIPT_PARAM(double, y1);
|
||||
@@ -54,14 +36,14 @@ SCRIPT_FUNCTION(linear_blend2) {
|
||||
return new_intrusive6<LinearBlendImage>(image1, image2, x1,y1, x2,y2);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(masked_blend2) {
|
||||
SCRIPT_FUNCTION(masked_blend) {
|
||||
SCRIPT_PARAM(GeneratedImageP, light);
|
||||
SCRIPT_PARAM(GeneratedImageP, dark);
|
||||
SCRIPT_PARAM(GeneratedImageP, mask);
|
||||
return new_intrusive3<MaskedBlendImage>(light, dark, mask);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(combine_blend2) {
|
||||
SCRIPT_FUNCTION(combine_blend) {
|
||||
SCRIPT_PARAM(String, combine);
|
||||
SCRIPT_PARAM(GeneratedImageP, image1);
|
||||
SCRIPT_PARAM(GeneratedImageP, image2);
|
||||
@@ -72,13 +54,13 @@ SCRIPT_FUNCTION(combine_blend2) {
|
||||
return new_intrusive3<CombineBlendImage>(image1, image2, image_combine);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(set_mask2) {
|
||||
SCRIPT_FUNCTION(set_mask) {
|
||||
SCRIPT_PARAM(GeneratedImageP, image);
|
||||
SCRIPT_PARAM(GeneratedImageP, mask);
|
||||
return new_intrusive2<SetMaskImage>(image, mask);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(set_combine2) {
|
||||
SCRIPT_FUNCTION(set_combine) {
|
||||
SCRIPT_PARAM(String, combine);
|
||||
SCRIPT_PARAM(GeneratedImageP, input);
|
||||
ImageCombine image_combine;
|
||||
@@ -88,7 +70,7 @@ SCRIPT_FUNCTION(set_combine2) {
|
||||
return new_intrusive2<SetCombineImage>(input, image_combine);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(symbol_variation2) {
|
||||
SCRIPT_FUNCTION(symbol_variation) {
|
||||
// find symbol
|
||||
SCRIPT_PARAM(ValueP, symbol);
|
||||
SymbolValueP value = dynamic_pointer_cast<SymbolValue>(symbol);
|
||||
@@ -108,125 +90,11 @@ SCRIPT_FUNCTION(symbol_variation2) {
|
||||
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(built_in_image2) {
|
||||
SCRIPT_FUNCTION(built_in_image) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
return new_intrusive1<BuiltInImage>(input);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Image functions
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(linear_blend) {
|
||||
SCRIPT_PARAM(ScriptImageP, image1);
|
||||
SCRIPT_PARAM(ScriptImageP, image2);
|
||||
SCRIPT_PARAM(double, x1); SCRIPT_PARAM(double, y1);
|
||||
SCRIPT_PARAM(double, x2); SCRIPT_PARAM(double, y2);
|
||||
linear_blend(image1->image, image2->image, x1, y1, x2, y2);
|
||||
return image1;
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
SCRIPT_RETURN(
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image1) &&
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image2)
|
||||
);
|
||||
}
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(masked_blend) {
|
||||
SCRIPT_PARAM(ScriptImageP, light);
|
||||
SCRIPT_PARAM(ScriptImageP, dark);
|
||||
SCRIPT_PARAM(ScriptImageP, mask);
|
||||
mask_blend(light->image, dark->image, mask->image);
|
||||
return light;
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
SCRIPT_RETURN(
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(light) &&
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(dark) &&
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(mask)
|
||||
);
|
||||
}
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(combine_blend) {
|
||||
SCRIPT_PARAM(String, combine);
|
||||
SCRIPT_PARAM(ScriptImageP, image1);
|
||||
SCRIPT_PARAM(ScriptImageP, image2);
|
||||
if (!parse_enum(combine, image1->combine)) {
|
||||
throw ScriptError(_("Not a valid combine mode: '") + combine + _("'"));
|
||||
}
|
||||
combine_image(image1->image, image2->image, image1->combine);
|
||||
return image1;
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
SCRIPT_RETURN(
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image1) &&
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image2)
|
||||
);
|
||||
}
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(set_mask) {
|
||||
SCRIPT_PARAM(ScriptImageP, image);
|
||||
SCRIPT_PARAM(ScriptImageP, mask);
|
||||
set_alpha(image->image, mask->image);
|
||||
return image;
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
SCRIPT_RETURN(
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image) &&
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(mask)
|
||||
);
|
||||
}
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(set_combine) {
|
||||
SCRIPT_PARAM(String, combine);
|
||||
SCRIPT_PARAM(ScriptImageP, input);
|
||||
// parse and set combine
|
||||
if (!parse_enum(combine, input->combine)) {
|
||||
throw ScriptError(_("Not a valid combine mode: '") + combine + _("'"));
|
||||
}
|
||||
return input;
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
SCRIPT_RETURN(
|
||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(input)
|
||||
);
|
||||
}
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(symbol_variation) {
|
||||
SCRIPT_PARAM(ValueP, symbol);
|
||||
SymbolValueP value = dynamic_pointer_cast<SymbolValue>(symbol);
|
||||
SCRIPT_PARAM(String, variation);
|
||||
// find set & style
|
||||
SCRIPT_PARAM(Set*, set);
|
||||
SCRIPT_OPTIONAL_PARAM_(CardP, card);
|
||||
SymbolStyleP style = dynamic_pointer_cast<SymbolStyle>(set->stylesheetFor(card)->styleFor(value->fieldP));
|
||||
if (!style) throw InternalError(_("Symbol value has a style of the wrong type"));
|
||||
// load symbol
|
||||
SymbolP the_symbol;
|
||||
if (value->filename.empty()) {
|
||||
the_symbol = default_symbol();
|
||||
} else {
|
||||
the_symbol = set->readFile<SymbolP>(value->filename);
|
||||
}
|
||||
// determine filter & render
|
||||
FOR_EACH(v, style->variations) {
|
||||
if (v->name == variation) {
|
||||
// render & filter
|
||||
return new_intrusive1<ScriptImage>(render_symbol(the_symbol, *v->filter, v->border_radius));
|
||||
}
|
||||
}
|
||||
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
// SCRIPT_RETURN(last_update_age() >= value->filename.last_update_age);
|
||||
SCRIPT_RETURN(last_update_age() > 1); // the symbol was created/loaded after program start,
|
||||
// don't use cached images
|
||||
}
|
||||
|
||||
SCRIPT_IMAGE_FUNCTION(buildin_image) {
|
||||
SCRIPT_PARAM(String, input);
|
||||
Image img = load_resource_image(input);
|
||||
if (!img.Ok()) {
|
||||
throw ScriptError(_("There is no build in image '") + input + _("'"));
|
||||
}
|
||||
return new_intrusive1<ScriptImage>(img);
|
||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
||||
SCRIPT_RETURN(true); // always up to date
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Init
|
||||
|
||||
void init_script_image_functions(Context& ctx) {
|
||||
@@ -236,5 +104,5 @@ void init_script_image_functions(Context& ctx) {
|
||||
ctx.setVariable(_("set mask"), script_set_mask);
|
||||
ctx.setVariable(_("set combine"), script_set_combine);
|
||||
ctx.setVariable(_("symbol variation"), script_symbol_variation);
|
||||
ctx.setVariable(_("buildin image"), script_buildin_image);
|
||||
ctx.setVariable(_("built in image"), script_built_in_image);
|
||||
}
|
||||
|
||||
+50
-172
@@ -11,8 +11,7 @@
|
||||
#include <script/to_value.hpp>
|
||||
#include <util/dynamic_arg.hpp>
|
||||
#include <util/io/package.hpp>
|
||||
|
||||
IMPLEMENT_DYNAMIC_ARG(Package*, load_images_from, nullptr);
|
||||
#include <gfx/generated_image.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- : Utility
|
||||
|
||||
@@ -27,167 +26,76 @@ GeneratedImageP image_from_script(const ScriptValueP& value) {
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : ScriptableImage2
|
||||
// ----------------------------------------------------------------------------- : ScriptableImage
|
||||
|
||||
Image ScriptableImage2::generate(const GeneratedImage::Options& options, bool cache) const {
|
||||
if (!isReady()) {
|
||||
Image ScriptableImage::generate(const GeneratedImage::Options& options, bool cache) const {
|
||||
if (cached.Ok() && cached.GetWidth() == options.width && cached.GetHeight() == options.height) {
|
||||
// cached, so we are done
|
||||
return cached;
|
||||
}
|
||||
// generate
|
||||
Image image;
|
||||
if (isReady()) {
|
||||
image = value->generate(options);
|
||||
} else {
|
||||
// error, return blank image
|
||||
Image i(1,1);
|
||||
i.InitAlpha();
|
||||
i.SetAlpha(0,0,0);
|
||||
return i;
|
||||
image = i;
|
||||
}
|
||||
if (cached.Ok() && cached.GetWidth() == options.width && cached.GetHeight() == options.height) {
|
||||
return cached;
|
||||
// resize?
|
||||
int iw = image.GetWidth(), ih = image.GetHeight();
|
||||
if ((iw == options.width && ih == options.height) || options.width == 0 || options.height == 0) {
|
||||
// already the right size
|
||||
} else if (options.preserve_aspect == ASPECT_FIT) {
|
||||
// determine actual size of resulting image
|
||||
int w, h;
|
||||
if (iw * options.height > ih * options.width) { // too much height requested
|
||||
w = options.width;
|
||||
h = options.width * ih / iw;
|
||||
} else {
|
||||
w = options.height * iw / ih;
|
||||
h = options.height;
|
||||
}
|
||||
Image resampled_image(w, h, false);
|
||||
resample(image, resampled_image);
|
||||
image = resampled_image;
|
||||
} else {
|
||||
Image resampled_image(options.width, options.height, false);
|
||||
if (options.preserve_aspect == ASPECT_BORDER && (options.width < options.height * 3) && (options.height < options.width * 3)) {
|
||||
// preserve the aspect ratio if there is not too much difference
|
||||
resample_preserve_aspect(image, resampled_image);
|
||||
} else {
|
||||
resample(image, resampled_image);
|
||||
}
|
||||
image = resampled_image;
|
||||
}
|
||||
Image img = value->generate(options);
|
||||
if (cache) cached = img;
|
||||
return img;
|
||||
if (options.saturate) {
|
||||
saturate(image, 40);
|
||||
}
|
||||
// cache? and return
|
||||
if (cache) cached = image;
|
||||
return image;
|
||||
}
|
||||
|
||||
ImageCombine ScriptableImage2::combine() const {
|
||||
ImageCombine ScriptableImage::combine() const {
|
||||
if (!isReady()) return COMBINE_NORMAL;
|
||||
return value->combine();
|
||||
}
|
||||
|
||||
bool ScriptableImage2::update(Context& ctx) {
|
||||
bool ScriptableImage::update(Context& ctx) {
|
||||
if (!isScripted()) return false;
|
||||
GeneratedImageP new_value = image_from_script(script.invoke(ctx));
|
||||
if (!new_value || !value || *new_value != *value) {
|
||||
value = new_value;
|
||||
cached = Image();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : ScriptImage
|
||||
|
||||
ScriptType ScriptImage::type() const { return SCRIPT_IMAGE; }
|
||||
String ScriptImage::typeName() const { return _("image"); }
|
||||
|
||||
// ----------------------------------------------------------------------------- : Utility
|
||||
|
||||
/// Convert a script value to an image
|
||||
ScriptImageP to_script_image(const ScriptValueP& value) {
|
||||
if (ScriptImageP img = dynamic_pointer_cast<ScriptImage>(value)) {
|
||||
return img; // already an image
|
||||
} else if (value->type() == SCRIPT_STRING) {
|
||||
// open a file
|
||||
String filename = *value;
|
||||
Package* pkg = load_images_from();
|
||||
if (!pkg) throw ScriptError(_("Can only load images in a context where an image is expected"));
|
||||
InputStreamP file = pkg->openIn(filename);
|
||||
ScriptImageP img = new_intrusive<ScriptImage>();
|
||||
if (img->image.LoadFile(*file)) {
|
||||
if (img->image.HasMask()) img->image.InitAlpha(); // we can't handle masks
|
||||
return img;
|
||||
} else {
|
||||
throw ScriptError(_("Unable to load image '") + filename + _("' from '" + pkg->name() + _("'")));
|
||||
}
|
||||
} else if (value->type() == SCRIPT_NIL) {
|
||||
// error, return blank image
|
||||
Image i(1,1);
|
||||
i.InitAlpha();
|
||||
i.SetAlpha(0,0,0);
|
||||
return new_intrusive1<ScriptImage>(i);
|
||||
} else {
|
||||
throw ScriptError(_("Can not convert from '") + value->typeName() + _("' to image"));
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the given image up to date?
|
||||
bool script_image_up_to_date(const ScriptValueP& value) {
|
||||
if (value->type() == SCRIPT_INT) {
|
||||
return (bool)*value; // boolean up-to-dateness from parameter
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : ScriptableImage
|
||||
|
||||
ScriptableImage::ScriptableImage(const String& script_)
|
||||
: script(script_)
|
||||
{}
|
||||
|
||||
ScriptImageP ScriptableImage::generate(Context& ctx, Package& pkg) const {
|
||||
try {
|
||||
WITH_DYNAMIC_ARG(load_images_from, &pkg);
|
||||
ScriptImageP img = to_script_image(script.invoke(ctx));
|
||||
return img;
|
||||
} catch (Error e) {
|
||||
// loading images can fail
|
||||
// it is likely we are inside a paint function or outside the main thread, handle error later
|
||||
handle_error(e, false, false);
|
||||
return new_intrusive1<ScriptImage>(Image(1,1));
|
||||
}
|
||||
}
|
||||
|
||||
ScriptImageP ScriptableImage::generate(Context& ctx, Package& pkg, UInt width, UInt height, PreserveAspect preserve_aspect, bool saturate) const {
|
||||
ScriptImageP image = generate(ctx, pkg);
|
||||
if (!image->image.Ok()) {
|
||||
// return an image so we don't fail
|
||||
image->image = Image(1,1);
|
||||
}
|
||||
UInt iw = image->image.GetWidth(), ih = image->image.GetHeight();
|
||||
if ((iw == width && ih == height) || width == 0) {
|
||||
// already the right size
|
||||
} else if (preserve_aspect == ASPECT_FIT) {
|
||||
// determine actual size of resulting image
|
||||
UInt w, h;
|
||||
if (iw * height > ih * width) { // too much height requested
|
||||
w = width;
|
||||
h = width * ih / iw;
|
||||
} else {
|
||||
w = height * iw / ih;
|
||||
h = height;
|
||||
}
|
||||
Image resampled_image(w, h, false);
|
||||
resample(image->image, resampled_image);
|
||||
image->image = resampled_image;
|
||||
} else {
|
||||
Image resampled_image(width, height, false);
|
||||
if (preserve_aspect == ASPECT_BORDER && (width < height * 3) && (height < width * 3)) {
|
||||
// preserve the aspect ratio if there is not too much difference
|
||||
resample_preserve_aspect(image->image, resampled_image);
|
||||
} else {
|
||||
resample(image->image, resampled_image);
|
||||
}
|
||||
image->image = resampled_image;
|
||||
}
|
||||
if (saturate) {
|
||||
::saturate(image->image, 40);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
ScriptImageP ScriptableImage::update(Context& ctx, Package& pkg, UInt width, UInt height, PreserveAspect preserve_aspect, bool saturate) {
|
||||
// up to date?
|
||||
if (!cache || (UInt)cache->image.GetWidth() != width || (UInt)cache->image.GetHeight() != height || !upToDate(ctx, last_update)) {
|
||||
// cache must be updated
|
||||
cache = generate(ctx, pkg, width, height, preserve_aspect, saturate);
|
||||
last_update.update();
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
bool ScriptableImage::upToDate(Context& ctx, Age age) const {
|
||||
if (!script) return true;
|
||||
try {
|
||||
WITH_DYNAMIC_ARG(last_update_age, age.get());
|
||||
return script_image_up_to_date(script.invoke(ctx));
|
||||
} catch (Error e) {
|
||||
return true; // script gives errors, don't update
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reflection
|
||||
|
||||
// we need some custom io, because the behaviour is different for each of Reader/Writer/GetMember
|
||||
@@ -200,10 +108,8 @@ template <> void Reader::handle(ScriptableImage& s) {
|
||||
} else if (s.script.unparsed.find_first_of('{') != String::npos) {
|
||||
s.script.parse(*this, true);
|
||||
} else {
|
||||
// script is a constant function
|
||||
s.script.script = new_intrusive<Script>();
|
||||
s.script.script->addInstruction(I_PUSH_CONST, s.script.unparsed);
|
||||
s.script.script->addInstruction(I_RET);
|
||||
// a filename
|
||||
s.value = new_intrusive1<PackagedImage>(s.script.unparsed);
|
||||
}
|
||||
}
|
||||
template <> void Writer::handle(const ScriptableImage& s) {
|
||||
@@ -212,31 +118,3 @@ template <> void Writer::handle(const ScriptableImage& s) {
|
||||
template <> void GetDefaultMember::handle(const ScriptableImage& s) {
|
||||
handle(s.script.unparsed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reflection
|
||||
|
||||
// we need some custom io, because the behaviour is different for each of Reader/Writer/GetMember
|
||||
|
||||
template <> void Reader::handle(ScriptableImage2& s) {
|
||||
handle(s.script.unparsed);
|
||||
if (starts_with(s.script.unparsed, _("script:"))) {
|
||||
s.script.unparsed = s.script.unparsed.substr(7);
|
||||
s.script.parse(*this);
|
||||
} else if (s.script.unparsed.find_first_of('{') != String::npos) {
|
||||
s.script.parse(*this, true);
|
||||
} else {
|
||||
// script is a constant function
|
||||
s.script.script = new_intrusive<Script>();
|
||||
s.script.script->addInstruction(I_PUSH_CONST, s.script.unparsed);
|
||||
s.script.script->addInstruction(I_RET);
|
||||
}
|
||||
}
|
||||
template <> void Writer::handle(const ScriptableImage2& s) {
|
||||
handle(s.script.unparsed);
|
||||
}
|
||||
template <> void GetDefaultMember::handle(const ScriptableImage2& s) {
|
||||
handle(s.script.unparsed);
|
||||
}
|
||||
|
||||
+5
-85
@@ -13,13 +13,8 @@
|
||||
#include <util/age.hpp>
|
||||
#include <util/dynamic_arg.hpp>
|
||||
#include <script/scriptable.hpp>
|
||||
//%%#include <gfx/gfx.hpp>
|
||||
#include <gfx/generated_image.hpp>
|
||||
|
||||
class Package;
|
||||
DECLARE_INTRUSIVE_POINTER_TYPE(ScriptImage); //%% OLD
|
||||
DECLARE_INTRUSIVE_POINTER_TYPE(GeneratedImage); //%% OLD
|
||||
|
||||
// ----------------------------------------------------------------------------- : ScriptableImage
|
||||
|
||||
/// An image that can also be scripted
|
||||
@@ -28,10 +23,11 @@ DECLARE_INTRUSIVE_POINTER_TYPE(GeneratedImage); //%% OLD
|
||||
* - Age is checked, chached images are used if possible
|
||||
* - The image can be scaled
|
||||
*/
|
||||
class ScriptableImage2 {
|
||||
class ScriptableImage {
|
||||
public:
|
||||
inline ScriptableImage2() {}
|
||||
inline ScriptableImage2(const String& script) : script(script) {}
|
||||
inline ScriptableImage() {}
|
||||
inline ScriptableImage(const String& script) : script(script) {}
|
||||
inline ScriptableImage(const GeneratedImageP& gen) : value(gen) {}
|
||||
|
||||
/// Is there an image set?
|
||||
inline bool isScripted() const { return script; }
|
||||
@@ -59,86 +55,10 @@ class ScriptableImage2 {
|
||||
};
|
||||
|
||||
/// Missing for now
|
||||
inline ScriptValueP to_script(const ScriptableImage2&) { return script_nil; }
|
||||
inline ScriptValueP to_script(const ScriptableImage&) { return script_nil; }
|
||||
|
||||
/// Convert a script value to a GeneratedImageP
|
||||
GeneratedImageP image_from_script(const ScriptValueP& value);
|
||||
|
||||
// ----------------------------------------------------------------------------- : ScriptableImage
|
||||
//%% OLD
|
||||
|
||||
DECLARE_DYNAMIC_ARG(Package*, load_images_from);
|
||||
|
||||
/// An image, returned by a script function
|
||||
class ScriptImage : public ScriptValue {
|
||||
public:
|
||||
inline ScriptImage() : combine(COMBINE_NORMAL) {}
|
||||
inline ScriptImage(const Image& image, ImageCombine combine = COMBINE_NORMAL)
|
||||
: image(image), combine(combine)
|
||||
{}
|
||||
|
||||
Image image; ///< The image
|
||||
ImageCombine combine; ///< How to combine the image with the background
|
||||
|
||||
virtual ScriptType type() const;
|
||||
virtual String typeName() const;
|
||||
};
|
||||
|
||||
|
||||
/// An image that can also be scripted
|
||||
/** Differs from Scriptable<Image> in that:
|
||||
* - A script is always used
|
||||
* - Age is checked, chached images are used if possible
|
||||
* - The image can be scaled
|
||||
*/
|
||||
class ScriptableImage {
|
||||
public:
|
||||
inline ScriptableImage() {}
|
||||
ScriptableImage(const String& script);
|
||||
|
||||
/// Is there an image set?
|
||||
inline operator bool() const { return script; }
|
||||
|
||||
/// Generate an image, doesn't cache, and doesn't scale
|
||||
/** Image files are loaded from the given package.
|
||||
* The result is always valid. */
|
||||
ScriptImageP generate(Context& ctx, Package&) const;
|
||||
/// Generate an image, scaling it and optionally saturating it
|
||||
ScriptImageP generate(Context& ctx, Package&, UInt width, UInt height, PreserveAspect preserve_aspect = ASPECT_STRETCH, bool saturate = false) const;
|
||||
|
||||
/// Update and return the cached image
|
||||
/** Only recomputes the image if it is out of date, or the size doesn't match.
|
||||
* If width==height==0 then doesn't resample.
|
||||
*/
|
||||
ScriptImageP update(Context& ctx, Package&, UInt width = 0, UInt height = 0, PreserveAspect preserve_aspect = ASPECT_STRETCH, bool saturate = false);
|
||||
|
||||
/// Is the cached image up to date?
|
||||
bool upToDate(Context& ctx, Age age) const;
|
||||
|
||||
inline void initDependencies(Context& ctx, const Dependency& dep) const {
|
||||
script.initDependencies(ctx, dep);
|
||||
}
|
||||
/// Invalidate the cached image
|
||||
inline void invalidate() {
|
||||
cache = ScriptImageP();
|
||||
}
|
||||
|
||||
private:
|
||||
OptionalScript script; ///< The script, not really optional
|
||||
ScriptImageP cache; ///< The cached image
|
||||
Age last_update; ///< Age of last image update of the cached image
|
||||
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
/// Missing for now
|
||||
inline ScriptValueP to_script(const ScriptableImage&) { return script_nil; }
|
||||
|
||||
/// Convert a script value to an image
|
||||
ScriptImageP to_script_image(const ScriptValueP& value);
|
||||
|
||||
/// Is the given image up to date?
|
||||
bool script_image_up_to_date(const ScriptValueP& value);
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
|
||||
@@ -75,7 +75,7 @@ Context& SetScriptContext::getContext(const CardP& card) {
|
||||
if (card) {
|
||||
ctx.setVariable(_("card"), to_script(card));
|
||||
} else {
|
||||
ctx.setVariable(_("card"), script_nil);
|
||||
ctx.setVariable(_("card"), ScriptValueP());
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
@@ -190,8 +190,9 @@ void SetScriptManager::updateStyles(const CardP& card) {
|
||||
// update all styles
|
||||
FOR_EACH(s, stylesheet->card_style) {
|
||||
if (s->update(ctx)) {
|
||||
s->tellListeners();
|
||||
// style has changed, tell listeners
|
||||
// ScriptStyleEvent change(s.get());
|
||||
//%% ScriptStyleEvent change(stylesheet.get(), s.get());
|
||||
// set->actions.tellListeners(change);
|
||||
}
|
||||
}
|
||||
@@ -298,7 +299,7 @@ void SetScriptManager::alsoUpdate(deque<ToUpdate>& to_update, const vector<Depen
|
||||
// because the index is not exact enough, it only gives the field
|
||||
StyleSheet* stylesheet = reinterpret_cast<StyleSheet*>(d.data);
|
||||
StyleP style = stylesheet->card_style.at(d.index);
|
||||
style->invalidate();
|
||||
style->invalidate(getContext(card));
|
||||
// something changed, send event
|
||||
ScriptStyleEvent change(stylesheet, style.get());
|
||||
set.actions.tellListeners(change, false);
|
||||
|
||||
Reference in New Issue
Block a user