<commit_before>//
//  yas_ui_blur.mm
//

#include "yas_ui_blur.h"
#include "yas_ui_effect.h"
#include "yas_property.h"
#include "yas_ui_texture.h"
#include "yas_ui_metal_texture.h"
#include <MetalPerformanceShaders/MetalPerformanceShaders.h>

#include <iostream>

using namespace yas;

struct ui::blur::impl : base::impl {
    void prepare(ui::blur &blur) {
        auto weak_blur = to_weak(blur);

        this->_observers.emplace_back(this->_sigma_property.subject().make_observer(
            property_method::did_change, [weak_blur](auto const &context) {
                if (auto blur = weak_blur.lock()) {
                    blur.impl_ptr<impl>()->_update_effect_handler();
                }
            }));

        this->_update_effect_handler();
    }

    property<double> _sigma_property{{.value = 0.0}};
    ui::effect _effect;

   private:
    void _update_effect_handler() {
        double const sigma = this->_sigma_property.value();

        if (sigma > 0.0) {
            this->_effect.set_metal_handler([
                sigma, prev_scale_factor = std::experimental::optional<double>{nullopt},
                blur = objc_ptr<MPSImageGaussianBlur *>{nullptr}
            ](ui::texture & src_texture, ui::texture & dst_texture, ui::metal_system & metal_system,
              id<MTLCommandBuffer> const commandBuffer) mutable {
                double const scale_factor = src_texture.scale_factor();

                if (!prev_scale_factor || scale_factor != *prev_scale_factor) {
                    prev_scale_factor = scale_factor;
                    double const blur_sigma = sigma * scale_factor;
                    blur = metal_system.makable().make_mtl_blur(blur_sigma);
                }

                auto const srcTexture = src_texture.metal_texture().texture();
                auto const dstTexture = dst_texture.metal_texture().texture();
                [*blur encodeToCommandBuffer:commandBuffer sourceTexture:srcTexture destinationTexture:dstTexture];
            });
        } else {
            this->_effect.set_metal_handler(ui::effect::through_metal_handler());
        }
    }

    std::vector<base> _observers;
};

ui::blur::blur() : base(std::make_shared<impl>()) {
    impl_ptr<impl>()->prepare(*this);
}

ui::blur::blur(std::nullptr_t) : base(nullptr) {
}

void ui::blur::set_sigma(double const sigma) {
    impl_ptr<impl>()->_sigma_property.set_value(sigma);
}

double ui::blur::sigma() const {
    return impl_ptr<impl>()->_sigma_property.value();<commit_msg>blur flow<commit_after>//
//  yas_ui_blur.mm
//

#include "yas_ui_blur.h"
#include "yas_ui_effect.h"
#include "yas_property.h"
#include "yas_ui_texture.h"
#include "yas_ui_metal_texture.h"
#include <MetalPerformanceShaders/MetalPerformanceShaders.h>

using namespace yas;

struct ui::blur::impl : base::impl {
    property<double> _sigma_property{{.value = 0.0}};
    ui::effect _effect;

    void prepare(ui::blur &blur) {
        auto weak_blur = to_weak(blur);

        this->_sigma_flow =
            this->_sigma_property.begin_value_flow()
                .guard([weak_blur](double const &) { return !!weak_blur; })
                .perform([weak_blur](double const &) { weak_blur.lock().impl_ptr<impl>()->_update_effect_handler(); })
                .sync();
    }

   private:
    flow::observer<double> _sigma_flow = nullptr;

    void _update_effect_handler() {
        double const sigma = this->_sigma_property.value();

        if (sigma > 0.0) {
            this->_effect.set_metal_handler([
                sigma, prev_scale_factor = std::experimental::optional<double>{nullopt},
                blur = objc_ptr<MPSImageGaussianBlur *>{nullptr}
            ](ui::texture & src_texture, ui::texture & dst_texture, ui::metal_system & metal_system,
              id<MTLCommandBuffer> const commandBuffer) mutable {
                double const scale_factor = src_texture.scale_factor();

                if (!prev_scale_factor || scale_factor != *prev_scale_factor) {
                    prev_scale_factor = scale_factor;
                    double const blur_sigma = sigma * scale_factor;
                    blur = metal_system.makable().make_mtl_blur(blur_sigma);
                }

                auto const srcTexture = src_texture.metal_texture().texture();
                auto const dstTexture = dst_texture.metal_texture().texture();
                [*blur encodeToCommandBuffer:commandBuffer sourceTexture:srcTexture destinationTexture:dstTexture];
            });
        } else {
            this->_effect.set_metal_handler(ui::effect::through_metal_handler());
        }
    }
};

ui::blur::blur() : base(std::make_shared<impl>()) {
    impl_ptr<impl>()->prepare(*this);
}

ui::blur::blur(std::nullptr_t) : base(nullptr) {
}

void ui::blur::set_sigma(double const sigma) {
    impl_ptr<impl>()->_sigma_property.set_value(sigma);
}

double ui::blur::sigma() const {
    return impl_ptr<impl>()->_sigma_property.value();
{'fraction_non_alphanumeric': 0.13140896245458217, 'fraction_numerical': 0.0016148566814695195, 'mean_word_length': 2.8620420888542477, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '65249', 'n_tokens_mistral': 1587, 'n_tokens_neox': 1471, 'n_words': 236}