diff --git a/krita/kritamenu.action b/krita/kritamenu.action
index 9783320af3..3aa7b9886e 100644
--- a/krita/kritamenu.action
+++ b/krita/kritamenu.action
@@ -1,1806 +1,1817 @@
File
document-new
&New
Create new document
New
0
0
Ctrl+N
false
document-open
&Open...
Open an existing document
Open
0
0
Ctrl+O
false
document-open-recent
Open &Recent
Open a document which was recently opened
Open Recent
1
0
false
document-save
&Save
Save
Save
1
0
Ctrl+S
false
document-save-as
Save &As...
Save document under a new name
Save As
1
0
Ctrl+Shift+S
false
Sessions...
Open session manager
Sessions
0
0
false
document-import
Open ex&isting Document as Untitled Document...
Open existing Document as Untitled Document
Open existing Document as Untitled Document
0
0
false
document-export
E&xport...
Export
Export
1
0
false
Import animation frames...
Import animation frames
Import animation frames
1
0
false
&Render Animation...
Render Animation to GIF, Image Sequence or Video
Render Animation
1000
0
false
&Render Animation Again
Render Animation Again
Render Animation
1000
0
false
Save Incremental &Version
Save Incremental Version
Save Incremental Version
1
0
Ctrl+Alt+S
false
Save Incremental &Backup
Save Incremental Backup
Save Incremental Backup
1
0
F4
false
&Create Template From Image...
Create Template From Image
Create Template From Image
1
0
false
Create Copy &From Current Image
Create Copy From Current Image
Create Copy From Current Image
1
0
false
document-print
&Print...
Print document
Print
1
0
Ctrl+P
false
document-print-preview
Print Previe&w
Show a print preview of document
Print Preview
1
0
false
configure
&Document Information
Document Information
Document Information
1
0
false
&Close All
Close All
Close All
1
0
Ctrl+Shift+W
false
C&lose
Close
Close
1
0
Ctrl+W
false
&Quit
Quit application
Quit
0
0
Ctrl+Q
false
Edit
edit-undo
Undo
Undo last action
Undo
1
0
Ctrl+Z
false
edit-redo
Redo
Redo last undone action
Redo
1
0
Ctrl+Shift+Z
false
edit-cut
Cu&t
Cut selection to clipboard
Cut
0
0
Ctrl+X
false
edit-copy
&Copy
Copy selection to clipboard
Copy
0
0
Ctrl+C
false
C&opy (sharp)
Copy (sharp)
Copy (sharp)
100000000
0
false
Cut (&sharp)
Cut (sharp)
Cut (sharp)
100000000
0
false
Copy &merged
Copy merged
Copy merged
100000000
0
Ctrl+Shift+C
false
edit-paste
&Paste
Paste clipboard content
Paste
0
0
Ctrl+V
false
Paste at Cursor
Paste at cursor
Paste at cursor
0
0
Ctrl+Alt+V
false
Paste into &New Image
Paste into New Image
Paste into New Image
0
0
Ctrl+Shift+N
false
edit-clear
C&lear
Clear
Clear
1
0
Del
false
&Fill with Foreground Color
Fill with Foreground Color
Fill with Foreground Color
10000
1
Shift+Backspace
false
Fill &with Background Color
Fill with Background Color
Fill with Background Color
10000
1
Backspace
false
F&ill with Pattern
Fill with Pattern
Fill with Pattern
10000
1
false
Fill Special
Fill with Foreground Color (Opacity)
Fill with Foreground Color (Opacity)
Fill with Foreground Color (Opacity)
10000
1
Ctrl+Shift+Backspace
false
Fill with Background Color (Opacity)
Fill with Background Color (Opacity)
Fill with Background Color (Opacity)
10000
1
Ctrl+Backspace
false
Fill with Pattern (Opacity)
Fill with Pattern (Opacity)
Fill with Pattern (Opacity)
10000
1
false
Stro&ke selected shapes
Stroke selected shapes
Stroke selected shapes
1000000000
0
false
Stroke Selec&tion...
Stroke selection
Stroke selection
10000000000
0
false
Delete keyframe
Delete keyframe
Delete keyframe
100000
0
false
Window
window-new
&New Window
New Window
New Window
0
0
false
N&ext
Next
Next
10
0
false
Previous
Previous
Previous
false
View
document-new
&Show Canvas Only
Show just the canvas or the whole window
Show Canvas Only
0
0
Tab
true
view-fullscreen
F&ull Screen Mode
Display the window in full screen
Full Screen Mode
0
0
Ctrl+Shift+F
true
&Wrap Around Mode
Wrap Around Mode
Wrap Around Mode
1
0
true
&Instant Preview Mode
Instant Preview Mode
Instant Preview Mode
1
0
Shift+L
true
Soft Proofing
Turns on Soft Proofing
Turns on Soft Proofing
Ctrl+Y
true
Out of Gamut Warnings
Turns on warnings for colors out of proofed gamut, needs soft proofing to be turned on.
Turns on warnings for colors out of proofed gamut, needs soft proofing to be turned on.
Ctrl+Shift+Y
true
mirror-view
Mirror View
Mirror View
Mirror View
M
false
zoom-original
&Reset zoom
Reset zoom
Reset zoom
1
0
Ctrl+0
false
zoom-in
Zoom &In
Zoom In
0
0
Ctrl++
false
zoom-out
Zoom &Out
Zoom Out
0
0
Ctrl+-
false
rotate-canvas-right
Rotate &Canvas Right
Rotate Canvas Right
Rotate Canvas Right
1
0
Ctrl+]
false
rotate-canvas-left
Rotate Canvas &Left
Rotate Canvas Left
Rotate Canvas Left
1
0
Ctrl+[
false
rotation-reset
Reset Canvas Rotation
Reset Canvas Rotation
Reset Canvas Rotation
1
0
false
Show &Rulers
The rulers show the horizontal and vertical positions of the mouse on the image and can be used to position your mouse at the right place on the canvas. <p>Uncheck this to hide the rulers.</p>
Show Rulers
Show Rulers
1
0
true
Rulers Track Pointer
The rulers will track current mouse position and show it on screen. It can cause suptle performance slowdown
Rulers Track Pointer
Rulers Track Pointer
1
0
true
Show Guides
Show or hide guides
Show Guides
1
0
true
Lock Guides
Lock or unlock guides
Lock Guides
1
0
true
Snap to Guides
Snap cursor to guides position
Snap to Guides
1
0
true
Show Status &Bar
Show or hide the status bar
Show Status Bar
0
0
true
Show Pixel Grid
Show Pixel Grid
Show Pixel Grid
1000
1000
true
view-grid
Show &Grid
Show Grid
Show Grid
1000
0
Ctrl+Shift+'
true
Snap To Grid
Snap To Grid
Snap To Grid
1000
Ctrl+Shift+;
true
Show Snap Options Popup
Show Snap Options Popup
Show Snap Options Popup
1000
Shift+s
false
Snap Orthogonal
Snap Orthogonal
Snap Orthogonal
1000
true
Snap Node
Snap Node
Snap Node
1000
true
Snap Extension
Snap Extension
Snap Extension
1000
true
+
+
+ Snap Pixel
+
+ Snap Pixel
+ Snap Pixel
+ 1000
+
+ true
+
+
Snap Intersection
Snap Intersection
Snap Intersection
1000
true
Snap Bounding Box
Snap Bounding Box
Snap Bounding Box
1000
true
Snap Image Bounds
Snap Image Bounds
Snap Image Bounds
1000
true
Snap Image Center
Snap Image Center
Snap Image Center
1000
true
S&how Painting Assistants
Show Painting Assistants
Show Painting Assistants
1000
0
true
Show &Assistant Previews
Show Assistant Previews
Show Assistant Previews
1000
0
true
S&how Reference Images
Show Reference Images
Show Reference Images
1000
0
true
Image
document-properties
&Properties...
Properties
Properties
1000
0
false
format-stroke-color
&Image Background Color and Transparency...
Change the background color of the image
Image Background Color and Transparency
1000
0
false
&Convert Image Color Space...
Convert Image Color Space
Convert Image Color Space
1000
0
false
trim-to-image
&Trim to Image Size
Trim to Image Size
Trim to Image Size
1
0
false
Trim to Current &Layer
Trim to Current Layer
Trim to Current Layer
100000
0
false
Trim to S&election
Trim to Selection
Trim to Selection
100000000
0
false
&Rotate Image...
Rotate Image
Rotate Image
1000
0
false
object-rotate-right
Rotate &Image 90° to the Right
Rotate Image 90° to the Right
Rotate Image 90° to the Right
1000
0
false
object-rotate-left
Rotate Image &90° to the Left
Rotate Image 90° to the Left
Rotate Image 90° to the Left
1000
0
false
Rotate Image &180°
Rotate Image 180°
Rotate Image 180°
1000
0
false
&Shear Image...
Shear Image
Shear Image
1000
0
false
symmetry-horizontal
&Mirror Image Horizontally
Mirror Image Horizontally
Mirror Image Horizontally
1000
0
false
symmetry-vertical
Mirror Image &Vertically
Mirror Image Vertically
Mirror Image Vertically
1000
0
false
Scale Image To &New Size...
Scale Image To New Size
Scale Image To New Size
1000
0
Ctrl+Alt+I
false
&Offset Image...
Offset Image
Offset Image
1000
0
false
R&esize Canvas...
Resize Canvas
Resize Canvas
1000
0
Ctrl+Alt+C
false
Im&age Split
Image Split
Image Split
1000
0
false
Separate Ima&ge...
Separate Image
Separate Image
1000
0
false
Select
edit-select-all
Select &All
Select All
Select All
0
0
Ctrl+A
false
edit-select-all
&Deselect
Deselect
Deselect
1100000000
0
Ctrl+Shift+A
false
&Reselect
Reselect
Reselect
0
0
Ctrl+Shift+D
false
&Convert to Vector Selection
Convert to Vector Selection
Convert to Vector Selection
100000000000000000
0
false
&Convert to Raster Selection
Convert to Raster Selection
Convert to Raster Selection
10000000000000000
0
false
Edit Selection
Edit Selection
Edit Selection
10000000000
100
false
Convert Shapes to &Vector Selection
Convert Shapes to Vector Selection
Convert Shapes to Vector Selection
1000000000
0
false
&Feather Selection...
Feather Selection
Feather Selection
10000000000
100
Shift+F6
false
Dis&play Selection
Display Selection
Display Selection
1000
0
Ctrl+H
true
Sca&le...
Scale
Scale
100000000
100
false
S&elect from Color Range...
Select from Color Range
Select from Color Range
10000
100
false
Select &Opaque (Replace)
Select Opaque
Select Opaque
10000
100
false
Select Opaque (&Add)
Select Opaque (Add)
Select Opaque (Add)
10000
100
false
Select Opaque (&Subtract)
Select Opaque (Subtract)
Select Opaque (Subtract)
10000
100
false
Select Opaque (&Intersect)
Select Opaque (Intersect)
Select Opaque (Intersect)
10000
100
false
&Grow Selection...
Grow Selection
Grow Selection
10000000000
100
false
S&hrink Selection...
Shrink Selection
Shrink Selection
10000000000
100
false
&Border Selection...
Border Selection
Border Selection
10000000000
100
false
S&mooth
Smooth
Smooth
10000000000
100
false
Filter
&Apply Filter Again
Apply Filter Again
Apply Filter Again
0
0
Ctrl+F
false
Adjust
Adjust
Adjust
false
Artistic
Artistic
Artistic
false
Blur
Blur
Blur
false
Colors
Colors
Colors
false
Edge Detection
Edge Detection
Edge Detection
false
Enhance
Enhance
Enhance
false
Emboss
Emboss
Emboss
false
Map
Map
Map
false
Other
Other
Other
false
gmic
Start G'MIC-Qt
Start G'Mic-Qt
Start G'Mic-Qt
false
gmic
Re-apply the last G'MIC filter
Apply the last G'Mic-Qt action again
Apply the last G'Mic-Qt action again
false
Settings
configure
&Configure Krita...
Configure Krita
Configure Krita
0
0
false
&Manage Resources...
Manage Resources
Manage Resources
0
0
false
preferences-desktop-locale
Switch Application &Language...
Switch Application Language
Switch Application Language
false
&Show Dockers
Show Dockers
Show Dockers
0
0
true
configure
Configure Tool&bars...
Configure Toolbars
Configure Toolbars
0
0
false
Dockers
Dockers
Dockers
false
&Themes
Themes
Themes
false
im-user
Active Author Profile
Active Author Profile
Active Author Profile
configure-shortcuts
Configure S&hortcuts...
Configure Shortcuts
Configure Shortcuts
0
0
false
&Window
Window
Window
false
Help
help-contents
Krita &Handbook
Krita Handbook
Krita Handbook
F1
false
tools-report-bug
&Report Bug...
Report Bug
Report Bug
false
calligrakrita
&About Krita
About Krita
About Krita
false
kde
About &KDE
About KDE
About KDE
false
Brushes and Stuff
&Gradients
Gradients
Gradients
false
&Patterns
Patterns
Patterns
false
&Color
Color
Color
false
&Painter's Tools
Painter's Tools
Painter's Tools
false
Brush composite
Brush composite
Brush composite
false
Brush option slider 1
Brush option slider 1
Brush option slider 1
false
Brush option slider 2
Brush option slider 2
Brush option slider 2
false
Brush option slider 3
Brush option slider 3
Brush option slider 3
false
Mirror
Mirror
Mirror
false
Layouts
Select layout
false
Workspaces
Workspaces
Workspaces
false
diff --git a/libs/ui/canvas/kis_guides_manager.cpp b/libs/ui/canvas/kis_guides_manager.cpp
index 43b0c7a938..5b4c2d00ca 100644
--- a/libs/ui/canvas/kis_guides_manager.cpp
+++ b/libs/ui/canvas/kis_guides_manager.cpp
@@ -1,815 +1,816 @@
/*
* Copyright (c) 2016 Dmitry Kazakov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU 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 "kis_guides_manager.h"
#include
#include
#include "kis_guides_decoration.h"
#include
#include "kis_guides_config.h"
#include "kis_action_manager.h"
#include "kis_action.h"
#include "kis_signals_blocker.h"
#include "input/kis_input_manager.h"
#include "kis_coordinates_converter.h"
#include "kis_zoom_manager.h"
#include "kis_signal_auto_connection.h"
#include "KisViewManager.h"
#include "KisDocument.h"
#include "kis_algebra_2d.h"
#include
#include "kis_snap_line_strategy.h"
#include "kis_change_guides_command.h"
#include "kis_snap_config.h"
#include "kis_canvas2.h"
#include "kis_signal_compressor.h"
struct KisGuidesManager::Private
{
Private(KisGuidesManager *_q)
: q(_q),
decoration(0),
invalidGuide(Qt::Horizontal, -1),
currentGuide(invalidGuide),
cursorSwitched(false),
dragStartGuidePos(0),
updateDocumentCompressor(40, KisSignalCompressor::FIRST_ACTIVE),
shouldSetModified(false) {}
KisGuidesManager *q;
KisGuidesDecoration *decoration;
KisGuidesConfig guidesConfig;
KisSnapConfig snapConfig;
QPointer view;
typedef QPair GuideHandle;
GuideHandle findGuide(const QPointF &docPos);
bool isGuideValid(const GuideHandle &h);
qreal guideValue(const GuideHandle &h);
void setGuideValue(const GuideHandle &h, qreal value);
void deleteGuide(const GuideHandle &h);
const GuideHandle invalidGuide;
bool updateCursor(const QPointF &docPos, bool forceDisableCursor = false);
void initDragStart(const GuideHandle &guide,
const QPointF &dragStart,
qreal guideValue,
bool snapToStart);
bool mouseMoveHandler(const QPointF &docPos, Qt::KeyboardModifiers modifiers);
bool mouseReleaseHandler(const QPointF &docPos);
void updateSnappingStatus(const KisGuidesConfig &value);
QPointF alignToPixels(const QPointF docPoint);
QPointF getDocPointFromEvent(QEvent *event);
Qt::MouseButton getButtonFromEvent(QEvent *event);
QAction* createShortenedAction(const QString &text, const QString &parentId, QObject *parent);
void syncAction(const QString &actionName, bool value);
GuideHandle currentGuide;
bool cursorSwitched;
QCursor oldCursor;
QPointF dragStartDoc;
QPointF dragPointerOffset;
qreal dragStartGuidePos;
KisSignalAutoConnectionsStore viewConnections;
KisSignalCompressor updateDocumentCompressor;
bool shouldSetModified;
};
KisGuidesManager::KisGuidesManager(QObject *parent)
: QObject(parent),
m_d(new Private(this))
{
connect(&m_d->updateDocumentCompressor, SIGNAL(timeout()), SLOT(slotUploadConfigToDocument()));
}
KisGuidesManager::~KisGuidesManager()
{
}
void KisGuidesManager::setGuidesConfig(const KisGuidesConfig &config)
{
if (config == m_d->guidesConfig) return;
setGuidesConfigImpl(config, true);
}
void KisGuidesManager::slotDocumentRequestedConfig(const KisGuidesConfig &config)
{
if (config == m_d->guidesConfig) return;
setGuidesConfigImpl(config, false);
}
void KisGuidesManager::slotUploadConfigToDocument()
{
const KisGuidesConfig &value = m_d->guidesConfig;
KisDocument *doc = m_d->view ? m_d->view->document() : 0;
if (doc) {
KisSignalsBlocker b(doc);
if (m_d->shouldSetModified) {
KUndo2Command *cmd = new KisChangeGuidesCommand(doc, value);
doc->addCommand(cmd);
} else {
doc->setGuidesConfig(value);
}
value.saveStaticData();
}
m_d->shouldSetModified = false;
}
void KisGuidesManager::setGuidesConfigImpl(const KisGuidesConfig &value, bool emitModified)
{
m_d->guidesConfig = value;
if (m_d->decoration && value != m_d->decoration->guidesConfig()) {
m_d->decoration->setVisible(value.showGuides());
m_d->decoration->setGuidesConfig(value);
}
m_d->shouldSetModified |= emitModified;
m_d->updateDocumentCompressor.start();
const bool shouldFilterEvent =
value.showGuides() && !value.lockGuides() && value.hasGuides();
attachEventFilterImpl(shouldFilterEvent);
syncActionsStatus();
if (!m_d->isGuideValid(m_d->currentGuide)) {
m_d->updateSnappingStatus(value);
}
if (m_d->view) {
m_d->view->document()->setUnit(KoUnit(m_d->guidesConfig.unitType()));
m_d->view->viewManager()->actionManager()->actionByName("ruler_pixel_multiple2")->setChecked(value.rulersMultiple2());
}
emit sigRequestUpdateGuidesConfig(m_d->guidesConfig);
}
void KisGuidesManager::attachEventFilterImpl(bool value)
{
if (!m_d->view) return;
KisInputManager *inputManager = m_d->view->globalInputManager();
if (inputManager) {
if (value) {
inputManager->attachPriorityEventFilter(this, 100);
} else {
inputManager->detachPriorityEventFilter(this);
}
}
}
void KisGuidesManager::Private::syncAction(const QString &actionName, bool value)
{
KisActionManager *actionManager = view->viewManager()->actionManager();
KisAction *action = actionManager->actionByName(actionName);
KIS_ASSERT_RECOVER_RETURN(action);
KisSignalsBlocker b(action);
action->setChecked(value);
}
void KisGuidesManager::syncActionsStatus()
{
if (!m_d->view) return;
m_d->syncAction("view_show_guides", m_d->guidesConfig.showGuides());
m_d->syncAction("view_lock_guides", m_d->guidesConfig.lockGuides());
m_d->syncAction("view_snap_to_guides", m_d->guidesConfig.snapToGuides());
m_d->syncAction("view_snap_orthogonal", m_d->snapConfig.orthogonal());
m_d->syncAction("view_snap_node", m_d->snapConfig.node());
m_d->syncAction("view_snap_extension", m_d->snapConfig.extension());
m_d->syncAction("view_snap_intersection", m_d->snapConfig.intersection());
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)
{
if (!view) return;
KoSnapGuide *snapGuide = view->canvasBase()->snapGuide();
KisSnapLineStrategy *guidesSnap = 0;
if (value.snapToGuides()) {
guidesSnap = new KisSnapLineStrategy(KoSnapGuide::GuideLineSnapping);
guidesSnap->setHorizontalLines(value.horizontalGuideLines());
guidesSnap->setVerticalLines(value.verticalGuideLines());
}
snapGuide->overrideSnapStrategy(KoSnapGuide::GuideLineSnapping, guidesSnap);
snapGuide->enableSnapStrategy(KoSnapGuide::GuideLineSnapping, guidesSnap);
snapGuide->enableSnapStrategy(KoSnapGuide::OrthogonalSnapping, snapConfig.orthogonal());
snapGuide->enableSnapStrategy(KoSnapGuide::NodeSnapping, snapConfig.node());
snapGuide->enableSnapStrategy(KoSnapGuide::ExtensionSnapping, snapConfig.extension());
snapGuide->enableSnapStrategy(KoSnapGuide::IntersectionSnapping, snapConfig.intersection());
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();
}
bool KisGuidesManager::showGuides() const
{
return m_d->guidesConfig.showGuides();
}
void KisGuidesManager::setShowGuides(bool value)
{
m_d->guidesConfig.setShowGuides(value);
setGuidesConfigImpl(m_d->guidesConfig);
}
bool KisGuidesManager::lockGuides() const
{
return m_d->guidesConfig.lockGuides();
}
void KisGuidesManager::setLockGuides(bool value)
{
m_d->guidesConfig.setLockGuides(value);
setGuidesConfigImpl(m_d->guidesConfig);
}
bool KisGuidesManager::snapToGuides() const
{
return m_d->guidesConfig.snapToGuides();
}
void KisGuidesManager::setSnapToGuides(bool value)
{
m_d->guidesConfig.setSnapToGuides(value);
setGuidesConfigImpl(m_d->guidesConfig);
}
bool KisGuidesManager::rulersMultiple2() const
{
return m_d->guidesConfig.rulersMultiple2();
}
void KisGuidesManager::setRulersMultiple2(bool value)
{
m_d->guidesConfig.setRulersMultiple2(value);
setGuidesConfigImpl(m_d->guidesConfig);
}
KoUnit::Type KisGuidesManager::unitType() const
{
return m_d->guidesConfig.unitType();
}
void KisGuidesManager::setUnitType(const KoUnit::Type type)
{
m_d->guidesConfig.setUnitType(type);
setGuidesConfigImpl(m_d->guidesConfig, false);
}
void KisGuidesManager::setup(KisActionManager *actionManager)
{
KisAction *action = 0;
action = actionManager->createAction("view_show_guides");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setShowGuides(bool)));
action = actionManager->createAction("view_lock_guides");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setLockGuides(bool)));
action = actionManager->createAction("view_snap_to_guides");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapToGuides(bool)));
action = actionManager->createAction("show_snap_options_popup");
connect(action, SIGNAL(triggered()), this, SLOT(slotShowSnapOptions()));
action = actionManager->createAction("view_snap_orthogonal");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapOrthogonal(bool)));
action = actionManager->createAction("view_snap_node");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapNode(bool)));
action = actionManager->createAction("view_snap_extension");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapExtension(bool)));
action = actionManager->createAction("view_snap_intersection");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapIntersection(bool)));
action = actionManager->createAction("view_snap_bounding_box");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapBoundingBox(bool)));
action = actionManager->createAction("view_snap_image_bounds");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapImageBounds(bool)));
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();
}
void KisGuidesManager::setView(QPointer view)
{
if (m_d->view) {
KoSnapGuide *snapGuide = m_d->view->canvasBase()->snapGuide();
snapGuide->overrideSnapStrategy(KoSnapGuide::GuideLineSnapping, 0);
snapGuide->enableSnapStrategy(KoSnapGuide::GuideLineSnapping, false);
if (m_d->updateDocumentCompressor.isActive()) {
m_d->updateDocumentCompressor.stop();
slotUploadConfigToDocument();
}
m_d->decoration = 0;
m_d->viewConnections.clear();
attachEventFilterImpl(false);
}
m_d->view = view;
if (m_d->view) {
KisGuidesDecoration* decoration = qobject_cast(m_d->view->canvasBase()->decoration(GUIDES_DECORATION_ID).data());
if (!decoration) {
decoration = new KisGuidesDecoration(m_d->view);
m_d->view->canvasBase()->addDecoration(decoration);
}
m_d->decoration = decoration;
m_d->guidesConfig = m_d->view->document()->guidesConfig();
setGuidesConfigImpl(m_d->guidesConfig, false);
m_d->viewConnections.addUniqueConnection(
m_d->view->zoomManager()->horizontalRuler(), SIGNAL(guideCreationInProgress(Qt::Orientation,QPoint)),
this, SLOT(slotGuideCreationInProgress(Qt::Orientation,QPoint)));
m_d->viewConnections.addUniqueConnection(
m_d->view->zoomManager()->horizontalRuler(), SIGNAL(guideCreationFinished(Qt::Orientation,QPoint)),
this, SLOT(slotGuideCreationFinished(Qt::Orientation,QPoint)));
m_d->viewConnections.addUniqueConnection(
m_d->view->zoomManager()->verticalRuler(), SIGNAL(guideCreationInProgress(Qt::Orientation,QPoint)),
this, SLOT(slotGuideCreationInProgress(Qt::Orientation,QPoint)));
m_d->viewConnections.addUniqueConnection(
m_d->view->zoomManager()->verticalRuler(), SIGNAL(guideCreationFinished(Qt::Orientation,QPoint)),
this, SLOT(slotGuideCreationFinished(Qt::Orientation,QPoint)));
m_d->viewConnections.addUniqueConnection(
m_d->view->document(), SIGNAL(sigGuidesConfigChanged(KisGuidesConfig)),
this, SLOT(slotDocumentRequestedConfig(KisGuidesConfig)));
}
}
KisGuidesManager::Private::GuideHandle
KisGuidesManager::Private::findGuide(const QPointF &docPos)
{
const int snapRadius = 16;
GuideHandle nearestGuide = invalidGuide;
qreal nearestRadius = std::numeric_limits::max();
for (int i = 0; i < guidesConfig.horizontalGuideLines().size(); i++) {
const qreal guide = guidesConfig.horizontalGuideLines()[i];
const qreal radius = qAbs(docPos.y() - guide);
if (radius < snapRadius && radius < nearestRadius) {
nearestGuide = GuideHandle(Qt::Horizontal, i);
nearestRadius = radius;
}
}
for (int i = 0; i < guidesConfig.verticalGuideLines().size(); i++) {
const qreal guide = guidesConfig.verticalGuideLines()[i];
const qreal radius = qAbs(docPos.x() - guide);
if (radius < snapRadius && radius < nearestRadius) {
nearestGuide = GuideHandle(Qt::Vertical, i);
nearestRadius = radius;
}
}
return nearestGuide;
}
bool KisGuidesManager::Private::isGuideValid(const GuideHandle &h)
{
return h.second >= 0;
}
qreal KisGuidesManager::Private::guideValue(const GuideHandle &h)
{
return h.first == Qt::Horizontal ?
guidesConfig.horizontalGuideLines()[h.second] :
guidesConfig.verticalGuideLines()[h.second];
}
void KisGuidesManager::Private::setGuideValue(const GuideHandle &h, qreal value)
{
if (h.first == Qt::Horizontal) {
QList guides = guidesConfig.horizontalGuideLines();
guides[h.second] = value;
guidesConfig.setHorizontalGuideLines(guides);
} else {
QList guides = guidesConfig.verticalGuideLines();
guides[h.second] = value;
guidesConfig.setVerticalGuideLines(guides);
}
}
void KisGuidesManager::Private::deleteGuide(const GuideHandle &h)
{
if (h.first == Qt::Horizontal) {
QList guides = guidesConfig.horizontalGuideLines();
guides.removeAt(h.second);
guidesConfig.setHorizontalGuideLines(guides);
} else {
QList guides = guidesConfig.verticalGuideLines();
guides.removeAt(h.second);
guidesConfig.setVerticalGuideLines(guides);
}
}
bool KisGuidesManager::Private::updateCursor(const QPointF &docPos, bool forceDisableCursor)
{
KisCanvas2 *canvas = view->canvasBase();
const GuideHandle guide = findGuide(docPos);
const bool guideValid = isGuideValid(guide) && !forceDisableCursor;
if (guideValid && !cursorSwitched) {
oldCursor = canvas->canvasWidget()->cursor();
}
if (guideValid) {
cursorSwitched = true;
QCursor newCursor = guide.first == Qt::Horizontal ?
Qt::SizeVerCursor : Qt::SizeHorCursor;
canvas->canvasWidget()->setCursor(newCursor);
}
if (!guideValid && cursorSwitched) {
canvas->canvasWidget()->setCursor(oldCursor);
cursorSwitched = false;
}
return guideValid;
}
void KisGuidesManager::Private::initDragStart(const GuideHandle &guide,
const QPointF &dragStart,
qreal guideValue,
bool snapToStart)
{
currentGuide = guide;
dragStartDoc = dragStart;
dragStartGuidePos = guideValue;
dragPointerOffset =
guide.first == Qt::Horizontal ?
QPointF(0, dragStartGuidePos - dragStartDoc.y()) :
QPointF(dragStartGuidePos - dragStartDoc.x(), 0);
KoSnapGuide *snapGuide = view->canvasBase()->snapGuide();
snapGuide->reset();
if (snapToStart) {
KisSnapLineStrategy *strategy = new KisSnapLineStrategy();
strategy->addLine(guide.first, guideValue);
snapGuide->addCustomSnapStrategy(strategy);
}
}
QPointF KisGuidesManager::Private::alignToPixels(const QPointF docPoint)
{
KisCanvas2 *canvas = view->canvasBase();
const KisCoordinatesConverter *converter = canvas->coordinatesConverter();
QPoint imagePoint = converter->documentToImage(docPoint).toPoint();
return converter->imageToDocument(imagePoint);
}
bool KisGuidesManager::Private::mouseMoveHandler(const QPointF &docPos, Qt::KeyboardModifiers modifiers)
{
if (isGuideValid(currentGuide)) {
KoSnapGuide *snapGuide = view->canvasBase()->snapGuide();
const QPointF snappedPos = snapGuide->snap(docPos, dragPointerOffset, modifiers);
const QPointF offset = snappedPos - dragStartDoc;
const qreal newValue = dragStartGuidePos +
(currentGuide.first == Qt::Horizontal ?
offset.y() : offset.x());
setGuideValue(currentGuide, newValue);
q->setGuidesConfigImpl(guidesConfig);
}
return updateCursor(docPos);
}
bool KisGuidesManager::Private::mouseReleaseHandler(const QPointF &docPos)
{
bool result = false;
KisCanvas2 *canvas = view->canvasBase();
const KisCoordinatesConverter *converter = canvas->coordinatesConverter();
if (isGuideValid(currentGuide)) {
const QRectF docRect = converter->imageRectInDocumentPixels();
// TODO: enable work rect after we fix painting guides
// outside canvas in openGL mode
const QRectF workRect = KisAlgebra2D::blowRect(docRect, 0 /*0.2*/);
if (!workRect.contains(docPos)) {
deleteGuide(currentGuide);
q->setGuidesConfigImpl(guidesConfig);
/**
* When we delete a guide, it might happen that we are
* deleting the last guide. Therefore we should eat the
* corresponding event so that the event filter would stop
* the filter processing.
*/
result = true;
}
currentGuide = invalidGuide;
dragStartDoc = QPointF();
dragPointerOffset = QPointF();
dragStartGuidePos = 0;
KoSnapGuide *snapGuide = view->canvasBase()->snapGuide();
snapGuide->reset();
updateSnappingStatus(guidesConfig);
}
return updateCursor(docPos) | result;
}
QPointF KisGuidesManager::Private::getDocPointFromEvent(QEvent *event)
{
QPointF result;
KisCanvas2 *canvas = view->canvasBase();
const KisCoordinatesConverter *converter = canvas->coordinatesConverter();
if (event->type() == QEvent::Enter) {
QEnterEvent *enterEvent = static_cast(event);
result = alignToPixels(converter->widgetToDocument(enterEvent->pos()));
} else if (event->type() == QEvent::MouseMove ||
event->type() == QEvent::MouseButtonPress ||
event->type() == QEvent::MouseButtonRelease) {
QMouseEvent *mouseEvent = static_cast(event);
result = alignToPixels(converter->widgetToDocument(mouseEvent->pos()));
} else if (event->type() == QEvent::TabletMove ||
event->type() == QEvent::TabletPress ||
event->type() == QEvent::TabletRelease) {
QTabletEvent *tabletEvent = static_cast(event);
result = alignToPixels(converter->widgetToDocument(tabletEvent->pos()));
} else {
// we shouldn't silently return QPointF(0,0), higher level code may
// snap to some unexpected guide
KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "event type is not supported!");
}
return result;
}
Qt::MouseButton KisGuidesManager::Private::getButtonFromEvent(QEvent *event)
{
Qt::MouseButton button = Qt::NoButton;
if (event->type() == QEvent::MouseMove ||
event->type() == QEvent::MouseButtonPress ||
event->type() == QEvent::MouseButtonRelease) {
QMouseEvent *mouseEvent = static_cast(event);
button = mouseEvent->button();
} else if (event->type() == QEvent::TabletMove ||
event->type() == QEvent::TabletPress ||
event->type() == QEvent::TabletRelease) {
QTabletEvent *tabletEvent = static_cast(event);
button = tabletEvent->button();
}
return button;
}
bool KisGuidesManager::eventFilter(QObject *obj, QEvent *event)
{
if (!m_d->view || obj != m_d->view->canvasBase()->canvasWidget()) return false;
bool retval = false;
switch (event->type()) {
case QEvent::Leave:
m_d->updateCursor(QPointF(), true);
break;
case QEvent::Enter:
case QEvent::TabletMove:
case QEvent::MouseMove: {
const QPointF docPos = m_d->getDocPointFromEvent(event);
const Qt::KeyboardModifiers modifiers = qApp->keyboardModifiers();
// we should never eat Enter events, input manager may get crazy about it
retval = m_d->mouseMoveHandler(docPos, modifiers) && event->type() != QEvent::Enter;
break;
}
case QEvent::TabletPress:
case QEvent::MouseButtonPress: {
if (m_d->getButtonFromEvent(event) != Qt::LeftButton) break;
const QPointF docPos = m_d->getDocPointFromEvent(event);
const Private::GuideHandle guide = m_d->findGuide(docPos);
const bool guideValid = m_d->isGuideValid(guide);
if (guideValid) {
m_d->initDragStart(guide, docPos, m_d->guideValue(guide), true);
}
retval = m_d->updateCursor(docPos);
break;
}
case QEvent::TabletRelease:
case QEvent::MouseButtonRelease: {
if (m_d->getButtonFromEvent(event) != Qt::LeftButton) break;
const QPointF docPos = m_d->getDocPointFromEvent(event);
retval = m_d->mouseReleaseHandler(docPos);
break;
}
default:
break;
}
return !retval ? QObject::eventFilter(obj, event) : true;
}
void KisGuidesManager::slotGuideCreationInProgress(Qt::Orientation orientation, const QPoint &globalPos)
{
if (m_d->guidesConfig.lockGuides()) return;
KisCanvas2 *canvas = m_d->view->canvasBase();
const KisCoordinatesConverter *converter = canvas->coordinatesConverter();
const QPointF widgetPos = canvas->canvasWidget()->mapFromGlobal(globalPos);
const QPointF docPos = m_d->alignToPixels(converter->widgetToDocument(widgetPos));
if (m_d->isGuideValid(m_d->currentGuide)) {
const Qt::KeyboardModifiers modifiers = qApp->keyboardModifiers();
m_d->mouseMoveHandler(docPos, modifiers);
} else {
m_d->guidesConfig.setShowGuides(true);
if (orientation == Qt::Horizontal) {
QList guides = m_d->guidesConfig.horizontalGuideLines();
guides.append(docPos.y());
m_d->currentGuide.first = orientation;
m_d->currentGuide.second = guides.size() - 1;
m_d->guidesConfig.setHorizontalGuideLines(guides);
m_d->initDragStart(m_d->currentGuide, docPos, docPos.y(), false);
} else {
QList guides = m_d->guidesConfig.verticalGuideLines();
guides.append(docPos.x());
m_d->currentGuide.first = orientation;
m_d->currentGuide.second = guides.size() - 1;
m_d->guidesConfig.setVerticalGuideLines(guides);
m_d->initDragStart(m_d->currentGuide, docPos, docPos.x(), false);
}
setGuidesConfigImpl(m_d->guidesConfig);
}
}
void KisGuidesManager::slotGuideCreationFinished(Qt::Orientation orientation, const QPoint &globalPos)
{
Q_UNUSED(orientation);
if (m_d->guidesConfig.lockGuides()) return;
KisCanvas2 *canvas = m_d->view->canvasBase();
const KisCoordinatesConverter *converter = canvas->coordinatesConverter();
const QPointF widgetPos = canvas->canvasWidget()->mapFromGlobal(globalPos);
const QPointF docPos = m_d->alignToPixels(converter->widgetToDocument(widgetPos));
m_d->mouseReleaseHandler(docPos);
}
QAction* KisGuidesManager::Private::createShortenedAction(const QString &text, const QString &parentId, QObject *parent)
{
KisActionManager *actionManager = view->viewManager()->actionManager();
QAction *action = 0;
KisAction *parentAction = 0;
action = new QAction(text, parent);
action->setCheckable(true);
parentAction = actionManager->actionByName(parentId);
action->setChecked(parentAction->isChecked());
+ qDebug() << parentAction;
connect(action, SIGNAL(toggled(bool)), parentAction, SLOT(setChecked(bool)));
return action;
}
void KisGuidesManager::slotShowSnapOptions()
{
const QPoint pos = QCursor::pos();
QMenu menu;
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));
menu.addAction(m_d->createShortenedAction(i18n("Extension"), "view_snap_extension", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Intersection"), "view_snap_intersection", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Bounding Box"), "view_snap_bounding_box", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Image Bounds"), "view_snap_image_bounds", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Image Center"), "view_snap_image_center", &menu));
menu.exec(pos);
}
void KisGuidesManager::setSnapOrthogonal(bool value)
{
m_d->snapConfig.setOrthogonal(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapNode(bool value)
{
m_d->snapConfig.setNode(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapExtension(bool value)
{
m_d->snapConfig.setExtension(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapIntersection(bool value)
{
m_d->snapConfig.setIntersection(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapBoundingBox(bool value)
{
m_d->snapConfig.setBoundingBox(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapImageBounds(bool value)
{
m_d->snapConfig.setImageBounds(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapImageCenter(bool value)
{
m_d->snapConfig.setImageCenter(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapToPixel(bool value)
{
+ qDebug() << "Checked";
m_d->snapConfig.setToPixel(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
- qDebug() << "Pressed";
}