diff --git a/libs/ui/CMakeLists.txt b/libs/ui/CMakeLists.txt --- a/libs/ui/CMakeLists.txt +++ b/libs/ui/CMakeLists.txt @@ -43,7 +43,8 @@ canvas/kis_snap_config.cpp canvas/kis_snap_line_strategy.cpp canvas/KisSnapPointStrategy.cpp - dialogs/kis_about_application.cpp + canvas/KisMirrorAxisConfig.cpp + dialogs/kis_about_application.cpp dialogs/kis_dlg_adj_layer_props.cc dialogs/kis_dlg_adjustment_layer.cc dialogs/kis_dlg_filter.cpp diff --git a/libs/ui/KisDocument.h b/libs/ui/KisDocument.h --- a/libs/ui/KisDocument.h +++ b/libs/ui/KisDocument.h @@ -64,6 +64,7 @@ class KisPart; class KisGridConfig; class KisGuidesConfig; +class KisMirrorAxisConfig; class QDomDocument; class KisReferenceImagesLayer; @@ -350,6 +351,9 @@ const KisGuidesConfig& guidesConfig() const; void setGuidesConfig(const KisGuidesConfig &data); + const KisMirrorAxisConfig& mirrorAxisConfig() const; + void setMirrorAxisConfig(const KisMirrorAxisConfig& config); + QList &paletteList(); void setPaletteList(const QList &paletteList); @@ -452,6 +456,8 @@ void sigReferenceImagesChanged(); + void sigMirrorAxisConfigChanged(); + private Q_SLOTS: void finishExportInBackground(); void slotChildCompletedSavingInBackground(KisImportExportFilter::ConversionStatus status, const QString &errorMessage); diff --git a/libs/ui/KisDocument.cpp b/libs/ui/KisDocument.cpp --- a/libs/ui/KisDocument.cpp +++ b/libs/ui/KisDocument.cpp @@ -121,6 +121,8 @@ #include "kis_async_action_feedback.h" #include "KisCloneDocumentStroke.h" +#include + // Define the protocol used here for embedded documents' URL // This used to "store" but QUrl didn't like it, @@ -256,6 +258,7 @@ , autoSaveTimer(new QTimer(q)) , undoStack(new UndoStack(q)) , guidesConfig(rhs.guidesConfig) + , mirrorAxisConfig(rhs.mirrorAxisConfig) , m_bAutoDetectedMime(rhs.m_bAutoDetectedMime) , m_url(rhs.m_url) , m_file(rhs.m_file) @@ -302,6 +305,7 @@ KUndo2Stack *undoStack = 0; KisGuidesConfig guidesConfig; + KisMirrorAxisConfig mirrorAxisConfig; bool m_bAutoDetectedMime = false; // whether the mimetype in the arguments was detected by the part itself QUrl m_url; // local url - the one displayed to the user. @@ -1585,6 +1589,23 @@ emit sigGuidesConfigChanged(d->guidesConfig); } +const KisMirrorAxisConfig& KisDocument::mirrorAxisConfig() const +{ + return d->mirrorAxisConfig; +} + +void KisDocument::setMirrorAxisConfig(const KisMirrorAxisConfig &config) +{ + if (d->mirrorAxisConfig == config) { + return; + } + + d->mirrorAxisConfig = config; + setModified(true); + + emit sigMirrorAxisConfigChanged(); +} + void KisDocument::resetURL() { setUrl(QUrl()); setLocalFilePath(QString()); diff --git a/libs/ui/canvas/KisMirrorAxisConfig.h b/libs/ui/canvas/KisMirrorAxisConfig.h new file mode 100644 --- /dev/null +++ b/libs/ui/canvas/KisMirrorAxisConfig.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#ifndef KISMIRRORAXISCONFIG_H +#define KISMIRRORAXISCONFIG_H + +#include + +#include "kritaui_export.h" +#include + +class QDomElement; +class QDomDocument; + +/** + * @brief The KisMirrorAxisConfig class stores configuration for the KisMirrorAxis + * canvas decoration. Contents are saved to/loaded from KRA documents. + */ + +class KRITAUI_EXPORT KisMirrorAxisConfig : public QObject, boost::equality_comparable +{ + Q_OBJECT + +public: + KisMirrorAxisConfig(); + ~KisMirrorAxisConfig(); + + KisMirrorAxisConfig(const KisMirrorAxisConfig &rhs); + KisMirrorAxisConfig& operator=(const KisMirrorAxisConfig& rhs); + bool operator==(const KisMirrorAxisConfig& rhs) const; + + bool mirrorHorizontal(); + void setMirrorHorizontal(bool state); + + bool mirrorVertical(); + void setMirrorVertical(bool state); + + bool lockHorizontal(); + void setLockHorizontal(bool state); + + bool lockVertical(); + void setLockVertical(bool state); + + bool hideVerticalDecoration(); + void setHideVerticalDecoration(bool state); + + bool hideHorizontalDecoration(); + void setHideHorizontalDecoration(bool state); + + float handleSize(); + void setHandleSize(float size); + + float horizontalHandlePosition(); + void setHorizontalHandlePosition(float position); + + float verticalHandlePosition(); + void setVerticalHandlePosition(float position); + + QPointF axisPosition(); + void setAxisPosition(QPointF position); + + /** + * @brief saveToXml() function for KisKraSaver + * @param doc + * @param tag + * @return + */ + QDomElement saveToXml(QDomDocument& doc, const QString &tag) const; + + /** + * @brief loadFromXml() function for KisKraLoader + * @param parent element + * @return + */ + bool loadFromXml(const QDomElement &parent); + + /** + * @brief Check whether the config object was changed, or is the class default. + * @return true, if the object is default; false, if the config was changed + */ + bool isDefault() const; + +private: + class Private; + const QScopedPointer d; +}; + +#endif // KISMIRRORAXISCONFIG_H diff --git a/libs/ui/canvas/KisMirrorAxisConfig.cpp b/libs/ui/canvas/KisMirrorAxisConfig.cpp new file mode 100644 --- /dev/null +++ b/libs/ui/canvas/KisMirrorAxisConfig.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2019 Anna Medonosova + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "KisMirrorAxisConfig.h" + + +class Q_DECL_HIDDEN KisMirrorAxisConfig::Private +{ +public: + Private() + : mirrorHorizontal(false) + , mirrorVertical(false) + , lockHorizontal(false) + , lockVertical(false) + , hideVerticalDecoration(false) + , hideHorizontalDecoration(false) + , handleSize(32.f) + , horizontalHandlePosition(64.f) + , verticalHandlePosition(64.f) + {} + + bool operator==(const Private& rhs) { + return mirrorHorizontal == rhs.mirrorHorizontal && + mirrorVertical == rhs.mirrorVertical && + lockHorizontal == rhs.lockHorizontal && + lockVertical == rhs.lockVertical && + hideHorizontalDecoration == rhs.hideHorizontalDecoration && + hideVerticalDecoration == rhs.hideVerticalDecoration && + handleSize == rhs.handleSize && + horizontalHandlePosition == rhs.horizontalHandlePosition && + verticalHandlePosition == rhs.verticalHandlePosition && + axisPosition == rhs.axisPosition; + } + + bool mirrorHorizontal; + bool mirrorVertical; + bool lockHorizontal; + bool lockVertical; + bool hideVerticalDecoration; + bool hideHorizontalDecoration; + + float handleSize; + float horizontalHandlePosition; + float verticalHandlePosition; + + QPointF axisPosition; +}; + + +KisMirrorAxisConfig::KisMirrorAxisConfig() + : QObject() + , d(new Private()) +{ + +} + +KisMirrorAxisConfig::~KisMirrorAxisConfig() +{ + +} + +KisMirrorAxisConfig::KisMirrorAxisConfig(const KisMirrorAxisConfig &rhs) + : QObject() + , d(new Private(*rhs.d)) +{ + +} + +KisMirrorAxisConfig &KisMirrorAxisConfig::operator=(const KisMirrorAxisConfig &rhs) +{ + if (&rhs != this) { + *d = *rhs.d; + } + + return *this; +} + +bool KisMirrorAxisConfig::operator==(const KisMirrorAxisConfig &rhs) const +{ + return *d == *rhs.d; +} + +bool KisMirrorAxisConfig::mirrorHorizontal() +{ + return d->mirrorHorizontal; +} + +void KisMirrorAxisConfig::setMirrorHorizontal(bool state) +{ + d->mirrorHorizontal = state; +} + +bool KisMirrorAxisConfig::mirrorVertical() +{ + return d->mirrorVertical; +} + +void KisMirrorAxisConfig::setMirrorVertical(bool state) +{ + d->mirrorVertical = state; +} + +bool KisMirrorAxisConfig::lockHorizontal() +{ + return d->lockHorizontal; +} + +void KisMirrorAxisConfig::setLockHorizontal(bool state) +{ + d->lockHorizontal = state; +} + +bool KisMirrorAxisConfig::lockVertical() +{ + return d->lockVertical; +} + +void KisMirrorAxisConfig::setLockVertical(bool state) +{ + d->lockVertical = state; +} + +bool KisMirrorAxisConfig::hideVerticalDecoration() +{ + return d->hideVerticalDecoration; +} + +void KisMirrorAxisConfig::setHideVerticalDecoration(bool state) +{ + d->hideVerticalDecoration = state; +} + +bool KisMirrorAxisConfig::hideHorizontalDecoration() +{ + return d->hideHorizontalDecoration; +} + +void KisMirrorAxisConfig::setHideHorizontalDecoration(bool state) +{ + d->hideHorizontalDecoration = state; +} + +float KisMirrorAxisConfig::handleSize() +{ + return d->handleSize; +} + +void KisMirrorAxisConfig::setHandleSize(float size) +{ + d->handleSize = size; +} + +float KisMirrorAxisConfig::horizontalHandlePosition() +{ + return d->horizontalHandlePosition; +} + +void KisMirrorAxisConfig::setHorizontalHandlePosition(float position) +{ + d->horizontalHandlePosition = position; +} + +float KisMirrorAxisConfig::verticalHandlePosition() +{ + return d->verticalHandlePosition; +} + +void KisMirrorAxisConfig::setVerticalHandlePosition(float position) +{ + d->verticalHandlePosition = position; +} + +QPointF KisMirrorAxisConfig::axisPosition() +{ + return d->axisPosition; +} + +void KisMirrorAxisConfig::setAxisPosition(QPointF position) +{ + d->axisPosition = position; +} + +QDomElement KisMirrorAxisConfig::saveToXml(QDomDocument &doc, const QString &tag) const +{ + QDomElement mirrorAxisElement = doc.createElement(tag); + KisDomUtils::saveValue(&mirrorAxisElement, "mirrorHorizontal", d->mirrorHorizontal); + KisDomUtils::saveValue(&mirrorAxisElement, "mirrorVertical", d->mirrorVertical); + KisDomUtils::saveValue(&mirrorAxisElement, "lockHorizontal", d->lockHorizontal); + KisDomUtils::saveValue(&mirrorAxisElement, "lockVertical", d->lockVertical); + + KisDomUtils::saveValue(&mirrorAxisElement, "hideHorizontalDecoration", d->hideHorizontalDecoration); + KisDomUtils::saveValue(&mirrorAxisElement, "hideVerticalDecoration", d->hideVerticalDecoration); + + KisDomUtils::saveValue(&mirrorAxisElement, "handleSize", d->handleSize); + + KisDomUtils::saveValue(&mirrorAxisElement, "horizontalHandlePosition", d->horizontalHandlePosition); + KisDomUtils::saveValue(&mirrorAxisElement, "verticalHandlePosition", d->verticalHandlePosition); + + KisDomUtils::saveValue(&mirrorAxisElement, "axisPosition", d->axisPosition); + + return mirrorAxisElement; +} + +bool KisMirrorAxisConfig::loadFromXml(const QDomElement &parent) +{ + bool result = true; + + result &= KisDomUtils::loadValue(parent, "mirrorHorizontal", &d->mirrorHorizontal); + result &= KisDomUtils::loadValue(parent, "mirrorVertical", &d->mirrorVertical); + result &= KisDomUtils::loadValue(parent, "lockHorizontal", &d->lockHorizontal); + result &= KisDomUtils::loadValue(parent, "lockVertical", &d->lockVertical); + + result &= KisDomUtils::loadValue(parent, "hideHorizontalDecoration", &d->hideHorizontalDecoration); + result &= KisDomUtils::loadValue(parent, "hideVerticalDecoration", &d->hideVerticalDecoration); + + result &= KisDomUtils::loadValue(parent, "handleSize", &d->handleSize); + + result &= KisDomUtils::loadValue(parent, "horizontalHandlePosition", &d->horizontalHandlePosition); + result &= KisDomUtils::loadValue(parent, "verticalHandlePosition", &d->verticalHandlePosition); + result &= KisDomUtils::loadValue(parent, "axisPosition", &d->axisPosition); + + return result; +} + +bool KisMirrorAxisConfig::isDefault() const +{ + KisMirrorAxisConfig defaultConfig; + return *this == defaultConfig; +} diff --git a/libs/ui/canvas/kis_mirror_axis.h b/libs/ui/canvas/kis_mirror_axis.h --- a/libs/ui/canvas/kis_mirror_axis.h +++ b/libs/ui/canvas/kis_mirror_axis.h @@ -24,6 +24,7 @@ class KisView; class KisCanvasResourceProvider; +class KisMirrorAxisConfig; class KisMirrorAxis : public KisCanvasDecoration { @@ -38,12 +39,17 @@ void setHandleSize(float newSize); void setVisible(bool v) override; + void setMirrorAxisConfig(const KisMirrorAxisConfig& config); + const KisMirrorAxisConfig& mirrorAxisConfig() const; + Q_SIGNALS: void handleSizeChanged(); + void sigConfigChanged(); protected: void drawDecoration(QPainter& gc, const QRectF& updateArea, const KisCoordinatesConverter* converter, KisCanvas2* canvas) override; bool eventFilter(QObject* target, QEvent* event) override; + void toggleMirrorActions(); private: class Private; diff --git a/libs/ui/canvas/kis_mirror_axis.cpp b/libs/ui/canvas/kis_mirror_axis.cpp --- a/libs/ui/canvas/kis_mirror_axis.cpp +++ b/libs/ui/canvas/kis_mirror_axis.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -39,29 +40,25 @@ #include "input/kis_input_manager.h" #include "kis_algebra_2d.h" +#include +#include +#include + class KisMirrorAxis::Private { public: Private(KisMirrorAxis* qq) : q(qq) , resourceProvider(0) - , mirrorHorizontal(false) - , mirrorVertical(false) - , lockHorizontal(false) - , lockVertical(false) - , hideVerticalDecoration(false) - , hideHorizontalDecoration(false) - , handleSize(32.f) , xActive(false) , yActive(false) - , horizontalHandlePosition(64.f) - , verticalHandlePosition(64.f) , sideMargin(10.f) , minHandlePosition(10.f + 32.f) , horizontalContainsCursor(false) , verticalContainsCursor(false) , horizontalAxis(QLineF()) , verticalAxis(QLineF()) + , config(KisMirrorAxisConfig()) { } void setAxisPosition(float x, float y); @@ -71,35 +68,26 @@ KisCanvasResourceProvider* resourceProvider; KisImageWSP image; - bool mirrorHorizontal; - bool mirrorVertical; - - bool lockHorizontal; - bool lockVertical; - bool hideVerticalDecoration; - bool hideHorizontalDecoration; - - - float handleSize; QPixmap horizontalHandleIcon; QPixmap verticalHandleIcon; QPixmap horizontalIcon; QPixmap verticalIcon; - QPointF axisPosition; + QRectF horizontalHandle; QRectF verticalHandle; bool xActive; bool yActive; - float horizontalHandlePosition; - float verticalHandlePosition; + float sideMargin; float minHandlePosition; bool horizontalContainsCursor; bool verticalContainsCursor; QLineF horizontalAxis; QLineF verticalAxis; + + KisMirrorAxisConfig config; }; KisMirrorAxis::KisMirrorAxis(KisCanvasResourceProvider* provider, QPointerparent) @@ -111,14 +99,13 @@ connect(d->resourceProvider, SIGNAL(moveMirrorVerticalCenter()), SLOT(moveVerticalAxisToCenter())); connect(d->resourceProvider, SIGNAL(moveMirrorHorizontalCenter()), SLOT(moveHorizontalAxisToCenter())); - d->mirrorHorizontal = d->resourceProvider->mirrorHorizontal(); - d->mirrorVertical = d->resourceProvider->mirrorVertical(); - d->horizontalIcon = KisIconUtils::loadIcon("mirrorAxis-HorizontalMove").pixmap(d->handleSize, QIcon::Normal, QIcon::On); - d->verticalIcon = KisIconUtils::loadIcon("mirrorAxis-VerticalMove").pixmap(d->handleSize, QIcon::Normal, QIcon::On); - d->horizontalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->handleSize, QIcon::Normal, QIcon::On); - d->verticalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->handleSize, QIcon::Normal, QIcon::On); - setVisible(d->mirrorHorizontal || d->mirrorVertical); - + d->config.setMirrorHorizontal(d->resourceProvider->mirrorHorizontal()); + d->config.setMirrorVertical(d->resourceProvider->mirrorVertical()); + d->horizontalIcon = KisIconUtils::loadIcon("mirrorAxis-HorizontalMove").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); + d->verticalIcon = KisIconUtils::loadIcon("mirrorAxis-VerticalMove").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); + d->horizontalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); + d->verticalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); + setVisible(d->config.mirrorHorizontal() || d->config.mirrorVertical()); d->image = parent->canvasBase()->image(); } @@ -130,19 +117,20 @@ float KisMirrorAxis::handleSize() const { - return d->handleSize; + return d->config.handleSize(); } void KisMirrorAxis::setHandleSize(float newSize) { - if(d->handleSize != newSize) { - d->handleSize = newSize; - d->horizontalIcon = KisIconUtils::loadIcon("symmetry-horyzontal").pixmap(d->handleSize, QIcon::Normal, QIcon::On); - d->verticalIcon = KisIconUtils::loadIcon("symmetry-vertical").pixmap(d->handleSize, QIcon::Normal, QIcon::On); - d->horizontalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->handleSize, QIcon::Normal, QIcon::On); - d->verticalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->handleSize, QIcon::Normal, QIcon::On); + if(d->config.handleSize() != newSize) { + d->config.setHandleSize(newSize); + d->horizontalIcon = KisIconUtils::loadIcon("symmetry-horyzontal").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); + d->verticalIcon = KisIconUtils::loadIcon("symmetry-vertical").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); + d->horizontalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); + d->verticalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->config.handleSize(), QIcon::Normal, QIcon::On); d->minHandlePosition = d->sideMargin + newSize; emit handleSizeChanged(); + emit sigConfigChanged(); } } @@ -152,6 +140,10 @@ Q_UNUSED(converter); Q_UNUSED(canvas); + if (!view()->isCurrent()) { + return; + } + gc.save(); gc.setPen(QPen(QColor(0, 0, 0, 128), 1)); gc.setBrush(Qt::white); @@ -169,27 +161,27 @@ gc.endNativePainting(); } - float halfHandleSize = d->handleSize / 2; + float halfHandleSize = d->config.handleSize() / 2; d->recomputeVisibleAxes(gc.viewport()); - if(d->mirrorHorizontal && !d->hideHorizontalDecoration) { + if(d->config.mirrorHorizontal() && !d->config.hideHorizontalDecoration()) { if (!d->horizontalAxis.isNull()) { // QPointF horizontalIndicatorCenter = d->horizontalAxis.unitVector().pointAt(15); - // QRectF horizontalIndicator = QRectF(horizontalIndicatorCenter.x() - halfHandleSize, horizontalIndicatorCenter.y() - halfHandleSize, d->handleSize, d->handleSize); + // QRectF horizontalIndicator = QRectF(horizontalIndicatorCenter.x() - halfHandleSize, horizontalIndicatorCenter.y() - halfHandleSize, d->config.handleSize(), d->config.handleSize()); - float horizontalHandlePosition = qBound(d->minHandlePosition, d->horizontalHandlePosition, d->horizontalAxis.length() - d->minHandlePosition); + float horizontalHandlePosition = qBound(d->minHandlePosition, d->config.horizontalHandlePosition(), d->horizontalAxis.length() - d->minHandlePosition); QPointF horizontalHandleCenter = d->horizontalAxis.unitVector().pointAt(horizontalHandlePosition); - d->horizontalHandle = QRectF(horizontalHandleCenter.x() - halfHandleSize, horizontalHandleCenter.y() - halfHandleSize, d->handleSize, d->handleSize); + d->horizontalHandle = QRectF(horizontalHandleCenter.x() - halfHandleSize, horizontalHandleCenter.y() - halfHandleSize, d->config.handleSize(), d->config.handleSize()); gc.setPen(QPen(QColor(0, 0, 0, 64), 2, Qt::DashDotDotLine, Qt::RoundCap, Qt::RoundJoin)); gc.drawLine(d->horizontalAxis); // gc.drawEllipse(horizontalIndicator); // gc.drawPixmap(horizontalIndicator.adjusted(5, 5, -5, -5).toRect(), d->horizontalIcon); // don't draw the handles if we are locking the axis for movement - if (!d->lockHorizontal) { + if (!d->config.lockHorizontal()) { gc.setPen(QPen(QColor(0, 0, 0, 128), 2)); gc.drawEllipse(d->horizontalHandle); gc.drawPixmap(d->horizontalHandle.adjusted(5, 5, -5, -5).toRect(), d->horizontalIcon); @@ -200,22 +192,22 @@ } } - if(d->mirrorVertical && !d->hideVerticalDecoration) { + if(d->config.mirrorVertical() && !d->config.hideVerticalDecoration()) { if (!d->verticalAxis.isNull()) { gc.setPen(QPen(QColor(0, 0, 0, 64), 2, Qt::DashDotDotLine, Qt::RoundCap, Qt::RoundJoin)); gc.drawLine(d->verticalAxis); // QPointF verticalIndicatorCenter = d->verticalAxis.unitVector().pointAt(15); - // QRectF verticalIndicator = QRectF(verticalIndicatorCenter.x() - halfHandleSize, verticalIndicatorCenter.y() - halfHandleSize, d->handleSize, d->handleSize); + // QRectF verticalIndicator = QRectF(verticalIndicatorCenter.x() - halfHandleSize, verticalIndicatorCenter.y() - halfHandleSize, d->config.handleSize(), d->config.handleSize()); - float verticalHandlePosition = qBound(d->minHandlePosition, d->verticalHandlePosition, d->verticalAxis.length() - d->minHandlePosition); + float verticalHandlePosition = qBound(d->minHandlePosition, d->config.verticalHandlePosition(), d->verticalAxis.length() - d->minHandlePosition); QPointF verticalHandleCenter = d->verticalAxis.unitVector().pointAt(verticalHandlePosition); - d->verticalHandle = QRectF(verticalHandleCenter.x() - halfHandleSize, verticalHandleCenter.y() - halfHandleSize, d->handleSize, d->handleSize); + d->verticalHandle = QRectF(verticalHandleCenter.x() - halfHandleSize, verticalHandleCenter.y() - halfHandleSize, d->config.handleSize(), d->config.handleSize()); // don't draw the handles if we are locking the axis for movement - if (!d->lockVertical) { + if (!d->config.lockVertical()) { gc.setPen(QPen(QColor(0, 0, 0, 128), 2)); gc.drawEllipse(d->verticalHandle); gc.drawPixmap(d->verticalHandle.adjusted(5, 5, -5, -5).toRect(), d->verticalIcon); @@ -250,17 +242,14 @@ QTabletEvent *te = dynamic_cast(event); QPoint pos = me ? me->pos() : (te ? te->pos() : QPoint(77,77)); - - - - if(d->mirrorHorizontal && d->horizontalHandle.contains(pos) && !d->lockHorizontal && !d->hideHorizontalDecoration ) { + if(d->config.mirrorHorizontal() && d->horizontalHandle.contains(pos) && !d->config.lockHorizontal() && !d->config.hideHorizontalDecoration() ) { d->xActive = true; QApplication::setOverrideCursor(Qt::ClosedHandCursor); event->accept(); return true; } - if(d->mirrorVertical && d->verticalHandle.contains(pos) && !d->lockVertical && !d->hideVerticalDecoration) { + if(d->config.mirrorVertical() && d->verticalHandle.contains(pos) && !d->config.lockVertical() && !d->config.hideVerticalDecoration()) { d->yActive = true; QApplication::setOverrideCursor(Qt::ClosedHandCursor); event->accept(); @@ -276,23 +265,25 @@ if(d->xActive) { float axisX = view()->viewConverter()->widgetToImage(pos).x(); - d->setAxisPosition(axisX, d->axisPosition.y()); - d->horizontalHandlePosition = KisAlgebra2D::dotProduct(pos - d->horizontalAxis.p1(), d->horizontalAxis.unitVector().p2() - d->horizontalAxis.p1()); + d->setAxisPosition(axisX, d->config.axisPosition().y()); + d->config.setHorizontalHandlePosition(KisAlgebra2D::dotProduct(pos - d->horizontalAxis.p1(), d->horizontalAxis.unitVector().p2() - d->horizontalAxis.p1())); + emit sigConfigChanged(); event->accept(); return true; } if(d->yActive) { float axisY = view()->viewConverter()->widgetToImage(pos).y(); - d->setAxisPosition(d->axisPosition.x(), axisY); - d->verticalHandlePosition = KisAlgebra2D::dotProduct(pos - d->verticalAxis.p1(), d->verticalAxis.unitVector().p2() - d->verticalAxis.p1()); + d->setAxisPosition(d->config.axisPosition().x(), axisY); + d->config.setVerticalHandlePosition(KisAlgebra2D::dotProduct(pos - d->verticalAxis.p1(), d->verticalAxis.unitVector().p2() - d->verticalAxis.p1())); + emit sigConfigChanged(); event->accept(); return true; } - if(d->mirrorHorizontal && !d->hideHorizontalDecoration) { - if(d->horizontalHandle.contains(pos) && !d->lockHorizontal) { + if(d->config.mirrorHorizontal() && !d->config.hideHorizontalDecoration()) { + if(d->horizontalHandle.contains(pos) && !d->config.lockHorizontal()) { if(!d->horizontalContainsCursor) { QApplication::setOverrideCursor(Qt::OpenHandCursor); d->horizontalContainsCursor = true; @@ -302,8 +293,8 @@ d->horizontalContainsCursor = false; } } - if(d->mirrorVertical && !d->hideVerticalDecoration) { - if(d->verticalHandle.contains(pos) && !d->lockVertical) { + if(d->config.mirrorVertical() && !d->config.hideVerticalDecoration()) { + if(d->verticalHandle.contains(pos) && !d->config.lockVertical()) { if(!d->verticalContainsCursor) { QApplication::setOverrideCursor(Qt::OpenHandCursor); d->verticalContainsCursor = true; @@ -335,17 +326,22 @@ void KisMirrorAxis::mirrorModeChanged() { - d->mirrorHorizontal = d->resourceProvider->mirrorHorizontal(); - d->mirrorVertical = d->resourceProvider->mirrorVertical(); + if (!view()->isCurrent()) { + return; + } - d->lockHorizontal = d->resourceProvider->mirrorHorizontalLock(); - d->lockVertical = d->resourceProvider->mirrorVerticalLock(); + d->config.setMirrorHorizontal(d->resourceProvider->mirrorHorizontal()); + d->config.setMirrorVertical(d->resourceProvider->mirrorVertical()); - d->hideHorizontalDecoration = d->resourceProvider->mirrorHorizontalHideDecorations(); - d->hideVerticalDecoration = d->resourceProvider->mirrorVerticalHideDecorations(); + d->config.setLockHorizontal(d->resourceProvider->mirrorHorizontalLock()); + d->config.setLockVertical(d->resourceProvider->mirrorVerticalLock()); - setVisible(d->mirrorHorizontal || d->mirrorVertical); + d->config.setHideHorizontalDecoration(d->resourceProvider->mirrorHorizontalHideDecorations()); + d->config.setHideVerticalDecoration(d->resourceProvider->mirrorVerticalHideDecorations()); + setVisible(d->config.mirrorHorizontal() || d->config.mirrorVertical()); + + emit sigConfigChanged(); } void KisMirrorAxis::setVisible(bool v) @@ -363,21 +359,88 @@ } } +void KisMirrorAxis::setMirrorAxisConfig(const KisMirrorAxisConfig &config) +{ + if (config != d->config) { + KisSignalsBlocker blocker(d->resourceProvider); + + d->config = config; + + d->setAxisPosition(d->config.axisPosition().x(), d->config.axisPosition().y()); + + d->resourceProvider->setMirrorHorizontal(d->config.mirrorHorizontal()); + d->resourceProvider->setMirrorVertical(d->config.mirrorVertical()); + + d->resourceProvider->setMirrorHorizontalLock(d->config.lockHorizontal()); + d->resourceProvider->setMirrorVerticalLock(d->config.lockVertical()); + + d->resourceProvider->setMirrorHorizontal(d->config.mirrorHorizontal()); + d->resourceProvider->setMirrorVertical(d->config.mirrorVertical()); + + d->resourceProvider->setMirrorHorizontalHideDecorations(d->config.hideHorizontalDecoration()); + d->resourceProvider->setMirrorVerticalHideDecorations(d->config.hideVerticalDecoration()); + } + + toggleMirrorActions(); + setVisible(d->config.mirrorHorizontal() || d->config.mirrorVertical()); +} + +const KisMirrorAxisConfig &KisMirrorAxis::mirrorAxisConfig() const +{ + return d->config; +} + +void KisMirrorAxis::toggleMirrorActions() +{ + KActionCollection* collection = view()->viewManager()->actionCollection(); + // first uncheck the action, then set according to config; + // otherwise the connected KisHighlightedToolButton's highlight color is not + // properly set + collection->action("hmirror_action")->setChecked(false); + collection->action("vmirror_action")->setChecked(false); + + if (d->config.mirrorHorizontal()) { + collection->action("hmirror_action")->setChecked(d->config.mirrorHorizontal()); + } + + if (d->config.mirrorVertical()) { + collection->action("vmirror_action")->setChecked(d->config.mirrorVertical()); + } + + collection->action("mirrorX-lock")->setChecked(d->config.lockHorizontal()); + collection->action("mirrorY-lock")->setChecked(d->config.lockVertical()); + + collection->action("mirrorX-hideDecorations")->setChecked(d->config.hideHorizontalDecoration()); + collection->action("mirrorY-hideDecorations")->setChecked(d->config.hideVerticalDecoration()); +} + void KisMirrorAxis::moveHorizontalAxisToCenter() { - d->setAxisPosition(d->image->width()/2, d->axisPosition.y()); + if (!view()->isCurrent()) { + return; + } + + d->setAxisPosition(d->image->width()/2, d->config.axisPosition().y()); + emit sigConfigChanged(); } void KisMirrorAxis::moveVerticalAxisToCenter() { - d->setAxisPosition(d->axisPosition.x(), d->image->height()/2 ); + if (!view()->isCurrent()) { + return; + } + + d->setAxisPosition(d->config.axisPosition().x(), d->image->height()/2 ); + emit sigConfigChanged(); } void KisMirrorAxis::Private::setAxisPosition(float x, float y) { QPointF newPosition = QPointF(x, y); + config.setAxisPosition(newPosition); + const QPointF relativePosition = KisAlgebra2D::absoluteToRelative(newPosition, image->bounds()); image->setMirrorAxesCenter(relativePosition); @@ -389,15 +452,15 @@ { KisCoordinatesConverter *converter = q->view()->viewConverter(); - axisPosition = KisAlgebra2D::relativeToAbsolute(image->mirrorAxesCenter(), image->bounds()); + config.setAxisPosition(KisAlgebra2D::relativeToAbsolute(image->mirrorAxesCenter(), image->bounds())); - QPointF samplePt1 = converter->imageToWidget(axisPosition); - QPointF samplePt2 = converter->imageToWidget(QPointF(axisPosition.x(), axisPosition.y() - 100)); + QPointF samplePt1 = converter->imageToWidget(config.axisPosition()); + QPointF samplePt2 = converter->imageToWidget(QPointF(config.axisPosition().x(), config.axisPosition().y() - 100)); horizontalAxis = QLineF(samplePt1, samplePt2); if (!KisAlgebra2D::intersectLineRect(horizontalAxis, viewport)) horizontalAxis = QLineF(); - samplePt2 = converter->imageToWidget(QPointF(axisPosition.x() - 100, axisPosition.y())); + samplePt2 = converter->imageToWidget(QPointF(config.axisPosition().x() - 100, config.axisPosition().y())); verticalAxis = QLineF(samplePt1, samplePt2); if (!KisAlgebra2D::intersectLineRect(verticalAxis, viewport)) verticalAxis = QLineF(); } diff --git a/libs/ui/kis_mirror_manager.h b/libs/ui/kis_mirror_manager.h --- a/libs/ui/kis_mirror_manager.h +++ b/libs/ui/kis_mirror_manager.h @@ -22,13 +22,14 @@ #include #include +#include #include "KisView.h" class KisViewManager; class KActionCollection; class KisMirrorAxis; - +class KisMirrorAxisConfig; class KisMirrorManager : public QObject { @@ -44,13 +45,17 @@ private Q_SLOTS: void updateAction(); + void slotDocumentConfigChanged(); + void slotMirrorAxisConfigChanged(); private: + class Private; + const QScopedPointer d; QPointer m_imageView; QAction *m_mirrorCanvas; KisMirrorAxis* hasDecoration(); - + const KisMirrorAxisConfig &mirrorAxisConfig() const; }; -#endif // KIS_PAINTING_ASSISTANTS_MANAGER_H +#endif // KIS__MANAGER_H diff --git a/libs/ui/kis_mirror_manager.cpp b/libs/ui/kis_mirror_manager.cpp --- a/libs/ui/kis_mirror_manager.cpp +++ b/libs/ui/kis_mirror_manager.cpp @@ -30,8 +30,23 @@ #include "kis_canvas2.h" #include "kis_mirror_axis.h" +#include +#include +#include + +class KisMirrorManager::Private +{ +public: + Private() + : mirrorAxisDecoration(nullptr) + {} + + KisMirrorAxis* mirrorAxisDecoration; +// KisMirrorAxisConfig mirrorAxisConfig() {} +}; KisMirrorManager::KisMirrorManager(KisViewManager* view) : QObject(view) + , d(new Private()) , m_imageView(0) { } @@ -56,14 +71,20 @@ { if (m_imageView) { m_mirrorCanvas->disconnect(); + m_imageView->document()->disconnect(); } m_imageView = imageView; if (m_imageView) { connect(m_mirrorCanvas, SIGNAL(toggled(bool)), dynamic_cast(m_imageView->canvasController()), SLOT(mirrorCanvas(bool))); + connect(m_imageView->document(), SIGNAL(sigMirrorAxisConfigChanged()), this, SLOT(slotDocumentConfigChanged()), Qt::UniqueConnection); if (!hasDecoration()) { - m_imageView->canvasBase()->addDecoration(new KisMirrorAxis(m_imageView->viewManager()->resourceProvider(), m_imageView)); + d->mirrorAxisDecoration = new KisMirrorAxis(m_imageView->viewManager()->resourceProvider(), m_imageView); + connect(d->mirrorAxisDecoration, SIGNAL(sigConfigChanged()), this, SLOT(slotMirrorAxisConfigChanged()), Qt::UniqueConnection); + m_imageView->canvasBase()->addDecoration(d->mirrorAxisDecoration); } + + d->mirrorAxisDecoration->setMirrorAxisConfig(mirrorAxisConfig()); } updateAction(); } @@ -80,10 +101,28 @@ } } +void KisMirrorManager::slotDocumentConfigChanged() +{ + d->mirrorAxisDecoration->setMirrorAxisConfig(mirrorAxisConfig()); +} + +void KisMirrorManager::slotMirrorAxisConfigChanged() +{ + if (m_imageView) { + KisSignalsBlocker blocker(m_imageView->document()); + m_imageView->document()->setMirrorAxisConfig(d->mirrorAxisDecoration->mirrorAxisConfig()); + } +} + KisMirrorAxis* KisMirrorManager::hasDecoration() { if (m_imageView && m_imageView->canvasBase() && m_imageView->canvasBase()->decoration("mirror_axis")) { return dynamic_cast(m_imageView->canvasBase()->decoration("mirror_axis").data()); } return 0; } + +const KisMirrorAxisConfig& KisMirrorManager::mirrorAxisConfig() const +{ + return m_imageView->document()->mirrorAxisConfig(); +} diff --git a/libs/ui/kis_paintop_box.cc b/libs/ui/kis_paintop_box.cc --- a/libs/ui/kis_paintop_box.cc +++ b/libs/ui/kis_paintop_box.cc @@ -879,6 +879,14 @@ m_disablePressureAction->setChecked(value.toBool()); } + if (key == KisCanvasResourceProvider::MirrorHorizontal) { + m_hMirrorAction->setChecked(value.toBool()); + } + + if (key == KisCanvasResourceProvider::MirrorVertical) { + m_vMirrorAction->setChecked(value.toBool()); + } + sender()->blockSignals(false); } } diff --git a/plugins/impex/libkra/kis_kra_loader.h b/plugins/impex/libkra/kis_kra_loader.h --- a/plugins/impex/libkra/kis_kra_loader.h +++ b/plugins/impex/libkra/kis_kra_loader.h @@ -110,6 +110,7 @@ void loadAssistantsList(const KoXmlElement& elem); void loadGrid(const KoXmlElement& elem); void loadGuides(const KoXmlElement& elem); + void loadMirrorAxis(const KoXmlElement& elem); void loadAudio(const KoXmlElement& elem, KisImageSP image); private: diff --git a/plugins/impex/libkra/kis_kra_loader.cpp b/plugins/impex/libkra/kis_kra_loader.cpp --- a/plugins/impex/libkra/kis_kra_loader.cpp +++ b/plugins/impex/libkra/kis_kra_loader.cpp @@ -87,6 +87,7 @@ #include "KisProofingConfiguration.h" #include "kis_layer_properties_icons.h" #include "kis_node_view_color_scheme.h" +#include "KisMirrorAxisConfig.h" /* @@ -356,6 +357,8 @@ loadGrid(e); } else if (e.tagName() == "guides") { loadGuides(e); + } else if (e.tagName() == MIRROR_AXIS) { + loadMirrorAxis(e); } else if (e.tagName() == "assistants") { loadAssistantsList(e); } else if (e.tagName() == "audio") { @@ -1180,6 +1183,17 @@ m_d->document->setGuidesConfig(guides); } +void KisKraLoader::loadMirrorAxis(const KoXmlElement &elem) +{ + QDomDocument dom; + KoXml::asQDomElement(dom, elem); + QDomElement domElement = dom.firstChildElement(); + + KisMirrorAxisConfig mirrorAxis; + mirrorAxis.loadFromXml(domElement); + m_d->document->setMirrorAxisConfig(mirrorAxis); +} + void KisKraLoader::loadAudio(const KoXmlElement& elem, KisImageSP image) { QDomDocument dom; diff --git a/plugins/impex/libkra/kis_kra_saver.h b/plugins/impex/libkra/kis_kra_saver.h --- a/plugins/impex/libkra/kis_kra_saver.h +++ b/plugins/impex/libkra/kis_kra_saver.h @@ -58,6 +58,7 @@ bool saveAssistantsList(QDomDocument& doc, QDomElement& element); bool saveGrid(QDomDocument& doc, QDomElement& element); bool saveGuides(QDomDocument& doc, QDomElement& element); + bool saveMirrorAxis(QDomDocument& doc, QDomElement& element); bool saveAudio(QDomDocument& doc, QDomElement& element); bool saveNodeKeyframes(KoStore *store, QString location, const KisNode *node); void savePalettesToXML(QDomDocument& doc, QDomElement &element); diff --git a/plugins/impex/libkra/kis_kra_saver.cpp b/plugins/impex/libkra/kis_kra_saver.cpp --- a/plugins/impex/libkra/kis_kra_saver.cpp +++ b/plugins/impex/libkra/kis_kra_saver.cpp @@ -61,6 +61,8 @@ #include "kis_guides_config.h" #include "KisProofingConfiguration.h" +#include + #include #include @@ -138,6 +140,7 @@ saveAssistantsList(doc, imageElement); saveGrid(doc, imageElement); saveGuides(doc, imageElement); + saveMirrorAxis(doc, imageElement); saveAudio(doc, imageElement); savePalettesToXML(doc, imageElement); @@ -482,6 +485,18 @@ return true; } +bool KisKraSaver::saveMirrorAxis(QDomDocument &doc, QDomElement &element) +{ + KisMirrorAxisConfig mirrorAxisConfig = m_d->doc->mirrorAxisConfig(); + + if (!mirrorAxisConfig.isDefault()) { + QDomElement mirrorAxisElement = mirrorAxisConfig.saveToXml(doc, MIRROR_AXIS); + element.appendChild(mirrorAxisElement); + } + + return true; +} + bool KisKraSaver::saveAudio(QDomDocument& doc, QDomElement& element) { const KisImageAnimationInterface *interface = m_d->doc->image()->animationInterface(); diff --git a/plugins/impex/libkra/kis_kra_tags.h b/plugins/impex/libkra/kis_kra_tags.h --- a/plugins/impex/libkra/kis_kra_tags.h +++ b/plugins/impex/libkra/kis_kra_tags.h @@ -137,6 +137,7 @@ const QString SIMPLECOLORDATA = "SimpleColorData"; // easier 8-bit color data that works well with XML const QString GLOBALASSISTANTSCOLOR = "GlobalAssistantsColor"; const QString PALETTES = "Palettes"; +const QString MIRROR_AXIS = "MirrorAxis"; }