mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-23 22:43:32 +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);
|
||||
}
|
||||
|
||||
void DocumentRange::selectLayers(const SelectedLayers& selLayers)
|
||||
{
|
||||
for (auto layer : selLayers)
|
||||
m_selectedLayers.insert(layer);
|
||||
}
|
||||
|
||||
bool DocumentRange::contains(Layer* layer) const
|
||||
{
|
||||
if (enabled())
|
||||
|
@ -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(); }
|
||||
|
||||
|
@ -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<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,
|
||||
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<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);
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user