diff --git a/krita/krita4.xmlgui b/krita/krita4.xmlgui
index bbf3369399..020d78ddb5 100644
--- a/krita/krita4.xmlgui
+++ b/krita/krita4.xmlgui
@@ -1,386 +1,387 @@
&View
&Canvas
&Snap To
&Image
&Rotate
&Layer
New
&Import/Export
Import
&Convert
&Select
&Group
&Transform
&Rotate
S&plit
S&plit Alpha
&Select
+
Select &Opaque
Filte&r
&Tools
Scripts
Setti&ngs
&Help
File
Brushes and Stuff
diff --git a/krita/kritamenu.action b/krita/kritamenu.action
index cdfdfa9470..3b2fce8b2e 100644
--- a/krita/kritamenu.action
+++ b/krita/kritamenu.action
@@ -1,1806 +1,1818 @@
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
application-pdf
&Export as PDF...
Export as PDF
Export as PDF
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 Image Sequence Again
Render Animation to Image Sequence 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
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
&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
W
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
0
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 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
&Invert Selection
Invert Selection
Invert Selection
10000
0
Ctrl+I
false
&Convert to Vector Selection
Convert to Vector Selection
Convert to Vector Selection
- 10000000000
+ 100000000000000000
+ 0
+
+ false
+
+
+
+
+ &Convert to Raster Selection
+
+ Convert to Raster Selection
+ Convert to Raster Selection
+ 10000000000000000
0
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/actions/kis_selection_action_factories.cpp b/libs/ui/actions/kis_selection_action_factories.cpp
index 5bf61127e7..5a0b4bb13b 100644
--- a/libs/ui/actions/kis_selection_action_factories.cpp
+++ b/libs/ui/actions/kis_selection_action_factories.cpp
@@ -1,615 +1,649 @@
/*
* Copyright (c) 2012 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_selection_action_factories.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "KisViewManager.h"
#include "kis_canvas_resource_provider.h"
#include "kis_clipboard.h"
#include "kis_pixel_selection.h"
#include "kis_paint_layer.h"
#include "kis_image.h"
#include "kis_image_barrier_locker.h"
#include "kis_fill_painter.h"
#include "kis_transaction.h"
#include "kis_iterator_ng.h"
#include "kis_processing_applicator.h"
#include "kis_group_layer.h"
#include "commands/kis_selection_commands.h"
#include "commands/kis_image_layer_add_command.h"
#include "kis_tool_proxy.h"
#include "kis_canvas2.h"
#include "kis_canvas_controller.h"
#include "kis_selection_manager.h"
#include "kis_transaction_based_command.h"
#include "kis_selection_filters.h"
#include "kis_shape_selection.h"
#include "kis_shape_layer.h"
#include
#include "kis_image_animation_interface.h"
#include "kis_time_range.h"
#include "kis_keyframe_channel.h"
#include
#include
#include "kis_figure_painting_tool_helper.h"
#include "kis_update_outline_job.h"
namespace ActionHelper {
void copyFromDevice(KisViewManager *view,
KisPaintDeviceSP device,
bool makeSharpClip = false,
const KisTimeRange &range = KisTimeRange())
{
KisImageWSP image = view->image();
if (!image) return;
KisSelectionSP selection = view->selection();
QRect rc = (selection) ? selection->selectedExactRect() : image->bounds();
KisPaintDeviceSP clip = new KisPaintDevice(device->colorSpace());
Q_CHECK_PTR(clip);
const KoColorSpace *cs = clip->colorSpace();
// TODO if the source is linked... copy from all linked layers?!?
// Copy image data
KisPainter::copyAreaOptimized(QPoint(), device, clip, rc);
if (selection) {
// Apply selection mask.
KisPaintDeviceSP selectionProjection = selection->projection();
KisHLineIteratorSP layerIt = clip->createHLineIteratorNG(0, 0, rc.width());
KisHLineConstIteratorSP selectionIt = selectionProjection->createHLineIteratorNG(rc.x(), rc.y(), rc.width());
const KoColorSpace *selCs = selection->projection()->colorSpace();
for (qint32 y = 0; y < rc.height(); y++) {
for (qint32 x = 0; x < rc.width(); x++) {
/**
* Sharp method is an exact reverse of COMPOSITE_OVER
* so if you cover the cut/copied piece over its source
* you get an exactly the same image without any seams
*/
if (makeSharpClip) {
qreal dstAlpha = cs->opacityF(layerIt->rawData());
qreal sel = selCs->opacityF(selectionIt->oldRawData());
qreal newAlpha = sel * dstAlpha / (1.0 - dstAlpha + sel * dstAlpha);
float mask = newAlpha / dstAlpha;
cs->applyAlphaNormedFloatMask(layerIt->rawData(), &mask, 1);
} else {
cs->applyAlphaU8Mask(layerIt->rawData(), selectionIt->oldRawData(), 1);
}
layerIt->nextPixel();
selectionIt->nextPixel();
}
layerIt->nextRow();
selectionIt->nextRow();
}
}
KisClipboard::instance()->setClip(clip, rc.topLeft(), range);
}
}
void KisSelectAllActionFactory::run(KisViewManager *view)
{
KisImageWSP image = view->image();
if (!image) return;
KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Select All"));
if (!image->globalSelection()) {
ap->applyCommand(new KisSetEmptyGlobalSelectionCommand(image),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
}
struct SelectAll : public KisTransactionBasedCommand {
SelectAll(KisImageSP image) : m_image(image) {}
KisImageSP m_image;
KUndo2Command* paint() override {
KisSelectionSP selection = m_image->globalSelection();
KisSelectionTransaction transaction(selection->pixelSelection());
selection->pixelSelection()->clear();
selection->pixelSelection()->select(m_image->bounds());
return transaction.endAndTake();
}
};
ap->applyCommand(new SelectAll(image),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
endAction(ap, KisOperationConfiguration(id()).toXML());
}
void KisDeselectActionFactory::run(KisViewManager *view)
{
KisImageWSP image = view->image();
if (!image) return;
KUndo2Command *cmd = new KisDeselectActiveSelectionCommand(view->selection(), image);
KisProcessingApplicator *ap = beginAction(view, cmd->text());
ap->applyCommand(cmd, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE);
endAction(ap, KisOperationConfiguration(id()).toXML());
}
void KisReselectActionFactory::run(KisViewManager *view)
{
KisImageWSP image = view->image();
if (!image) return;
KUndo2Command *cmd = new KisReselectActiveSelectionCommand(view->activeNode(), image);
KisProcessingApplicator *ap = beginAction(view, cmd->text());
ap->applyCommand(cmd, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE);
endAction(ap, KisOperationConfiguration(id()).toXML());
}
void KisFillActionFactory::run(const QString &fillSource, KisViewManager *view)
{
KisNodeSP node = view->activeNode();
if (!node || !node->hasEditablePaintDevice()) return;
KisSelectionSP selection = view->selection();
QRect selectedRect = selection ?
selection->selectedRect() : view->image()->bounds();
Q_UNUSED(selectedRect);
KisPaintDeviceSP filled = node->paintDevice()->createCompositionSourceDevice();
Q_UNUSED(filled);
bool usePattern = false;
bool useBgColor = false;
if (fillSource.contains("pattern")) {
usePattern = true;
} else if (fillSource.contains("bg")) {
useBgColor = true;
}
KisProcessingApplicator applicator(view->image(), node,
KisProcessingApplicator::NONE,
KisImageSignalVector() << ModifiedSignal,
kundo2_i18n("Flood Fill Layer"));
KisResourcesSnapshotSP resources =
new KisResourcesSnapshot(view->image(), node, view->resourceProvider()->resourceManager());
if (!fillSource.contains("opacity")) {
resources->setOpacity(1.0);
}
KisProcessingVisitorSP visitor =
new FillProcessingVisitor(QPoint(0, 0), // start position
selection,
resources,
false, // fast mode
usePattern,
true, // fill only selection,
0, // feathering radius
0, // sizemod
80, // threshold,
false, // unmerged
useBgColor);
applicator.applyVisitor(visitor,
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
applicator.end();
}
void KisClearActionFactory::run(KisViewManager *view)
{
// XXX: "Add saving of XML data for Clear action"
view->canvasBase()->toolProxy()->deleteSelection();
}
void KisImageResizeToSelectionActionFactory::run(KisViewManager *view)
{
// XXX: "Add saving of XML data for Image Resize To Selection action"
KisSelectionSP selection = view->selection();
if (!selection) return;
view->image()->cropImage(selection->selectedExactRect());
}
void KisCutCopyActionFactory::run(bool willCut, bool makeSharpClip, KisViewManager *view)
{
KisImageSP image = view->image();
if (!image) return;
bool haveShapesSelected = view->selectionManager()->haveShapesSelected();
if (haveShapesSelected) {
// XXX: "Add saving of XML data for Cut/Copy of shapes"
KisImageBarrierLocker locker(image);
if (willCut) {
view->canvasBase()->toolProxy()->cut();
} else {
view->canvasBase()->toolProxy()->copy();
}
} else {
KisNodeSP node = view->activeNode();
if (!node) return;
KisSelectionSP selection = view->selection();
if (selection.isNull()) return;
{
KisImageBarrierLocker locker(image);
KisPaintDeviceSP dev = node->paintDevice();
if (!dev) {
dev = node->projection();
}
if (!dev) {
view->showFloatingMessage(
i18nc("floating message when cannot copy from a node",
"Cannot copy pixels from this type of layer "),
QIcon(), 3000, KisFloatingMessage::Medium);
return;
}
if (dev->exactBounds().isEmpty()) {
view->showFloatingMessage(
i18nc("floating message when copying empty selection",
"Selection is empty: no pixels were copied "),
QIcon(), 3000, KisFloatingMessage::Medium);
return;
}
KisTimeRange range;
KisKeyframeChannel *channel = node->getKeyframeChannel(KisKeyframeChannel::Content.id());
if (channel) {
const int currentTime = image->animationInterface()->currentTime();
range = channel->affectedFrames(currentTime);
}
ActionHelper::copyFromDevice(view, dev, makeSharpClip, range);
}
KUndo2Command *command = 0;
if (willCut && node->hasEditablePaintDevice()) {
struct ClearSelection : public KisTransactionBasedCommand {
ClearSelection(KisNodeSP node, KisSelectionSP sel)
: m_node(node), m_sel(sel) {}
KisNodeSP m_node;
KisSelectionSP m_sel;
KUndo2Command* paint() override {
KisSelectionSP cutSelection = m_sel;
// Shrinking the cutting area was previously used
// for getting seamless cut-paste. Now we use makeSharpClip
// instead.
// QRect originalRect = cutSelection->selectedExactRect();
// static const int preciseSelectionThreshold = 16;
//
// if (originalRect.width() > preciseSelectionThreshold ||
// originalRect.height() > preciseSelectionThreshold) {
// cutSelection = new KisSelection(*m_sel);
// delete cutSelection->flatten();
//
// KisSelectionFilter* filter = new KisShrinkSelectionFilter(1, 1, false);
//
// QRect processingRect = filter->changeRect(originalRect);
// filter->process(cutSelection->pixelSelection(), processingRect);
// }
KisTransaction transaction(m_node->paintDevice());
m_node->paintDevice()->clearSelection(cutSelection);
m_node->setDirty(cutSelection->selectedRect());
return transaction.endAndTake();
}
};
command = new ClearSelection(node, selection);
}
KUndo2MagicString actionName = willCut ?
kundo2_i18n("Cut") :
kundo2_i18n("Copy");
KisProcessingApplicator *ap = beginAction(view, actionName);
if (command) {
ap->applyCommand(command,
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::NORMAL);
}
KisOperationConfiguration config(id());
config.setProperty("will-cut", willCut);
endAction(ap, config.toXML());
}
}
void KisCopyMergedActionFactory::run(KisViewManager *view)
{
KisImageWSP image = view->image();
if (!image) return;
if (!view->blockUntilOperationsFinished(image)) return;
image->barrierLock();
KisPaintDeviceSP dev = image->root()->projection();
ActionHelper::copyFromDevice(view, dev);
image->unlock();
KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Copy Merged"));
endAction(ap, KisOperationConfiguration(id()).toXML());
}
void KisPasteNewActionFactory::run(KisViewManager *viewManager)
{
Q_UNUSED(viewManager);
KisPaintDeviceSP clip = KisClipboard::instance()->clip(QRect(), true);
if (!clip) return;
QRect rect = clip->exactBounds();
if (rect.isEmpty()) return;
KisDocument *doc = KisPart::instance()->createDocument();
doc->documentInfo()->setAboutInfo("title", i18n("Untitled"));
KisImageSP image = new KisImage(doc->createUndoStore(),
rect.width(),
rect.height(),
clip->colorSpace(),
i18n("Pasted"));
KisPaintLayerSP layer =
new KisPaintLayer(image.data(), image->nextLayerName() + " " + i18n("(pasted)"),
OPACITY_OPAQUE_U8, clip->colorSpace());
KisPainter::copyAreaOptimized(QPoint(), clip, layer->paintDevice(), rect);
image->addNode(layer.data(), image->rootLayer());
doc->setCurrentImage(image);
KisPart::instance()->addDocument(doc);
KisMainWindow *win = viewManager->mainWindow();
win->addViewAndNotifyLoadingCompleted(doc);
}
void KisInvertSelectionOperation::runFromXML(KisViewManager* view, const KisOperationConfiguration& config)
{
KisSelectionFilter* filter = new KisInvertSelectionFilter();
runFilter(filter, view, config);
}
void KisSelectionToVectorActionFactory::run(KisViewManager *view)
{
KisSelectionSP selection = view->selection();
if (selection->hasShapeSelection()) {
view->showFloatingMessage(i18nc("floating message",
"Selection is already in a vector format "),
QIcon(), 2000, KisFloatingMessage::Low);
return;
}
if (!selection->outlineCacheValid()) {
view->image()->addSpontaneousJob(new KisUpdateOutlineJob(selection, false, Qt::transparent));
if (!view->blockUntilOperationsFinished(view->image())) {
return;
}
}
QPainterPath selectionOutline = selection->outlineCache();
QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform();
KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(selectionOutline));
shape->setShapeId(KoPathShapeId);
/**
* Mark a shape that it belongs to a shape selection
*/
if(!shape->userData()) {
shape->setUserData(new KisShapeSelectionMarker);
}
KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Convert to Vector Selection"));
ap->applyCommand(view->canvasBase()->shapeController()->addShape(shape, 0),
KisStrokeJobData::SEQUENTIAL,
KisStrokeJobData::EXCLUSIVE);
endAction(ap, KisOperationConfiguration(id()).toXML());
}
+void KisSelectionToRasterActionFactory::run(KisViewManager *view)
+{
+ KisSelectionSP selection = view->selection();
+
+ if (!selection->hasShapeSelection()) {
+ view->showFloatingMessage(i18nc("floating message",
+ "Selection is already in a raster format "),
+ QIcon(), 2000, KisFloatingMessage::Low);
+ return;
+ }
+
+ KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Convert to Vector Selection"));
+
+ struct RasterizeSelection : public KisTransactionBasedCommand {
+ RasterizeSelection(KisSelectionSP sel)
+ : m_sel(sel) {}
+ KisSelectionSP m_sel;
+
+ KUndo2Command* paint() override {
+ // just create an empty transaction: it will rasterize the
+ // selection and emit the necessary signals
+
+ KisTransaction transaction(m_sel->pixelSelection());
+ return transaction.endAndTake();
+ }
+ };
+
+ ap->applyCommand(new RasterizeSelection(selection),
+ KisStrokeJobData::SEQUENTIAL,
+ KisStrokeJobData::EXCLUSIVE);
+
+ endAction(ap, KisOperationConfiguration(id()).toXML());
+}
+
void KisShapesToVectorSelectionActionFactory::run(KisViewManager* view)
{
const QList originalShapes = view->canvasBase()->shapeManager()->selection()->selectedShapes();
bool hasSelectionShapes = false;
QList clonedShapes;
Q_FOREACH (KoShape *shape, originalShapes) {
if (dynamic_cast(shape->userData())) {
hasSelectionShapes = true;
continue;
}
clonedShapes << shape->cloneShape();
}
if (clonedShapes.isEmpty()) {
if (hasSelectionShapes) {
view->showFloatingMessage(i18nc("floating message",
"The shape already belongs to a selection"),
QIcon(), 2000, KisFloatingMessage::Low);
}
return;
}
KisSelectionToolHelper helper(view->canvasBase(), kundo2_i18n("Convert shapes to vector selection"));
helper.addSelectionShapes(clonedShapes);
}
void KisSelectionToShapeActionFactory::run(KisViewManager *view)
{
KisSelectionSP selection = view->selection();
if (!selection->outlineCacheValid()) {
return;
}
QPainterPath selectionOutline = selection->outlineCache();
QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform();
KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(selectionOutline));
shape->setShapeId(KoPathShapeId);
KoColor fgColor = view->canvasBase()->resourceManager()->resource(KoCanvasResourceManager::ForegroundColor).value();
KoShapeStrokeSP border(new KoShapeStroke(1.0, fgColor.toQColor()));
shape->setStroke(border);
view->document()->shapeController()->addShape(shape);
}
void KisStrokeSelectionActionFactory::run(KisViewManager *view, StrokeSelectionOptions params)
{
KisImageWSP image = view->image();
if (!image) {
return;
}
KisSelectionSP selection = view->selection();
if (!selection) {
return;
}
int size = params.lineSize;
KisPixelSelectionSP pixelSelection = selection->projection();
if (!pixelSelection->outlineCacheValid()) {
pixelSelection->recalculateOutlineCache();
}
QPainterPath outline = pixelSelection->outlineCache();
QColor color = params.color.toQColor();
KisNodeSP currentNode = view->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value();
if (!currentNode->inherits("KisShapeLayer") && currentNode->paintDevice()) {
KoCanvasResourceManager * rManager = view->resourceProvider()->resourceManager();
KisPainter::StrokeStyle strokeStyle = KisPainter::StrokeStyleBrush;
KisPainter::FillStyle fillStyle = params.fillStyle();
KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Polyline"),
image,
currentNode,
rManager ,
strokeStyle,
fillStyle);
helper.setFGColorOverride(params.color);
helper.setSelectionOverride(0);
QPen pen(Qt::red, size);
pen.setJoinStyle(Qt::RoundJoin);
if (fillStyle != KisPainter::FillStyleNone) {
helper.paintPainterPathQPenFill(outline, pen, params.fillColor);
}
else {
helper.paintPainterPathQPen(outline, pen, params.fillColor);
}
}
else {
QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform();
KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(outline));
shape->setShapeId(KoPathShapeId);
KoShapeStrokeSP border(new KoShapeStroke(size, color));
shape->setStroke(border);
view->document()->shapeController()->addShape(shape);
}
image->setModified();
}
void KisStrokeBrushSelectionActionFactory::run(KisViewManager *view, StrokeSelectionOptions params)
{
KisImageWSP image = view->image();
if (!image) {
return;
}
KisSelectionSP selection = view->selection();
if (!selection) {
return;
}
KisPixelSelectionSP pixelSelection = selection->projection();
if (!pixelSelection->outlineCacheValid()) {
pixelSelection->recalculateOutlineCache();
}
KisNodeSP currentNode = view->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value();
if (!currentNode->inherits("KisShapeLayer") && currentNode->paintDevice())
{
KoCanvasResourceManager * rManager = view->resourceProvider()->resourceManager();
QPainterPath outline = pixelSelection->outlineCache();
KisPainter::StrokeStyle strokeStyle = KisPainter::StrokeStyleBrush;
KisPainter::FillStyle fillStyle = KisPainter::FillStyleNone;
KoColor color = params.color;
KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Polyline"),
image,
currentNode,
rManager ,
strokeStyle,
fillStyle);
helper.setFGColorOverride(color);
helper.setSelectionOverride(0);
helper.paintPainterPath(outline);
image->setModified();
}
}
diff --git a/libs/ui/actions/kis_selection_action_factories.h b/libs/ui/actions/kis_selection_action_factories.h
index adfe7dcbac..8fe9e3d39b 100644
--- a/libs/ui/actions/kis_selection_action_factories.h
+++ b/libs/ui/actions/kis_selection_action_factories.h
@@ -1,129 +1,134 @@
/*
* Copyright (c) 2012 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.
*/
#ifndef __KIS_SELECTION_ACTION_FACTORIES_H
#define __KIS_SELECTION_ACTION_FACTORIES_H
#include "operations/kis_operation.h"
#include "operations/kis_operation_configuration.h"
#include "operations/kis_filter_selection_operation.h"
#include "dialogs/kis_dlg_stroke_selection_properties.h"
class KRITAUI_EXPORT KisNoParameterActionFactory : public KisOperation
{
public:
KisNoParameterActionFactory(const QString &id) : KisOperation(id) {}
void runFromXML(KisViewManager *view, const KisOperationConfiguration &config) override {
Q_UNUSED(config);
run(view);
}
virtual void run(KisViewManager *view) = 0;
};
struct KRITAUI_EXPORT KisSelectAllActionFactory : public KisNoParameterActionFactory {
KisSelectAllActionFactory() : KisNoParameterActionFactory("select-all-ui-action") {}
void run(KisViewManager *view) override;
};
struct KRITAUI_EXPORT KisDeselectActionFactory : public KisNoParameterActionFactory {
KisDeselectActionFactory() : KisNoParameterActionFactory("deselect-ui-action") {}
void run(KisViewManager *view) override;
};
struct KRITAUI_EXPORT KisReselectActionFactory : public KisNoParameterActionFactory {
KisReselectActionFactory() : KisNoParameterActionFactory("reselect-ui-action") {}
void run(KisViewManager *view) override;
};
struct KRITAUI_EXPORT KisFillActionFactory : public KisOperation
{
KisFillActionFactory() : KisOperation("fill-ui-action") {}
void runFromXML(KisViewManager *view, const KisOperationConfiguration &config) override {
run(config.getString("fill-source", "fg"), view);
}
/**
* \p fillColor may be one of three variants:
* - "fg" --- foreground color
* - "bg" --- background color
* - "pattern" --- current pattern
*/
void run(const QString &fillSource, KisViewManager *view);
};
struct KRITAUI_EXPORT KisClearActionFactory : public KisNoParameterActionFactory {
KisClearActionFactory() : KisNoParameterActionFactory("clear-ui-action") {}
void run(KisViewManager *view) override;
};
struct KRITAUI_EXPORT KisImageResizeToSelectionActionFactory : public KisNoParameterActionFactory {
KisImageResizeToSelectionActionFactory() : KisNoParameterActionFactory("resize-to-selection-ui-action") {}
void run(KisViewManager *view) override;
};
struct KRITAUI_EXPORT KisCutCopyActionFactory : public KisOperation {
KisCutCopyActionFactory() : KisOperation("cut-copy-ui-action") {}
void runFromXML(KisViewManager *view, const KisOperationConfiguration &config) override {
run(config.getBool("will-cut", false), config.getBool("use-sharp-clip", false), view);
}
void run(bool willCut, bool makeSharpClip, KisViewManager *view);
};
struct KRITAUI_EXPORT KisCopyMergedActionFactory : public KisNoParameterActionFactory {
KisCopyMergedActionFactory() : KisNoParameterActionFactory("copy-merged-ui-action") {}
void run(KisViewManager *view) override;
};
struct KRITAUI_EXPORT KisPasteNewActionFactory : public KisNoParameterActionFactory {
KisPasteNewActionFactory() : KisNoParameterActionFactory("paste-new-ui-action") {}
void run(KisViewManager *view) override;
};
struct KisInvertSelectionOperation : public KisFilterSelectionOperation {
KisInvertSelectionOperation() : KisFilterSelectionOperation("invertselection") {}
void runFromXML(KisViewManager *view, const KisOperationConfiguration &config) override;
};
struct KRITAUI_EXPORT KisSelectionToVectorActionFactory : public KisNoParameterActionFactory {
- KisSelectionToVectorActionFactory() : KisNoParameterActionFactory("paste-new-ui-action") {}
+ KisSelectionToVectorActionFactory() : KisNoParameterActionFactory("selection-to-vector") {}
+ void run(KisViewManager *view) override;
+};
+
+struct KRITAUI_EXPORT KisSelectionToRasterActionFactory : public KisNoParameterActionFactory {
+ KisSelectionToRasterActionFactory() : KisNoParameterActionFactory("selection-to-raster") {}
void run(KisViewManager *view) override;
};
struct KRITAUI_EXPORT KisShapesToVectorSelectionActionFactory : public KisNoParameterActionFactory {
- KisShapesToVectorSelectionActionFactory() : KisNoParameterActionFactory("paste-new-ui-action") {}
+ KisShapesToVectorSelectionActionFactory() : KisNoParameterActionFactory("shapes-to-vector-selection") {}
void run(KisViewManager *view) override;
};
struct KRITAUI_EXPORT KisSelectionToShapeActionFactory : public KisNoParameterActionFactory {
KisSelectionToShapeActionFactory() : KisNoParameterActionFactory("selection-to-shape-action") {}
void run(KisViewManager *view) override;
};
struct KRITAUI_EXPORT KisStrokeSelectionActionFactory : public KisOperation {
KisStrokeSelectionActionFactory() : KisOperation("selection-to-shape-action") {}
void run(KisViewManager *view, StrokeSelectionOptions params);
};
struct KRITAUI_EXPORT KisStrokeBrushSelectionActionFactory : public KisOperation {
KisStrokeBrushSelectionActionFactory() : KisOperation("selection-to-shape-action") {}
void run(KisViewManager *view, StrokeSelectionOptions params);
};
#endif /* __KIS_SELECTION_ACTION_FACTORIES_H */
diff --git a/libs/ui/kis_action.h b/libs/ui/kis_action.h
index 623fd713e8..8777a09e8b 100644
--- a/libs/ui/kis_action.h
+++ b/libs/ui/kis_action.h
@@ -1,131 +1,133 @@
/*
* Copyright (c) 2013 Sven Langkamp
*
* 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.
*/
#ifndef KIS_ACTION_H
#define KIS_ACTION_H
#include
#include
#include
#include
class KisActionManager;
/**
* KisAction, inheriting from QWidgetAction, is a convenience class for GUI
* actions, with Krita's configuration system and GUI states. A widget like a
* "save" button may be enabled/disabled, hidden or shown depending on the
* state of the application, e.g. whether the image currently being viewed was
* modified since it was opened.
*
* Copies of these actions are created for each MainWindow instance. They are
* owned by a KisActionManager, of which there is one for each MainWindow. Most
* of these instantiations happen inside the constructor for KisMainWindow as
* well as the various functions called in KisViewManager::setupManagers().
*
**/
class KRITAUI_EXPORT KisAction : public QWidgetAction
{
Q_OBJECT
public:
/**
* If you re-order these, you must change the associated values in
* krita.action and kritamenu.action!
*/
enum ActivationFlag {
NONE = 0x0000, ///< Always activate
ACTIVE_IMAGE = 0x0001, ///< Activate if there is at least one image
MULTIPLE_IMAGES = 0x0002, ///< Activate if there is more than one image open
CURRENT_IMAGE_MODIFIED = 0x0004, ///< Activate if the current image is modified
ACTIVE_NODE = 0x0008, ///< Activate if there's an active node (layer or mask)
ACTIVE_DEVICE = 0x0010, ///< Activate if the active node has a paint device, i.e. there are pixels to be modified
ACTIVE_LAYER = 0x0020, ///< Activate if the current node is a layer (vector or pixel)
ACTIVE_TRANSPARENCY_MASK = 0x0040, ///< Activate if the current node is a transparency mask
ACTIVE_SHAPE_LAYER = 0x0080, ///< Activate if the current node is a vector layer
- PIXELS_SELECTED = 0x0100, ///< Activate if there is an active pixel selection
- SHAPES_SELECTED = 0x0200, ///< Activate if there is an active vector selection
- PIXEL_SELECTION_WITH_PIXELS = 0x0400, ///< ???
+ PIXELS_SELECTED = 0x0100, ///< Activate if any pixels are selcted (with any kind of selection)
+ SHAPES_SELECTED = 0x0200, ///< Activate if any vector shape is selected
+ ANY_SELECTION_WITH_PIXELS = 0x0400, ///< ???
PIXELS_IN_CLIPBOARD = 0x0800, ///< Activate if the clipboard contains pixels
SHAPES_IN_CLIPBOARD = 0x1000, ///< Activate if the clipboard contains vector data
NEVER_ACTIVATE = 0x2000, ///< ???
LAYERS_IN_CLIPBOARD = 0x4000, ///< ???
IMAGE_HAS_ANIMATION = 0x8000, ///< Activate if the image has an animation
+ SHAPE_SELECTION_WITH_SHAPES = 0x10000, ///< Activate there is a vector selection active
+ PIXEL_SELECTION_WITH_PIXELS = 0x20000, ///< Activate there is a raster selection active
};
Q_DECLARE_FLAGS(ActivationFlags, ActivationFlag)
enum ActivationCondition {
NO_CONDITION = 0,
ACTIVE_NODE_EDITABLE = 0x1,
ACTIVE_NODE_EDITABLE_PAINT_DEVICE = 0x2,
SELECTION_EDITABLE = 0x4
};
Q_DECLARE_FLAGS(ActivationConditions, ActivationCondition)
explicit KisAction(QObject* parent = 0);
KisAction(const QString& text, QObject* parent = 0);
KisAction(const QIcon& icon, const QString& text, QObject* parent = 0);
~KisAction() override;
void setDefaultShortcut(const QKeySequence & shortcut);
QKeySequence defaultShortcut() const;
void setActivationFlags(ActivationFlags flags);
ActivationFlags activationFlags();
void setActivationConditions(ActivationConditions conditions);
ActivationConditions activationConditions();
void setExcludedNodeTypes(const QStringList &nodeTypes);
const QStringList& excludedNodeTypes() const;
virtual void setActionEnabled(bool enabled);
/**
* Set operation id. This will used to run an operation in the KisActionManager
*/
void setOperationID(const QString& id);
Q_SIGNALS:
void sigEnableSlaves(bool value);
private Q_SLOTS:
void slotTriggered();
void slotChanged();
private:
friend class KisActionManager;
/**
* Set the action manager. Only used by KisActionManager
*/
void setActionManager(KisActionManager* actionManager);
class Private;
Private* const d;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(KisAction::ActivationFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(KisAction::ActivationConditions)
#endif // KIS_ACTION_H
diff --git a/libs/ui/kis_action_manager.cpp b/libs/ui/kis_action_manager.cpp
index b6aea8507b..3ad124c55a 100644
--- a/libs/ui/kis_action_manager.cpp
+++ b/libs/ui/kis_action_manager.cpp
@@ -1,483 +1,491 @@
/*
* Copyright (c) 2013 Sven Langkamp
*
* 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_action_manager.h"
#include
#include
#include
#include "KisPart.h"
#include "kis_action.h"
#include "KisViewManager.h"
#include "kis_selection_manager.h"
#include "operations/kis_operation_ui_factory.h"
#include "operations/kis_operation_registry.h"
#include "operations/kis_operation.h"
#include "kis_layer.h"
#include "KisDocument.h"
#include "kis_clipboard.h"
#include
#include
#include "QFile"
#include
#include
class Q_DECL_HIDDEN KisActionManager::Private {
public:
Private()
: viewManager(0)
{}
~Private()
{
qDeleteAll(uiRegistry.values());
}
KisViewManager* viewManager;
KActionCollection *actionCollection;
QList> actions;
KoGenericRegistry uiRegistry;
KisOperationRegistry operationRegistry;
};
KisActionManager::KisActionManager(KisViewManager* viewManager, KActionCollection *actionCollection)
: d(new Private)
{
d->viewManager = viewManager;
d->actionCollection = actionCollection;
connect(d->actionCollection,
SIGNAL(inserted(QAction*)), SLOT(slotActionAddedToCollection(QAction*)));
}
KisActionManager::~KisActionManager()
{
#if 0
if ((d->actions.size() > 0)) {
QDomDocument doc;
QDomElement e = doc.createElement("Actions");
e.setAttribute("version", "2");
doc.appendChild(e);
Q_FOREACH (KisAction *action, d->actions) {
QDomElement a = doc.createElement("Action");
a.setAttribute("name", action->objectName());
// But seriously, XML is the worst format ever designed
auto addElement = [&](QString title, QString content) {
QDomElement newNode = doc.createElement(title);
QDomText newText = doc.createTextNode(content);
newNode.appendChild(newText);
a.appendChild(newNode);
};
addElement("icon", action->icon().name());
addElement("text", action->text());
addElement("whatsThis" , action->whatsThis());
addElement("toolTip" , action->toolTip());
addElement("iconText" , action->iconText());
addElement("shortcut" , action->shortcut().toString());
addElement("activationFlags" , QString::number(action->activationFlags(),2));
addElement("activationConditions" , QString::number(action->activationConditions(),2));
addElement("defaultShortcut" , action->defaultShortcut().toString());
addElement("isCheckable" , QString((action->isChecked() ? "true" : "false")));
addElement("statusTip", action->statusTip());
e.appendChild(a);
}
QFile f("ActionManager.action");
f.open(QFile::WriteOnly);
f.write(doc.toString().toUtf8());
f.close();
}
#endif
delete d;
}
void KisActionManager::setView(QPointer imageView)
{
Q_UNUSED(imageView);
}
void KisActionManager::slotActionAddedToCollection(QAction *action)
{
/**
* Small hack alert: not all the actions are still created by the manager and
* immediately added to the action collection. Some plugins add actions
* directly to the action collection when a document is created. Here we
* catch these cases
*/
KisActionRegistry::instance()->updateShortcut(action->objectName(), action);
}
void KisActionManager::addAction(const QString& name, KisAction* action)
{
Q_ASSERT(!name.isEmpty());
Q_ASSERT(action);
Q_ASSERT(d->viewManager);
Q_ASSERT(d->actionCollection);
d->actionCollection->addAction(name, action);
action->setParent(d->actionCollection);
d->actions.append(action);
action->setActionManager(this);
}
void KisActionManager::takeAction(KisAction* action)
{
d->actions.removeOne(action);
if (!action->objectName().isEmpty()) {
KIS_ASSERT_RECOVER_RETURN(d->actionCollection);
d->actionCollection->takeAction(action);
}
}
KisAction *KisActionManager::actionByName(const QString &name) const
{
Q_FOREACH (KisAction *action, d->actions) {
if (action->objectName() == name) {
return action;
}
}
return 0;
}
KisAction *KisActionManager::createAction(const QString &name)
{
KisAction *a = actionByName(name); // Check if the action already exists
if (a) {
return a;
}
// There is some tension here. KisActionManager is supposed to be in control
// of global actions, but these actions are supposed to be duplicated. We
// will add them to the KisActionRegistry for the time being so we can get
// properly categorized shortcuts.
a = new KisAction();
KisActionRegistry *actionRegistry = KisActionRegistry::instance();
// Add extra properties
actionRegistry->propertizeAction(name, a);
bool ok; // We will skip this check
int activationFlags = actionRegistry->getActionProperty(name, "activationFlags").toInt(&ok, 2);
int activationConditions = actionRegistry->getActionProperty(name, "activationConditions").toInt(&ok, 2);
a->setActivationFlags((KisAction::ActivationFlags) activationFlags);
a->setActivationConditions((KisAction::ActivationConditions) activationConditions);
addAction(name, a);
return a;
}
void KisActionManager::updateGUI()
{
//TODO other flags
KisAction::ActivationFlags flags;
KisImageWSP image;
KisNodeSP node;
KisLayerSP layer;
KisSelectionManager *selectionManager = 0;
KisAction::ActivationConditions conditions = KisAction::NO_CONDITION;
if (d->viewManager) {
node = d->viewManager->activeNode();
selectionManager = d->viewManager->selectionManager();
// if there are no views, that means no document is open.
// we cannot have nodes (selections), devices, or documents without a view
if ( d->viewManager->viewCount() > 0 )
{
image = d->viewManager->image();
flags |= KisAction::ACTIVE_IMAGE;
if (image && image->animationInterface()->hasAnimation()) {
flags |= KisAction::IMAGE_HAS_ANIMATION;
}
if (d->viewManager->viewCount() > 1) {
flags |= KisAction::MULTIPLE_IMAGES;
}
if (d->viewManager->document() && d->viewManager->document()->isModified()) {
flags |= KisAction::CURRENT_IMAGE_MODIFIED;
}
if (d->viewManager->activeDevice()) {
flags |= KisAction::ACTIVE_DEVICE;
}
}
if (d->viewManager->selectionEditable()) {
conditions |= KisAction::SELECTION_EDITABLE;
}
}
// is there a selection/mask?
// you have to have at least one view (document) open for this to be true
if (node) {
// if a node exists, we know there is an active layer as well
flags |= KisAction::ACTIVE_NODE;
layer = qobject_cast(node.data());
if (layer) {
flags |= KisAction::ACTIVE_LAYER;
}
if (node->inherits("KisTransparencyMask")) {
flags |= KisAction::ACTIVE_TRANSPARENCY_MASK;
}
if (layer && layer->inherits("KisShapeLayer")) {
flags |= KisAction::ACTIVE_SHAPE_LAYER;
}
if (KisClipboard::instance()->hasLayers()) {
flags |= KisAction::LAYERS_IN_CLIPBOARD;
}
if (selectionManager) {
if (selectionManager->havePixelsSelected()) {
flags |= KisAction::PIXELS_SELECTED;
}
if (selectionManager->haveShapesSelected()) {
flags |= KisAction::SHAPES_SELECTED;
}
- if (selectionManager->havePixelSelectionWithPixels()) {
+ if (selectionManager->haveAnySelectionWithPixels()) {
+ flags |= KisAction::ANY_SELECTION_WITH_PIXELS;
+ }
+
+ if (selectionManager->haveShapeSelectionWithShapes()) {
+ flags |= KisAction::SHAPE_SELECTION_WITH_SHAPES;
+ }
+
+ if (selectionManager->haveRasterSelectionWithPixels()) {
flags |= KisAction::PIXEL_SELECTION_WITH_PIXELS;
}
if (selectionManager->havePixelsInClipboard()) {
flags |= KisAction::PIXELS_IN_CLIPBOARD;
}
if (selectionManager->haveShapesInClipboard()) {
flags |= KisAction::SHAPES_IN_CLIPBOARD;
}
}
if (node->isEditable(false)) {
conditions |= KisAction::ACTIVE_NODE_EDITABLE;
}
if (node->hasEditablePaintDevice()) {
conditions |= KisAction::ACTIVE_NODE_EDITABLE_PAINT_DEVICE;
}
}
// loop through all actions in action manager and determine what should be enabled
Q_FOREACH (QPointer action, d->actions) {
bool enable;
if (action) {
if (action->activationFlags() == KisAction::NONE) {
enable = true;
}
else {
enable = action->activationFlags() & flags; // combine action flags with updateGUI flags
}
enable = enable && (int)(action->activationConditions() & conditions) == (int)action->activationConditions();
if (node && enable) {
Q_FOREACH (const QString &type, action->excludedNodeTypes()) {
if (node->inherits(type.toLatin1())) {
enable = false;
break;
}
}
}
action->setActionEnabled(enable);
}
}
}
KisAction *KisActionManager::createStandardAction(KStandardAction::StandardAction actionType, const QObject *receiver, const char *member)
{
QAction *standardAction = KStandardAction::create(actionType, receiver, member, 0);
KisAction *action = new KisAction(standardAction->icon(), standardAction->text());
const QList defaultShortcuts = standardAction->property("defaultShortcuts").value >();
const QKeySequence defaultShortcut = defaultShortcuts.isEmpty() ? QKeySequence() : defaultShortcuts.at(0);
action->setDefaultShortcut(standardAction->shortcut());
#ifdef Q_OS_WIN
if (actionType == KStandardAction::SaveAs && defaultShortcuts.isEmpty()) {
action->setShortcut(QKeySequence("CTRL+SHIFT+S"));
}
#endif
action->setCheckable(standardAction->isCheckable());
if (action->isCheckable()) {
action->setChecked(standardAction->isChecked());
}
action->setMenuRole(standardAction->menuRole());
action->setText(standardAction->text());
action->setToolTip(standardAction->toolTip());
if (receiver && member) {
if (actionType == KStandardAction::OpenRecent) {
QObject::connect(action, SIGNAL(urlSelected(QUrl)), receiver, member);
}
else if (actionType == KStandardAction::ConfigureToolbars) {
QObject::connect(action, SIGNAL(triggered(bool)), receiver, member, Qt::QueuedConnection);
}
else {
QObject::connect(action, SIGNAL(triggered(bool)), receiver, member);
}
}
KisActionRegistry *actionRegistry = KisActionRegistry::instance();
actionRegistry->propertizeAction(standardAction->objectName(), action);
addAction(standardAction->objectName(), action);
delete standardAction;
return action;
}
void KisActionManager::safePopulateMenu(QMenu *menu, const QString &actionId, KisActionManager *actionManager)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(actionManager);
KisAction *action = actionManager->actionByName(actionId);
KIS_SAFE_ASSERT_RECOVER_RETURN(action);
menu->addAction(action);
}
void KisActionManager::registerOperationUIFactory(KisOperationUIFactory* factory)
{
d->uiRegistry.add(factory);
}
void KisActionManager::registerOperation(KisOperation* operation)
{
d->operationRegistry.add(operation);
}
void KisActionManager::runOperation(const QString& id)
{
KisOperationConfigurationSP config = new KisOperationConfiguration(id);
KisOperationUIFactory* uiFactory = d->uiRegistry.get(id);
if (uiFactory) {
bool gotConfig = uiFactory->fetchConfiguration(d->viewManager, config);
if (!gotConfig) {
return;
}
}
runOperationFromConfiguration(config);
}
void KisActionManager::runOperationFromConfiguration(KisOperationConfigurationSP config)
{
KisOperation* operation = d->operationRegistry.get(config->id());
Q_ASSERT(operation);
operation->runFromXML(d->viewManager, *config);
}
void KisActionManager::dumpActionFlags()
{
QFile data("actions.txt");
if (data.open(QFile::WriteOnly | QFile::Truncate)) {
QTextStream out(&data);
out.setCodec("UTF-8");
Q_FOREACH (KisAction* action, d->actions) {
KisAction::ActivationFlags flags = action->activationFlags();
out << "-------- " << action->text() << " --------\n";
out << "Action will activate on: \n";
if (flags & KisAction::ACTIVE_IMAGE) {
out << " Active image\n";
}
if (flags & KisAction::MULTIPLE_IMAGES) {
out << " More than one image open\n";
}
if (flags & KisAction::CURRENT_IMAGE_MODIFIED) {
out << " Active image modified\n";
}
if (flags & KisAction::ACTIVE_DEVICE) {
out << " Active device\n";
}
if (flags & KisAction::ACTIVE_LAYER) {
out << " Active layer\n";
}
if (flags & KisAction::ACTIVE_TRANSPARENCY_MASK) {
out << " Active transparency mask\n";
}
if (flags & KisAction::ACTIVE_NODE) {
out << " Active node\n";
}
if (flags & KisAction::ACTIVE_SHAPE_LAYER) {
out << " Active shape layer\n";
}
if (flags & KisAction::PIXELS_SELECTED) {
out << " Pixels selected\n";
}
if (flags & KisAction::SHAPES_SELECTED) {
out << " Shapes selected\n";
}
- if (flags & KisAction::PIXEL_SELECTION_WITH_PIXELS) {
- out << " Pixel selection with pixels\n";
+ if (flags & KisAction::ANY_SELECTION_WITH_PIXELS) {
+ out << " Any selection with pixels\n";
}
if (flags & KisAction::PIXELS_IN_CLIPBOARD) {
out << " Pixels in clipboard\n";
}
if (flags & KisAction::SHAPES_IN_CLIPBOARD) {
out << " Shape in clipboard\n";
}
if (flags & KisAction::IMAGE_HAS_ANIMATION) {
out << " Image has animation\n";
}
out << "\n\n";
out << "Action will only activate if the following conditions are met: \n";
KisAction::ActivationConditions conditions = action->activationConditions();
if ((int)conditions == 0) {
out << " -\n";
}
if (conditions & KisAction::ACTIVE_NODE_EDITABLE) {
out << " Active Node editable\n";
}
if (conditions & KisAction::ACTIVE_NODE_EDITABLE_PAINT_DEVICE) {
out << " Active Node has editable paint device\n";
}
if (conditions & KisAction::SELECTION_EDITABLE) {
out << " Selection is editable\n";
}
out << "\n\n";
}
}
}
diff --git a/libs/ui/kis_selection_manager.cc b/libs/ui/kis_selection_manager.cc
index b7ff576663..ab79dacfe5 100644
--- a/libs/ui/kis_selection_manager.cc
+++ b/libs/ui/kis_selection_manager.cc
@@ -1,678 +1,696 @@
/*
* Copyright (c) 2004 Boudewijn Rempt
* Copyright (c) 2007 Sven Langkamp
*
* The outline algorithm uses the limn algorithm of fontutils by
* Karl Berry and Kathryn Hargreaves
*
* 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_selection_manager.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "KoCanvasController.h"
#include "KoChannelInfo.h"
#include "KoIntegerMaths.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_adjustment_layer.h"
#include "kis_node_manager.h"
#include "canvas/kis_canvas2.h"
#include "kis_config.h"
#include "kis_convolution_painter.h"
#include "kis_convolution_kernel.h"
#include "kis_debug.h"
#include "kis_fill_painter.h"
#include "kis_group_layer.h"
#include "kis_layer.h"
#include "kis_statusbar.h"
#include "kis_paint_device.h"
#include "kis_paint_layer.h"
#include "kis_painter.h"
#include "kis_transaction.h"
#include "kis_selection.h"
#include "kis_types.h"
#include "kis_canvas_resource_provider.h"
#include "kis_undo_adapter.h"
#include "kis_pixel_selection.h"
#include "flake/kis_shape_selection.h"
#include "commands/kis_selection_commands.h"
#include "kis_selection_mask.h"
#include "flake/kis_shape_layer.h"
#include "kis_selection_decoration.h"
#include "canvas/kis_canvas_decoration.h"
#include "kis_node_commands_adapter.h"
#include "kis_iterator_ng.h"
#include "kis_clipboard.h"
#include "KisViewManager.h"
#include "kis_selection_filters.h"
#include "kis_figure_painting_tool_helper.h"
#include "KisView.h"
#include "dialogs/kis_dlg_stroke_selection_properties.h"
#include "actions/kis_selection_action_factories.h"
#include "actions/KisPasteActionFactory.h"
#include "kis_action.h"
#include "kis_action_manager.h"
#include "operations/kis_operation_configuration.h"
//new
#include "kis_node_query_path.h"
#include "kis_tool_shape.h"
KisSelectionManager::KisSelectionManager(KisViewManager * view)
: m_view(view),
m_doc(0),
m_imageView(0),
m_adapter(new KisNodeCommandsAdapter(view)),
m_copy(0),
m_copyMerged(0),
m_cut(0),
m_paste(0),
m_pasteNew(0),
m_cutToNewLayer(0),
m_selectAll(0),
m_deselect(0),
m_clear(0),
m_reselect(0),
m_invert(0),
m_copyToNewLayer(0),
m_fillForegroundColor(0),
m_fillBackgroundColor(0),
m_fillPattern(0),
m_imageResizeToSelection(0),
m_selectionDecoration(0)
{
m_clipboard = KisClipboard::instance();
}
KisSelectionManager::~KisSelectionManager()
{
}
void KisSelectionManager::setup(KisActionManager* actionManager)
{
m_cut = actionManager->createStandardAction(KStandardAction::Cut, this, SLOT(cut()));
m_copy = actionManager->createStandardAction(KStandardAction::Copy, this, SLOT(copy()));
m_paste = actionManager->createStandardAction(KStandardAction::Paste, this, SLOT(paste()));
KisAction *action = actionManager->createAction("copy_sharp");
connect(action, SIGNAL(triggered()), this, SLOT(copySharp()));
action = actionManager->createAction("cut_sharp");
connect(action, SIGNAL(triggered()), this, SLOT(cutSharp()));
m_pasteNew = actionManager->createAction("paste_new");
connect(m_pasteNew, SIGNAL(triggered()), this, SLOT(pasteNew()));
m_pasteAt = actionManager->createAction("paste_at");
connect(m_pasteAt, SIGNAL(triggered()), this, SLOT(pasteAt()));
m_copyMerged = actionManager->createAction("copy_merged");
connect(m_copyMerged, SIGNAL(triggered()), this, SLOT(copyMerged()));
m_selectAll = actionManager->createAction("select_all");
connect(m_selectAll, SIGNAL(triggered()), this, SLOT(selectAll()));
m_deselect = actionManager->createAction("deselect");
connect(m_deselect, SIGNAL(triggered()), this, SLOT(deselect()));
m_clear = actionManager->createAction("clear");
connect(m_clear, SIGNAL(triggered()), SLOT(clear()));
m_reselect = actionManager->createAction("reselect");
connect(m_reselect, SIGNAL(triggered()), this, SLOT(reselect()));
m_invert = actionManager->createAction("invert_selection");
m_invert->setOperationID("invertselection");
actionManager->registerOperation(new KisInvertSelectionOperation);
m_copyToNewLayer = actionManager->createAction("copy_selection_to_new_layer");
connect(m_copyToNewLayer, SIGNAL(triggered()), this, SLOT(copySelectionToNewLayer()));
m_cutToNewLayer = actionManager->createAction("cut_selection_to_new_layer");
connect(m_cutToNewLayer, SIGNAL(triggered()), this, SLOT(cutToNewLayer()));
m_fillForegroundColor = actionManager->createAction("fill_selection_foreground_color");
connect(m_fillForegroundColor, SIGNAL(triggered()), this, SLOT(fillForegroundColor()));
m_fillBackgroundColor = actionManager->createAction("fill_selection_background_color");
connect(m_fillBackgroundColor, SIGNAL(triggered()), this, SLOT(fillBackgroundColor()));
m_fillPattern = actionManager->createAction("fill_selection_pattern");
connect(m_fillPattern, SIGNAL(triggered()), this, SLOT(fillPattern()));
m_fillForegroundColorOpacity = actionManager->createAction("fill_selection_foreground_color_opacity");
connect(m_fillForegroundColorOpacity, SIGNAL(triggered()), this, SLOT(fillForegroundColorOpacity()));
m_fillBackgroundColorOpacity = actionManager->createAction("fill_selection_background_color_opacity");
connect(m_fillBackgroundColorOpacity, SIGNAL(triggered()), this, SLOT(fillBackgroundColorOpacity()));
m_fillPatternOpacity = actionManager->createAction("fill_selection_pattern_opacity");
connect(m_fillPatternOpacity, SIGNAL(triggered()), this, SLOT(fillPatternOpacity()));
m_strokeShapes = actionManager->createAction("stroke_shapes");
connect(m_strokeShapes, SIGNAL(triggered()), this, SLOT(paintSelectedShapes()));
m_toggleDisplaySelection = actionManager->createAction("toggle_display_selection");
connect(m_toggleDisplaySelection, SIGNAL(triggered()), this, SLOT(toggleDisplaySelection()));
m_toggleDisplaySelection->setChecked(true);
m_imageResizeToSelection = actionManager->createAction("resizeimagetoselection");
connect(m_imageResizeToSelection, SIGNAL(triggered()), this, SLOT(imageResizeToSelection()));
action = actionManager->createAction("convert_to_vector_selection");
connect(action, SIGNAL(triggered()), SLOT(convertToVectorSelection()));
+ action = actionManager->createAction("convert_to_raster_selection");
+ connect(action, SIGNAL(triggered()), SLOT(convertToRasterSelection()));
+
action = actionManager->createAction("convert_shapes_to_vector_selection");
connect(action, SIGNAL(triggered()), SLOT(convertShapesToVectorSelection()));
action = actionManager->createAction("convert_selection_to_shape");
connect(action, SIGNAL(triggered()), SLOT(convertToShape()));
m_toggleSelectionOverlayMode = actionManager->createAction("toggle-selection-overlay-mode");
connect(m_toggleSelectionOverlayMode, SIGNAL(triggered()), SLOT(slotToggleSelectionDecoration()));
m_strokeSelected = actionManager->createAction("stroke_selection");
connect(m_strokeSelected, SIGNAL(triggered()), SLOT(slotStrokeSelection()));
QClipboard *cb = QApplication::clipboard();
connect(cb, SIGNAL(dataChanged()), SLOT(clipboardDataChanged()));
}
void KisSelectionManager::setView(QPointerimageView)
{
if (m_imageView && m_imageView->canvasBase()) {
disconnect(m_imageView->canvasBase()->toolProxy(), SIGNAL(toolChanged(const QString&)), this, SLOT(clipboardDataChanged()));
KoSelection *selection = m_imageView->canvasBase()->globalShapeManager()->selection();
selection->disconnect(this, SLOT(shapeSelectionChanged()));
KisSelectionDecoration *decoration = qobject_cast(m_imageView->canvasBase()->decoration("selection").data());
if (decoration) {
disconnect(SIGNAL(currentSelectionChanged()), decoration);
}
m_imageView->image()->undoAdapter()->disconnect(this);
m_selectionDecoration = 0;
}
m_imageView = imageView;
if (m_imageView) {
connect(m_imageView->canvasBase()->selectedShapesProxy(), SIGNAL(selectionChanged()), this, SLOT(shapeSelectionChanged()));
KisSelectionDecoration* decoration = qobject_cast(m_imageView->canvasBase()->decoration("selection").data());
if (!decoration) {
decoration = new KisSelectionDecoration(m_imageView);
decoration->setVisible(true);
m_imageView->canvasBase()->addDecoration(decoration);
}
m_selectionDecoration = decoration;
connect(this, SIGNAL(currentSelectionChanged()), decoration, SLOT(selectionChanged()));
connect(m_imageView->image()->undoAdapter(), SIGNAL(selectionChanged()), SLOT(selectionChanged()));
connect(m_imageView->canvasBase()->toolProxy(), SIGNAL(toolChanged(const QString&)), SLOT(clipboardDataChanged()));
}
}
void KisSelectionManager::clipboardDataChanged()
{
m_view->updateGUI();
}
bool KisSelectionManager::havePixelsSelected()
{
KisSelectionSP activeSelection = m_view->selection();
return activeSelection && !activeSelection->selectedRect().isEmpty();
}
bool KisSelectionManager::havePixelsInClipboard()
{
return m_clipboard->hasClip();
}
bool KisSelectionManager::haveShapesSelected()
{
if (m_view && m_view->canvasBase()) {
return m_view->canvasBase()->selectedShapesProxy()->selection()->count() > 0;
}
return false;
}
bool KisSelectionManager::haveShapesInClipboard()
{
KoSvgPaste paste;
return paste.hasShapes();
}
-bool KisSelectionManager::havePixelSelectionWithPixels()
+bool KisSelectionManager::haveAnySelectionWithPixels()
{
KisSelectionSP selection = m_view->selection();
- if (selection && selection->hasPixelSelection()) {
- return !selection->pixelSelection()->selectedRect().isEmpty();
- }
- return false;
+ return selection && selection->hasPixelSelection();
+}
+
+bool KisSelectionManager::haveShapeSelectionWithShapes()
+{
+ KisSelectionSP selection = m_view->selection();
+ return selection && selection->hasShapeSelection();
+}
+
+bool KisSelectionManager::haveRasterSelectionWithPixels()
+{
+ KisSelectionSP selection = m_view->selection();
+ return selection && selection->hasPixelSelection() && !selection->hasShapeSelection();
}
void KisSelectionManager::updateGUI()
{
Q_ASSERT(m_view);
Q_ASSERT(m_clipboard);
if (!m_view || !m_clipboard) return;
bool havePixelsSelected = this->havePixelsSelected();
bool havePixelsInClipboard = this->havePixelsInClipboard();
bool haveShapesSelected = this->haveShapesSelected();
bool haveShapesInClipboard = this->haveShapesInClipboard();
bool haveDevice = m_view->activeDevice();
KisLayerSP activeLayer = m_view->activeLayer();
KisImageWSP image = activeLayer ? activeLayer->image() : 0;
bool canReselect = image && image->canReselectGlobalSelection();
bool canDeselect = image && image->globalSelection();
m_clear->setEnabled(haveDevice || havePixelsSelected || haveShapesSelected);
m_cut->setEnabled(havePixelsSelected || haveShapesSelected);
m_copy->setEnabled(havePixelsSelected || haveShapesSelected);
m_paste->setEnabled(havePixelsInClipboard || haveShapesInClipboard);
m_pasteAt->setEnabled(havePixelsInClipboard || haveShapesInClipboard);
// FIXME: how about pasting shapes?
m_pasteNew->setEnabled(havePixelsInClipboard);
m_selectAll->setEnabled(true);
m_deselect->setEnabled(canDeselect);
m_reselect->setEnabled(canReselect);
// m_load->setEnabled(true);
// m_save->setEnabled(havePixelsSelected);
updateStatusBar();
emit signalUpdateGUI();
}
void KisSelectionManager::updateStatusBar()
{
if (m_view && m_view->statusBar()) {
m_view->statusBar()->setSelection(m_view->image());
}
}
void KisSelectionManager::selectionChanged()
{
m_view->updateGUI();
emit currentSelectionChanged();
}
void KisSelectionManager::cut()
{
KisCutCopyActionFactory factory;
factory.run(true, false, m_view);
}
void KisSelectionManager::copy()
{
KisCutCopyActionFactory factory;
factory.run(false, false, m_view);
}
void KisSelectionManager::cutSharp()
{
KisCutCopyActionFactory factory;
factory.run(true, true, m_view);
}
void KisSelectionManager::copySharp()
{
KisCutCopyActionFactory factory;
factory.run(false, true, m_view);
}
void KisSelectionManager::copyMerged()
{
KisCopyMergedActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::paste()
{
KisPasteActionFactory factory;
factory.run(false, m_view);
}
void KisSelectionManager::pasteAt()
{
KisPasteActionFactory factory;
factory.run(true, m_view);
}
void KisSelectionManager::pasteNew()
{
KisPasteNewActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::selectAll()
{
KisSelectAllActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::deselect()
{
KisDeselectActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::invert()
{
if(m_invert)
m_invert->trigger();
}
void KisSelectionManager::reselect()
{
KisReselectActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::convertToVectorSelection()
{
KisSelectionToVectorActionFactory factory;
factory.run(m_view);
}
+void KisSelectionManager::convertToRasterSelection()
+{
+ KisSelectionToRasterActionFactory factory;
+ factory.run(m_view);
+}
+
void KisSelectionManager::convertShapesToVectorSelection()
{
KisShapesToVectorSelectionActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::convertToShape()
{
KisSelectionToShapeActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::clear()
{
KisClearActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::fillForegroundColor()
{
KisFillActionFactory factory;
factory.run("fg", m_view);
}
void KisSelectionManager::fillBackgroundColor()
{
KisFillActionFactory factory;
factory.run("bg", m_view);
}
void KisSelectionManager::fillPattern()
{
KisFillActionFactory factory;
factory.run("pattern", m_view);
}
void KisSelectionManager::fillForegroundColorOpacity()
{
KisFillActionFactory factory;
factory.run("fg_opacity", m_view);
}
void KisSelectionManager::fillBackgroundColorOpacity()
{
KisFillActionFactory factory;
factory.run("bg_opacity", m_view);
}
void KisSelectionManager::fillPatternOpacity()
{
KisFillActionFactory factory;
factory.run("pattern_opacity", m_view);
}
void KisSelectionManager::copySelectionToNewLayer()
{
copy();
paste();
}
void KisSelectionManager::cutToNewLayer()
{
cut();
paste();
}
void KisSelectionManager::toggleDisplaySelection()
{
KIS_ASSERT_RECOVER_RETURN(m_selectionDecoration);
m_selectionDecoration->toggleVisibility();
m_toggleDisplaySelection->blockSignals(true);
m_toggleDisplaySelection->setChecked(m_selectionDecoration->visible());
m_toggleDisplaySelection->blockSignals(false);
emit displaySelectionChanged();
}
bool KisSelectionManager::displaySelection()
{
return m_toggleDisplaySelection->isChecked();
}
void KisSelectionManager::shapeSelectionChanged()
{
KoShapeManager* shapeManager = m_view->canvasBase()->globalShapeManager();
KoSelection * selection = shapeManager->selection();
QList selectedShapes = selection->selectedShapes();
KoShapeStrokeSP border(new KoShapeStroke(0, Qt::lightGray));
Q_FOREACH (KoShape* shape, shapeManager->shapes()) {
if (dynamic_cast(shape->parent())) {
if (selectedShapes.contains(shape))
shape->setStroke(border);
else
shape->setStroke(KoShapeStrokeSP());
}
}
m_view->updateGUI();
}
void KisSelectionManager::imageResizeToSelection()
{
KisImageResizeToSelectionActionFactory factory;
factory.run(m_view);
}
void KisSelectionManager::paintSelectedShapes()
{
KisImageWSP image = m_view->image();
if (!image) return;
KisLayerSP layer = m_view->activeLayer();
if (!layer) return;
QList shapes = m_view->canvasBase()->shapeManager()->selection()->selectedShapes();
KisPaintLayerSP paintLayer = new KisPaintLayer(image, i18n("Stroked Shapes"), OPACITY_OPAQUE_U8);
KUndo2MagicString actionName = kundo2_i18n("Stroke Shapes");
m_adapter->beginMacro(actionName);
m_adapter->addNode(paintLayer.data(), layer->parent().data(), layer.data());
KisFigurePaintingToolHelper helper(actionName,
image,
paintLayer.data(),
m_view->resourceProvider()->resourceManager(),
KisPainter::StrokeStyleBrush,
KisPainter::FillStyleNone);
Q_FOREACH (KoShape* shape, shapes) {
QTransform matrix = shape->absoluteTransformation(0) * QTransform::fromScale(image->xRes(), image->yRes());
QPainterPath mapedOutline = matrix.map(shape->outline());
helper.paintPainterPath(mapedOutline);
}
m_adapter->endMacro();
}
void KisSelectionManager::slotToggleSelectionDecoration()
{
KIS_ASSERT_RECOVER_RETURN(m_selectionDecoration);
KisSelectionDecoration::Mode mode =
m_selectionDecoration->mode() ?
KisSelectionDecoration::Ants : KisSelectionDecoration::Mask;
m_selectionDecoration->setMode(mode);
emit displaySelectionChanged();
}
bool KisSelectionManager::showSelectionAsMask() const
{
if (m_selectionDecoration) {
return m_selectionDecoration->mode() == KisSelectionDecoration::Mask;
}
return false;
}
void KisSelectionManager::slotStrokeSelection()
{
KisImageWSP image = m_view->image();
if (!image ) {
return;
}
KisNodeSP currentNode = m_view->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value();
bool isVectorLayer = false;
if (currentNode->inherits("KisShapeLayer")) {
isVectorLayer = true;
}
QPointer dlg = new KisDlgStrokeSelection(image, m_view, isVectorLayer);
if (dlg->exec() == QDialog::Accepted) {
StrokeSelectionOptions params = dlg->getParams();
if (params.brushSelected){
KisStrokeBrushSelectionActionFactory factory;
factory.run(m_view, params);
}
else {
KisStrokeSelectionActionFactory factory;
factory.run(m_view, params);
}
}
delete dlg;
}
#include "kis_image_barrier_locker.h"
#include "kis_selection_tool_helper.h"
void KisSelectionManager::selectOpaqueOnNode(KisNodeSP node, SelectionAction action)
{
KisImageSP image = m_view->image();
if (!m_view->blockUntilOperationsFinished(image)) {
return;
}
KUndo2MagicString actionName;
KisPixelSelectionSP tmpSel = KisPixelSelectionSP(new KisPixelSelection());
KisCanvas2 *canvas = m_view->canvasBase();
{
KisImageBarrierLocker locker(image);
KisPaintDeviceSP device = node->projection();
if (!device) device = node->paintDevice();
if (!device) device = node->original();
KIS_ASSERT_RECOVER_RETURN(canvas && device);
QRect rc = device->exactBounds();
if (rc.isEmpty()) return;
/**
* If there is nothing selected, just create a new selection
*/
if (!canvas->imageView()->selection()) {
action = SELECTION_REPLACE;
}
switch (action) {
case SELECTION_ADD:
actionName = kundo2_i18n("Select Opaque (Add)");
break;
case SELECTION_SUBTRACT:
actionName = kundo2_i18n("Select Opaque (Subtract)");
break;
case SELECTION_INTERSECT:
actionName = kundo2_i18n("Select Opaque (Intersect)");
break;
default:
actionName = kundo2_i18n("Select Opaque");
break;
}
qint32 x, y, w, h;
rc.getRect(&x, &y, &w, &h);
const KoColorSpace * cs = device->colorSpace();
KisHLineConstIteratorSP deviter = device->createHLineConstIteratorNG(x, y, w);
KisHLineIteratorSP selIter = tmpSel ->createHLineIteratorNG(x, y, w);
for (int row = y; row < h + y; ++row) {
do {
*selIter->rawData() = cs->opacityU8(deviter->oldRawData());
} while (deviter->nextPixel() && selIter->nextPixel());
deviter->nextRow();
selIter->nextRow();
}
}
KisSelectionToolHelper helper(canvas, actionName);
tmpSel->invalidateOutlineCache();
helper.selectPixelSelection(tmpSel, action);
}
diff --git a/libs/ui/kis_selection_manager.h b/libs/ui/kis_selection_manager.h
index bd165eb952..3aaa4f4509 100644
--- a/libs/ui/kis_selection_manager.h
+++ b/libs/ui/kis_selection_manager.h
@@ -1,174 +1,177 @@
/*
* Copyright (c) 2004 Boudewijn Rempt
*
* 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.
*/
#ifndef KIS_SELECTION_MANAGER_
#define KIS_SELECTION_MANAGER_
#include
#include
#include
#include
#include "KisView.h"
#include
#include
class KisActionManager;
class KisAction;
class QAction;
class KoViewConverter;
class KisDocument;
class KisViewManager;
class KisClipboard;
class KisNodeCommandsAdapter;
class KisView;
class KisSelectionFilter;
class KisSelectionDecoration;
/**
* The selection manager is responsible selections
* and the clipboard.
*/
class KRITAUI_EXPORT KisSelectionManager : public QObject
{
Q_OBJECT
Q_PROPERTY(bool displaySelection READ displaySelection NOTIFY displaySelectionChanged);
Q_PROPERTY(bool havePixelsSelected READ havePixelsSelected NOTIFY currentSelectionChanged);
public:
KisSelectionManager(KisViewManager * view);
~KisSelectionManager() override;
void setup(KisActionManager* actionManager);
void setView(QPointerimageView);
public:
/**
* This function return if the selection should be displayed
*/
bool displaySelection();
bool showSelectionAsMask() const;
public Q_SLOTS:
void updateGUI();
void selectionChanged();
void clipboardDataChanged();
void cut();
void copy();
void cutSharp();
void copySharp();
void copyMerged();
void paste();
void pasteNew();
void pasteAt();
void cutToNewLayer();
void selectAll();
void deselect();
void invert();
void clear();
void fillForegroundColor();
void fillBackgroundColor();
void fillPattern();
void fillForegroundColorOpacity();
void fillBackgroundColorOpacity();
void fillPatternOpacity();
void reselect();
void convertToVectorSelection();
+ void convertToRasterSelection();
void convertShapesToVectorSelection();
void convertToShape();
void copySelectionToNewLayer();
void toggleDisplaySelection();
void shapeSelectionChanged();
void imageResizeToSelection();
void paintSelectedShapes();
void slotToggleSelectionDecoration();
void slotStrokeSelection();
void selectOpaqueOnNode(KisNodeSP node, SelectionAction action);
Q_SIGNALS:
void currentSelectionChanged();
void signalUpdateGUI();
void displaySelectionChanged();
void strokeSelected();
public:
bool havePixelsSelected();
bool havePixelsInClipboard();
bool haveShapesSelected();
bool haveShapesInClipboard();
/// Checks if the current selection is editable and has some pixels selected in the pixel selection
- bool havePixelSelectionWithPixels();
+ bool haveAnySelectionWithPixels();
+ bool haveShapeSelectionWithShapes();
+ bool haveRasterSelectionWithPixels();
private:
void fill(const KoColor& color, bool fillWithPattern, const QString& transactionText);
void updateStatusBar();
KisViewManager * m_view;
KisDocument * m_doc;
QPointerm_imageView;
KisClipboard * m_clipboard;
KisNodeCommandsAdapter* m_adapter;
KisAction *m_copy;
KisAction *m_copyMerged;
KisAction *m_cut;
KisAction *m_paste;
KisAction *m_pasteAt;
KisAction *m_pasteNew;
KisAction *m_cutToNewLayer;
KisAction *m_selectAll;
KisAction *m_deselect;
KisAction *m_clear;
KisAction *m_reselect;
KisAction *m_invert;
KisAction *m_copyToNewLayer;
KisAction *m_fillForegroundColor;
KisAction *m_fillBackgroundColor;
KisAction *m_fillPattern;
KisAction *m_fillForegroundColorOpacity;
KisAction *m_fillBackgroundColorOpacity;
KisAction *m_fillPatternOpacity;
KisAction *m_imageResizeToSelection;
KisAction *m_strokeShapes;
KisAction *m_toggleDisplaySelection;
KisAction *m_toggleSelectionOverlayMode;
KisAction *m_strokeSelected;
QList m_pluginActions;
QPointer m_selectionDecoration;
};
#endif // KIS_SELECTION_MANAGER_
diff --git a/libs/ui/tool/kis_selection_tool_helper.cpp b/libs/ui/tool/kis_selection_tool_helper.cpp
index dab79c1e49..6133454f5e 100644
--- a/libs/ui/tool/kis_selection_tool_helper.cpp
+++ b/libs/ui/tool/kis_selection_tool_helper.cpp
@@ -1,330 +1,338 @@
/*
* Copyright (c) 2007 Sven Langkamp
*
* 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_selection_tool_helper.h"
#include
#include
#include
#include "kis_pixel_selection.h"
#include "kis_shape_selection.h"
#include "kis_image.h"
#include "canvas/kis_canvas2.h"
#include "KisViewManager.h"
#include "kis_selection_manager.h"
#include "kis_transaction.h"
#include "commands/kis_selection_commands.h"
#include "kis_shape_controller.h"
#include
#include "kis_processing_applicator.h"
#include "kis_transaction_based_command.h"
#include "kis_gui_context_command.h"
#include "kis_command_utils.h"
#include "commands/kis_deselect_global_selection_command.h"
#include "kis_algebra_2d.h"
#include "kis_config.h"
#include "kis_action_manager.h"
#include "kis_action.h"
#include
KisSelectionToolHelper::KisSelectionToolHelper(KisCanvas2* canvas, const KUndo2MagicString& name)
: m_canvas(canvas)
, m_name(name)
{
m_image = m_canvas->viewManager()->image();
}
KisSelectionToolHelper::~KisSelectionToolHelper()
{
}
struct LazyInitGlobalSelection : public KisTransactionBasedCommand {
LazyInitGlobalSelection(KisViewManager *view) : m_view(view) {}
KisViewManager *m_view;
KUndo2Command* paint() override {
return !m_view->selection() ?
new KisSetEmptyGlobalSelectionCommand(m_view->image()) : 0;
}
};
void KisSelectionToolHelper::selectPixelSelection(KisPixelSelectionSP selection, SelectionAction action)
{
KisViewManager* view = m_canvas->viewManager();
if (selection->selectedExactRect().isEmpty()) {
m_canvas->viewManager()->selectionManager()->deselect();
return;
}
KisProcessingApplicator applicator(view->image(),
0 /* we need no automatic updates */,
KisProcessingApplicator::SUPPORTS_WRAPAROUND_MODE,
KisImageSignalVector() << ModifiedSignal,
m_name);
applicator.applyCommand(new LazyInitGlobalSelection(view));
struct ApplyToPixelSelection : public KisTransactionBasedCommand {
ApplyToPixelSelection(KisViewManager *view,
KisPixelSelectionSP selection,
SelectionAction action) : m_view(view),
m_selection(selection),
m_action(action) {}
KisViewManager *m_view;
KisPixelSelectionSP m_selection;
SelectionAction m_action;
KUndo2Command* paint() override {
KisPixelSelectionSP pixelSelection = m_view->selection()->pixelSelection();
KIS_ASSERT_RECOVER(pixelSelection) { return 0; }
bool hasSelection = !pixelSelection->isEmpty();
KisSelectionTransaction transaction(pixelSelection);
if (!hasSelection && m_action == SELECTION_SUBTRACT) {
pixelSelection->invert();
}
pixelSelection->applySelection(m_selection, m_action);
QRect dirtyRect = m_view->image()->bounds();
if (hasSelection && m_action != SELECTION_REPLACE && m_action != SELECTION_INTERSECT) {
dirtyRect = m_selection->selectedRect();
}
m_view->selection()->updateProjection(dirtyRect);
KUndo2Command *savedCommand = transaction.endAndTake();
pixelSelection->setDirty(dirtyRect);
if (m_view->selection()->selectedExactRect().isEmpty()) {
KisCommandUtils::CompositeCommand *cmd = new KisCommandUtils::CompositeCommand();
cmd->addCommand(savedCommand);
cmd->addCommand(new KisDeselectGlobalSelectionCommand(m_view->image()));
savedCommand = cmd;
}
return savedCommand;
}
};
applicator.applyCommand(new ApplyToPixelSelection(view, selection, action));
applicator.end();
}
void KisSelectionToolHelper::addSelectionShape(KoShape* shape, SelectionAction action)
{
QList shapes;
shapes.append(shape);
addSelectionShapes(shapes, action);
}
void KisSelectionToolHelper::addSelectionShapes(QList< KoShape* > shapes, SelectionAction action)
{
KisViewManager* view = m_canvas->viewManager();
if (view->image()->wrapAroundModePermitted()) {
view->showFloatingMessage(
i18n("Shape selection does not fully "
"support wraparound mode. Please "
"use pixel selection instead"),
KisIconUtils::loadIcon("selection-info"));
}
KisProcessingApplicator applicator(view->image(),
0 /* we need no automatic updates */,
KisProcessingApplicator::NONE,
KisImageSignalVector() << ModifiedSignal,
m_name);
applicator.applyCommand(new LazyInitGlobalSelection(view));
struct ClearPixelSelection : public KisTransactionBasedCommand {
ClearPixelSelection(KisViewManager *view) : m_view(view) {}
KisViewManager *m_view;
KUndo2Command* paint() override {
KisPixelSelectionSP pixelSelection = m_view->selection()->pixelSelection();
KIS_ASSERT_RECOVER(pixelSelection) { return 0; }
KisSelectionTransaction transaction(pixelSelection);
pixelSelection->clear();
return transaction.endAndTake();
}
};
if (action == SELECTION_REPLACE || action == SELECTION_DEFAULT) {
applicator.applyCommand(new ClearPixelSelection(view));
}
struct AddSelectionShape : public KisTransactionBasedCommand {
AddSelectionShape(KisViewManager *view, KoShape* shape, SelectionAction action)
: m_view(view),
m_shape(shape),
m_action(action) {}
KisViewManager *m_view;
KoShape* m_shape;
SelectionAction m_action;
KUndo2Command* paint() override {
KUndo2Command *resultCommand = 0;
KisSelectionSP selection = m_view->selection();
if (selection) {
KisShapeSelection * shapeSelection = static_cast(selection->shapeSelection());
if (shapeSelection) {
QList existingShapes = shapeSelection->shapes();
if (existingShapes.size() == 1) {
KoShape *currentShape = existingShapes.first();
QPainterPath path1 = currentShape->absoluteTransformation(0).map(currentShape->outline());
QPainterPath path2 = m_shape->absoluteTransformation(0).map(m_shape->outline());
QPainterPath path = path2;
switch (m_action) {
case SELECTION_DEFAULT:
case SELECTION_REPLACE:
path = path2;
break;
case SELECTION_INTERSECT:
path = path1 & path2;
break;
case SELECTION_ADD:
path = path1 | path2;
break;
case SELECTION_SUBTRACT:
path = path1 - path2;
break;
}
KoShape *newShape = KoPathShape::createShapeFromPainterPath(path);
newShape->setUserData(new KisShapeSelectionMarker);
KUndo2Command *parentCommand = new KUndo2Command();
m_view->canvasBase()->shapeController()->removeShape(currentShape, parentCommand);
m_view->canvasBase()->shapeController()->addShape(newShape, 0, parentCommand);
resultCommand = parentCommand;
}
}
}
if (!resultCommand) {
/**
* Mark a shape that it belongs to a shape selection
*/
if(!m_shape->userData()) {
m_shape->setUserData(new KisShapeSelectionMarker);
}
resultCommand = m_view->canvasBase()->shapeController()->addShape(m_shape, 0);
}
return resultCommand;
}
};
Q_FOREACH (KoShape* shape, shapes) {
applicator.applyCommand(
new KisGuiContextCommand(new AddSelectionShape(view, shape, action), view));
}
applicator.end();
}
bool KisSelectionToolHelper::canShortcutToDeselect(const QRect &rect, SelectionAction action)
{
return rect.isEmpty() && (action == SELECTION_INTERSECT || action == SELECTION_REPLACE);
}
bool KisSelectionToolHelper::canShortcutToNoop(const QRect &rect, SelectionAction action)
{
return rect.isEmpty() && action == SELECTION_ADD;
}
bool KisSelectionToolHelper::tryDeselectCurrentSelection(const QRectF selectionViewRect, SelectionAction action)
{
bool result = false;
if (KisAlgebra2D::maxDimension(selectionViewRect) < KisConfig(true).selectionViewSizeMinimum() &&
(action == SELECTION_INTERSECT || action == SELECTION_REPLACE)) {
// Queueing this action to ensure we avoid a race condition when unlocking the node system
QTimer::singleShot(0, m_canvas->viewManager()->selectionManager(), SLOT(deselect()));
result = true;
}
return result;
}
QMenu* KisSelectionToolHelper::getSelectionContextMenu(KisCanvas2* canvas)
{
QMenu *m_contextMenu = new QMenu();
KisActionManager * actionMan = canvas->viewManager()->actionManager();
-
m_contextMenu->addAction(actionMan->actionByName("deselect"));
m_contextMenu->addAction(actionMan->actionByName("invert"));
m_contextMenu->addAction(actionMan->actionByName("select_all"));
m_contextMenu->addSeparator();
m_contextMenu->addAction(actionMan->actionByName("cut_selection_to_new_layer"));
m_contextMenu->addAction(actionMan->actionByName("copy_selection_to_new_layer"));
m_contextMenu->addSeparator();
- QMenu *transformMenu = m_contextMenu->addMenu(i18n("Transform"));
- transformMenu->addAction(actionMan->actionByName("selectionscale"));
- transformMenu->addAction(actionMan->actionByName("growselection"));
- transformMenu->addAction(actionMan->actionByName("shrinkselection"));
- transformMenu->addAction(actionMan->actionByName("borderselection"));
- transformMenu->addAction(actionMan->actionByName("smoothselection"));
- transformMenu->addAction(actionMan->actionByName("featherselection"));
- transformMenu->addAction(actionMan->actionByName("stroke_selection"));
+ KisSelectionSP selection = canvas->viewManager()->selection();
+ if (selection && canvas->viewManager()->selectionEditable()) {
+ if (!selection->hasShapeSelection()) {
+ m_contextMenu->addAction(actionMan->actionByName("convert_to_vector_selection"));
+ } else {
+ m_contextMenu->addAction(actionMan->actionByName("convert_to_raster_selection"));
+ }
- m_contextMenu->addSeparator();
+ QMenu *transformMenu = m_contextMenu->addMenu(i18n("Transform"));
+ transformMenu->addAction(actionMan->actionByName("selectionscale"));
+ transformMenu->addAction(actionMan->actionByName("growselection"));
+ transformMenu->addAction(actionMan->actionByName("shrinkselection"));
+ transformMenu->addAction(actionMan->actionByName("borderselection"));
+ transformMenu->addAction(actionMan->actionByName("smoothselection"));
+ transformMenu->addAction(actionMan->actionByName("featherselection"));
+ transformMenu->addAction(actionMan->actionByName("stroke_selection"));
+
+ m_contextMenu->addSeparator();
+ }
m_contextMenu->addAction(actionMan->actionByName("resizeimagetoselection"));
m_contextMenu->addSeparator();
m_contextMenu->addAction(actionMan->actionByName("toggle_display_selection"));
m_contextMenu->addAction(actionMan->actionByName("show-global-selection-mask"));
return m_contextMenu;
}