diff --git a/data/strings/en.ini b/data/strings/en.ini index 37938020a..19cda74a7 100644 --- a/data/strings/en.ini +++ b/data/strings/en.ini @@ -6,6 +6,9 @@ title = Warning - Important description = You are going to enter in "Advanced Mode". dont_show_again = Don't show this again +[statusbar_tips] +all_layers_are_locked = All selected layers are locked + [alerts] applying_filter = FX<getApi(transaction); + Timeline* timeline = App::instance()->timeline(); + LockTimelineRange lockRange(timeline); + CelList cels; if (m_flipMask) { - auto range = App::instance()->timeline()->range(); - if (range.enabled()) - cels = get_unique_cels(sprite, range); - else if (writer.cel()) + auto range = timeline->range(); + if (range.enabled()) { + cels = get_unlocked_unique_cels(sprite, range); + } + else if (writer.cel() && + writer.layer() && + writer.layer()->isEditable()) { cels.push_back(writer.cel()); + } + + if (cels.empty()) { + StatusBar::instance()->showTip( + 1000, Strings::statusbar_tips_all_layers_are_locked().c_str()); + return; + } } + // Flip the whole sprite (even locked layers) else { for (Cel* cel : sprite->uniqueCels()) cels.push_back(cel); diff --git a/src/app/commands/cmd_rotate.cpp b/src/app/commands/cmd_rotate.cpp index 6163d1b00..73ec11222 100644 --- a/src/app/commands/cmd_rotate.cpp +++ b/src/app/commands/cmd_rotate.cpp @@ -23,6 +23,7 @@ #include "app/transaction.h" #include "app/ui/color_bar.h" #include "app/ui/editor/editor.h" +#include "app/ui/status_bar.h" #include "app/ui/timeline/timeline.h" #include "app/ui/toolbar.h" #include "app/util/range_utils.h" @@ -196,12 +197,17 @@ void RotateCommand::onExecute(Context* context) CelList cels; bool rotateSprite = false; + Timeline* timeline = App::instance()->timeline(); + LockTimelineRange lockRange(timeline); + // Flip the mask or current cel if (m_flipMask) { auto range = App::instance()->timeline()->range(); if (range.enabled()) - cels = get_unique_cels(site.sprite(), range); - else if (site.cel()) { + cels = get_unlocked_unique_cels(site.sprite(), range); + else if (site.cel() && + site.layer() && + site.layer()->isEditable()) { // If we want to rotate the visible mask for the current cel, // we can go to MovingPixelsState. if (static_cast(site.document())->isMaskVisible()) { @@ -216,8 +222,14 @@ void RotateCommand::onExecute(Context* context) cels.push_back(site.cel()); } + + if (cels.empty()) { + StatusBar::instance()->showTip( + 1000, Strings::statusbar_tips_all_layers_are_locked().c_str()); + return; + } } - // Flip the whole sprite + // Flip the whole sprite (even locked layers) else if (site.sprite()) { for (Cel* cel : site.sprite()->uniqueCels()) cels.push_back(cel); diff --git a/src/app/ui/editor/moving_cel_state.cpp b/src/app/ui/editor/moving_cel_state.cpp index 5868babbb..7b0fc0812 100644 --- a/src/app/ui/editor/moving_cel_state.cpp +++ b/src/app/ui/editor/moving_cel_state.cpp @@ -64,7 +64,7 @@ MovingCelCollect::MovingCelCollect(Editor* editor, Layer* layer) } // Record start positions of all cels in selected range - for (Cel* cel : get_unique_cels(editor->sprite(), range2)) { + for (Cel* cel : get_unlocked_unique_cels(editor->sprite(), range2)) { Layer* layer = cel->layer(); ASSERT(layer); diff --git a/src/app/ui/timeline/timeline.cpp b/src/app/ui/timeline/timeline.cpp index ee9f735d8..37642b78e 100644 --- a/src/app/ui/timeline/timeline.cpp +++ b/src/app/ui/timeline/timeline.cpp @@ -201,6 +201,7 @@ Timeline::Timeline() , m_editor(NULL) , m_document(NULL) , m_sprite(NULL) + , m_rangeLocks(0) , m_state(STATE_STANDBY) , m_tagBands(0) , m_tagFocusBand(-1) @@ -284,7 +285,8 @@ void Timeline::updateUsingEditor(Editor* editor) detachDocument(); - if (m_range.enabled()) { + if (m_range.enabled() && + m_rangeLocks == 0) { m_range.clearRange(); invalidate(); } @@ -1560,7 +1562,8 @@ void Timeline::onRemoveFrame(doc::DocumentEvent& ev) void Timeline::onSelectionChanged(doc::DocumentEvent& ev) { - m_range.clearRange(); + if (m_rangeLocks == 0) + m_range.clearRange(); invalidate(); } @@ -3378,6 +3381,17 @@ void Timeline::setViewScroll(const gfx::Point& pt) invalidate(); } + +void Timeline::lockRange() +{ + ++m_rangeLocks; +} + +void Timeline::unlockRange() +{ + --m_rangeLocks; +} + void Timeline::updateDropRange(const gfx::Point& pt) { DropTarget::HHit oldHHit = m_dropTarget.hhit; @@ -3544,7 +3558,9 @@ void Timeline::onNewInputPriority(InputChainElement* element) // That is why we don't disable the range in this case. Workspace* workspace = dynamic_cast(element); if (!workspace) { - m_range.clearRange(); + if (m_rangeLocks == 0) + m_range.clearRange(); + invalidate(); } } @@ -3629,7 +3645,9 @@ bool Timeline::onClear(Context* ctx) void Timeline::onCancel(Context* ctx) { - m_range.clearRange(); + if (m_rangeLocks == 0) + m_range.clearRange(); + clearClipboardRange(); invalidate(); } diff --git a/src/app/ui/timeline/timeline.h b/src/app/ui/timeline/timeline.h index 9069871b4..e27fbc9ca 100644 --- a/src/app/ui/timeline/timeline.h +++ b/src/app/ui/timeline/timeline.h @@ -112,6 +112,9 @@ namespace app { gfx::Point viewScroll() const override; void setViewScroll(const gfx::Point& pt) override; + void lockRange(); + void unlockRange(); + protected: bool onProcessMessage(ui::Message* msg) override; void onInitTheme(ui::InitThemeEvent& ev) override; @@ -327,6 +330,7 @@ namespace app { Sprite* m_sprite; Layer* m_layer; frame_t m_frame; + int m_rangeLocks; Range m_range; Range m_startRange; Range m_dropRange; @@ -380,6 +384,19 @@ namespace app { } m_moveRangeData; }; + class LockTimelineRange { + public: + LockTimelineRange(Timeline* timeline) + : m_timeline(timeline) { + m_timeline->lockRange(); + } + ~LockTimelineRange() { + m_timeline->unlockRange(); + } + private: + Timeline* m_timeline; + }; + } // namespace app #endif diff --git a/src/app/util/range_utils.cpp b/src/app/util/range_utils.cpp index 17790edca..a374e2684 100644 --- a/src/app/util/range_utils.cpp +++ b/src/app/util/range_utils.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2016 David Capello +// Copyright (C) 2001-2017 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -24,7 +24,7 @@ namespace app { using namespace doc; // TODO the DocumentRange should be "iteratable" to replace this function -CelList get_unique_cels(Sprite* sprite, const DocumentRange& inrange) +CelList get_unlocked_unique_cels(Sprite* sprite, const DocumentRange& inrange) { DocumentRange range = inrange; CelList cels; @@ -34,7 +34,9 @@ CelList get_unique_cels(Sprite* sprite, const DocumentRange& inrange) std::set visited; for (Layer* layer : range.selectedLayers()) { - if (!layer || !layer->isImage()) + if (!layer || + !layer->isImage() || + !layer->isEditable()) continue; LayerImage* layerImage = static_cast(layer); diff --git a/src/app/util/range_utils.h b/src/app/util/range_utils.h index c98ed4c2b..c62db8e1e 100644 --- a/src/app/util/range_utils.h +++ b/src/app/util/range_utils.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2017 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -21,7 +21,7 @@ namespace app { class DocumentRange; - doc::CelList get_unique_cels(doc::Sprite* sprite, const DocumentRange& range); + doc::CelList get_unlocked_unique_cels(doc::Sprite* sprite, const DocumentRange& range); } // namespace app