mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-25 10:43:46 +00:00
Add support to move layer groups with the move tool
Related to #1172, #1318, #454
This commit is contained in:
parent
1378275364
commit
2e457fecad
@ -65,6 +65,12 @@ void DocumentRange::endRange(Layer* toLayer, frame_t toFrame)
|
|||||||
selectFrameRange(m_selectingFromFrame, toFrame);
|
selectFrameRange(m_selectingFromFrame, toFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DocumentRange::selectLayers(const SelectedLayers& selLayers)
|
||||||
|
{
|
||||||
|
for (auto layer : selLayers)
|
||||||
|
m_selectedLayers.insert(layer);
|
||||||
|
}
|
||||||
|
|
||||||
bool DocumentRange::contains(Layer* layer) const
|
bool DocumentRange::contains(Layer* layer) const
|
||||||
{
|
{
|
||||||
if (enabled())
|
if (enabled())
|
||||||
|
@ -37,11 +37,9 @@ namespace app {
|
|||||||
void displace(layer_t layerDelta, frame_t frameDelta);
|
void displace(layer_t layerDelta, frame_t frameDelta);
|
||||||
|
|
||||||
bool contains(Layer* layer) const;
|
bool contains(Layer* layer) const;
|
||||||
|
|
||||||
bool contains(frame_t frame) const {
|
bool contains(frame_t frame) const {
|
||||||
return m_selectedFrames.contains(frame);
|
return m_selectedFrames.contains(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contains(Layer* layer, frame_t frame) const {
|
bool contains(Layer* layer, frame_t frame) const {
|
||||||
return contains(layer) && contains(frame);
|
return contains(layer) && contains(frame);
|
||||||
}
|
}
|
||||||
@ -50,6 +48,8 @@ namespace app {
|
|||||||
void startRange(Layer* fromLayer, frame_t fromFrame, Type type);
|
void startRange(Layer* fromLayer, frame_t fromFrame, Type type);
|
||||||
void endRange(Layer* toLayer, frame_t toFrame);
|
void endRange(Layer* toLayer, frame_t toFrame);
|
||||||
|
|
||||||
|
void selectLayers(const SelectedLayers& selLayers);
|
||||||
|
|
||||||
frame_t firstFrame() const { return m_selectedFrames.firstFrame(); }
|
frame_t firstFrame() const { return m_selectedFrames.firstFrame(); }
|
||||||
frame_t lastFrame() const { return m_selectedFrames.lastFrame(); }
|
frame_t lastFrame() const { return m_selectedFrames.lastFrame(); }
|
||||||
|
|
||||||
|
@ -33,10 +33,51 @@ namespace app {
|
|||||||
|
|
||||||
using namespace ui;
|
using namespace ui;
|
||||||
|
|
||||||
|
MovingCelCollect::MovingCelCollect(Editor* editor, Layer* layer)
|
||||||
|
: m_mainCel(nullptr)
|
||||||
|
{
|
||||||
|
ASSERT(editor);
|
||||||
|
|
||||||
|
if (layer && layer->isImage())
|
||||||
|
m_mainCel = layer->cel(editor->frame());
|
||||||
|
|
||||||
|
DocumentRange range = App::instance()->timeline()->range();
|
||||||
|
if (!range.enabled()) {
|
||||||
|
range.startRange(editor->layer(), editor->frame(), DocumentRange::kCels);
|
||||||
|
range.endRange(editor->layer(), editor->frame());
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentRange range2 = range;
|
||||||
|
for (Layer* layer : range.selectedLayers()) {
|
||||||
|
if (layer && layer->isGroup()) {
|
||||||
|
LayerList childrenList;
|
||||||
|
static_cast<LayerGroup*>(layer)->allLayers(childrenList);
|
||||||
|
|
||||||
|
SelectedLayers selChildren;
|
||||||
|
for (auto layer : childrenList)
|
||||||
|
selChildren.insert(layer);
|
||||||
|
|
||||||
|
range2.selectLayers(selChildren);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record start positions of all cels in selected range
|
||||||
|
for (Cel* cel : get_unique_cels(editor->sprite(), range2)) {
|
||||||
|
Layer* layer = cel->layer();
|
||||||
|
ASSERT(layer);
|
||||||
|
|
||||||
|
if (layer && layer->isMovable() && !layer->isBackground())
|
||||||
|
m_celList.push_back(cel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MovingCelState::MovingCelState(Editor* editor,
|
MovingCelState::MovingCelState(Editor* editor,
|
||||||
MouseMessage* msg,
|
MouseMessage* msg,
|
||||||
const HandleType handle)
|
const HandleType handle,
|
||||||
|
const MovingCelCollect& collect)
|
||||||
: m_reader(UIContext::instance(), 500)
|
: m_reader(UIContext::instance(), 500)
|
||||||
|
, m_cel(nullptr)
|
||||||
|
, m_celList(collect.celList())
|
||||||
, m_celOffset(0.0, 0.0)
|
, m_celOffset(0.0, 0.0)
|
||||||
, m_celScale(1.0, 1.0)
|
, m_celScale(1.0, 1.0)
|
||||||
, m_canceled(false)
|
, m_canceled(false)
|
||||||
@ -46,28 +87,19 @@ MovingCelState::MovingCelState(Editor* editor,
|
|||||||
{
|
{
|
||||||
ContextWriter writer(m_reader, 500);
|
ContextWriter writer(m_reader, 500);
|
||||||
Document* document = editor->document();
|
Document* document = editor->document();
|
||||||
auto range = App::instance()->timeline()->range();
|
ASSERT(!m_celList.empty());
|
||||||
LayerImage* layer = static_cast<LayerImage*>(editor->layer());
|
|
||||||
ASSERT(layer->isImage());
|
|
||||||
|
|
||||||
m_cel = layer->cel(editor->frame());
|
|
||||||
ASSERT(m_cel); // The cel cannot be null
|
|
||||||
|
|
||||||
if (!range.enabled())
|
|
||||||
range = DocumentRange(m_cel);
|
|
||||||
|
|
||||||
|
m_cel = collect.mainCel();
|
||||||
if (m_cel)
|
if (m_cel)
|
||||||
m_celMainSize = m_cel->boundsF().size();
|
m_celMainSize = m_cel->boundsF().size();
|
||||||
|
|
||||||
// Record start positions of all cels in selected range
|
// Record start positions of all cels in selected range
|
||||||
for (Cel* cel : get_unique_cels(writer.sprite(), range)) {
|
for (Cel* cel : m_celList) {
|
||||||
Layer* layer = cel->layer();
|
Layer* layer = cel->layer();
|
||||||
ASSERT(layer);
|
ASSERT(layer);
|
||||||
|
|
||||||
if (layer && layer->isMovable() && !layer->isBackground()) {
|
if (layer && layer->isMovable() && !layer->isBackground()) {
|
||||||
m_celList.push_back(cel);
|
if (layer->isReference()) {
|
||||||
|
|
||||||
if (cel->layer()->isReference()) {
|
|
||||||
m_celStarts.push_back(cel->boundsF());
|
m_celStarts.push_back(cel->boundsF());
|
||||||
m_hasReference = true;
|
m_hasReference = true;
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,26 @@ namespace doc {
|
|||||||
namespace app {
|
namespace app {
|
||||||
class Editor;
|
class Editor;
|
||||||
|
|
||||||
|
class MovingCelCollect {
|
||||||
|
public:
|
||||||
|
MovingCelCollect(Editor* editor, Layer* layer);
|
||||||
|
|
||||||
|
bool empty() const { return m_celList.empty(); }
|
||||||
|
|
||||||
|
Cel* mainCel() const { return m_mainCel; }
|
||||||
|
const CelList& celList() const { return m_celList; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Cel* m_mainCel;
|
||||||
|
CelList m_celList;
|
||||||
|
};
|
||||||
|
|
||||||
class MovingCelState : public StandbyState {
|
class MovingCelState : public StandbyState {
|
||||||
public:
|
public:
|
||||||
MovingCelState(Editor* editor,
|
MovingCelState(Editor* editor,
|
||||||
ui::MouseMessage* msg,
|
ui::MouseMessage* msg,
|
||||||
const HandleType handle);
|
const HandleType handle,
|
||||||
|
const MovingCelCollect& collect);
|
||||||
|
|
||||||
virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
|
virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
|
||||||
virtual bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
|
virtual bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
|
||||||
|
@ -204,7 +204,7 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layer && layer->isImage()) {
|
if (layer) {
|
||||||
// TODO we should be able to move the `Background' with tiled mode
|
// TODO we should be able to move the `Background' with tiled mode
|
||||||
if (layer->isBackground()) {
|
if (layer->isBackground()) {
|
||||||
StatusBar::instance()->showTip(1000,
|
StatusBar::instance()->showTip(1000,
|
||||||
@ -218,24 +218,28 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
|||||||
StatusBar::instance()->showTip(1000,
|
StatusBar::instance()->showTip(1000,
|
||||||
"Layer '%s' is locked", layer->name().c_str());
|
"Layer '%s' is locked", layer->name().c_str());
|
||||||
}
|
}
|
||||||
else if (!layer->cel(editor->frame())) {
|
|
||||||
StatusBar::instance()->showTip(1000,
|
|
||||||
"Cel is empty, nothing to move");
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
try {
|
MovingCelCollect collect(editor, layer);
|
||||||
// Change to MovingCelState
|
if (collect.empty()) {
|
||||||
HandleType handle = MoveHandle;
|
StatusBar::instance()->showTip(
|
||||||
if (resizeCelBounds(editor).contains(msg->position()))
|
1000, "Nothing to move");
|
||||||
handle = ScaleSEHandle;
|
|
||||||
|
|
||||||
MovingCelState* newState = new MovingCelState(editor, msg, handle);
|
|
||||||
editor->setState(EditorStatePtr(newState));
|
|
||||||
}
|
}
|
||||||
catch (const LockedDocumentException&) {
|
else {
|
||||||
// TODO break the background task that is locking this sprite
|
try {
|
||||||
StatusBar::instance()->showTip(1000,
|
// Change to MovingCelState
|
||||||
"Sprite is used by a backup/data recovery task");
|
HandleType handle = MoveHandle;
|
||||||
|
if (resizeCelBounds(editor).contains(msg->position()))
|
||||||
|
handle = ScaleSEHandle;
|
||||||
|
|
||||||
|
MovingCelState* newState = new MovingCelState(
|
||||||
|
editor, msg, handle, collect);
|
||||||
|
editor->setState(EditorStatePtr(newState));
|
||||||
|
}
|
||||||
|
catch (const LockedDocumentException&) {
|
||||||
|
// TODO break the background task that is locking this sprite
|
||||||
|
StatusBar::instance()->showTip(
|
||||||
|
1000, "Sprite is used by a backup/data recovery task");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user