10#include <QGuiApplication>
60 bool updateCursor(
const QPointF &docPos,
bool forceDisableCursor =
false);
63 const QPointF &dragStart,
66 bool mouseMoveHandler(
const QPointF &docPos, Qt::KeyboardModifiers modifiers);
104 if (config ==
m_d->guidesConfig)
return;
111 if (config ==
m_d->guidesConfig)
return;
127 value.saveStaticData();
130 m_d->shouldSetModified =
false;
137 if (
m_d->decoration &&
value !=
m_d->decoration->guidesConfig()) {
138 m_d->decoration->setVisible(
value.showGuides());
139 m_d->decoration->setGuidesConfig(
value);
142 m_d->shouldSetModified |= emitModified;
144 const bool shouldFilterEvent =
150 if (!
m_d->isGuideValid(
m_d->currentGuide)) {
155 m_d->view->document()->setUnit(
KoUnit(
m_d->guidesConfig.unitType()));
156 m_d->view->viewManager()->actionManager()->actionByName(
"ruler_pixel_multiple2")->setChecked(
value.rulersMultiple2());
164 if (!
m_d->view)
return;
182 action->setChecked(
value);
187 return !(oldGuidesConfig.hasSamePositionAs(guidesConfig));
193 if (doc && needsUndoCommand()) {
195 view->canvasBase()->addCommand(cmd);
201 if (!
m_d->view)
return;
203 m_d->syncAction(
"view_show_guides",
m_d->guidesConfig.showGuides());
204 m_d->syncAction(
"view_lock_guides",
m_d->guidesConfig.lockGuides());
205 m_d->syncAction(
"view_snap_to_guides",
m_d->guidesConfig.snapToGuides());
207 m_d->syncAction(
"view_snap_orthogonal",
m_d->snapConfig.orthogonal());
208 m_d->syncAction(
"view_snap_node",
m_d->snapConfig.node());
209 m_d->syncAction(
"view_snap_extension",
m_d->snapConfig.extension());
210 m_d->syncAction(
"view_snap_intersection",
m_d->snapConfig.intersection());
211 m_d->syncAction(
"view_snap_bounding_box",
m_d->snapConfig.boundingBox());
212 m_d->syncAction(
"view_snap_image_bounds",
m_d->snapConfig.imageBounds());
213 m_d->syncAction(
"view_snap_image_center",
m_d->snapConfig.imageCenter());
214 m_d->syncAction(
"view_snap_to_pixel",
m_d->snapConfig.toPixel());
221 KoSnapGuide *snapGuide = view->canvasBase()->snapGuide();
224 if (
value.snapToGuides()) {
242 snapConfig.saveStaticData();
247 return m_d->guidesConfig.showGuides();
252 m_d->guidesConfig.setShowGuides(
value);
259 return m_d->guidesConfig.lockGuides();
264 m_d->guidesConfig.setLockGuides(
value);
271 return m_d->guidesConfig.snapToGuides();
276 m_d->guidesConfig.setSnapToGuides(
value);
283 return m_d->guidesConfig.rulersMultiple2();
288 m_d->guidesConfig.setRulersMultiple2(
value);
295 return m_d->guidesConfig.unitType();
300 m_d->guidesConfig.setUnitType(type);
309 action = actionManager->
createAction(
"view_show_guides");
312 action = actionManager->
createAction(
"view_lock_guides");
315 action = actionManager->
createAction(
"view_snap_to_guides");
318 action = actionManager->
createAction(
"show_snap_options_popup");
321 action = actionManager->
createAction(
"view_snap_orthogonal");
327 action = actionManager->
createAction(
"view_snap_extension");
330 action = actionManager->
createAction(
"view_snap_intersection");
333 action = actionManager->
createAction(
"view_snap_bounding_box");
336 action = actionManager->
createAction(
"view_snap_image_bounds");
339 action = actionManager->
createAction(
"view_snap_image_center");
342 action = actionManager->
createAction(
"view_snap_to_pixel");
345 m_d->updateSnappingStatus(
m_d->guidesConfig);
359 m_d->viewConnections.clear();
369 m_d->view->canvasBase()->addDecoration(decoration);
371 m_d->decoration = decoration;
376 m_d->viewConnections.addUniqueConnection(
377 m_d->view->zoomManager()->horizontalRuler(), SIGNAL(guideCreationInProgress(Qt::Orientation,QPoint)),
380 m_d->viewConnections.addUniqueConnection(
381 m_d->view->zoomManager()->horizontalRuler(), SIGNAL(guideCreationFinished(Qt::Orientation,QPoint)),
384 m_d->viewConnections.addUniqueConnection(
385 m_d->view->zoomManager()->verticalRuler(), SIGNAL(guideCreationInProgress(Qt::Orientation,QPoint)),
388 m_d->viewConnections.addUniqueConnection(
389 m_d->view->zoomManager()->verticalRuler(), SIGNAL(guideCreationFinished(Qt::Orientation,QPoint)),
392 m_d->viewConnections.addUniqueConnection(
401 const int snapRadius = 16;
402 const KoViewConverter *converter = view->canvasBase()->viewConverter();
406 qreal nearestRadius = std::numeric_limits<int>::max();
409 for (
int i = 0; i < guidesConfig.horizontalGuideLines().size(); i++) {
410 const QPointF guideCoord = {0, guidesConfig.horizontalGuideLines()[i]};
412 const qreal radius = qAbs(docPosView.y() - guide);
413 if (radius < snapRadius && radius < nearestRadius) {
415 nearestRadius = radius;
419 for (
int i = 0; i < guidesConfig.verticalGuideLines().size(); i++) {
420 const QPointF guideCoord = {guidesConfig.verticalGuideLines()[i], 0};
422 const qreal radius = qAbs(docPosView.x() - guide);
423 if (radius < snapRadius && radius < nearestRadius) {
425 nearestRadius = radius;
434 return h.second >= 0;
439 return h.first == Qt::Horizontal ?
440 guidesConfig.horizontalGuideLines()[h.second] :
441 guidesConfig.verticalGuideLines()[h.second];
446 if (h.first == Qt::Horizontal) {
447 QList<qreal> guides = guidesConfig.horizontalGuideLines();
448 guides[h.second] =
value;
449 guidesConfig.setHorizontalGuideLines(guides);
451 QList<qreal> guides = guidesConfig.verticalGuideLines();
452 guides[h.second] =
value;
453 guidesConfig.setVerticalGuideLines(guides);
459 if (h.first == Qt::Horizontal) {
460 QList<qreal> guides = guidesConfig.horizontalGuideLines();
461 guides.removeAt(h.second);
462 guidesConfig.setHorizontalGuideLines(guides);
464 QList<qreal> guides = guidesConfig.verticalGuideLines();
465 guides.removeAt(h.second);
466 guidesConfig.setVerticalGuideLines(guides);
475 const bool guideValid = isGuideValid(guide) && !forceDisableCursor;
477 if (guideValid && !cursorSwitched) {
482 cursorSwitched =
true;
483 QCursor newCursor = guide.first == Qt::Horizontal ?
484 Qt::SizeVerCursor : Qt::SizeHorCursor;
488 if (!guideValid && cursorSwitched) {
490 cursorSwitched =
false;
497 const QPointF &dragStart,
501 currentGuide = guide;
502 dragStartDoc = dragStart;
503 dragStartGuidePos = guideValue;
505 guide.first == Qt::Horizontal ?
506 QPointF(0, dragStartGuidePos - dragStartDoc.y()) :
507 QPointF(dragStartGuidePos - dragStartDoc.x(), 0);
509 KoSnapGuide *snapGuide = view->canvasBase()->snapGuide();
514 strategy->
addLine(guide.first, guideValue);
529 if (isGuideValid(currentGuide)) {
530 KoSnapGuide *snapGuide = view->canvasBase()->snapGuide();
531 const QPointF snappedPos = snapGuide->
snap(docPos, dragPointerOffset, modifiers);
532 const QPointF offset = snappedPos - dragStartDoc;
533 const qreal newValue = dragStartGuidePos +
534 (currentGuide.first == Qt::Horizontal ?
535 offset.y() : offset.x());
537 setGuideValue(currentGuide, newValue);
538 q->setGuidesConfigImpl(guidesConfig);
541 if(currentGuide.first == Qt::Horizontal) {
542 view->canvasBase()->viewManager()->showFloatingMessage(
543 i18n(
"Y: %1 px", converter->
documentToImage(docPos).toPoint().y()), QIcon(), 1000
547 view->canvasBase()->viewManager()->showFloatingMessage(
548 i18n(
"X: %1 px", converter->
documentToImage(docPos).toPoint().x()), QIcon(), 1000
553 return updateCursor(docPos);
562 if (isGuideValid(currentGuide)) {
567 if (!workRect.contains(docPos)) {
568 deleteGuide(currentGuide);
569 q->setGuidesConfigImpl(guidesConfig);
580 currentGuide = invalidGuide;
581 dragStartDoc = QPointF();
582 dragPointerOffset = QPointF();
583 dragStartGuidePos = 0;
585 KoSnapGuide *snapGuide = view->canvasBase()->snapGuide();
588 updateSnappingStatus(guidesConfig);
591 q->slotUploadConfigToDocument();
592 createUndoCommandIfNeeded();
594 return updateCursor(docPos) | result;
604 if (event->type() == QEvent::Enter) {
605 QEnterEvent *enterEvent =
static_cast<QEnterEvent*
>(event);
607 }
else if (event->type() == QEvent::MouseMove ||
608 event->type() == QEvent::MouseButtonPress ||
609 event->type() == QEvent::MouseButtonRelease) {
611 QMouseEvent *mouseEvent =
static_cast<QMouseEvent*
>(event);
614 }
else if (event->type() == QEvent::TabletMove ||
615 event->type() == QEvent::TabletPress ||
616 event->type() == QEvent::TabletRelease) {
618 QTabletEvent *tabletEvent =
static_cast<QTabletEvent*
>(event);
631 Qt::MouseButton
button = Qt::NoButton;
633 if (event->type() == QEvent::MouseMove ||
634 event->type() == QEvent::MouseButtonPress ||
635 event->type() == QEvent::MouseButtonRelease) {
637 QMouseEvent *mouseEvent =
static_cast<QMouseEvent*
>(event);
638 button = mouseEvent->button();
640 }
else if (event->type() == QEvent::TabletMove ||
641 event->type() == QEvent::TabletPress ||
642 event->type() == QEvent::TabletRelease) {
644 QTabletEvent *tabletEvent =
static_cast<QTabletEvent*
>(event);
645 button = tabletEvent->button();
653 if (!
m_d->view || obj !=
m_d->view->canvasBase()->canvasWidget())
return false;
657 switch (event->type()) {
659 m_d->updateCursor(QPointF(),
true);
662 case QEvent::TabletMove:
663 case QEvent::MouseMove: {
664 const QPointF docPos =
m_d->getDocPointFromEvent(event);
665 const Qt::KeyboardModifiers modifiers = qApp->keyboardModifiers();
668 retval =
m_d->mouseMoveHandler(docPos, modifiers) &&
event->type() != QEvent::Enter;
672 case QEvent::TabletPress:
673 case QEvent::MouseButtonPress: {
674 if (
m_d->getButtonFromEvent(event) != Qt::LeftButton)
break;
676 const QPointF docPos =
m_d->getDocPointFromEvent(event);
678 const bool guideValid =
m_d->isGuideValid(guide);
681 m_d->oldGuidesConfig =
m_d->guidesConfig;
682 m_d->initDragStart(guide, docPos,
m_d->guideValue(guide),
true);
685 retval =
m_d->updateCursor(docPos);
689 case QEvent::TabletRelease:
690 case QEvent::MouseButtonRelease: {
691 if (
m_d->getButtonFromEvent(event) != Qt::LeftButton)
break;
693 const QPointF docPos =
m_d->getDocPointFromEvent(event);
694 retval =
m_d->mouseReleaseHandler(docPos);
702 return !retval ? QObject::eventFilter(obj, event) :
true;
707 if (
m_d->guidesConfig.lockGuides())
return;
711 const QPointF widgetPos = canvas->
canvasWidget()->mapFromGlobal(globalPos);
714 if (
m_d->isGuideValid(
m_d->currentGuide)) {
715 const Qt::KeyboardModifiers modifiers = qApp->keyboardModifiers();
716 m_d->mouseMoveHandler(docPos, modifiers);
718 m_d->guidesConfig.setShowGuides(
true);
720 m_d->oldGuidesConfig =
m_d->guidesConfig;
722 if (orientation == Qt::Horizontal) {
724 guides.append(docPos.y());
725 m_d->currentGuide.first = orientation;
726 m_d->currentGuide.second = guides.size() - 1;
727 m_d->guidesConfig.setHorizontalGuideLines(guides);
728 m_d->initDragStart(
m_d->currentGuide, docPos, docPos.y(),
false);
731 guides.append(docPos.x());
732 m_d->currentGuide.first = orientation;
733 m_d->currentGuide.second = guides.size() - 1;
734 m_d->guidesConfig.setVerticalGuideLines(guides);
735 m_d->initDragStart(
m_d->currentGuide, docPos, docPos.x(),
false);
744 Q_UNUSED(orientation);
745 if (
m_d->guidesConfig.lockGuides())
return;
749 const QPointF widgetPos = canvas->
canvasWidget()->mapFromGlobal(globalPos);
752 m_d->mouseReleaseHandler(docPos);
761 action =
new QAction(text, parent);
762 action->setCheckable(
true);
764 action->setChecked(parentAction->isChecked());
765 connect(action, SIGNAL(toggled(
bool)), parentAction, SLOT(setChecked(
bool)));
772 const QPoint pos = QCursor::pos();
775 menu.addSection(i18n(
"Snap to:"));
776 menu.addAction(
m_d->createShortenedAction(i18n(
"Grid"),
"view_snap_to_grid", &menu));
777 menu.addAction(
m_d->createShortenedAction(i18n(
"Guides"),
"view_snap_to_guides", &menu));
778 menu.addAction(
m_d->createShortenedAction(i18n(
"Pixel"),
"view_snap_to_pixel", &menu));
779 menu.addAction(
m_d->createShortenedAction(i18n(
"Orthogonal"),
"view_snap_orthogonal", &menu));
781 menu.addAction(
m_d->createShortenedAction(i18n(
"Node"),
"view_snap_node", &menu));
782 menu.addAction(
m_d->createShortenedAction(i18n(
"Extension"),
"view_snap_extension", &menu));
783 menu.addAction(
m_d->createShortenedAction(i18n(
"Intersection"),
"view_snap_intersection", &menu));
785 menu.addAction(
m_d->createShortenedAction(i18n(
"Bounding Box"),
"view_snap_bounding_box", &menu));
786 menu.addAction(
m_d->createShortenedAction(i18n(
"Image Bounds"),
"view_snap_image_bounds", &menu));
787 menu.addAction(
m_d->createShortenedAction(i18n(
"Image Center"),
"view_snap_image_center", &menu));
794 m_d->snapConfig.setOrthogonal(
value);
795 m_d->updateSnappingStatus(
m_d->guidesConfig);
801 m_d->updateSnappingStatus(
m_d->guidesConfig);
806 m_d->snapConfig.setExtension(
value);
807 m_d->updateSnappingStatus(
m_d->guidesConfig);
812 m_d->snapConfig.setIntersection(
value);
813 m_d->updateSnappingStatus(
m_d->guidesConfig);
818 m_d->snapConfig.setBoundingBox(
value);
819 m_d->updateSnappingStatus(
m_d->guidesConfig);
824 m_d->snapConfig.setImageBounds(
value);
825 m_d->updateSnappingStatus(
m_d->guidesConfig);
830 m_d->snapConfig.setImageCenter(
value);
831 m_d->updateSnappingStatus(
m_d->guidesConfig);
837 m_d->updateSnappingStatus(
m_d->guidesConfig);
float value(const T *src, size_t ch)
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
A KisActionManager class keeps track of KisActions. These actions are always associated with the GUI....
KisAction * createAction(const QString &name)
KisAction * actionByName(const QString &name) const
KisViewManager * viewManager
KisCoordinatesConverter * coordinatesConverter
KisAbstractCanvasWidget * canvasWidget
_Private::Traits< T >::Result widgetToDocument(const T &obj) const
QRectF imageRectInDocumentPixels() const
_Private::Traits< T >::Result documentToImage(const T &obj) const
_Private::Traits< T >::Result imageToDocument(const T &obj) const
void setGuidesConfig(const KisGuidesConfig &data)
bool hasSamePositionAs(const KisGuidesConfig &rhs) const
const KisGuidesConfig & guidesConfig() const
void setView(QPointer< KisView > view)
void setRulersMultiple2(bool value)
const QScopedPointer< Private > m_d
void slotDocumentRequestedConfig(const KisGuidesConfig &config)
void setSnapBoundingBox(bool value)
KoUnit::Type unitType() const
void setSnapToGuides(bool value)
void setShowGuides(bool value)
bool rulersMultiple2() const
void setSnapImageCenter(bool value)
bool eventFilter(QObject *obj, QEvent *event) override
void setSnapOrthogonal(bool value)
void setGuidesConfigImpl(const KisGuidesConfig &value, bool emitModified=true)
void setGuidesConfig(const KisGuidesConfig &config)
void setLockGuides(bool value)
KisGuidesManager(QObject *parent=0)
void setSnapNode(bool value)
void attachEventFilterImpl(bool value)
void slotUploadConfigToDocument()
void setUnitType(KoUnit::Type type)
void setSnapExtension(bool value)
void slotGuideCreationInProgress(Qt::Orientation orientation, const QPoint &globalPos)
void sigRequestUpdateGuidesConfig(const KisGuidesConfig &config)
void setSnapImageBounds(bool value)
void setSnapIntersection(bool value)
~KisGuidesManager() override
void setup(KisActionManager *actionManager)
void slotGuideCreationFinished(Qt::Orientation orientation, const QPoint &globalPos)
bool snapToGuides() const
void slotShowSnapOptions()
void setSnapToPixel(bool value)
void setVerticalLines(const QList< qreal > &lines)
void addLine(Qt::Orientation orientation, qreal pos)
void setHorizontalLines(const QList< qreal > &lines)
KisActionManager * actionManager() const
bool addCustomSnapStrategy(KoSnapStrategy *customStrategy)
void reset()
Resets the snap guide.
QPointF snap(const QPointF &mousePosition, Qt::KeyboardModifiers modifiers)
snaps the mouse position, returns if mouse was snapped
void enableSnapStrategy(Strategy type, bool value)
void overrideSnapStrategy(Strategy type, KoSnapStrategy *strategy)
virtual QPointF documentToView(const QPointF &documentPoint) const
#define KIS_ASSERT_RECOVER_RETURN(cond)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
static const QString GUIDES_DECORATION_ID
QString button(const QWheelEvent &ev)
Rect blowRect(const Rect &rect, qreal coeff)
QAction * createShortenedAction(const QString &text, const QString &parentId, QObject *parent)
KisGuidesDecoration * decoration
bool mouseReleaseHandler(const QPointF &docPos)
QPointF getDocPointFromEvent(QEvent *event)
KisGuidesConfig oldGuidesConfig
bool isGuideValid(const GuideHandle &h)
bool updateCursor(const QPointF &docPos, bool forceDisableCursor=false)
const GuideHandle invalidGuide
QPointF dragPointerOffset
KisGuidesConfig guidesConfig
void updateSnappingStatus(const KisGuidesConfig &value)
void syncAction(const QString &actionName, bool value)
Qt::MouseButton getButtonFromEvent(QEvent *event)
QPair< Qt::Orientation, int > GuideHandle
bool mouseMoveHandler(const QPointF &docPos, Qt::KeyboardModifiers modifiers)
qreal guideValue(const GuideHandle &h)
QPointF alignToPixels(const QPointF docPoint)
void deleteGuide(const GuideHandle &h)
KisSignalAutoConnectionsStore viewConnections
Private(KisGuidesManager *_q)
void setGuideValue(const GuideHandle &h, qreal value)
void initDragStart(const GuideHandle &guide, const QPointF &dragStart, qreal guideValue, bool snapToStart)
GuideHandle findGuide(const QPointF &docPos)
void createUndoCommandIfNeeded()