Create file layer from layer.
ClosedPublic

Authored by woltherav on Oct 18 2017, 5:05 PM.

Details

Summary

This adds an action that will...

  1. Take the active layer.
  2. Make a new document with a clone of this layer.
  3. Save said document with the file name given by the user.
  4. make a file layer referncing the new document and add that to the layer stack.
  5. remove the original layer.

The idea behind this one is that if people's layer stacks become too complicated, they can save out a section of it to a file layer, reducing the complexity of the document.

There's still bugs with the position, that I need user feedback for, as well as general testing.

Test Plan
  1. Make a document with layers
  2. go to layers->convert->convert layer to file layer

Things that needs testing:

  1. saving & loading.

Diff Detail

Repository
R37 Krita
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.
woltherav created this revision.Oct 18 2017, 5:05 PM

Idea: fill path with .kra file ()path and name with .kra file name + layer name by default.
like path - "C:\myart\october" and name - "the_best_painting - background.kra" (png?)

woltherav updated this revision to Diff 20959.Oct 18 2017, 6:10 PM

This fixes the offset/coordinates issue, and proposes a basename if the image that is converted from has a filename already.

dkazakov requested changes to this revision.Oct 23 2017, 11:35 AM
dkazakov added a subscriber: dkazakov.

Hi, @woltherav!

The patch almost works fine. To make it perfect I would also recommend two mode fixes:

  1. Call KisAction::setExcludedNodeTypes() for your action so it would forbid calling the action for the file layers themselves. That is how normal conversion actions work usually.
  2. Add some label to the dialog with more words, so the user would understand what Krita wants from him/her. Right now it looks a bit frightening :)
krita/krita.action
2615

The title should use Caption Case: "Convert Layer to File Layer"

libs/ui/kis_layer_manager.cc
467

Please use KisImageSP for local variables. WSPs are only for storing stuff somewhere.

482

It doesn't provide any default file path if the user tries to create the file layer on yet unsaved image. In that case the dialog looks frighteningly empty :)

485

Please use QFileInfo::absolutePath() instead of manual parsing of the path string. It'll be much more robust :)

This revision now requires changes to proceed.Oct 23 2017, 11:35 AM
woltherav updated this revision to Diff 21183.Oct 23 2017, 2:53 PM
woltherav marked 3 inline comments as done.

Added all of dmitry's requested changes, as well as adding the action to the layer context menu, as well as removing a check for group layers which appeared to be unnecessary.

dkazakov requested changes to this revision.Oct 25 2017, 8:47 AM

Hi, @woltherav!

I have added two inlined comments. I've also see an offset problem once, but I couldn't reproduce it :(

There is also a minor bug happens: after converting a node, "active layer" changes to the layer below the converted one, and it should be kept intact (all the other conversion operations work like that). As far as I can tell, to achive that you should swap the order of adding and removing the nodes. You should first remove the old one, and the add the new one. The lastly added node should become active.

libs/ui/kis_layer_manager.cc
182

Now the action is created and connected to the slot in two places: in KisNodeManager and KisLayerManager. As far as I can tell, the connection should only be in KisNodeManager::convertNode(), and this slot should call your implementation layerManager->convertLayerToFileLayer(node).

Right now the code in node manager warns about being called with unknown layer type :)

460

Could you set some default path, e.g. "$HOME/layer_name.kra" as the default when the image has never been saved yet?

This revision now requires changes to proceed.Oct 25 2017, 8:47 AM

I based most of my stuff on group_to_animated, is that one then wrong to begin with?

libs/ui/kis_layer_manager.cc
182

Doesn't the convert_group_to_animated above have the same issue?

woltherav updated this revision to Diff 21538.Oct 29 2017, 11:06 PM

I added a default file name for the case where the image hadn't been saved yet. But... I still need my answer on the other thing...?

dkazakov accepted this revision.Oct 30 2017, 12:40 PM

Hi, @woltherav!

