File indexing completed on 2024-06-16 04:18:01
0001 /* 0002 * SPDX-FileCopyrightText: 2013 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_tool_transform_config_widget.h" 0008 0009 #include <kis_icon.h> 0010 #include "rotation_icons.h" 0011 #include "kis_canvas2.h" 0012 #include <KisSignalMapper.h> 0013 #include "kis_liquify_properties.h" 0014 0015 #include "KisMainWindow.h" 0016 #include "KisViewManager.h" 0017 #include "kis_transform_utils.h" 0018 #include "kis_config_notifier.h" 0019 #include <kstandardguiitem.h> 0020 0021 0022 template<typename T> inline T sign(T x) { 0023 return x > 0 ? 1 : x == (T)0 ? 0 : -1; 0024 } 0025 0026 const int KisToolTransformConfigWidget::DEFAULT_POINTS_PER_LINE = 3; 0027 0028 0029 KisToolTransformConfigWidget::KisToolTransformConfigWidget(TransformTransactionProperties *transaction, KisCanvas2 *canvas, QWidget *parent) 0030 : QWidget(parent), 0031 m_transaction(transaction), 0032 m_notificationsBlocked(0), 0033 m_uiSlotsBlocked(0), 0034 m_configChanged(false) 0035 { 0036 setupUi(this); 0037 0038 KConfigGroup group = KSharedConfig::openConfig()->group("KisToolTransform"); 0039 bool useInStackPreview = !group.readEntry("useOverlayPreviewStyle", false); 0040 bool forceLodMode = group.readEntry("forceLodMode", true); 0041 0042 if (useInStackPreview && !forceLodMode) { 0043 cmbPreviewMode->setCurrentIndex(0); 0044 } 0045 else if (useInStackPreview && forceLodMode) { 0046 cmbPreviewMode->setCurrentIndex(1); 0047 } 0048 else { 0049 cmbPreviewMode->setCurrentIndex(2); 0050 } 0051 0052 connect(cmbPreviewMode, SIGNAL(currentIndexChanged(int)), this, SLOT(slotPreviewChanged(int))); 0053 0054 flipXButton->setIcon(KisIconUtils::loadIcon("transform_icons_mirror_x")); 0055 flipYButton->setIcon(KisIconUtils::loadIcon("transform_icons_mirror_y")); 0056 rotateCWButton->setIcon(KisIconUtils::loadIcon("transform_icons_rotate_cw")); 0057 rotateCCWButton->setIcon(KisIconUtils::loadIcon("transform_icons_rotate_ccw")); 0058 0059 // Granularity can only be specified in the power of 2's 0060 QStringList granularityValues{"4","8","16","32"}; 0061 changeGranularity->addItems(granularityValues); 0062 changeGranularity->setCurrentIndex(1); 0063 granularityPreview->addItems(granularityValues); 0064 granularityPreview->setCurrentIndex(2); 0065 0066 connect(changeGranularity,SIGNAL(currentIndexChanged(QString)), 0067 this,SLOT(slotGranularityChanged(QString))); 0068 connect(granularityPreview, SIGNAL(currentIndexChanged(QString)), 0069 this,SLOT(slotPreviewGranularityChanged(QString))); 0070 0071 // Init Filter combo 0072 cmbFilter->setIDList(KisFilterStrategyRegistry::instance()->listKeys()); 0073 cmbFilter->setCurrent("Bicubic"); 0074 cmbFilter->setToolTip(i18nc("@info:tooltip", 0075 "<p>Select filtering mode:\n" 0076 "<ul>" 0077 "<li><b>Nearest neighbor</b> for pixel art. Does not produce new color.</li>" 0078 "<li><b>Bilinear</b> for areas with uniform color to avoid artifacts.</li>" 0079 "<li><b>Bicubic</b> for smoother results.</li>" 0080 "<li><b>Lanczos3</b> for sharp results. May produce aerials.</li>" 0081 "</ul></p>")); 0082 connect(cmbFilter, SIGNAL(activated(KoID)), 0083 this, SLOT(slotFilterChanged(KoID))); 0084 0085 // Init Warp Type combo 0086 cmbWarpType->insertItem(KisWarpTransformWorker::AFFINE_TRANSFORM,i18n("Default (Affine)")); 0087 cmbWarpType->insertItem(KisWarpTransformWorker::RIGID_TRANSFORM,i18n("Strong (Rigid)")); 0088 cmbWarpType->insertItem(KisWarpTransformWorker::SIMILITUDE_TRANSFORM,i18n("Strongest (Similitude)")); 0089 cmbWarpType->setCurrentIndex(KisWarpTransformWorker::AFFINE_TRANSFORM); 0090 connect(cmbWarpType, SIGNAL(currentIndexChanged(int)), this, SLOT(slotWarpTypeChanged(int))); 0091 0092 // Init Rotation Center buttons 0093 m_handleDir[0] = QPointF(1, 0); 0094 m_handleDir[1] = QPointF(1, -1); 0095 m_handleDir[2] = QPointF(0, -1); 0096 m_handleDir[3] = QPointF(-1, -1); 0097 m_handleDir[4] = QPointF(-1, 0); 0098 m_handleDir[5] = QPointF(-1, 1); 0099 m_handleDir[6] = QPointF(0, 1); 0100 m_handleDir[7] = QPointF(1, 1); 0101 m_handleDir[8] = QPointF(0, 0); // also add the center 0102 0103 m_rotationCenterButtons = new QButtonGroup(0); 0104 // we set the ids to match m_handleDir 0105 m_rotationCenterButtons->addButton(middleRightButton, 0); 0106 m_rotationCenterButtons->addButton(topRightButton, 1); 0107 m_rotationCenterButtons->addButton(middleTopButton, 2); 0108 m_rotationCenterButtons->addButton(topLeftButton, 3); 0109 m_rotationCenterButtons->addButton(middleLeftButton, 4); 0110 m_rotationCenterButtons->addButton(bottomLeftButton, 5); 0111 m_rotationCenterButtons->addButton(middleBottomButton, 6); 0112 m_rotationCenterButtons->addButton(bottomRightButton, 7); 0113 m_rotationCenterButtons->addButton(centerButton, 8); 0114 0115 QToolButton *nothingSelected = new QToolButton(0); 0116 nothingSelected->setCheckable(true); 0117 nothingSelected->setAutoExclusive(true); 0118 nothingSelected->hide(); // a convenient button for when no button is checked in the group 0119 m_rotationCenterButtons->addButton(nothingSelected, 9); 0120 0121 0122 // initialize values for free transform sliders 0123 shearXBox->setSuffix(QChar(Qt::Key_Percent)); 0124 shearYBox->setSuffix(QChar(Qt::Key_Percent)); 0125 shearXBox->setRange(-500, 500, 2); 0126 shearYBox->setRange(-500, 500, 2); 0127 shearXBox->setSingleStep(1); 0128 shearYBox->setSingleStep(1); 0129 shearXBox->setValue(0.0); 0130 shearYBox->setValue(0.0); 0131 0132 0133 translateXBox->setSuffix(i18n(" px")); 0134 translateYBox->setSuffix(i18n(" px")); 0135 translateXBox->setRange(-10000, 10000); 0136 translateYBox->setRange(-10000, 10000); 0137 0138 0139 scaleXBox->setRange(-10000, 10000); 0140 scaleYBox->setRange(-10000, 10000); 0141 scaleXBox->setValue(100.0); 0142 scaleYBox->setValue(100.0); 0143 0144 m_scaleRatio = 1.0; 0145 0146 0147 aXBox->setIncreasingDirection(KisAngleGauge::IncreasingDirection_Clockwise); 0148 aYBox->setIncreasingDirection(KisAngleGauge::IncreasingDirection_Clockwise); 0149 aZBox->setIncreasingDirection(KisAngleGauge::IncreasingDirection_Clockwise); 0150 aXBox->setFlipOptionsMode(KisAngleSelector::FlipOptionsMode_MenuButton); 0151 aYBox->setFlipOptionsMode(KisAngleSelector::FlipOptionsMode_MenuButton); 0152 aZBox->setFlipOptionsMode(KisAngleSelector::FlipOptionsMode_MenuButton); 0153 0154 cameraHeightBox->setRange(1, 20000, 2); 0155 0156 connect(m_rotationCenterButtons, SIGNAL(buttonPressed(int)), this, SLOT(slotRotationCenterChanged(int))); 0157 connect(btnTransformAroundPivotPoint, SIGNAL(clicked(bool)), this, SLOT(slotTransformAroundRotationCenter(bool))); 0158 0159 // Init Free Transform Values 0160 connect(scaleXBox, SIGNAL(valueChanged(int)), this, SLOT(slotSetScaleX(int))); 0161 connect(scaleYBox, SIGNAL(valueChanged(int)), this, SLOT(slotSetScaleY(int))); 0162 connect(shearXBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetShearX(qreal))); 0163 connect(shearYBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetShearY(qreal))); 0164 connect(translateXBox, SIGNAL(valueChanged(int)), this, SLOT(slotSetTranslateX(int))); 0165 connect(translateYBox, SIGNAL(valueChanged(int)), this, SLOT(slotSetTranslateY(int))); 0166 connect(aXBox, SIGNAL(angleChanged(qreal)), this, SLOT(slotSetAX(qreal))); 0167 connect(aYBox, SIGNAL(angleChanged(qreal)), this, SLOT(slotSetAY(qreal))); 0168 connect(aZBox, SIGNAL(angleChanged(qreal)), this, SLOT(slotSetAZ(qreal))); 0169 connect(cameraHeightBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetCameraHeight(qreal))); 0170 connect(aspectButton, SIGNAL(keepAspectRatioChanged(bool)), this, SLOT(slotSetKeepAspectRatio(bool))); 0171 connect(flipXButton, SIGNAL(clicked(bool)), this, SLOT(slotFlipX())); 0172 connect(flipYButton, SIGNAL(clicked(bool)), this, SLOT(slotFlipY())); 0173 connect(rotateCWButton, SIGNAL(clicked(bool)), this, SLOT(slotRotateCW())); 0174 connect(rotateCCWButton, SIGNAL(clicked(bool)), this, SLOT(slotRotateCCW())); 0175 0176 // toggle visibility of different free buttons 0177 connect(freeMoveRadioButton, SIGNAL(clicked(bool)), SLOT(slotTransformAreaVisible(bool))); 0178 connect(freeRotationRadioButton, SIGNAL(clicked(bool)), SLOT(slotTransformAreaVisible(bool))); 0179 connect(freeScaleRadioButton, SIGNAL(clicked(bool)), SLOT(slotTransformAreaVisible(bool))); 0180 connect(freeShearRadioButton, SIGNAL(clicked(bool)), SLOT(slotTransformAreaVisible(bool))); 0181 0182 // only first group for free transform 0183 rotationGroup->hide(); 0184 moveGroup->show(); 0185 scaleGroup->hide(); 0186 shearGroup->hide(); 0187 0188 0189 0190 // Init Warp Transform Values 0191 alphaBox->setSingleStep(0.1); 0192 alphaBox->setRange(0, 10, 1); 0193 0194 connect(alphaBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetWarpAlpha(qreal))); 0195 connect(densityBox, SIGNAL(valueChanged(int)), this, SLOT(slotSetWarpDensity(int))); 0196 0197 connect(defaultRadioButton, SIGNAL(clicked(bool)), this, SLOT(slotWarpDefaultPointsButtonClicked(bool))); 0198 connect(customRadioButton, SIGNAL(clicked(bool)), this, SLOT(slotWarpCustomPointsButtonClicked(bool))); 0199 connect(lockUnlockPointsButton, SIGNAL(clicked()), this, SLOT(slotWarpLockPointsButtonClicked())); 0200 connect(resetPointsButton, SIGNAL(clicked()), this, SLOT(slotWarpResetPointsButtonClicked())); 0201 0202 // Init Cage Transform Values 0203 cageTransformButtonGroup->setId(cageAddEditRadio, 0); // we need to set manually since Qt Designer generates negative by default 0204 cageTransformButtonGroup->setId(cageDeformRadio, 1); 0205 connect(cageTransformButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotCageOptionsChanged(int))); 0206 0207 // Init Liquify Transform Values 0208 liquifySizeSlider->setRange(KisLiquifyProperties::minSize(), 0209 KisLiquifyProperties::maxSize(), 2); 0210 liquifySizeSlider->setExponentRatio(3); 0211 liquifySizeSlider->setValue(60.0); 0212 connect(liquifySizeSlider, SIGNAL(valueChanged(qreal)), this, SLOT(liquifySizeChanged(qreal))); 0213 connect(liquifySizeSlider, SIGNAL(editingFinished()), SLOT(notifyEditingFinished())); 0214 liquifySizeSlider->setToolTip(i18nc("@info:tooltip", "Size of the deformation brush")); 0215 0216 liquifyAmountSlider->setRange(0.0, 1.0, 2); 0217 liquifyAmountSlider->setSingleStep(0.01); 0218 liquifyAmountSlider->setValue(0.05); 0219 connect(liquifyAmountSlider, SIGNAL(valueChanged(qreal)), this, SLOT(liquifyAmountChanged(qreal))); 0220 connect(liquifyAmountSlider, SIGNAL(editingFinished()), SLOT(notifyEditingFinished())); 0221 liquifyAmountSlider->setToolTip(i18nc("@info:tooltip", "Amount of the deformation you get")); 0222 0223 liquifyFlowSlider->setRange(0.0, 1.0, 2); 0224 liquifyFlowSlider->setSingleStep(0.01); 0225 liquifyFlowSlider->setValue(1.0); 0226 connect(liquifyFlowSlider, SIGNAL(valueChanged(qreal)), this, SLOT(liquifyFlowChanged(qreal))); 0227 connect(liquifyFlowSlider, SIGNAL(editingFinished()), SLOT(notifyEditingFinished())); 0228 liquifyFlowSlider->setToolTip(i18nc("@info:tooltip", "When in non-buildup mode, shows how fast the deformation limit is reached.")); 0229 0230 buildupModeComboBox->setCurrentIndex(0); // set to build-up mode by default 0231 connect(buildupModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(liquifyBuildUpChanged(int))); 0232 connect(buildupModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(notifyEditingFinished())); 0233 buildupModeComboBox->setToolTip("<p>" + i18nc("@info:tooltip", "Switch between Build Up and Wash mode of painting. Build Up mode adds deformations one on top of the other without any limits. Wash mode gradually deforms the piece to the selected deformation level.") + "</p>"); 0234 0235 liquifySpacingSlider->setRange(0.0, 3.0, 2); 0236 liquifySpacingSlider->setExponentRatio(3); 0237 liquifySpacingSlider->setSingleStep(0.01); 0238 liquifySpacingSlider->setValue(0.2); 0239 connect(liquifySpacingSlider, SIGNAL(valueChanged(qreal)), this, SLOT(liquifySpacingChanged(qreal))); 0240 connect(liquifySpacingSlider, SIGNAL(editingFinished()), SLOT(notifyEditingFinished())); 0241 liquifySpacingSlider->setToolTip(i18nc("@info:tooltip", "Space between two sequential applications of the deformation")); 0242 0243 liquifySizePressureBox->setChecked(true); 0244 connect(liquifySizePressureBox, SIGNAL(toggled(bool)), this, SLOT(liquifySizePressureChanged(bool))); 0245 connect(liquifySizePressureBox, SIGNAL(toggled(bool)), this, SLOT(notifyEditingFinished())); 0246 liquifySizePressureBox->setToolTip(i18nc("@info:tooltip", "Scale <b>Size</b> value according to current stylus pressure")); 0247 0248 liquifyAmountPressureBox->setChecked(true); 0249 connect(liquifyAmountPressureBox, SIGNAL(toggled(bool)), this, SLOT(liquifyAmountPressureChanged(bool))); 0250 connect(liquifyAmountPressureBox, SIGNAL(toggled(bool)), this, SLOT(notifyEditingFinished())); 0251 liquifyAmountPressureBox->setToolTip(i18nc("@info:tooltip", "Scale <b>Amount</b> value according to current stylus pressure")); 0252 0253 liquifyReverseDirectionChk->setChecked(false); 0254 connect(liquifyReverseDirectionChk, SIGNAL(toggled(bool)), this, SLOT(liquifyReverseDirectionChanged(bool))); 0255 connect(liquifyReverseDirectionChk, SIGNAL(toggled(bool)), this, SLOT(notifyEditingFinished())); 0256 liquifyReverseDirectionChk->setToolTip(i18nc("@info:tooltip", "Reverse direction of the current deformation tool")); 0257 0258 KisSignalMapper *liquifyModeMapper = new KisSignalMapper(this); 0259 connect(liquifyMove, SIGNAL(toggled(bool)), liquifyModeMapper, SLOT(map())); 0260 connect(liquifyScale, SIGNAL(toggled(bool)), liquifyModeMapper, SLOT(map())); 0261 connect(liquifyRotate, SIGNAL(toggled(bool)), liquifyModeMapper, SLOT(map())); 0262 connect(liquifyOffset, SIGNAL(toggled(bool)), liquifyModeMapper, SLOT(map())); 0263 connect(liquifyUndo, SIGNAL(toggled(bool)), liquifyModeMapper, SLOT(map())); 0264 liquifyModeMapper->setMapping(liquifyMove, (int)KisLiquifyProperties::MOVE); 0265 liquifyModeMapper->setMapping(liquifyScale, (int)KisLiquifyProperties::SCALE); 0266 liquifyModeMapper->setMapping(liquifyRotate, (int)KisLiquifyProperties::ROTATE); 0267 liquifyModeMapper->setMapping(liquifyOffset, (int)KisLiquifyProperties::OFFSET); 0268 liquifyModeMapper->setMapping(liquifyUndo, (int)KisLiquifyProperties::UNDO); 0269 connect(liquifyModeMapper, SIGNAL(mapped(int)), SLOT(slotLiquifyModeChanged(int))); 0270 connect(liquifyModeMapper, SIGNAL(mapped(int)), SLOT(notifyEditingFinished())); 0271 0272 liquifyMove->setToolTip(i18nc("@info:tooltip", "Move: drag the image along the brush stroke")); 0273 liquifyScale->setToolTip(i18nc("@info:tooltip", "Scale: grow/shrink image under cursor")); 0274 liquifyRotate->setToolTip(i18nc("@info:tooltip", "Rotate: twirl image under cursor")); 0275 liquifyOffset->setToolTip(i18nc("@info:tooltip", "Offset: shift the image to the right of the stroke direction")); 0276 liquifyUndo->setToolTip(i18nc("@info:tooltip", "Undo: erase actions of other tools")); 0277 0278 // Connect all edit boxes to the Editing Finished signal 0279 connect(densityBox, SIGNAL(editingFinished()), this, SLOT(notifyEditingFinished())); 0280 0281 0282 0283 // Connect other widget (not having editingFinished signal) to 0284 // the same slot. From Qt 4.6 onwards the sequence of the signal 0285 // delivery is definite. 0286 connect(cmbFilter, SIGNAL(activated(KoID)), this, SLOT(notifyEditingFinished())); 0287 connect(cmbWarpType, SIGNAL(currentIndexChanged(int)), this, SLOT(notifyEditingFinished())); 0288 connect(m_rotationCenterButtons, SIGNAL(buttonPressed(int)), this, SLOT(notifyEditingFinished())); 0289 connect(aspectButton, SIGNAL(keepAspectRatioChanged(bool)), this, SLOT(notifyEditingFinished())); 0290 0291 connect(lockUnlockPointsButton, SIGNAL(clicked()), this, SLOT(notifyEditingFinished())); 0292 connect(resetPointsButton, SIGNAL(clicked()), this, SLOT(notifyEditingFinished())); 0293 0294 connect(defaultRadioButton, SIGNAL(clicked(bool)), this, SLOT(notifyEditingFinished())); 0295 connect(customRadioButton, SIGNAL(clicked(bool)), this, SLOT(notifyEditingFinished())); 0296 0297 // Liquify 0298 // 0299 // liquify brush options do not affect the image directly and are not 0300 // saved to undo, so we don't emit notifyEditingFinished() for them 0301 0302 // Connect Apply/Reset buttons 0303 connect(buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(slotButtonBoxClicked(QAbstractButton*))); 0304 0305 // Mesh. First set up, then connect. 0306 intNumRows->setRange(1, 999); 0307 intNumColumns->setRange(1, 999); 0308 0309 connect(chkShowControlPoints, SIGNAL(toggled(bool)), this, SLOT(slotMeshShowHandlesChanged())); 0310 connect(chkSymmetricalHandles, SIGNAL(toggled(bool)), this, SLOT(slotMeshSymmetricalHandlesChanged())); 0311 connect(chkScaleHandles, SIGNAL(toggled(bool)), this, SLOT(slotMeshScaleHandlesChanged())); 0312 connect(intNumColumns, SIGNAL(valueChanged(int)), this, SLOT(slotMeshSizeChanged())); 0313 connect(intNumRows, SIGNAL(valueChanged(int)), this, SLOT(slotMeshSizeChanged())); 0314 connect(intNumColumns, SIGNAL(editingFinished()), this, SLOT(notifyEditingFinished())); 0315 connect(intNumRows, SIGNAL(editingFinished()), this, SLOT(notifyEditingFinished())); 0316 0317 // Mode switch buttons 0318 connect(freeTransformButton, SIGNAL(clicked(bool)), this, SLOT(slotSetFreeTransformModeButtonClicked(bool))); 0319 connect(warpButton, SIGNAL(clicked(bool)), this, SLOT(slotSetWarpModeButtonClicked(bool))); 0320 connect(cageButton, SIGNAL(clicked(bool)), this, SLOT(slotSetCageModeButtonClicked(bool))); 0321 connect(perspectiveTransformButton, SIGNAL(clicked(bool)), this, SLOT(slotSetPerspectiveModeButtonClicked(bool))); 0322 connect(liquifyButton, SIGNAL(clicked(bool)), this, SLOT(slotSetLiquifyModeButtonClicked(bool))); 0323 connect(meshButton, SIGNAL(clicked(bool)), this, SLOT(slotSetMeshModeButtonClicked(bool))); 0324 0325 0326 tooBigLabelWidget->hide(); 0327 0328 connect(canvas->viewManager()->mainWindow(), SIGNAL(themeChanged()), SLOT(slotUpdateIcons()), Qt::UniqueConnection); 0329 slotUpdateIcons(); 0330 0331 KGuiItem::assign(buttonBox->button(QDialogButtonBox::Apply), KStandardGuiItem::apply()); 0332 KGuiItem::assign(buttonBox->button(QDialogButtonBox::Reset), KStandardGuiItem::reset()); 0333 } 0334 0335 void KisToolTransformConfigWidget::slotUpdateIcons() 0336 { 0337 freeTransformButton->setIcon(KisIconUtils::loadIcon("transform_icons_main")); 0338 warpButton->setIcon(KisIconUtils::loadIcon("transform_icons_warp")); 0339 cageButton->setIcon(KisIconUtils::loadIcon("transform_icons_cage")); 0340 perspectiveTransformButton->setIcon(KisIconUtils::loadIcon("transform_icons_perspective")); 0341 liquifyButton->setIcon(KisIconUtils::loadIcon("transform_icons_liquify_main")); 0342 meshButton->setIcon(KisIconUtils::loadIcon("transform_icons_mesh")); 0343 0344 liquifyMove->setIcon(KisIconUtils::loadIcon("transform_icons_liquify_move")); 0345 liquifyScale->setIcon(KisIconUtils::loadIcon("transform_icons_liquify_resize")); 0346 liquifyRotate->setIcon(KisIconUtils::loadIcon("transform_icons_liquify_rotate")); 0347 liquifyOffset->setIcon(KisIconUtils::loadIcon("transform_icons_liquify_offset")); 0348 liquifyUndo->setIcon(KisIconUtils::loadIcon("transform_icons_liquify_erase")); 0349 0350 0351 0352 middleRightButton->setIcon(KisIconUtils::loadIcon("arrow-right")); 0353 topRightButton->setIcon(KisIconUtils::loadIcon("arrow-topright")); 0354 middleTopButton->setIcon(KisIconUtils::loadIcon("arrow-up")); 0355 topLeftButton->setIcon(KisIconUtils::loadIcon("arrow-topleft")); 0356 middleLeftButton->setIcon(KisIconUtils::loadIcon("arrow-left")); 0357 bottomLeftButton->setIcon(KisIconUtils::loadIcon("arrow-downleft")); 0358 middleBottomButton->setIcon(KisIconUtils::loadIcon("arrow-down")); 0359 bottomRightButton->setIcon(KisIconUtils::loadIcon("arrow-downright")); 0360 0361 btnTransformAroundPivotPoint->setIcon(KisIconUtils::loadIcon("pivot-point")); 0362 0363 0364 // pressure icons 0365 liquifySizePressureBox->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure")); 0366 liquifyAmountPressureBox->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure")); 0367 } 0368 0369 void KisToolTransformConfigWidget::updateLiquifyControls() 0370 { 0371 blockUiSlots(); 0372 0373 ToolTransformArgs *config = m_transaction->currentConfig(); 0374 KisLiquifyProperties *props = 0375 config->liquifyProperties(); 0376 0377 const bool useWashMode = props->useWashMode(); 0378 0379 liquifySizeSlider->setValue(props->size()); 0380 liquifyAmountSlider->setValue(props->amount()); 0381 liquifyFlowSlider->setValue(props->flow()); 0382 buildupModeComboBox->setCurrentIndex(useWashMode); 0383 0384 liquifySpacingSlider->setValue(props->spacing()); 0385 liquifySizePressureBox->setChecked(props->sizeHasPressure()); 0386 liquifyAmountPressureBox->setChecked(props->amountHasPressure()); 0387 liquifyReverseDirectionChk->setChecked(props->reverseDirection()); 0388 0389 0390 KisLiquifyProperties::LiquifyMode mode = 0391 static_cast<KisLiquifyProperties::LiquifyMode>(props->mode()); 0392 0393 bool canInverseDirection = 0394 mode != KisLiquifyProperties::UNDO; 0395 0396 bool canUseWashMode = mode != KisLiquifyProperties::UNDO; 0397 0398 liquifyReverseDirectionChk->setEnabled(canInverseDirection); 0399 liquifyFlowSlider->setEnabled(canUseWashMode && useWashMode); 0400 buildupModeComboBox->setEnabled(canUseWashMode); 0401 0402 const qreal maxAmount = canUseWashMode ? 5.0 : 1.0; 0403 liquifyAmountSlider->setRange(0.0, maxAmount, 2); 0404 0405 unblockUiSlots(); 0406 } 0407 0408 void KisToolTransformConfigWidget::slotLiquifyModeChanged(int value) 0409 { 0410 if (m_uiSlotsBlocked) return; 0411 0412 ToolTransformArgs *config = m_transaction->currentConfig(); 0413 0414 KisLiquifyProperties *props = 0415 config->liquifyProperties(); 0416 0417 KisLiquifyProperties::LiquifyMode mode = 0418 static_cast<KisLiquifyProperties::LiquifyMode>(value); 0419 0420 if (mode == props->mode()) return; 0421 0422 props->setMode(mode); 0423 props->loadMode(); 0424 0425 updateLiquifyControls(); 0426 0427 notifyConfigChanged(false); 0428 } 0429 0430 void KisToolTransformConfigWidget::liquifySizeChanged(qreal value) 0431 { 0432 if (m_uiSlotsBlocked) return; 0433 0434 ToolTransformArgs *config = m_transaction->currentConfig(); 0435 KisLiquifyProperties *props = 0436 config->liquifyProperties(); 0437 0438 props->setSize(value); 0439 notifyConfigChanged(false); 0440 } 0441 0442 void KisToolTransformConfigWidget::liquifyAmountChanged(qreal value) 0443 { 0444 if (m_uiSlotsBlocked) return; 0445 0446 ToolTransformArgs *config = m_transaction->currentConfig(); 0447 KisLiquifyProperties *props = 0448 config->liquifyProperties(); 0449 0450 props->setAmount(value); 0451 notifyConfigChanged(false); 0452 } 0453 0454 void KisToolTransformConfigWidget::liquifyFlowChanged(qreal value) 0455 { 0456 if (m_uiSlotsBlocked) return; 0457 0458 ToolTransformArgs *config = m_transaction->currentConfig(); 0459 KisLiquifyProperties *props = 0460 config->liquifyProperties(); 0461 0462 props->setFlow(value); 0463 notifyConfigChanged(false); 0464 } 0465 0466 void KisToolTransformConfigWidget::liquifyBuildUpChanged(int value) 0467 { 0468 if (m_uiSlotsBlocked) return; 0469 0470 ToolTransformArgs *config = m_transaction->currentConfig(); 0471 KisLiquifyProperties *props = 0472 config->liquifyProperties(); 0473 0474 props->setUseWashMode(value); // 0 == build up mode / 1 == wash mode 0475 0476 notifyConfigChanged(false); 0477 0478 // we need to enable/disable flow slider 0479 updateLiquifyControls(); 0480 } 0481 0482 void KisToolTransformConfigWidget::liquifySpacingChanged(qreal value) 0483 { 0484 if (m_uiSlotsBlocked) return; 0485 0486 ToolTransformArgs *config = m_transaction->currentConfig(); 0487 KisLiquifyProperties *props = 0488 config->liquifyProperties(); 0489 0490 props->setSpacing(value); 0491 notifyConfigChanged(false); 0492 } 0493 0494 void KisToolTransformConfigWidget::liquifySizePressureChanged(bool value) 0495 { 0496 if (m_uiSlotsBlocked) return; 0497 0498 ToolTransformArgs *config = m_transaction->currentConfig(); 0499 KisLiquifyProperties *props = 0500 config->liquifyProperties(); 0501 0502 props->setSizeHasPressure(value); 0503 notifyConfigChanged(false); 0504 } 0505 0506 void KisToolTransformConfigWidget::liquifyAmountPressureChanged(bool value) 0507 { 0508 if (m_uiSlotsBlocked) return; 0509 0510 ToolTransformArgs *config = m_transaction->currentConfig(); 0511 KisLiquifyProperties *props = 0512 config->liquifyProperties(); 0513 0514 props->setAmountHasPressure(value); 0515 notifyConfigChanged(false); 0516 } 0517 0518 void KisToolTransformConfigWidget::liquifyReverseDirectionChanged(bool value) 0519 { 0520 if (m_uiSlotsBlocked) return; 0521 0522 ToolTransformArgs *config = m_transaction->currentConfig(); 0523 KisLiquifyProperties *props = 0524 config->liquifyProperties(); 0525 0526 props->setReverseDirection(value); 0527 notifyConfigChanged(false); 0528 } 0529 0530 void KisToolTransformConfigWidget::updateConfig(const ToolTransformArgs &config) 0531 { 0532 blockUiSlots(); 0533 0534 if (config.mode() == ToolTransformArgs::FREE_TRANSFORM || 0535 config.mode() == ToolTransformArgs::PERSPECTIVE_4POINT) { 0536 0537 quickTransformGroup->setEnabled(config.mode() == ToolTransformArgs::FREE_TRANSFORM); 0538 0539 stackedWidget->setCurrentIndex(0); 0540 0541 bool freeTransformIsActive = config.mode() == ToolTransformArgs::FREE_TRANSFORM; 0542 0543 if (freeTransformIsActive) 0544 { 0545 freeTransformButton->setChecked(true); 0546 } 0547 else 0548 { 0549 perspectiveTransformButton->setChecked(true); 0550 } 0551 0552 aXBox->setEnabled(freeTransformIsActive); 0553 aYBox->setEnabled(freeTransformIsActive); 0554 aZBox->setEnabled(freeTransformIsActive); 0555 cameraHeightBox->setEnabled(freeTransformIsActive); 0556 freeRotationRadioButton->setEnabled(freeTransformIsActive); 0557 0558 scaleXBox->setValue(config.scaleX() * 100.); 0559 scaleYBox->setValue(config.scaleY() * 100.); 0560 shearXBox->setValue(config.shearX() * 100.); 0561 shearYBox->setValue(config.shearY() * 100.); 0562 0563 const QPointF anchorPoint = config.originalCenter() + config.rotationCenterOffset(); 0564 const KisTransformUtils::MatricesPack m(config); 0565 const QPointF anchorPointView = m.finalTransform().map(anchorPoint); 0566 0567 translateXBox->setValue(anchorPointView.x()); 0568 translateYBox->setValue(anchorPointView.y()); 0569 0570 aXBox->setAngle(normalizeAngleDegrees(kisRadiansToDegrees(config.aX()))); 0571 aYBox->setAngle(normalizeAngleDegrees(kisRadiansToDegrees(config.aY()))); 0572 aZBox->setAngle(normalizeAngleDegrees(kisRadiansToDegrees(config.aZ()))); 0573 cameraHeightBox->setValue(config.cameraPos().z()); 0574 aspectButton->setKeepAspectRatio(config.keepAspectRatio()); 0575 cmbFilter->setCurrent(config.filterId()); 0576 0577 QPointF pt = m_transaction->currentConfig()->rotationCenterOffset(); 0578 pt.rx() /= m_transaction->originalHalfWidth(); 0579 pt.ry() /= m_transaction->originalHalfHeight(); 0580 0581 for (int i = 0; i < 9; i++) { 0582 if (qFuzzyCompare(m_handleDir[i].x(), pt.x()) && 0583 qFuzzyCompare(m_handleDir[i].y(), pt.y())) { 0584 0585 m_rotationCenterButtons->button(i)->setChecked(true); 0586 break; 0587 } 0588 } 0589 0590 btnTransformAroundPivotPoint->setChecked(config.transformAroundRotationCenter()); 0591 0592 } else if (config.mode() == ToolTransformArgs::WARP) { 0593 0594 stackedWidget->setCurrentIndex(1); 0595 warpButton->setChecked(true); 0596 0597 if (config.defaultPoints()) { 0598 densityBox->setValue(std::sqrt(config.numPoints())); 0599 } 0600 0601 cmbWarpType->setCurrentIndex((int)config.warpType()); 0602 defaultRadioButton->setChecked(config.defaultPoints()); 0603 customRadioButton->setChecked(!config.defaultPoints()); 0604 densityBox->setEnabled(config.defaultPoints()); 0605 customWarpWidget->setEnabled(!config.defaultPoints()); 0606 0607 updateLockPointsButtonCaption(); 0608 0609 } else if (config.mode() == ToolTransformArgs::CAGE) { 0610 0611 // default UI options 0612 resetUIOptions(); 0613 0614 // we need at least 3 point before we can start actively deforming 0615 if (config.origPoints().size() >= 3) 0616 { 0617 cageTransformDirections->setText(i18n("Switch between editing and deforming cage")); 0618 cageAddEditRadio->setVisible(true); 0619 cageDeformRadio->setVisible(true); 0620 0621 // update to correct radio button 0622 if (config.isEditingTransformPoints()) 0623 cageAddEditRadio->setChecked(true); 0624 else 0625 cageDeformRadio->setChecked(true); 0626 0627 changeGranularity->setCurrentIndex(log2(config.pixelPrecision()) - 2); 0628 granularityPreview->setCurrentIndex(log2(config.previewPixelPrecision()) - 2); 0629 0630 } 0631 0632 } else if (config.mode() == ToolTransformArgs::LIQUIFY) { 0633 0634 stackedWidget->setCurrentIndex(3); 0635 liquifyButton->setChecked(true); 0636 0637 const KisLiquifyProperties *props = 0638 config.liquifyProperties(); 0639 0640 switch (props->mode()) { 0641 case KisLiquifyProperties::MOVE: 0642 liquifyMove->setChecked(true); 0643 break; 0644 case KisLiquifyProperties::SCALE: 0645 liquifyScale->setChecked(true); 0646 break; 0647 case KisLiquifyProperties::ROTATE: 0648 liquifyRotate->setChecked(true); 0649 break; 0650 case KisLiquifyProperties::OFFSET: 0651 liquifyOffset->setChecked(true); 0652 break; 0653 case KisLiquifyProperties::UNDO: 0654 liquifyUndo->setChecked(true); 0655 break; 0656 case KisLiquifyProperties::N_MODES: 0657 qFatal("Unsupported mode"); 0658 } 0659 0660 updateLiquifyControls(); 0661 } else if (config.mode() == ToolTransformArgs::MESH) { 0662 stackedWidget->setCurrentIndex(4); 0663 intNumColumns->setValue(config.meshTransform()->size().width() - 1); 0664 intNumRows->setValue(config.meshTransform()->size().height() - 1); 0665 chkShowControlPoints->setChecked(config.meshShowHandles()); 0666 chkSymmetricalHandles->setChecked(config.meshSymmetricalHandles()); 0667 chkScaleHandles->setChecked(config.meshScaleHandles()); 0668 } 0669 0670 unblockUiSlots(); 0671 } 0672 0673 void KisToolTransformConfigWidget::updateLockPointsButtonCaption() 0674 { 0675 ToolTransformArgs *config = m_transaction->currentConfig(); 0676 0677 if (config->isEditingTransformPoints()) { 0678 lockUnlockPointsButton->setText(i18n("Lock Points")); 0679 } else { 0680 lockUnlockPointsButton->setText(i18n("Unlock Points")); 0681 } 0682 } 0683 0684 void KisToolTransformConfigWidget::setApplyResetDisabled(bool disabled) 0685 { 0686 QAbstractButton *applyButton = buttonBox->button(QDialogButtonBox::Apply); 0687 QAbstractButton *resetButton = buttonBox->button(QDialogButtonBox::Reset); 0688 0689 Q_ASSERT(applyButton); 0690 Q_ASSERT(resetButton); 0691 0692 applyButton->setDisabled(disabled); 0693 resetButton->setDisabled(disabled); 0694 } 0695 0696 void KisToolTransformConfigWidget::resetRotationCenterButtons() 0697 { 0698 int checkedId = m_rotationCenterButtons->checkedId(); 0699 0700 if (checkedId >= 0 && checkedId <= 8) { 0701 // uncheck the current checked button 0702 m_rotationCenterButtons->button(9)->setChecked(true); 0703 } 0704 } 0705 0706 void KisToolTransformConfigWidget::setTooBigLabelVisible(bool value) 0707 { 0708 tooBigLabelWidget->setVisible(value); 0709 } 0710 0711 void KisToolTransformConfigWidget::blockNotifications() 0712 { 0713 m_notificationsBlocked++; 0714 } 0715 0716 void KisToolTransformConfigWidget::unblockNotifications() 0717 { 0718 m_notificationsBlocked--; 0719 } 0720 0721 void KisToolTransformConfigWidget::notifyConfigChanged(bool needsPreviewRecalculation) 0722 { 0723 if (!m_notificationsBlocked) { 0724 emit sigConfigChanged(needsPreviewRecalculation); 0725 } 0726 m_configChanged = true; 0727 } 0728 0729 void KisToolTransformConfigWidget::blockUiSlots() 0730 { 0731 m_uiSlotsBlocked++; 0732 } 0733 0734 void KisToolTransformConfigWidget::unblockUiSlots() 0735 { 0736 m_uiSlotsBlocked--; 0737 } 0738 0739 void KisToolTransformConfigWidget::notifyEditingFinished() 0740 { 0741 if (m_uiSlotsBlocked || m_notificationsBlocked || !m_configChanged) return; 0742 0743 emit sigEditingFinished(); 0744 m_configChanged = false; 0745 } 0746 0747 0748 void KisToolTransformConfigWidget::resetUIOptions() 0749 { 0750 // reset tool states since we are done (probably can encapsulate this later) 0751 ToolTransformArgs *config = m_transaction->currentConfig(); 0752 if (config->mode() == ToolTransformArgs::CAGE) 0753 { 0754 cageAddEditRadio->setVisible(false); 0755 cageAddEditRadio->setChecked(true); 0756 cageDeformRadio->setVisible(false); 0757 cageTransformDirections->setText(i18n("Create 3 points on the canvas to begin")); 0758 0759 // ensure we are on the right options view 0760 stackedWidget->setCurrentIndex(2); 0761 } 0762 0763 0764 0765 } 0766 0767 void KisToolTransformConfigWidget::slotButtonBoxClicked(QAbstractButton *button) 0768 { 0769 QAbstractButton *applyButton = buttonBox->button(QDialogButtonBox::Apply); 0770 QAbstractButton *resetButton = buttonBox->button(QDialogButtonBox::Reset); 0771 0772 resetUIOptions(); 0773 0774 if (button == applyButton) { 0775 emit sigApplyTransform(); 0776 } 0777 else if (button == resetButton) { 0778 emit sigCancelTransform(); 0779 } 0780 0781 } 0782 0783 void KisToolTransformConfigWidget::slotSetMeshModeButtonClicked(bool value) 0784 { 0785 if (!value) return; 0786 0787 lblTransformType->setText(meshButton->toolTip()); 0788 0789 emit sigResetTransform(ToolTransformArgs::MESH); 0790 } 0791 0792 void KisToolTransformConfigWidget::slotSetFreeTransformModeButtonClicked(bool value) 0793 { 0794 if (!value) return; 0795 0796 lblTransformType->setText(freeTransformButton->toolTip()); 0797 0798 emit sigResetTransform(ToolTransformArgs::FREE_TRANSFORM); 0799 } 0800 0801 void KisToolTransformConfigWidget::slotSetWarpModeButtonClicked(bool value) 0802 { 0803 if (!value) return; 0804 0805 lblTransformType->setText(warpButton->toolTip()); 0806 0807 emit sigResetTransform(ToolTransformArgs::WARP); 0808 } 0809 0810 void KisToolTransformConfigWidget::slotSetCageModeButtonClicked(bool value) 0811 { 0812 if (!value) return; 0813 0814 lblTransformType->setText(cageButton->toolTip()); 0815 0816 emit sigResetTransform(ToolTransformArgs::CAGE); 0817 } 0818 0819 void KisToolTransformConfigWidget::slotSetLiquifyModeButtonClicked(bool value) 0820 { 0821 if (!value) return; 0822 0823 lblTransformType->setText(liquifyButton->toolTip()); 0824 0825 emit sigResetTransform(ToolTransformArgs::LIQUIFY); 0826 } 0827 0828 void KisToolTransformConfigWidget::slotSetPerspectiveModeButtonClicked(bool value) 0829 { 0830 if (!value) return; 0831 0832 lblTransformType->setText(perspectiveTransformButton->toolTip()); 0833 0834 emit sigResetTransform(ToolTransformArgs::PERSPECTIVE_4POINT); 0835 } 0836 0837 void KisToolTransformConfigWidget::slotFilterChanged(const KoID &filterId) 0838 { 0839 ToolTransformArgs *config = m_transaction->currentConfig(); 0840 config->setFilterId(filterId.id()); 0841 notifyConfigChanged(); 0842 } 0843 0844 void KisToolTransformConfigWidget::slotRotationCenterChanged(int index) 0845 { 0846 if (m_uiSlotsBlocked) return; 0847 0848 if (index >= 0 && index <= 8) { 0849 ToolTransformArgs *config = m_transaction->currentConfig(); 0850 0851 double i = m_handleDir[index].x(); 0852 double j = m_handleDir[index].y(); 0853 0854 config->setRotationCenterOffset(QPointF(i * m_transaction->originalHalfWidth(), 0855 j * m_transaction->originalHalfHeight())); 0856 0857 notifyConfigChanged(); 0858 updateConfig(*config); 0859 } 0860 } 0861 0862 void KisToolTransformConfigWidget::slotTransformAroundRotationCenter(bool value) 0863 { 0864 if (m_uiSlotsBlocked) return; 0865 0866 ToolTransformArgs *config = m_transaction->currentConfig(); 0867 config->setTransformAroundRotationCenter(value); 0868 notifyConfigChanged(); 0869 notifyEditingFinished(); 0870 } 0871 0872 void KisToolTransformConfigWidget::slotSetScaleX(int value) 0873 { 0874 if (m_uiSlotsBlocked) return; 0875 0876 ToolTransformArgs *config = m_transaction->currentConfig(); 0877 0878 { 0879 KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); 0880 config->setScaleX(value / 100.); 0881 } 0882 0883 if (config->keepAspectRatio()) { 0884 0885 blockNotifications(); 0886 int calculatedValue = int( value/ m_scaleRatio ); 0887 0888 scaleYBox->blockSignals(true); 0889 scaleYBox->setValue(calculatedValue); 0890 { 0891 KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); 0892 config->setScaleY(calculatedValue / 100.); 0893 } 0894 scaleYBox->blockSignals(false); 0895 0896 unblockNotifications(); 0897 } 0898 0899 notifyConfigChanged(); 0900 notifyEditingFinished(); 0901 } 0902 0903 void KisToolTransformConfigWidget::slotSetScaleY(int value) 0904 { 0905 if (m_uiSlotsBlocked) return; 0906 0907 ToolTransformArgs *config = m_transaction->currentConfig(); 0908 0909 { 0910 KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); 0911 config->setScaleY(value / 100.); 0912 } 0913 0914 if (config->keepAspectRatio()) { 0915 blockNotifications(); 0916 int calculatedValue = int(m_scaleRatio * value); 0917 scaleXBox->blockSignals(true); 0918 scaleXBox->setValue(calculatedValue); 0919 { 0920 KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); 0921 config->setScaleX(calculatedValue / 100.); 0922 } 0923 scaleXBox->blockSignals(false); 0924 unblockNotifications(); 0925 } 0926 0927 notifyConfigChanged(); 0928 notifyEditingFinished(); 0929 } 0930 0931 void KisToolTransformConfigWidget::slotSetShearX(qreal value) 0932 { 0933 if (m_uiSlotsBlocked) return; 0934 0935 ToolTransformArgs *config = m_transaction->currentConfig(); 0936 0937 { 0938 KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); 0939 config->setShearX((double)value / 100.); 0940 } 0941 0942 notifyConfigChanged(); 0943 notifyEditingFinished(); 0944 } 0945 0946 void KisToolTransformConfigWidget::slotSetShearY(qreal value) 0947 { 0948 if (m_uiSlotsBlocked) return; 0949 0950 ToolTransformArgs *config = m_transaction->currentConfig(); 0951 0952 { 0953 KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); 0954 config->setShearY((double)value / 100.); 0955 } 0956 0957 0958 notifyConfigChanged(); 0959 notifyEditingFinished(); 0960 } 0961 0962 void KisToolTransformConfigWidget::slotSetTranslateX(int value) 0963 { 0964 if (m_uiSlotsBlocked) return; 0965 0966 ToolTransformArgs *config = m_transaction->currentConfig(); 0967 0968 const QPointF anchorPoint = config->originalCenter() + config->rotationCenterOffset(); 0969 const KisTransformUtils::MatricesPack m(*config); 0970 0971 const QPointF anchorPointView = m.finalTransform().map(anchorPoint); 0972 const QPointF newAnchorPointView(value, anchorPointView.y()); 0973 config->setTransformedCenter(config->transformedCenter() + newAnchorPointView - anchorPointView); 0974 translateXBox->setValue(value); 0975 notifyConfigChanged(); 0976 } 0977 0978 void KisToolTransformConfigWidget::slotSetTranslateY(int value) 0979 { 0980 if (m_uiSlotsBlocked) return; 0981 0982 ToolTransformArgs *config = m_transaction->currentConfig(); 0983 0984 const QPointF anchorPoint = config->originalCenter() + config->rotationCenterOffset(); 0985 const KisTransformUtils::MatricesPack m(*config); 0986 0987 const QPointF anchorPointView = m.finalTransform().map(anchorPoint); 0988 const QPointF newAnchorPointView(anchorPointView.x(), value); 0989 config->setTransformedCenter(config->transformedCenter() + newAnchorPointView - anchorPointView); 0990 translateYBox->setValue(value); 0991 notifyConfigChanged(); 0992 } 0993 0994 void KisToolTransformConfigWidget::slotSetAX(qreal value) 0995 { 0996 if (m_uiSlotsBlocked) return; 0997 0998 ToolTransformArgs *config = m_transaction->currentConfig(); 0999 { 1000 KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); 1001 config->setAX(kisDegreesToRadians(value)); 1002 } 1003 notifyConfigChanged(); 1004 notifyEditingFinished(); 1005 } 1006 1007 void KisToolTransformConfigWidget::slotSetAY(qreal value) 1008 { 1009 if (m_uiSlotsBlocked) return; 1010 1011 ToolTransformArgs *config = m_transaction->currentConfig(); 1012 1013 { 1014 KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); 1015 config->setAY(kisDegreesToRadians(value)); 1016 } 1017 1018 notifyConfigChanged(); 1019 notifyEditingFinished(); 1020 } 1021 1022 void KisToolTransformConfigWidget::slotSetAZ(qreal value) 1023 { 1024 if (m_uiSlotsBlocked) return; 1025 1026 ToolTransformArgs *config = m_transaction->currentConfig(); 1027 1028 { 1029 KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); 1030 config->setAZ(kisDegreesToRadians(value)); 1031 } 1032 1033 notifyConfigChanged(); 1034 notifyEditingFinished(); 1035 } 1036 1037 void KisToolTransformConfigWidget::slotSetCameraHeight(qreal value) 1038 { 1039 if (m_uiSlotsBlocked) return; 1040 1041 ToolTransformArgs *config = m_transaction->currentConfig(); 1042 config->setCameraPos(QVector3D(0,0,value)); 1043 1044 notifyConfigChanged(); 1045 notifyEditingFinished(); 1046 } 1047 1048 void KisToolTransformConfigWidget::slotFlipX() 1049 { 1050 ToolTransformArgs *config = m_transaction->currentConfig(); 1051 1052 { 1053 KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); 1054 config->setScaleX(config->scaleX() * -1); 1055 } 1056 1057 notifyConfigChanged(); 1058 notifyEditingFinished(); 1059 } 1060 1061 void KisToolTransformConfigWidget::slotFlipY() 1062 { 1063 ToolTransformArgs *config = m_transaction->currentConfig(); 1064 1065 { 1066 KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); 1067 config->setScaleY(config->scaleY() * -1); 1068 } 1069 1070 notifyConfigChanged(); 1071 notifyEditingFinished(); 1072 } 1073 1074 void KisToolTransformConfigWidget::slotRotateCW() 1075 { 1076 ToolTransformArgs *config = m_transaction->currentConfig(); 1077 1078 { 1079 KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); 1080 config->setAZ(normalizeAngle(config->aZ() + M_PI_2)); 1081 } 1082 1083 notifyConfigChanged(); 1084 notifyEditingFinished(); 1085 } 1086 1087 void KisToolTransformConfigWidget::slotRotateCCW() 1088 { 1089 ToolTransformArgs *config = m_transaction->currentConfig(); 1090 1091 { 1092 KisTransformUtils::AnchorHolder keeper(config->transformAroundRotationCenter(), config); 1093 config->setAZ(normalizeAngle(config->aZ() - M_PI_2)); 1094 } 1095 1096 notifyConfigChanged(); 1097 notifyEditingFinished(); 1098 } 1099 1100 1101 // change free transform setting we want to alter (all radio buttons call this) 1102 void KisToolTransformConfigWidget::slotTransformAreaVisible(bool value) 1103 { 1104 Q_UNUSED(value); 1105 1106 //QCheckBox sender = (QCheckBox)(*)(QObject::sender()); 1107 QString senderName = QObject::sender()->objectName(); 1108 1109 1110 // only show setting with what we have selected 1111 rotationGroup->hide(); 1112 shearGroup->hide(); 1113 scaleGroup->hide(); 1114 moveGroup->hide(); 1115 1116 1117 if ("freeMoveRadioButton" == senderName) 1118 { 1119 moveGroup->show(); 1120 } 1121 else if ("freeShearRadioButton" == senderName) 1122 { 1123 shearGroup->show(); 1124 } 1125 else if ("freeScaleRadioButton" == senderName) 1126 { 1127 scaleGroup->show(); 1128 } 1129 else 1130 { 1131 rotationGroup->show(); 1132 } 1133 1134 } 1135 1136 void KisToolTransformConfigWidget::slotSetKeepAspectRatio(bool value) 1137 { 1138 if (m_uiSlotsBlocked) return; 1139 1140 ToolTransformArgs *config = m_transaction->currentConfig(); 1141 config->setKeepAspectRatio(value); 1142 1143 if (value) { 1144 blockNotifications(); 1145 int tmpXScaleBox = scaleXBox->value(); 1146 int tmpYScaleBox = scaleYBox->value(); 1147 m_scaleRatio = (tmpXScaleBox / (double) tmpYScaleBox); 1148 unblockNotifications(); 1149 } 1150 1151 notifyConfigChanged(); 1152 } 1153 1154 void KisToolTransformConfigWidget::slotSetWarpAlpha(qreal value) 1155 { 1156 if (m_uiSlotsBlocked) return; 1157 1158 ToolTransformArgs *config = m_transaction->currentConfig(); 1159 1160 config->setAlpha((double)value); 1161 notifyConfigChanged(); 1162 notifyEditingFinished(); 1163 } 1164 1165 void KisToolTransformConfigWidget::slotSetWarpDensity(int value) 1166 { 1167 if (m_uiSlotsBlocked) return; 1168 setDefaultWarpPoints(value); 1169 } 1170 1171 void KisToolTransformConfigWidget::setDefaultWarpPoints(int pointsPerLine) 1172 { 1173 ToolTransformArgs *config = m_transaction->currentConfig(); 1174 1175 KisTransformUtils::setDefaultWarpPoints(pointsPerLine, m_transaction, config); 1176 notifyConfigChanged(); 1177 } 1178 1179 void KisToolTransformConfigWidget::activateCustomWarpPoints(bool enabled) 1180 { 1181 ToolTransformArgs *config = m_transaction->currentConfig(); 1182 1183 densityBox->setEnabled(!enabled); 1184 customWarpWidget->setEnabled(enabled); 1185 1186 if (!enabled) { 1187 config->setEditingTransformPoints(false); 1188 setDefaultWarpPoints(densityBox->value()); 1189 config->setWarpCalculation(KisWarpTransformWorker::WarpCalculation::GRID); 1190 } else { 1191 config->setEditingTransformPoints(true); 1192 config->setWarpCalculation(KisWarpTransformWorker::WarpCalculation::DRAW); 1193 setDefaultWarpPoints(0); 1194 } 1195 1196 1197 1198 1199 updateLockPointsButtonCaption(); 1200 } 1201 1202 void KisToolTransformConfigWidget::slotWarpDefaultPointsButtonClicked(bool value) 1203 { 1204 if (m_uiSlotsBlocked) return; 1205 1206 activateCustomWarpPoints(!value); 1207 } 1208 1209 void KisToolTransformConfigWidget::slotWarpCustomPointsButtonClicked(bool value) 1210 { 1211 if (m_uiSlotsBlocked) return; 1212 1213 activateCustomWarpPoints(value); 1214 } 1215 1216 void KisToolTransformConfigWidget::slotWarpResetPointsButtonClicked() 1217 { 1218 if (m_uiSlotsBlocked) return; 1219 1220 activateCustomWarpPoints(true); 1221 } 1222 1223 void KisToolTransformConfigWidget::slotWarpLockPointsButtonClicked() 1224 { 1225 if (m_uiSlotsBlocked) return; 1226 1227 ToolTransformArgs *config = m_transaction->currentConfig(); 1228 config->setEditingTransformPoints(!config->isEditingTransformPoints()); 1229 1230 if (config->isEditingTransformPoints()) { 1231 // reinit the transf points to their original value 1232 ToolTransformArgs *config = m_transaction->currentConfig(); 1233 int nbPoints = config->origPoints().size(); 1234 for (int i = 0; i < nbPoints; ++i) { 1235 config->transfPoint(i) = config->origPoint(i); 1236 } 1237 } 1238 1239 updateLockPointsButtonCaption(); 1240 notifyConfigChanged(); 1241 } 1242 1243 void KisToolTransformConfigWidget::slotWarpTypeChanged(int index) 1244 { 1245 if (m_uiSlotsBlocked) return; 1246 1247 ToolTransformArgs *config = m_transaction->currentConfig(); 1248 1249 switch (index) { 1250 case KisWarpTransformWorker::AFFINE_TRANSFORM: 1251 case KisWarpTransformWorker::SIMILITUDE_TRANSFORM: 1252 case KisWarpTransformWorker::RIGID_TRANSFORM: 1253 config->setWarpType((KisWarpTransformWorker::WarpType)index); 1254 break; 1255 default: 1256 config->setWarpType(KisWarpTransformWorker::RIGID_TRANSFORM); 1257 break; 1258 } 1259 1260 notifyConfigChanged(); 1261 } 1262 1263 void KisToolTransformConfigWidget::slotCageOptionsChanged(int value) 1264 { 1265 if ( value == 0) 1266 { 1267 slotEditCagePoints(true); 1268 } 1269 else 1270 { 1271 slotEditCagePoints(false); 1272 } 1273 1274 notifyEditingFinished(); 1275 } 1276 1277 void KisToolTransformConfigWidget::slotEditCagePoints(bool value) 1278 { 1279 if (m_uiSlotsBlocked) return; 1280 1281 ToolTransformArgs *config = m_transaction->currentConfig(); 1282 config->refTransformedPoints() = config->origPoints(); 1283 1284 config->setEditingTransformPoints(value); 1285 notifyConfigChanged(); 1286 } 1287 1288 void KisToolTransformConfigWidget::slotGranularityChanged(QString value) 1289 { 1290 if (m_uiSlotsBlocked) return; 1291 KIS_SAFE_ASSERT_RECOVER_RETURN(value.toInt() > 1); 1292 ToolTransformArgs *config = m_transaction->currentConfig(); 1293 config->setPixelPrecision(value.toInt()); 1294 notifyConfigChanged(); 1295 } 1296 1297 void KisToolTransformConfigWidget::slotPreviewGranularityChanged(QString value) 1298 { 1299 if (m_uiSlotsBlocked) return; 1300 KIS_SAFE_ASSERT_RECOVER_RETURN(value.toInt() > 1); 1301 ToolTransformArgs *config = m_transaction->currentConfig(); 1302 config->setPreviewPixelPrecision(value.toInt()); 1303 notifyConfigChanged(); 1304 } 1305 1306 void KisToolTransformConfigWidget::slotMeshSizeChanged() 1307 { 1308 if (m_uiSlotsBlocked) return; 1309 1310 ToolTransformArgs *config = m_transaction->currentConfig(); 1311 KisBezierTransformMesh &mesh = *config->meshTransform(); 1312 1313 if (mesh.size().width() != intNumColumns->value() + 1) { 1314 mesh.reshapeMeshHorizontally(intNumColumns->value() + 1); 1315 } 1316 1317 if (mesh.size().height() != intNumRows->value() + 1) { 1318 mesh.reshapeMeshVertically(intNumRows->value() + 1); 1319 } 1320 1321 notifyConfigChanged(); 1322 } 1323 1324 void KisToolTransformConfigWidget::slotMeshShowHandlesChanged() 1325 { 1326 if (m_uiSlotsBlocked) return; 1327 ToolTransformArgs *config = m_transaction->currentConfig(); 1328 config->setMeshShowHandles(this->chkShowControlPoints->isChecked()); 1329 notifyConfigChanged(); 1330 notifyEditingFinished(); 1331 } 1332 1333 void KisToolTransformConfigWidget::slotMeshSymmetricalHandlesChanged() 1334 { 1335 if (m_uiSlotsBlocked) return; 1336 ToolTransformArgs *config = m_transaction->currentConfig(); 1337 config->setMeshSymmetricalHandles(this->chkSymmetricalHandles->isChecked()); 1338 notifyConfigChanged(); 1339 notifyEditingFinished(); 1340 } 1341 1342 void KisToolTransformConfigWidget::slotMeshScaleHandlesChanged() 1343 { 1344 if (m_uiSlotsBlocked) return; 1345 ToolTransformArgs *config = m_transaction->currentConfig(); 1346 config->setMeshScaleHandles(this->chkScaleHandles->isChecked()); 1347 notifyConfigChanged(); 1348 notifyEditingFinished(); 1349 } 1350 1351 void KisToolTransformConfigWidget::slotPreviewChanged(int index) 1352 { 1353 KConfigGroup group = KSharedConfig::openConfig()->group("KisToolTransform"); 1354 switch(index) { 1355 case 0: 1356 group.writeEntry("useOverlayPreviewStyle", false); 1357 group.writeEntry("forceLodMode", false); 1358 break; 1359 case 1: 1360 group.writeEntry("useOverlayPreviewStyle", false); 1361 group.writeEntry("forceLodMode", true); 1362 break; 1363 default: 1364 group.writeEntry("useOverlayPreviewStyle", true); 1365 } 1366 1367 /** 1368 * We don't use global config notifier here, because it 1369 * requires too many updates in the GUI, which can theoretically 1370 * lead to deadlocks 1371 */ 1372 emit sigUpdateGlobalConfig(); 1373 emit sigRestartAndContinueTransform(); 1374 }