diff --git a/src/app/document_range.cpp b/src/app/document_range.cpp index 8419e1a99..d2eba5782 100644 --- a/src/app/document_range.cpp +++ b/src/app/document_range.cpp @@ -65,6 +65,12 @@ void DocumentRange::endRange(Layer* toLayer, frame_t 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 { if (enabled()) diff --git a/src/app/document_range.h b/src/app/document_range.h index 2c04d8e24..30a8fc651 100644 --- a/src/app/document_range.h +++ b/src/app/document_range.h @@ -37,11 +37,9 @@ namespace app { void displace(layer_t layerDelta, frame_t frameDelta); bool contains(Layer* layer) const; - bool contains(frame_t frame) const { return m_selectedFrames.contains(frame); } - bool contains(Layer* layer, frame_t frame) const { return contains(layer) && contains(frame); } @@ -50,6 +48,8 @@ namespace app { void startRange(Layer* fromLayer, frame_t fromFrame, Type type); void endRange(Layer* toLayer, frame_t toFrame); + void selectLayers(const SelectedLayers& selLayers); + frame_t firstFrame() const { return m_selectedFrames.firstFrame(); } frame_t lastFrame() const { return m_selectedFrames.lastFrame(); } diff --git a/src/app/ui/editor/moving_cel_state.cpp b/src/app/ui/editor/moving_cel_state.cpp index f6741869c..d5181a366 100644 --- a/src/app/ui/editor/moving_cel_state.cpp +++ b/src/app/ui/editor/moving_cel_state.cpp @@ -33,10 +33,51 @@ namespace app { 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(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, MouseMessage* msg, - const HandleType handle) + const HandleType handle, + const MovingCelCollect& collect) : m_reader(UIContext::instance(), 500) + , m_cel(nullptr) + , m_celList(collect.celList()) , m_celOffset(0.0, 0.0) , m_celScale(1.0, 1.0) , m_canceled(false) @@ -46,28 +87,19 @@ MovingCelState::MovingCelState(Editor* editor, { ContextWriter writer(m_reader, 500); Document* document = editor->document(); - auto range = App::instance()->timeline()->range(); - LayerImage* layer = static_cast(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); + ASSERT(!m_celList.empty()); + m_cel = collect.mainCel(); if (m_cel) m_celMainSize = m_cel->boundsF().size(); // 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(); ASSERT(layer); if (layer && layer->isMovable() && !layer->isBackground()) { - m_celList.push_back(cel); - - if (cel->layer()->isReference()) { + if (layer->isReference()) { m_celStarts.push_back(cel->boundsF()); m_hasReference = true; } diff --git a/src/app/ui/editor/moving_cel_state.h b/src/app/ui/editor/moving_cel_state.h index 9459272b5..0dda9bc40 100644 --- a/src/app/ui/editor/moving_cel_state.h +++ b/src/app/ui/editor/moving_cel_state.h @@ -23,11 +23,26 @@ namespace doc { namespace app { 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 { public: MovingCelState(Editor* editor, ui::MouseMessage* msg, - const HandleType handle); + const HandleType handle, + const MovingCelCollect& collect); virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override; virtual bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override; diff --git a/src/app/ui/editor/standby_state.cpp b/src/app/ui/editor/standby_state.cpp index 25813d1c9..f3a21a77f 100644 --- a/src/app/ui/editor/standby_state.cpp +++ b/src/app/ui/editor/standby_state.cpp @@ -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 if (layer->isBackground()) { StatusBar::instance()->showTip(1000, @@ -218,24 +218,28 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg) StatusBar::instance()->showTip(1000, "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 { - try { - // Change to MovingCelState - HandleType handle = MoveHandle; - if (resizeCelBounds(editor).contains(msg->position())) - handle = ScaleSEHandle; - - MovingCelState* newState = new MovingCelState(editor, msg, handle); - editor->setState(EditorStatePtr(newState)); + MovingCelCollect collect(editor, layer); + if (collect.empty()) { + StatusBar::instance()->showTip( + 1000, "Nothing to move"); } - 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"); + else { + try { + // Change to MovingCelState + 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"); + } } } }