aseprite/src/doc/selected_layers.cpp

233 lines
4.7 KiB
C++

// Aseprite Document Library
// Copyright (c) 2016, 2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "doc/selected_layers.h"
#include "base/base.h"
#include "base/debug.h"
#include "base/serialization.h"
#include "doc/layer.h"
#include "doc/sprite.h"
#include <iostream>
namespace doc {
using namespace base::serialization;
using namespace base::serialization::little_endian;
void SelectedLayers::clear()
{
m_set.clear();
}
void SelectedLayers::insert(Layer* layer)
{
ASSERT(layer);
m_set.insert(layer);
}
void SelectedLayers::erase(Layer* layer)
{
m_set.erase(layer);
}
bool SelectedLayers::contains(Layer* layer) const
{
return m_set.find(layer) != m_set.end();
}
bool SelectedLayers::hasSameParent() const
{
Layer* parent = nullptr;
for (auto layer : *this) {
if (parent) {
if (layer->parent() != parent)
return false;
}
else
parent = layer->parent();
}
return true;
}
LayerList SelectedLayers::toLayerList() const
{
LayerList output;
if (empty())
return output;
ASSERT(*begin());
ASSERT((*begin())->sprite());
for (Layer* layer = (*begin())->sprite()->firstBrowsableLayer();
layer != nullptr;
layer = layer->getNextBrowsable()) {
if (contains(layer))
output.push_back(layer);
}
return output;
}
void SelectedLayers::removeChildrenIfParentIsSelected()
{
SelectedLayers removeThese;
for (Layer* child : *this) {
Layer* parent = child->parent();
while (parent) {
if (contains(parent)) {
removeThese.insert(child);
break;
}
parent = parent->parent();
}
}
for (Layer* child : removeThese)
erase(child);
}
void SelectedLayers::selectAllLayers(LayerGroup* group)
{
for (Layer* layer : group->layers()) {
if (layer->isGroup())
selectAllLayers(static_cast<LayerGroup*>(layer));
insert(layer);
}
}
void SelectedLayers::expandCollapsedGroups()
{
auto copy = m_set;
for (Layer* layer : copy) {
if (layer->isGroup() && layer->isCollapsed())
selectAllLayers(static_cast<LayerGroup*>(layer));
}
}
void SelectedLayers::displace(layer_t layerDelta)
{
// Do nothing case
if (layerDelta == 0)
return;
const SelectedLayers original = *this;
retry:;
clear();
for (auto it : original) {
Layer* layer = it;
if (layerDelta > 0) {
for (layer_t i=0; layer && i<layerDelta; ++i)
layer = layer->getNextBrowsable();
}
else if (layerDelta < 0) {
for (layer_t i=0; layer && i>layerDelta; --i) {
layer = layer->getPreviousBrowsable();
}
}
if (layer) {
insert(layer);
}
// If some layer is outside the range it means that the delta is
// too big (out of bounds), we reduce the delta and try again the
// whole process.
else {
layerDelta -= SGN(layerDelta);
if (layerDelta == 0) {
m_set = original.m_set;
break;
}
goto retry;
}
}
}
// This will select:
// 1. all visible children in case the parent is selected and none of
// its children is selected.
// 2. all parent if one children is selected
void SelectedLayers::propagateSelection()
{
SelectedLayers newSel;
for (Layer* layer : *this) {
if (!layer->isGroup())
continue;
LayerList children;
static_cast<LayerGroup*>(layer)->allLayers(children);
bool allDeselected = true;
for (Layer* child : children) {
if (contains(child)) {
allDeselected = false;
break;
}
}
if (allDeselected) {
for (Layer* child : children) {
if (child->isVisible())
newSel.insert(child);
}
}
}
for (Layer* layer : *this) {
Layer* parent = layer->parent();
while (parent != layer->sprite()->root() &&
!contains(parent)) {
newSel.insert(parent);
parent = parent->parent();
}
}
for (Layer* layer : newSel)
insert(layer);
}
bool SelectedLayers::write(std::ostream& os) const
{
write32(os, size());
for (const Layer* layer : *this)
write32(os, layer->id());
return os.good();
}
bool SelectedLayers::read(std::istream& is)
{
clear();
int nlayers = read32(is);
for (int i=0; i<nlayers && is; ++i) {
ObjectId id = read32(is);
Layer* layer = doc::get<Layer>(id);
// Check that the layer does exist. You will see a little trick in
// UndoCommand::onExecute() deserializing the DocumentRange stream
// after the undo/redo is executed so layers exist at this point.
// TODO This should be an assert, but there is a bug that make this fail
//ASSERT(layer);
if (layer)
insert(layer);
}
return is.good();
}
} // namespace doc