File indexing completed on 2024-06-16 04:17:21

0001 /*
0002  * SPDX-FileCopyrightText: 2009, 2010 Lukáš Tvrdý (lukast.dev@gmail.com)
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include <KisPaintingModeOptionData.h>
0008 
0009 #include "kis_grid_paintop_settings.h"
0010 #include "kis_grid_paintop_settings_widget.h"
0011 
0012 #include "KisGridShapeOptionData.h"
0013 #include "KisGridOpOptionData.h"
0014 
0015 #include <KisColorOptionData.h>
0016 #include <KisOptimizedBrushOutline.h>
0017 
0018 struct KisGridPaintOpSettings::Private
0019 {
0020     QList<KisUniformPaintOpPropertyWSP> uniformProperties;
0021 };
0022 
0023 KisGridPaintOpSettings::KisGridPaintOpSettings(KisResourcesInterfaceSP resourcesInterface)
0024     : KisOutlineGenerationPolicy<KisPaintOpSettings>(KisCurrentOutlineFetcher::NO_OPTION,
0025                                                      resourcesInterface),
0026     m_d(new Private),
0027     m_modifyOffsetWithShortcut(false)
0028 {
0029 }
0030 
0031 void KisGridPaintOpSettings::setPaintOpSize(qreal value)
0032 {
0033     KisGridOpOptionData option;
0034     option.read(this);
0035     option.diameter = value;
0036     option.write(this);
0037 }
0038 
0039 qreal KisGridPaintOpSettings::paintOpSize() const
0040 {
0041     KisGridOpOptionData option;
0042     option.read(this);
0043     return option.diameter;
0044 }
0045 
0046 void KisGridPaintOpSettings::setPaintOpAngle(qreal value)
0047 {
0048     Q_UNUSED(value);
0049 }
0050 
0051 qreal KisGridPaintOpSettings::paintOpAngle() const
0052 {
0053     return 0.0;
0054 }
0055 
0056 KisGridPaintOpSettings::~KisGridPaintOpSettings()
0057 {
0058 }
0059 
0060 bool KisGridPaintOpSettings::paintIncremental()
0061 {
0062     KisPaintingModeOptionData data;
0063     data.read(this);
0064     return data.paintingMode == enumPaintingMode::BUILDUP;
0065 }
0066 
0067 bool KisGridPaintOpSettings::mousePressEvent(const KisPaintInformation& info, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode)
0068 {
0069     Q_UNUSED(currentNode);
0070 
0071     KisGridOpOptionData option;
0072     option.read(this);
0073     bool eventIgnored = true;
0074     qreal newHorizontalOffset = std::fmod(info.pos().x() + option.grid_width/2.0, (float)option.grid_width);
0075     qreal newVerticalOffset = std::fmod(info.pos().y() + option.grid_height/2.0, (float)option.grid_height);
0076 
0077     // If pressing ctrl+alt change the offset according to mouse position
0078     if (modifiers == (Qt::ControlModifier | Qt::AltModifier) || m_modifyOffsetWithShortcut) {
0079         m_modifyOffsetWithShortcut = true;
0080         newHorizontalOffset = (newHorizontalOffset / (float)option.grid_width);
0081         newVerticalOffset = (newVerticalOffset / (float)option.grid_height);
0082 
0083         if (newHorizontalOffset > 0.5) {
0084             newHorizontalOffset = newHorizontalOffset - 1;
0085         }
0086         if (newVerticalOffset > 0.5) {
0087             newVerticalOffset = newVerticalOffset -1;
0088         }
0089         option.horizontal_offset = newHorizontalOffset * option.grid_width;
0090         option.vertical_offset = newVerticalOffset * option.grid_height;
0091         option.write(this);
0092         eventIgnored = false;
0093     }
0094     return eventIgnored;
0095 }
0096 
0097 bool KisGridPaintOpSettings::mouseReleaseEvent()
0098 {
0099     m_modifyOffsetWithShortcut = false;
0100     bool ignoreEvent = true;
0101     return ignoreEvent;
0102 }
0103 KisOptimizedBrushOutline KisGridPaintOpSettings::brushOutline(const KisPaintInformation &info, const OutlineMode &mode, qreal alignForZoom)
0104 {
0105     KisOptimizedBrushOutline path;
0106     KisGridOpOptionData option;
0107     option.read(this);
0108     KisGridShapeOptionData shapeOption;
0109     shapeOption.read(this);
0110     if (mode.isVisible) {
0111         qreal sizex = option.diameter * option.grid_scale;
0112         qreal sizey = option.diameter * option.grid_scale;
0113         QRectF rc(0, 0, sizex, sizey);
0114         rc.translate(-rc.center());
0115         path.addRect(rc);
0116 
0117         path = outlineFetcher()->fetchOutline(info, this, path, mode, alignForZoom);
0118 
0119         if (mode.showTiltDecoration) {
0120             QPainterPath tiltLine = makeTiltIndicator(info, QPointF(0.0, 0.0), sizex * 0.5, 3.0);
0121             path.addPath(outlineFetcher()->fetchOutline(info, this, tiltLine, mode, alignForZoom, 1.0, 0.0, true, 0, 0));
0122         }
0123     }
0124     else if (m_modifyOffsetWithShortcut) {
0125         qreal gridWidth = option.diameter * option.grid_scale ;
0126         qreal gridHeight = option.diameter * option.grid_scale ;
0127 
0128         qreal cellWidth = option.grid_width * option.grid_scale ;
0129         qreal cellHeight = option.grid_height * option.grid_scale;
0130 
0131         qreal horizontalOffset = option.horizontal_offset;
0132         qreal verticalOffset = option.vertical_offset;
0133 
0134         int divide;
0135         if (option.grid_pressure_division) {
0136             divide = option.grid_division_level * info.pressure();
0137         }
0138         else {
0139             divide = option.grid_division_level;
0140         }
0141 
0142         divide = qRound(option.grid_scale * divide);
0143 
0144         //Adjust the start position of the drawn grid to the top left of the brush instead of in the center
0145         qreal posX = info.pos().x() - (gridWidth/2) + (cellWidth/2) - horizontalOffset;
0146         qreal posY = info.pos().y() - (gridHeight/2) + (cellHeight/2) - verticalOffset;
0147 
0148         //Lock the grid alignment
0149         posX = posX - std::fmod(posX, cellWidth) + horizontalOffset;
0150         posY = posY - std::fmod(posY, cellHeight) + verticalOffset;
0151         const QRectF dabRect(posX , posY , cellWidth, cellHeight);
0152 
0153         divide = qMax(1, divide);
0154         const qreal yStep = cellHeight / (qreal)divide;
0155         const qreal xStep = cellWidth / (qreal)divide;
0156 
0157         QRectF tile;
0158         QPainterPath cellPath;
0159         for (int y = 0; y < (gridHeight)/yStep; y++) {
0160             for (int x = 0; x < (gridWidth)/xStep; x++) {
0161                 tile = QRectF(dabRect.x() + x * xStep, dabRect.y() + y * yStep, xStep, yStep);
0162                 switch (shapeOption.shape) {
0163                 case 0: {
0164                     cellPath.addEllipse(tile);
0165                     break;
0166                 }
0167                 case 1: {
0168                     cellPath.addRect(tile);
0169                     break;
0170                 }
0171                 case 2: {
0172                     cellPath.moveTo(tile.topRight());
0173                     cellPath.lineTo(tile.bottomLeft());
0174                     break;
0175                 }
0176                 case 3: {
0177                     cellPath.moveTo(tile.topRight());
0178                     cellPath.lineTo(tile.bottomLeft());
0179                     break;
0180                 }
0181                 case 4: {
0182                     cellPath.moveTo(tile.topRight());
0183                     cellPath.lineTo(tile.bottomLeft());
0184                     break;
0185                 }
0186                 default: {
0187                 break;
0188                 }
0189                 }
0190             }
0191         }
0192         KisOptimizedBrushOutline cellPath2 = outlineFetcher()->fetchOutline(info, this, cellPath, mode, alignForZoom);
0193         path.addPath(cellPath2);
0194     }
0195     return path;
0196 }
0197 
0198 
0199 #include <brushengine/kis_slider_based_paintop_property.h>
0200 #include "kis_paintop_preset.h"
0201 #include "KisPaintOpPresetUpdateProxy.h"
0202 
0203 QList<KisUniformPaintOpPropertySP> KisGridPaintOpSettings::uniformProperties(KisPaintOpSettingsSP settings, QPointer<KisPaintOpPresetUpdateProxy> updateProxy)
0204 {
0205     QList<KisUniformPaintOpPropertySP> props =
0206         listWeakToStrong(m_d->uniformProperties);
0207 
0208     if (props.isEmpty()) {
0209         {
0210             KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback(KisIntSliderBasedPaintOpPropertyCallback::Int,
0211                                                                                                           KoID("grid_divisionlevel", i18n("Division Level")),
0212                                                                                                           settings,
0213                                                                                                           0);
0214 
0215             prop->setRange(1, 25);
0216             prop->setSingleStep(1);
0217 
0218             prop->setReadCallback(
0219                 [](KisUniformPaintOpProperty *prop) {
0220                     KisGridOpOptionData option;
0221                     option.read(prop->settings().data());
0222 
0223                     prop->setValue(int(option.grid_division_level));
0224                 });
0225             prop->setWriteCallback(
0226                 [](KisUniformPaintOpProperty *prop) {
0227                     KisGridOpOptionData option;
0228                     option.read(prop->settings().data());
0229                     option.grid_division_level = prop->value().toInt();
0230                     option.write(prop->settings().data());
0231                 });
0232 
0233             QObject::connect(updateProxy, SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue()));
0234             prop->requestReadValue();
0235             props << toQShared(prop);
0236         }
0237     }
0238 
0239     return KisPaintOpSettings::uniformProperties(settings, updateProxy) + props;
0240 }