Fix export of groups/layers via CLI

We have to propagate show/hide layers/groups visibility properly to
export them correctly. We use the same code that in the "Export Sprite
Sheet" for this (a new RestoreVisibleLayers class is separated for
this).
This commit is contained in:
David Capello 2016-09-16 11:15:47 -03:00
parent 682e9b8307
commit f4b5340dfb
5 changed files with 116 additions and 72 deletions

View File

@ -327,6 +327,7 @@ add_library(app-lib
res/palettes_loader_delegate.cpp
res/resources_loader.cpp
resource_finder.cpp
restore_visible_layers.cpp
script/app_object.cpp
script/app_scripting.cpp
script/console_object.cpp

View File

@ -21,6 +21,7 @@
#include "app/document_undo.h"
#include "app/file/file.h"
#include "app/filename_formatter.h"
#include "app/restore_visible_layers.h"
#include "app/ui_context.h"
#include "base/convert_to.h"
#include "base/path.h"
@ -29,6 +30,7 @@
#include "doc/frame_tags.h"
#include "doc/layer.h"
#include "doc/selected_frames.h"
#include "doc/selected_layers.h"
namespace app {
@ -418,13 +420,6 @@ void CliProcessor::saveFile(const CliOpenFile& cof)
ctx->executeCommand(cropCommand, cropParams);
}
// Store in "visibility" the original "visible" state of every layer.
LayerList allLayers = doc->sprite()->allLayers();
std::vector<bool> visibility(allLayers.size());
int i = 0;
for (doc::Layer* layer : allLayers)
visibility[i++] = layer->isVisible();
std::string fn = cof.filename;
std::string filenameFormat = cof.filenameFormat;
if (filenameFormat.empty()) { // Default format
@ -437,7 +432,9 @@ void CliProcessor::saveFile(const CliOpenFile& cof)
cof.splitTags); // Has frame tag
}
std::vector<doc::Layer*> layers;
SelectedLayers filteredLayers;
LayerList allLayers = doc->sprite()->allLayers();
LayerList layers;
// --save-as with --split-layers or --split-tags
if (cof.splitLayers) {
for (doc::Layer* layer : doc->sprite()->allVisibleLayers())
@ -447,17 +444,13 @@ void CliProcessor::saveFile(const CliOpenFile& cof)
// Show only one layer
if (!cof.importLayer.empty()) {
for (Layer* layer : allLayers) {
if (layer->name() == cof.importLayer) {
layer->setVisible(true);
layers.push_back(layer);
}
else
layer->setVisible(false);
if (layer->name() == cof.importLayer)
filteredLayers.insert(layer);
}
}
// All visible layers
else
layers.push_back(nullptr);
layers.push_back(nullptr);
}
std::vector<doc::FrameTag*> frameTags;
@ -487,19 +480,21 @@ void CliProcessor::saveFile(const CliOpenFile& cof)
for (doc::FrameTag* frameTag : frameTags) {
// For each layer, hide other ones and save the sprite.
i = 0;
for (doc::Layer* layer : layers) {
RestoreVisibleLayers layersVisibility;
if (cof.splitLayers) {
ASSERT(layer);
// If the user doesn't want all layers and this one is hidden.
if (!visibility[i++])
if (!layer->isVisible())
continue; // Just ignore this layer.
// Make this layer ("show") the only one visible.
for (doc::Layer* hide : allLayers)
hide->setVisible(hide == layer);
layersVisibility.showLayer(layer);
}
else if (!filteredLayers.empty())
layersVisibility.showSelectedLayers(doc->sprite(), filteredLayers);
if (layer) {
if ((layerInFormat && layer->isGroup()) ||
@ -548,11 +543,6 @@ void CliProcessor::saveFile(const CliOpenFile& cof)
}
}
// Restore layer visibility
i = 0;
for (Layer* layer : allLayers)
layer->setVisible(visibility[i++]);
// Undo crop
if (!cof.crop.isEmpty()) {
ctx->executeCommand(undoCommand);

View File

@ -8,7 +8,6 @@
#include "config.h"
#endif
#include "base/string.h"
#include "app/app.h"
#include "app/commands/command.h"
#include "app/context.h"
@ -19,6 +18,7 @@
#include "app/file_selector.h"
#include "app/modules/editors.h"
#include "app/pref/preferences.h"
#include "app/restore_visible_layers.h"
#include "app/ui/editor/editor.h"
#include "app/ui/status_bar.h"
#include "app/ui/timeline.h"
@ -26,6 +26,7 @@
#include "base/convert_to.h"
#include "base/fs.h"
#include "base/path.h"
#include "base/string.h"
#include "doc/frame_tag.h"
#include "doc/layer.h"
@ -188,50 +189,6 @@ namespace {
return frameTag;
}
class RestoreSelectedLayers {
public:
~RestoreSelectedLayers() {
for (auto item : m_restore)
item.first->setVisible(item.second);
}
void showSelectedLayers(Sprite* sprite) {
// TODO the range of selected frames should be in doc::Site.
auto range = App::instance()->timeline()->range();
if (!range.enabled()) {
if (current_editor) {
ASSERT(current_editor->sprite() == sprite);
range.clearRange();
range.startRange(current_editor->layer(),
current_editor->frame(), DocumentRange::kCels);
range.endRange(current_editor->layer(),
current_editor->frame());
}
else
return;
}
SelectedLayers selLayers = range.selectedLayers();
selLayers.propagateSelection();
setLayerVisiblity(sprite->root(), selLayers);
}
private:
void setLayerVisiblity(LayerGroup* group, const SelectedLayers& selLayers) {
for (Layer* layer : group->layers()) {
bool selected = (selLayers.contains(layer));
if (selected != layer->isVisible()) {
m_restore.push_back(std::make_pair(layer, layer->isVisible()));
layer->setVisible(selected);
}
if (selected && layer->isGroup())
setLayerVisiblity(static_cast<LayerGroup*>(layer), selLayers);
}
}
std::vector<std::pair<Layer*, bool> > m_restore;
};
}
class ExportSpriteSheetWindow : public app::gen::ExportSpriteSheet {
@ -822,9 +779,14 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
// If the user choose to render selected layers only, we can
// temporaly make them visible and hide the other ones.
Layer* layer = nullptr;
RestoreSelectedLayers layersVisibility;
RestoreVisibleLayers layersVisibility;
if (layerName == kSelectedLayers) {
layersVisibility.showSelectedLayers(sprite);
// TODO the range of selected frames should be in doc::Site.
auto range = App::instance()->timeline()->range();
if (range.enabled())
layersVisibility.showSelectedLayers(sprite, range.selectedLayers());
else if (current_editor)
layersVisibility.showLayer(current_editor->layer());
}
else {
// TODO add a getLayerByName

View File

@ -0,0 +1,54 @@
// Aseprite
// Copyright (C) 2016 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/restore_visible_layers.h"
#include "doc/layer.h"
#include "doc/selected_layers.h"
#include "doc/sprite.h"
namespace app {
using namespace doc;
RestoreVisibleLayers::~RestoreVisibleLayers()
{
for (auto item : m_restore)
item.first->setVisible(item.second);
}
void RestoreVisibleLayers::showLayer(Layer* layer)
{
SelectedLayers selLayers;
selLayers.insert(layer);
showSelectedLayers(layer->sprite(), selLayers);
}
void RestoreVisibleLayers::showSelectedLayers(Sprite* sprite, const SelectedLayers& inSelLayers)
{
SelectedLayers selLayers = inSelLayers;
selLayers.propagateSelection();
setLayerVisiblity(sprite->root(), selLayers);
}
void RestoreVisibleLayers::setLayerVisiblity(LayerGroup* group, const SelectedLayers& selLayers)
{
for (Layer* layer : group->layers()) {
bool selected = (selLayers.contains(layer));
if (selected != layer->isVisible()) {
m_restore.push_back(std::make_pair(layer, layer->isVisible()));
layer->setVisible(selected);
}
if (selected && layer->isGroup())
setLayerVisiblity(static_cast<LayerGroup*>(layer), selLayers);
}
}
} // namespace app

View File

@ -0,0 +1,37 @@
// Aseprite
// Copyright (C) 2016 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_RESTORE_VISIBLE_LAYERS_H_INCLUDED
#define APP_RESTORE_VISIBLE_LAYERS_H_INCLUDED
#pragma once
#include <vector>
namespace doc {
class Layer;
class LayerGroup;
class SelectedLayers;
class Sprite;
}
namespace app {
class RestoreVisibleLayers {
public:
~RestoreVisibleLayers();
void showLayer(doc::Layer* layer);
void showSelectedLayers(doc::Sprite* sprite, const doc::SelectedLayers& selLayers);
private:
void setLayerVisiblity(doc::LayerGroup* group, const doc::SelectedLayers& selLayers);
std::vector<std::pair<doc::Layer*, bool> > m_restore;
};
} // namespace app
#endif