diff --git a/src/gfx/combine_image.cpp b/src/gfx/combine_image.cpp index 119f84ff..e347d3ef 100644 --- a/src/gfx/combine_image.cpp +++ b/src/gfx/combine_image.cpp @@ -108,7 +108,7 @@ void combine_image(Image& a, const Image& b, ImageCombine combine) { // Combine image data, by dispatching to combineImageDo switch(combine) { #define DISPATCH(comb) case comb: combine_image_do(a,b); return - DISPATCH(COMBINE_NORMAL); + case COMBINE_NORMAL: a = b; return; // no need to do a per pixel operation DISPATCH(COMBINE_ADD); DISPATCH(COMBINE_SUBTRACT); DISPATCH(COMBINE_STAMP); @@ -135,5 +135,18 @@ void combine_image(Image& a, const Image& b, ImageCombine combine) { } void draw_combine_image(DC& dc, UInt x, UInt y, const Image& img, ImageCombine combine) { - // todo -} \ No newline at end of file + if (combine == COMBINE_NORMAL) { + dc.DrawBitmap(img, x, y); + } else { + // Capture the current image in the target rectangle + Bitmap sourceB(img.GetWidth(), img.GetHeight()); + wxMemoryDC sourceDC; + sourceDC.SelectObject(sourceB); + sourceDC.Blit(0, 0, img.GetWidth(), img.GetHeight(), &dc, x, y); + sourceDC.SelectObject(wxNullBitmap); + Image source = sourceB.ConvertToImage(); + // Combine and draw + combine_image(source, img, combine); + dc.DrawBitmap(source, x, y); + } +} diff --git a/src/mse.vcproj b/src/mse.vcproj index 96652ac7..31a9f6cc 100644 --- a/src/mse.vcproj +++ b/src/mse.vcproj @@ -178,7 +178,7 @@ Name="VCCustomBuildTool"/> #include +#include // ----------------------------------------------------------------------------- : ChoiceValueViewer @@ -22,12 +23,12 @@ void ChoiceValueViewer::draw(RotatedDC& dc) { ScriptableImage& img = it->second; ScriptImageP i; if (nativeLook()) { - i = img.update(viewer.getContext(), 16, 16, ASPECT_BORDER, false); + i = img.update(viewer.getContext(), *getSet().stylesheet, 16, 16, ASPECT_BORDER, false); } else if(style().render_style & RENDER_TEXT) { // also drawing text - i = img.update(viewer.getContext(), 0, 0); + i = img.update(viewer.getContext(), *getSet().stylesheet, 0, 0); } else { - i = img.update(viewer.getContext(), + i = img.update(viewer.getContext(), *getSet().stylesheet, dc.trS(style().width), dc.trS(style().height), style().alignment == ALIGN_STRETCH ? ASPECT_STRETCH : ASPECT_FIT ); diff --git a/src/script/functions.cpp b/src/script/functions.cpp index 6e208f8e..e6d645e1 100644 --- a/src/script/functions.cpp +++ b/src/script/functions.cpp @@ -24,7 +24,44 @@ class ScriptReplaceRule : public ScriptValue { virtual ScriptType type() const { return SCRIPT_FUNCTION; } virtual String typeName() const { return _("replace_rule"); } virtual ScriptValueP eval(Context& ctx) const { - throw "TODO"; + SCRIPT_PARAM(String, input); + if (context.IsValid() || replacement_function) { + // match first, then check context of match + String ret; + while (regex.Matches(input)) { + // for each match ... + size_t start, len; + bool ok = regex.GetMatch(&start, &len, 0); + assert(ok); + ret += input.substr(0, start); // everything before the match position stays + String inside = input.substr(start, len); // inside the match + String next_input = input.substr(start + len); // next loop the input is after this match + String after_replace = ret + _("") + next_input; // after replacing, the resulting context would be + if (!context.IsValid() || context.Matches(after_replace)) { + // the context matches -> perform replacement + if (replacement_function) { + // set match results in context + for (UInt m = 0 ; m < regex.GetMatchCount() ; ++m) { + regex.GetMatch(&start, &len, m); + String name = m == 0 ? _("input") : String(_("_")) << m; + String value = input.substr(start, len); + ctx.setVariable(name, toScript(value)); + } + // call + inside = (String)*replacement_function->eval(ctx); + } else { + regex.Replace(&inside, replacement, 1); // replace inside + } + } + ret += inside; + input = next_input; + } + SCRIPT_RETURN(ret); + } else { + // dumb replacing + regex.Replace(&input, replacement); + SCRIPT_RETURN(input); + } } wxRegEx regex; ///< Regex to match @@ -59,6 +96,38 @@ SCRIPT_FUNCTION(replace_rule) { // ----------------------------------------------------------------------------- : Rules : regex filter +class ScriptFilterRule : public ScriptValue { + public: + virtual ScriptType type() const { return SCRIPT_FUNCTION; } + virtual String typeName() const { return _("replace_rule"); } + virtual ScriptValueP eval(Context& ctx) const { + SCRIPT_PARAM(String, input); + String ret; + while (regex.Matches(input)) { + // match, append to result + size_t start, len; + bool ok = regex.GetMatch(&start, &len, 0); + assert(ok); + ret += input.substr(start, len); // the match + input = input.substr(start + len); // everything after the match + } + SCRIPT_RETURN(ret); + } + + wxRegEx regex; ///< Regex to match +}; + +// Create a regular expression rule for filtering strings +SCRIPT_FUNCTION(filter_rule) { + intrusive_ptr ret(new ScriptFilterRule); + // match + SCRIPT_PARAM(String, match); + if (!ret->regex.Compile(match, wxRE_ADVANCED)) { + throw ScriptError(_("Error while compiling regular expression: '")+match+_("'")); + } + return ret; +} + // ----------------------------------------------------------------------------- : Rules : sort /// Sort a string using a specification using the shortest cycle metric, see spec_sort @@ -247,6 +316,7 @@ SCRIPT_FUNCTION(number_of_items) { void init_script_functions(Context& ctx) { ctx.setVariable(_("replace rule"), script_replace_rule); + ctx.setVariable(_("filter rule"), script_filter_rule); ctx.setVariable(_("sort rule"), script_sort_rule); ctx.setVariable(_("to upper"), script_to_upper); ctx.setVariable(_("to lower"), script_to_lower); diff --git a/src/script/image.cpp b/src/script/image.cpp index dbb05805..09485b35 100644 --- a/src/script/image.cpp +++ b/src/script/image.cpp @@ -59,8 +59,9 @@ bool script_image_up_to_date(const ScriptValueP& value) { // ----------------------------------------------------------------------------- : ScriptableImage -ScriptImageP ScriptableImage::generate(Context& ctx) const { +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) { @@ -71,8 +72,8 @@ ScriptImageP ScriptableImage::generate(Context& ctx) const { } } -ScriptImageP ScriptableImage::generate(Context& ctx, UInt width, UInt height, PreserveAspect preserve_aspect, bool saturate) const { - ScriptImageP image = generate(ctx); +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); @@ -109,11 +110,11 @@ ScriptImageP ScriptableImage::generate(Context& ctx, UInt width, UInt height, Pr return image; } -ScriptImageP ScriptableImage::update(Context& ctx, UInt width, UInt height, PreserveAspect preserve_aspect, bool saturate) { +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, width, height, preserve_aspect, saturate); + cache = generate(ctx, pkg, width, height, preserve_aspect, saturate); last_update.update(); } return cache; diff --git a/src/script/image.hpp b/src/script/image.hpp index cd636466..5ed11b42 100644 --- a/src/script/image.hpp +++ b/src/script/image.hpp @@ -50,15 +50,16 @@ class ScriptableImage { inline operator bool() const { return script; } /// Generate an image, doesn't cache, and doesn't scale - ScriptImageP generate(Context& ctx) const; + /** Image files are loaded from the given package */ + ScriptImageP generate(Context& ctx, Package&) const; /// Generate an image, scaling it and optionally saturating it - ScriptImageP generate(Context& ctx, UInt width, UInt height, PreserveAspect preserve_aspect = ASPECT_STRETCH, bool saturate = false) const; + 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, UInt width = 0, UInt height = 0, PreserveAspect preserve_aspect = ASPECT_STRETCH, bool saturate = false); + 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; diff --git a/src/script/value.cpp b/src/script/value.cpp index 95a892d2..df51a441 100644 --- a/src/script/value.cpp +++ b/src/script/value.cpp @@ -20,7 +20,7 @@ ScriptValue::operator Color() const { throw ScriptError(_("Can't convert from " ScriptValueP ScriptValue::eval(Context&) const { throw ScriptError(_("Can't convert from ")+typeName()+_(" to function" )); } ScriptValueP ScriptValue::getMember(const String& name) const - { throw (typeName() + _(" has no member '") + name + _("'")); } + { throw ScriptError(typeName() + _(" has no member '") + name + _("'")); } ScriptValueP ScriptValue::next() { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); } ScriptValueP ScriptValue::makeIterator() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to collection")); } int ScriptValue::itemCount() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to collection")); }