Here is the patch that fixes a few issues:

  • double creation of an action
  • initialization of the file name path
  • order of the layers after the layer is converted

Please test this patch and push together with yours :)

1diff --git a/libs/ui/kis_layer_manager.cc b/libs/ui/kis_layer_manager.cc
2index 2f0c344..fd7470f 100644
3--- a/libs/ui/kis_layer_manager.cc
4+++ b/libs/ui/kis_layer_manager.cc
5@@ -179,9 +179,6 @@ void KisLayerManager::setup(KisActionManager* actionManager)
6 m_convertGroupAnimated = actionManager->createAction("convert_group_to_animated");
7 connect(m_convertGroupAnimated, SIGNAL(triggered()), this, SLOT(convertGroupToAnimated()));
8
9- m_convertLayerFileLayer = actionManager->createAction("convert_layer_to_file_layer");
10- connect(m_convertLayerFileLayer, SIGNAL(triggered()), this, SLOT(convertLayerToFileLayer()));
11-
12 m_imageResizeToLayer = actionManager->createAction("resizeimagetolayer");
13 connect(m_imageResizeToLayer, SIGNAL(triggered()), this, SLOT(imageResizeToActiveLayer()));
14
15@@ -438,7 +435,7 @@ void KisLayerManager::convertGroupToAnimated()
16 m_commandsAdapter->endMacro();
17 }
18
19-void KisLayerManager::convertLayerToFileLayer()
20+void KisLayerManager::convertLayerToFileLayer(KisNodeSP source)
21 {
22 KisImageSP image = m_view->image();
23 if (!image) return;
24@@ -458,14 +455,13 @@ void KisLayerManager::convertLayerToFileLayer()
25 urlRequester->setMimeTypeFilters(listMimeFilter);
26 urlRequester->setFileName(m_view->document()->url().toLocalFile());
27 if (m_view->document()->url().isLocalFile()) {
28- urlRequester->setStartDir(QFileInfo(m_view->document()->url().toLocalFile()).absolutePath());
29 QFileInfo location = QFileInfo(m_view->document()->url().toLocalFile()).baseName();
30- location.setFile(location.dir(), location.baseName()+"_"+activeLayer()->name()+".kra");
31+ location.setFile(location.dir(), location.baseName()+"_"+ source->name()+".kra");
32 urlRequester->setFileName(location.absoluteFilePath());
33 } else {
34- QFileInfo location = QFileInfo(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
35- urlRequester->setStartDir(location.absolutePath());
36- urlRequester->setFileName(activeLayer()->name()+".kra");
37+ const QFileInfo location = QFileInfo(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
38+ const QString proposedFileName = QDir(location.absoluteFilePath()).absoluteFilePath(source->name() + ".kra");
39+ urlRequester->setFileName(proposedFileName);
40 }
41
42 layout->addWidget(urlRequester);
43@@ -482,20 +478,20 @@ void KisLayerManager::convertLayerToFileLayer()
44 mimeType = "image/png";
45 }
46
47- KisNodeSP layer = activeLayer();
48+
49 QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
50
51- QRect bounds = activeLayer()->exactBounds();
52+ QRect bounds = source->exactBounds();
53
54 KisImageSP dst = new KisImage(doc->createUndoStore(),
55 image->width(),
56 image->height(),
57 image->projection()->compositionSourceColorSpace(),
58- layer->name());
59+ source->name());
60 dst->setResolution(image->xRes(), image->yRes());
61 doc->setFileBatchMode(false);
62 doc->setCurrentImage(dst);
63- KisNodeSP node = layer->clone();
64+ KisNodeSP node = source->clone();
65 dst->addNode(node);
66 dst->initialRefreshGraph();
67 dst->cropImage(bounds);
68@@ -508,12 +504,17 @@ void KisLayerManager::convertLayerToFileLayer()
69 } else {
70 QString basePath = QFileInfo(m_view->document()->url().toLocalFile()).absolutePath();
71 QString relativePath = QDir(basePath).relativeFilePath(path);
72- KisFileLayer *fileLayer = new KisFileLayer(image, basePath, relativePath, KisFileLayer::None, layer->name(), OPACITY_OPAQUE_U8);
73+ KisFileLayer *fileLayer = new KisFileLayer(image, basePath, relativePath, KisFileLayer::None, source->name(), OPACITY_OPAQUE_U8);
74 fileLayer->setX(bounds.x());
75 fileLayer->setY(bounds.y());
76+
77+ KisNodeSP dstParent = source->parent();
78+ KisNodeSP dstAboveThis = source->prevSibling();
79+
80+
81 m_commandsAdapter->beginMacro(kundo2_i18n("Convert to a file layer"));
82- m_commandsAdapter->addNode(fileLayer, layer->parent(), layer);
83- m_commandsAdapter->removeNode(layer);
84+ m_commandsAdapter->removeNode(source);
85+ m_commandsAdapter->addNode(fileLayer, dstParent, dstAboveThis);
86 m_commandsAdapter->endMacro();
87 }
88 doc->closeUrl(false);
89diff --git a/libs/ui/kis_layer_manager.h b/libs/ui/kis_layer_manager.h
90index 0349c5f..17f9d9c 100644
91--- a/libs/ui/kis_layer_manager.h
92+++ b/libs/ui/kis_layer_manager.h
93@@ -91,7 +91,7 @@ private Q_SLOTS:
94 void convertNodeToPaintLayer(KisNodeSP source);
95 void convertGroupToAnimated();
96
97- void convertLayerToFileLayer();
98+ void convertLayerToFileLayer(KisNodeSP source);
99
100 KisLayerSP addLayer(KisNodeSP activeNode);
101 void addGroupLayer(KisNodeSP activeNode);
102@@ -125,7 +125,6 @@ private:
103 KisAction *m_imageResizeToLayer;
104 KisAction *m_flattenLayer;
105 KisAction *m_rasterizeLayer;
106- KisAction *m_convertLayerFileLayer;
107 KisNodeCommandsAdapter* m_commandsAdapter;
108
109 KisAction *m_layerStyle;
110diff --git a/libs/ui/kis_node_manager.cpp b/libs/ui/kis_node_manager.cpp
111index 02b93e0..de463e0 100644
112--- a/libs/ui/kis_node_manager.cpp
113+++ b/libs/ui/kis_node_manager.cpp
114@@ -592,6 +592,8 @@ void KisNodeManager::convertNode(const QString &nodeType)
115 m_d->commandsAdapter.removeNode(activeNode);
116 m_d->commandsAdapter.endMacro();
117
118+ } else if (nodeType == "KisFileLayer") {
119+ m_d->layerManager.convertLayerToFileLayer(activeNode);
120 } else {
121 warnKrita << "Unsupported node conversion type:" << nodeType;
122 }
123diff --git a/libs/widgets/kis_file_name_requester.cpp b/libs/widgets/kis_file_name_requester.cpp
124index 966cc46..3942e80 100644
125--- a/libs/widgets/kis_file_name_requester.cpp
126+++ b/libs/widgets/kis_file_name_requester.cpp
127@@ -49,6 +49,7 @@ void KisFileNameRequester::setStartDir(const QString &path)
128 void KisFileNameRequester::setFileName(const QString &path)
129 {
130 m_ui->txtFileName->setText(path);
131+ m_basePath = path;
132 emit fileSelected(path);
133 }
134

libs/ui/kis_layer_manager.cc
182

convert_group_to_animated is correct, although has a bug. It doesn't request the action from two separate places (good), but it doesn't get deactivated when a node of a wrong type is selected. We don't have a built-in framework for activation an action by a selected layer type. We have only "exclude" layer types.

Anyway, convert_group_to_animated is not the best example for your case. The best example is "convert_to_paint_layer"

This revision is now accepted and ready to land.Oct 30 2017, 12:40 PM
This revision was automatically updated to reflect the committed changes.