File indexing completed on 2024-05-19 04:25:09
0001 /* 0002 * SPDX-FileCopyrightText: 2023 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 #ifndef KISLAGER_H 0007 #define KISLAGER_H 0008 0009 #include <QtGlobal> 0010 #include <type_traits> 0011 #include "KisMpl.h" 0012 0013 #include <lager/lenses.hpp> 0014 #include <lager/reader.hpp> 0015 0016 0017 namespace kislager { 0018 0019 /** 0020 * Fold all valid optional cursors from a set into one by using \p func 0021 * 0022 * Example: 0023 * 0024 * std::optional<lager::reader<int>> brushSize1 = ...; 0025 * std::optional<lager::reader<int>> brushSize2 = ...; 0026 * 0027 * std::optional<lager::reader<int>> maxSize = 0028 * fold_optional_cursors(&std::max, brushSize1, brushSize2); 0029 * 0030 * The resulting reader 'maxSize' will hold the maximum value of the two 0031 * brushes, or nothing if the source readers do not exist. 0032 */ 0033 template <typename Func, typename... Cursors, 0034 typename FirstCursor = typename kismpl::first_type_t<std::remove_reference_t<Cursors>...>::value_type, 0035 typename T = typename FirstCursor::value_type> 0036 std::optional<lager::reader<T>> fold_optional_cursors(const Func &func, Cursors&& ...cursors) { 0037 auto fold_func = [func] (const auto &lhs, const auto &rhs) { 0038 return lager::with(lhs, rhs).map(func); 0039 }; 0040 0041 return kismpl::fold_optional(fold_func, cursors...); 0042 } 0043 0044 namespace lenses { 0045 template <typename T> 0046 auto scale = [] (T multiplier) { 0047 return lager::lenses::getset( 0048 [multiplier] (T value) { return value * multiplier; }, 0049 [multiplier] (T, T value) { return value / multiplier; } 0050 ); 0051 }; 0052 0053 constexpr auto scale_int_to_real = [] (qreal multiplier) { 0054 return lager::lenses::getset( 0055 [multiplier] (int value) { return value * multiplier; }, 0056 [multiplier] (int, qreal value) { return qRound(value / multiplier); } 0057 ); 0058 }; 0059 0060 constexpr auto scale_real_to_int = [] (qreal multiplier) { 0061 return lager::lenses::getset( 0062 [multiplier] (qreal value) { return qRound(value * multiplier); }, 0063 [multiplier] (qreal, int value) { return value / multiplier; } 0064 ); 0065 }; 0066 0067 template <typename Src, typename Dst> 0068 auto do_static_cast = lager::lenses::getset( 0069 [] (Src value) { return static_cast<Dst>(value); }, 0070 [] (Src, Dst value) { return static_cast<Src>(value); } 0071 ); 0072 0073 /** 0074 * A lens that accesses a base class \p Base of the derived 0075 * type \p Derived 0076 * 0077 * to_base2 variant accepts two types, Base and Derived, 0078 * which might be convenient for debugging. 0079 */ 0080 template <typename Derived, typename Base, 0081 typename = std::enable_if_t< 0082 std::is_base_of_v<Base, Derived>>> 0083 auto to_base2 = lager::lenses::getset( 0084 [] (const Derived &value) -> Base { return static_cast<const Base&>(value); }, 0085 [] (Derived src, const Base &value) { static_cast<Base&>(src) = value; return src; } 0086 ); 0087 0088 /** 0089 * A lens that accesses a base class \p Base of the derived 0090 * type \p Derived 0091 * 0092 * to_base variant accepts only one type \p Base, that is, 0093 * destination type into which we should convert the value 0094 * to 0095 */ 0096 template <typename Base> 0097 auto to_base = lager::lenses::getset( 0098 [] (const auto &value) -> Base { return static_cast<const Base&>(value); }, 0099 [] (auto src, const Base &value) { static_cast<Base&>(src) = value; return src; } 0100 ); 0101 0102 } // namespace lenses 0103 0104 } // namespace kislager 0105 0106 0107 #endif // KISLAGER_H