File indexing completed on 2024-05-26 04:34:13

0001 /*
0002  *  SPDX-FileCopyrightText: 2022 Agata Cacko <cacko.azh@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #include "KisSprayShapeOptionModel.h"
0007 
0008 #include <KisLager.h>
0009 #include <klocalizedstring.h>
0010 
0011 namespace {
0012 
0013 auto makeSizePack = lager::lenses::getset(
0014     /**
0015      * In SizePack we use a two-stage approach in calculation of the
0016      * particles size. First we unpack the size into a special structure
0017      * that stores both, pixel and proportional sizes of the particles.
0018      * This way we are able to toggle the `proportional` switch without
0019      * invalidating existing value.
0020      *
0021      * Please note that  we connect to `KisSprayShapeOptionData` as a whole
0022      * instead of its members to avoid partial updates when we change the
0023      * `proportional` value.
0024      *
0025      * Theoretically, we could use only one stage, but that would make the
0026      * code a bit more complicated.
0027      *
0028      */
0029     [](const std::tuple<KisSprayShapeOptionData, int, qreal> &value) -> SprayShapeSizePack {
0030         auto [optionData, diameter, scale] = value;
0031 
0032         SprayShapeSizePack pack;
0033         pack.isProportional = optionData.proportional;
0034 
0035         if (optionData.proportional) {
0036             pack.pxSize = optionData.size * qreal(diameter) * scale / 100.0;
0037             pack.proportionalSize = optionData.size;
0038         } else {
0039             pack.pxSize = optionData.size;
0040             pack.proportionalSize = optionData.size * 100.0 / (qreal(diameter) * scale);
0041         }
0042         pack.diameter = diameter;
0043         pack.scale = scale;
0044 
0045         return pack;
0046     },
0047     [] (std::tuple<KisSprayShapeOptionData, int, qreal> value, const SprayShapeSizePack &pack) -> std::tuple<KisSprayShapeOptionData, int, qreal> {
0048         auto [optionData, diameter, scale] = value;
0049 
0050         optionData.size = pack.isProportional ? pack.proportionalSize : pack.pxSize;
0051         optionData.proportional = pack.isProportional;
0052 
0053         return std::make_tuple(optionData,
0054                                diameter,
0055                                scale);
0056     }
0057     );
0058 
0059 auto calcEffectiveSize = lager::lenses::getset(
0060     [](const SprayShapeSizePack &pack) -> QSize {
0061         return pack.isProportional ? pack.proportionalSize : pack.pxSize;
0062     },
0063     [] (SprayShapeSizePack pack, const QSize &size) -> SprayShapeSizePack {
0064         if (pack.isProportional) {
0065             pack.proportionalSize = size;
0066             pack.pxSize = size * pack.diameter * pack.scale / 100.0;
0067         } else {
0068             pack.proportionalSize = size * 100.0 / (pack.diameter * pack.scale);
0069             pack.pxSize = size;
0070         }
0071         return pack;
0072     }
0073     );
0074 }
0075 
0076 KisSprayShapeOptionModel::KisSprayShapeOptionModel(lager::cursor<KisSprayShapeOptionData> _optionData, lager::cursor<int> diameter, lager::cursor<qreal> scale)
0077     : optionData(_optionData)
0078     , sizePack {lager::with(
0079                    _optionData,
0080                    diameter,
0081                    scale
0082                    ).zoom(makeSizePack)}
0083     , LAGER_QT(shape) {_optionData[&KisSprayShapeOptionData::shape].zoom(kislager::lenses::do_static_cast<quint8, int>)}
0084     , LAGER_QT(effectiveSize) {sizePack.zoom(calcEffectiveSize)}
0085     , LAGER_QT(effectiveProportional) {sizePack[&SprayShapeSizePack::isProportional]}
0086     , LAGER_QT(enabled) {_optionData[&KisSprayShapeOptionData::enabled]}
0087     , LAGER_QT(imageUrl) {_optionData[&KisSprayShapeOptionData::imageUrl]}
0088     , LAGER_QT(sizeSuffix) { sizePack[&SprayShapeSizePack::isProportional].map([] (bool isProportional) { return isProportional ? i18n("%") : i18n(" px"); } ) }
0089 {
0090 }