...
 
Commits (3)
......@@ -9,7 +9,7 @@
Krita is a free and open source digital painting application. It is for artists who want to create professional work from start to end. Krita is used by comic book artists, illustrators, concept artists, matte and texture painters and in the digital VFX industry.
If you are reading this on Github, be aware that this is just a mirror. Our real
code repository is provided by KDE: https://phabricator.kde.org/source/krita/
code repository is provided by KDE: https://invent.kde.org/kde/krita
![Picture](https://krita.org/wp-content/uploads/2016/04/krita-30-screenshot.jpg)
......
......@@ -38,7 +38,7 @@ set(kis_low_memory_benchmark_SRCS kis_low_memory_benchmark.cpp)
set(KisAnimationRenderingBenchmark_SRCS KisAnimationRenderingBenchmark.cpp)
set(kis_filter_selections_benchmark_SRCS kis_filter_selections_benchmark.cpp)
if (UNIX)
set(kis_composition_benchmark_SRCS kis_composition_benchmark.cpp)
set(kis_composition_benchmark_SRCS kis_composition_benchmark.cpp)
endif()
set(kis_thumbnail_benchmark_SRCS kis_thumbnail_benchmark.cpp)
......@@ -60,7 +60,7 @@ krita_add_benchmark(KisLowMemoryBenchmark TESTNAME krita-benchmarks-KisLowMemory
krita_add_benchmark(KisAnimationRenderingBenchmark TESTNAME krita-benchmarks-KisAnimationRenderingBenchmark ${KisAnimationRenderingBenchmark_SRCS})
krita_add_benchmark(KisFilterSelectionsBenchmark TESTNAME krita-image-KisFilterSelectionsBenchmark ${kis_filter_selections_benchmark_SRCS})
if(UNIX)
krita_add_benchmark(KisCompositionBenchmark TESTNAME krita-benchmarks-KisComposition ${kis_composition_benchmark_SRCS})
krita_add_benchmark(KisCompositionBenchmark TESTNAME krita-benchmarks-KisComposition ${kis_composition_benchmark_SRCS})
endif()
krita_add_benchmark(KisThumbnailBenchmark TESTNAME krita-benchmarks-KisThumbnail ${kis_thumbnail_benchmark_SRCS})
......
......@@ -114,6 +114,7 @@ xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0 http://www.kde.org
<text>&amp;Snap To</text>
<Action name="view_snap_to_guides"/>
<Action name="view_snap_to_grid"/>
<Action name="view_snap_to_pixel"/>
<Action name="view_snap_orthogonal" />
<Action name="view_snap_node" />
<Action name="view_snap_extension" />
......
......@@ -866,6 +866,17 @@
<statusTip></statusTip>
</Action>
<Action name="view_snap_to_pixel">
<icon></icon>
<text>Snap Pixel</text>
<whatsThis></whatsThis>
<toolTip>Snap Pixel</toolTip>
<iconText>Snap Pixel</iconText>
<activationFlags>1000</activationFlags>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_snap_intersection">
<icon></icon>
<text>Snap Intersection</text>
......
......@@ -97,6 +97,14 @@ public:
*/
virtual void setCursor(const QCursor &cursor) = 0;
/**
* converts image coordinates to document one
*
* @param point the point to be converted
* @return the converted point
*/
virtual QPointF mapImageToDocument(const QPointF &point) { return point; }
/**
* Adds a command to the history. Call this for each @p command you create.
* This will also execute the command.
......
......@@ -74,6 +74,7 @@ KoSnapGuide::KoSnapGuide(KoCanvasBase *canvas)
d->strategies.append(toQShared(new ExtensionSnapStrategy()));
d->strategies.append(toQShared(new IntersectionSnapStrategy()));
d->strategies.append(toQShared(new BoundingBoxSnapStrategy()));
d->strategies.append(toQShared(new PixelSnapStrategy()));
}
KoSnapGuide::~KoSnapGuide()
......
......@@ -69,7 +69,8 @@ public:
GuideLineSnapping = 0x40,
DocumentBoundsSnapping = 0x80,
DocumentCenterSnapping = 0x100,
CustomSnapping = 0x200
CustomSnapping = 0x200,
PixelSnapping = 0x400
};
Q_DECLARE_FLAGS(Strategies, Strategy)
......
......@@ -581,6 +581,73 @@ QPainterPath BoundingBoxSnapStrategy::decoration(const KoViewConverter &converte
return decoration;
}
PixelSnapStrategy::PixelSnapStrategy()
: KoSnapStrategy(KoSnapGuide::PixelSnapping)
{
}
bool PixelSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance)
{
Q_ASSERT(std::isfinite(maxSnapDistance));
QPointF p = proxy->canvas()->mapImageToDocument(QPointF(1,1));
QSizeF spacing(p.x(),p.y());
int col = static_cast<int>((mousePosition.x()) / spacing.width() + 1e-10);
int nextCol = col + 1;
int row = static_cast<int>((mousePosition.y()) / spacing.height() + 1e-10);
int nextRow = row + 1;
// now check which grid line has less distance to the point
qreal distToCol = qAbs(col * spacing.width() - mousePosition.x());
qreal distToNextCol = qAbs(nextCol * spacing.width() - mousePosition.x());
if (distToCol > distToNextCol) {
col = nextCol;
distToCol = distToNextCol;
}
qreal distToRow = qAbs(row * spacing.height() - mousePosition.y());
qreal distToNextRow = qAbs(nextRow * spacing.height() - mousePosition.y());
if (distToRow > distToNextRow) {
row = nextRow;
distToRow = distToNextRow;
}
QPointF snappedPoint = mousePosition;
bool pointIsSnapped = false;
const qreal sqDistance = distToCol * distToCol + distToRow * distToRow;
const qreal maxSqDistance = maxSnapDistance * maxSnapDistance;
// now check if we are inside the snap distance
if (sqDistance < maxSqDistance) {
snappedPoint = QPointF(col * spacing.width(), row * spacing.height());
pointIsSnapped = true;
} else if (distToRow < maxSnapDistance) {
snappedPoint.ry() = row * spacing.height();
pointIsSnapped = true;
} else if (distToCol < maxSnapDistance) {
snappedPoint.rx() = col * spacing.width();
pointIsSnapped = true;
}
setSnappedPosition(snappedPoint);
return pointIsSnapped;
}
QPainterPath PixelSnapStrategy::decoration(const KoViewConverter &converter) const
{
QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5));
QPainterPath decoration;
decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), 0));
decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), 0));
decoration.moveTo(snappedPosition() - QPointF(0, unzoomedSize.height()));
decoration.lineTo(snappedPosition() + QPointF(0, unzoomedSize.height()));
return decoration;
}
// KoGuidesData has been moved into Krita. Please port this class!
// LineGuideSnapStrategy::LineGuideSnapStrategy()
......
......@@ -128,6 +128,15 @@ private:
QPointF m_boxPoints[5];
};
/// snaps to the pixels
class KRITAFLAKE_EXPORT PixelSnapStrategy : public KoSnapStrategy
{
public:
PixelSnapStrategy();
bool snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) override;
QPainterPath decoration(const KoViewConverter &converter) const override;
};
// KoGuidesData has been moved into Krita. Please port this class!
//
/// snaps to line guides
......
......@@ -80,6 +80,9 @@ KisSelection::KisSelection(const KisPaintDeviceSP source, KritaUtils::DeviceCopy
m_d->defaultBounds = defaultBounds;
m_d->pixelSelection = new KisPixelSelection(source, copyMode);
m_d->pixelSelection->setParentSelection(this);
m_d->pixelSelection->setParentNode(m_d->parentNode);
m_d->pixelSelection->setDefaultBounds(m_d->defaultBounds);
}
KisSelection &KisSelection::operator=(const KisSelection &rhs)
......
......@@ -350,6 +350,12 @@ void KisCanvas2::gridSize(QPointF *offset, QSizeF *spacing) const
*offset = transform.map(QPointF(intOffset));
}
QPointF KisCanvas2::mapImageToDocument(const QPointF &point) {
QTransform transform = coordinatesConverter()->imageToDocumentTransform();
QPointF newPoint = transform.map(point);
return newPoint;
}
bool KisCanvas2::snapToGrid() const
{
return m_d->view->document()->gridConfig().snapToGrid();
......
......@@ -95,6 +95,8 @@ public: // KoCanvasBase implementation
bool snapToGrid() const override;
QPointF mapImageToDocument(const QPointF &point) override;
// This method only exists to support flake-related operations
void addCommand(KUndo2Command *command) override;
......
......@@ -211,6 +211,7 @@ void KisGuidesManager::syncActionsStatus()
m_d->syncAction("view_snap_bounding_box", m_d->snapConfig.boundingBox());
m_d->syncAction("view_snap_image_bounds", m_d->snapConfig.imageBounds());
m_d->syncAction("view_snap_image_center", m_d->snapConfig.imageCenter());
m_d->syncAction("view_snap_to_pixel",m_d->snapConfig.toPixel());
}
void KisGuidesManager::Private::updateSnappingStatus(const KisGuidesConfig &value)
......@@ -236,6 +237,7 @@ void KisGuidesManager::Private::updateSnappingStatus(const KisGuidesConfig &valu
snapGuide->enableSnapStrategy(KoSnapGuide::BoundingBoxSnapping, snapConfig.boundingBox());
snapGuide->enableSnapStrategy(KoSnapGuide::DocumentBoundsSnapping, snapConfig.imageBounds());
snapGuide->enableSnapStrategy(KoSnapGuide::DocumentCenterSnapping, snapConfig.imageCenter());
snapGuide->enableSnapStrategy(KoSnapGuide::PixelSnapping, snapConfig.toPixel());
snapConfig.saveStaticData();
}
......@@ -332,6 +334,9 @@ void KisGuidesManager::setup(KisActionManager *actionManager)
action = actionManager->createAction("view_snap_image_center");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapImageCenter(bool)));
action = actionManager->createAction("view_snap_to_pixel");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapToPixel(bool)));
m_d->updateSnappingStatus(m_d->guidesConfig);
syncActionsStatus();
}
......@@ -746,6 +751,7 @@ void KisGuidesManager::slotShowSnapOptions()
menu.addSection(i18n("Snap to:"));
menu.addAction(m_d->createShortenedAction(i18n("Grid"), "view_snap_to_grid", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Guides"), "view_snap_to_guides", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Pixel"), "view_snap_to_pixel", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Orthogonal"), "view_snap_orthogonal", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Node"), "view_snap_node", &menu));
......@@ -800,3 +806,9 @@ void KisGuidesManager::setSnapImageCenter(bool value)
m_d->snapConfig.setImageCenter(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapToPixel(bool value)
{
m_d->snapConfig.setToPixel(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
......@@ -74,6 +74,7 @@ public Q_SLOTS:
void setSnapBoundingBox(bool value);
void setSnapImageBounds(bool value);
void setSnapImageCenter(bool value);
void setSnapToPixel(bool value);
void slotUploadConfigToDocument();
......
......@@ -27,7 +27,8 @@ KisSnapConfig::KisSnapConfig(bool loadValues)
m_intersection(false),
m_boundingBox(false),
m_imageBounds(true),
m_imageCenter(true)
m_imageCenter(true),
m_toPixel(false)
{
if (loadValues) {
loadStaticData();
......
......@@ -75,6 +75,13 @@ public:
m_imageCenter = value;
}
bool toPixel() const {
return m_toPixel;
}
void setToPixel(bool value) {
m_toPixel = value;
}
void saveStaticData() const;
void loadStaticData();
......@@ -86,6 +93,7 @@ private:
bool m_boundingBox;
bool m_imageBounds;
bool m_imageCenter;
bool m_toPixel;
};
#endif /* __KIS_SNAP_CONFIG_H */
......@@ -853,6 +853,7 @@ void KisConfig::loadSnapConfig(KisSnapConfig *config, bool defaultValue) const
config->setBoundingBox(m_cfg.readEntry("globalSnapBoundingBox", defaultConfig.boundingBox()));
config->setImageBounds(m_cfg.readEntry("globalSnapImageBounds", defaultConfig.imageBounds()));
config->setImageCenter(m_cfg.readEntry("globalSnapImageCenter", defaultConfig.imageCenter()));
config->setToPixel(m_cfg.readEntry("globalSnapToPixel", defaultConfig.toPixel()));
}
void KisConfig::saveSnapConfig(const KisSnapConfig &config)
......@@ -864,6 +865,7 @@ void KisConfig::saveSnapConfig(const KisSnapConfig &config)
m_cfg.writeEntry("globalSnapBoundingBox", config.boundingBox());
m_cfg.writeEntry("globalSnapImageBounds", config.imageBounds());
m_cfg.writeEntry("globalSnapImageCenter", config.imageCenter());
m_cfg.writeEntry("globalSnapToPixel", config.toPixel());
}
qint32 KisConfig::checkSize(bool defaultValue) const
......