Commit c5690b18 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Basic implementation of the Scale Around Pivot Point

This patch implements the basic functionality. You can scale around the
pivot point by:

1) Activating a special button in the Tool Options and dragging the corners
2) Pressing Alt while dragging the corners

Still TODO:
 - changing the values in spinboxes should also handle the anchor

Ref T119
parent cc63ae3a
......@@ -383,15 +383,20 @@ bool KisFreeTransformStrategy::beginPrimaryAction(const QPointF &pt)
return true;
}
void KisFreeTransformStrategy::continuePrimaryAction(const QPointF &mousePos, bool specialModifierActive)
void KisFreeTransformStrategy::continuePrimaryAction(const QPointF &mousePos,
bool shiftModifierActive,
bool altModifierActive)
{
// Note: "specialModifierActive" just tells us if the shift key is being pressed
// Note: "shiftModifierActive" just tells us if the shift key is being pressed
// Note: "altModifierActive" just tells us if the alt key is being pressed
const QPointF anchorPoint = m_d->clickArgs.originalCenter() + m_d->clickArgs.rotationCenterOffset();
switch (m_d->function) {
case MOVE: {
QPointF diff = mousePos - m_d->clickPos;
if (specialModifierActive) {
if (shiftModifierActive) {
KisTransformUtils::MatricesPack m(m_d->clickArgs);
QTransform t = m.S * m.projectedP;
......@@ -426,7 +431,7 @@ void KisFreeTransformStrategy::continuePrimaryAction(const QPointF &mousePos, bo
qreal theta = a2 - a1;
// Snap with shift key
if (specialModifierActive) {
if (shiftModifierActive) {
const qreal snapAngle = M_PI_4 / 6.0; // fifteen degrees
qint32 thetaIndex = static_cast<qint32>((theta / snapAngle) + 0.5);
m_d->currentArgs.setAZ(normalizeAngle(thetaIndex * snapAngle));
......@@ -472,7 +477,6 @@ void KisFreeTransformStrategy::continuePrimaryAction(const QPointF &mousePos, bo
qreal extraSign;
if (m_d->function == TOPSCALE) {
staticPoint = m_d->transaction.originalMiddleBottom();
movingPoint = m_d->transaction.originalMiddleTop();
extraSign = -1.0;
......@@ -482,6 +486,13 @@ void KisFreeTransformStrategy::continuePrimaryAction(const QPointF &mousePos, bo
extraSign = 1.0;
}
// override scale static point if it is locked
if ((m_d->currentArgs.scaleFromRotationCenter() ^ altModifierActive) &&
!qFuzzyCompare(anchorPoint.y(), movingPoint.y())) {
staticPoint = anchorPoint;
}
QPointF mouseImagePos = m_d->transform.inverted().map(mousePos);
qreal sign = mouseImagePos.y() <= staticPoint.y() ? -extraSign : extraSign;
......@@ -498,7 +509,7 @@ void KisFreeTransformStrategy::continuePrimaryAction(const QPointF &mousePos, bo
movingPoint,
dist);
if (specialModifierActive || m_d->currentArgs.keepAspectRatio()) {
if (shiftModifierActive || m_d->currentArgs.keepAspectRatio()) {
qreal aspectRatio = m_d->clickArgs.scaleX() / m_d->clickArgs.scaleY();
m_d->currentArgs.setScaleX(aspectRatio * result.scale);
}
......@@ -525,6 +536,13 @@ void KisFreeTransformStrategy::continuePrimaryAction(const QPointF &mousePos, bo
extraSign = 1.0;
}
// override scale static point if it is locked
if ((m_d->currentArgs.scaleFromRotationCenter() ^ altModifierActive) &&
!qFuzzyCompare(anchorPoint.x(), movingPoint.x())) {
staticPoint = anchorPoint;
}
QPointF mouseImagePos = m_d->transform.inverted().map(mousePos);
qreal sign = mouseImagePos.x() <= staticPoint.x() ? -extraSign : extraSign;
......@@ -541,7 +559,7 @@ void KisFreeTransformStrategy::continuePrimaryAction(const QPointF &mousePos, bo
movingPoint,
dist);
if (specialModifierActive || m_d->currentArgs.keepAspectRatio()) {
if (shiftModifierActive || m_d->currentArgs.keepAspectRatio()) {
qreal aspectRatio = m_d->clickArgs.scaleY() / m_d->clickArgs.scaleX();
m_d->currentArgs.setScaleY(aspectRatio * result.scale);
}
......@@ -571,10 +589,18 @@ void KisFreeTransformStrategy::continuePrimaryAction(const QPointF &mousePos, bo
movingPoint = m_d->transaction.originalBottomLeft();
}
// override scale static point if it is locked
if ((m_d->currentArgs.scaleFromRotationCenter() ^ altModifierActive) &&
!(qFuzzyCompare(anchorPoint.x(), movingPoint.x()) ||
qFuzzyCompare(anchorPoint.y(), movingPoint.y()))) {
staticPoint = anchorPoint;
}
QPointF staticPointInView = m_d->transform.map(staticPoint);
QPointF movingPointInView = mousePos;
if (specialModifierActive || m_d->currentArgs.keepAspectRatio()) {
if (shiftModifierActive || m_d->currentArgs.keepAspectRatio()) {
KisTransformUtils::MatricesPack m(m_d->clickArgs);
QTransform t = m.finalTransform();
......@@ -603,7 +629,7 @@ void KisFreeTransformStrategy::continuePrimaryAction(const QPointF &mousePos, bo
QPointF newRotationCenterOffset = pt - m_d->currentArgs.originalCenter();
if (specialModifierActive) {
if (shiftModifierActive) {
if (qAbs(newRotationCenterOffset.x()) > qAbs(newRotationCenterOffset.y())) {
newRotationCenterOffset.ry() = 0;
} else {
......
......@@ -52,7 +52,7 @@ public:
using KisTransformStrategyBase::endPrimaryAction;
bool beginPrimaryAction(const QPointF &pt);
void continuePrimaryAction(const QPointF &pt, bool specialModifierActve);
void continuePrimaryAction(const QPointF &pt, bool shiftModifierActve, bool altModifierActive);
bool endPrimaryAction();
Q_SIGNALS:
......
......@@ -440,9 +440,10 @@ QPointF toQPointF(const QVector4D &v) {
return v.toVector2DAffine().toPointF();
}
void KisPerspectiveTransformStrategy::continuePrimaryAction(const QPointF &mousePos, bool specialModifierActve)
void KisPerspectiveTransformStrategy::continuePrimaryAction(const QPointF &mousePos, bool shiftModifierActve, bool altModifierActive)
{
Q_UNUSED(specialModifierActve);
Q_UNUSED(shiftModifierActve);
Q_UNUSED(altModifierActive);
switch (m_d->function) {
case NONE:
......
......@@ -52,7 +52,7 @@ public:
using KisTransformStrategyBase::endPrimaryAction;
bool beginPrimaryAction(const QPointF &pt);
void continuePrimaryAction(const QPointF &pt, bool specialModifierActve);
void continuePrimaryAction(const QPointF &pt, bool shiftModifierActve, bool altModifierActive);
bool endPrimaryAction();
Q_SIGNALS:
......
......@@ -94,13 +94,14 @@ void KisSimplifiedActionPolicyStrategy::continuePrimaryAction(KoPointerEvent *ev
* See bug 340496
*/
const bool shiftIsActive = event->modifiers() & Qt::ShiftModifier;
const bool altIsActive = event->modifiers() & Qt::AltModifier;
const QPointF pos =
m_d->snapGuide ?
m_d->snapGuide->snap(event->point, m_d->dragOffset, event->modifiers()) :
event->point;
return continuePrimaryAction(m_d->converter->documentToImage(pos), shiftIsActive);
return continuePrimaryAction(m_d->converter->documentToImage(pos), shiftIsActive, altIsActive);
}
void KisSimplifiedActionPolicyStrategy::hoverActionCommon(KoPointerEvent *event)
......@@ -150,8 +151,9 @@ void KisSimplifiedActionPolicyStrategy::continueAlternateAction(KoPointerEvent *
Q_UNUSED(action);
if (!m_d->changeSizeModifierActive && !m_d->anyPickerModifierActive) return;
const bool altIsActive = event->modifiers() & Qt::AltModifier;
continuePrimaryAction(m_d->converter->documentToImage(event->point), m_d->changeSizeModifierActive);
continuePrimaryAction(m_d->converter->documentToImage(event->point), m_d->changeSizeModifierActive, altIsActive);
}
bool KisSimplifiedActionPolicyStrategy::endAlternateAction(KoPointerEvent *event, KisTool::AlternateAction action)
......
......@@ -53,7 +53,7 @@ protected:
virtual void setTransformFunction(const QPointF &mousePos, bool perspectiveModifierActive) = 0;
virtual bool beginPrimaryAction(const QPointF &pt) = 0;
virtual void continuePrimaryAction(const QPointF &pt, bool specialModifierActve) = 0;
virtual void continuePrimaryAction(const QPointF &pt, bool shiftModifierActve, bool altModifierActive) = 0;
virtual bool endPrimaryAction() = 0;
virtual void hoverActionCommon(const QPointF &pt);
......
......@@ -146,6 +146,7 @@ KisToolTransformConfigWidget::KisToolTransformConfigWidget(TransformTransactionP
connect(m_rotationCenterButtons, SIGNAL(buttonPressed(int)), this, SLOT(slotRotationCenterChanged(int)));
connect(btnScaleFromPivotPoint, SIGNAL(clicked(bool)), this, SLOT(slotScaleFromRotationCenter(bool)));
// Init Free Transform Values
connect(scaleXBox, SIGNAL(valueChanged(int)), this, SLOT(slotSetScaleX(int)));
......@@ -322,6 +323,9 @@ void KisToolTransformConfigWidget::slotUpdateIcons()
middleBottomButton->setIcon(KisIconUtils::loadIcon("arrow-down"));
bottomRightButton->setIcon(KisIconUtils::loadIcon("arrow-downright"));
// TODO: change the icon!
btnScaleFromPivotPoint->setIcon(KisIconUtils::loadIcon("transform_icons_liquify_main"));
// pressure icons
liquifySizePressureBox->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure"));
......@@ -571,6 +575,9 @@ void KisToolTransformConfigWidget::updateConfig(const ToolTransformArgs &config)
break;
}
}
btnScaleFromPivotPoint->setChecked(config.scaleFromRotationCenter());
} else if (config.mode() == ToolTransformArgs::WARP) {
stackedWidget->setCurrentIndex(1);
......@@ -841,6 +848,16 @@ void KisToolTransformConfigWidget::slotRotationCenterChanged(int index)
}
}
void KisToolTransformConfigWidget::slotScaleFromRotationCenter(bool value)
{
if (m_uiSlotsBlocked) return;
ToolTransformArgs *config = m_transaction->currentConfig();
config->setScaleFromRotationCenter(value);
notifyConfigChanged();
notifyEditingFinished();
}
void KisToolTransformConfigWidget::slotSetScaleX(int value)
{
if (m_uiSlotsBlocked) return;
......
......@@ -56,6 +56,7 @@ public Q_SLOTS:
void slotFilterChanged(const KoID &filter);
void slotWarpTypeChanged(int index);
void slotRotationCenterChanged(int index);
void slotScaleFromRotationCenter(bool value);
void slotSetScaleX(int value);
void slotSetScaleY(int value);
......
......@@ -406,9 +406,10 @@ QVector<QPointF*> KisWarpTransformStrategy::Private::getSelectedPoints(QPointF *
return selectedPoints;
}
void KisWarpTransformStrategy::continuePrimaryAction(const QPointF &pt, bool specialModifierActve)
void KisWarpTransformStrategy::continuePrimaryAction(const QPointF &pt, bool shiftModifierActve, bool altModifierActive)
{
Q_UNUSED(specialModifierActve);
Q_UNUSED(shiftModifierActve);
Q_UNUSED(altModifierActive);
// toplevel code switches to HOVER mode if nothing is selected
KIS_ASSERT_RECOVER_RETURN(m_d->mode == Private::MOVE_MODE ||
......
......@@ -53,7 +53,7 @@ public:
using KisTransformStrategyBase::endPrimaryAction;
bool beginPrimaryAction(const QPointF &pt);
void continuePrimaryAction(const QPointF &pt, bool specialModifierActve);
void continuePrimaryAction(const QPointF &pt, bool shiftModifierActve, bool altModifierActive);
bool endPrimaryAction();
bool acceptsClicks() const;
......
......@@ -55,6 +55,7 @@ ToolTransformArgs::ToolTransformArgs()
KConfigGroup configGroup = KSharedConfig::openConfig()->group("KisToolTransform");
QString savedFilterId = configGroup.readEntry("filterId", "Bicubic");
setFilterId(savedFilterId);
m_scaleFromRotationCenter = configGroup.readEntry("scaleFromRotationCenter", "0").toInt();
m_editTransformPoints = false;
}
......@@ -68,12 +69,21 @@ void ToolTransformArgs::setFilterId(const QString &id) {
}
}
void ToolTransformArgs::setScaleFromRotationCenter(bool value)
{
m_scaleFromRotationCenter = value;
KConfigGroup configGroup = KSharedConfig::openConfig()->group("KisToolTransform");
configGroup.writeEntry("scaleFromRotationCenter", int(value));
}
void ToolTransformArgs::init(const ToolTransformArgs& args)
{
m_mode = args.mode();
m_transformedCenter = args.transformedCenter();
m_originalCenter = args.originalCenter();
m_rotationCenterOffset = args.rotationCenterOffset();
m_scaleFromRotationCenter = args.scaleFromRotationCenter();
m_cameraPos = args.m_cameraPos;
m_aX = args.aX();
m_aY = args.aY();
......@@ -133,6 +143,7 @@ bool ToolTransformArgs::operator==(const ToolTransformArgs& other) const
m_transformedCenter == other.m_transformedCenter &&
m_originalCenter == other.m_originalCenter &&
m_rotationCenterOffset == other.m_rotationCenterOffset &&
m_scaleFromRotationCenter == other.m_scaleFromRotationCenter &&
m_aX == other.m_aX &&
m_aY == other.m_aY &&
m_aZ == other.m_aZ &&
......@@ -209,6 +220,7 @@ ToolTransformArgs::ToolTransformArgs(TransformMode mode,
QPointF transformedCenter,
QPointF originalCenter,
QPointF rotationCenterOffset,
bool scaleFromRotationCenter,
double aX, double aY, double aZ,
double scaleX, double scaleY,
double shearX, double shearY,
......@@ -222,6 +234,7 @@ ToolTransformArgs::ToolTransformArgs(TransformMode mode,
m_transformedCenter = transformedCenter;
m_originalCenter = originalCenter;
m_rotationCenterOffset = rotationCenterOffset;
m_scaleFromRotationCenter = scaleFromRotationCenter;
m_cameraPos = QVector3D(0,0,1024);
m_aX = aX;
m_aY = aY;
......@@ -318,6 +331,7 @@ void ToolTransformArgs::toXML(QDomElement *e) const
KisDomUtils::saveValue(&freeEl, "transformedCenter", m_transformedCenter);
KisDomUtils::saveValue(&freeEl, "originalCenter", m_originalCenter);
KisDomUtils::saveValue(&freeEl, "rotationCenterOffset", m_rotationCenterOffset);
KisDomUtils::saveValue(&freeEl, "scaleFromRotationCenter", m_scaleFromRotationCenter);
KisDomUtils::saveValue(&freeEl, "aX", m_aX);
KisDomUtils::saveValue(&freeEl, "aY", m_aY);
......@@ -386,6 +400,7 @@ ToolTransformArgs ToolTransformArgs::fromXML(const QDomElement &e)
KisDomUtils::loadValue(freeEl, "transformedCenter", &args.m_transformedCenter) &&
KisDomUtils::loadValue(freeEl, "originalCenter", &args.m_originalCenter) &&
KisDomUtils::loadValue(freeEl, "rotationCenterOffset", &args.m_rotationCenterOffset) &&
KisDomUtils::loadValue(freeEl, "scaleFromRotationCenter", &args.m_scaleFromRotationCenter) &&
KisDomUtils::loadValue(freeEl, "aX", &args.m_aX) &&
KisDomUtils::loadValue(freeEl, "aY", &args.m_aY) &&
......
......@@ -69,7 +69,7 @@ public:
ToolTransformArgs(TransformMode mode,
QPointF transformedCenter,
QPointF originalCenter,
QPointF rotationCenterOffset,
QPointF rotationCenterOffset, bool scaleFromRotationCenter,
double aX, double aY, double aZ,
double scaleX, double scaleY,
double shearX, double shearY,
......@@ -148,6 +148,9 @@ public:
inline QPointF rotationCenterOffset() const {
return m_rotationCenterOffset;
}
inline bool scaleFromRotationCenter() const {
return m_scaleFromRotationCenter;
}
inline double aX() const {
return m_aX;
}
......@@ -185,6 +188,7 @@ public:
inline void setRotationCenterOffset(QPointF rotationCenterOffset) {
m_rotationCenterOffset = rotationCenterOffset;
}
void setScaleFromRotationCenter(bool value);
inline void setAX(double aX) {
KIS_ASSERT_RECOVER_NOOP(aX == normalizeAngle(aX));
m_aX = aX;
......@@ -289,6 +293,9 @@ private:
QPointF m_rotationCenterOffset; // the position of the rotation center relative to
// the original top left corner of the selection
// before any transformation
bool m_scaleFromRotationCenter; // In freehand mode makes the scaling be anchored to
// the rotation center point.
double m_aX;
double m_aY;
double m_aZ;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment