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 }