mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-01 18:00:26 +00:00
Don't apply Flip/Rotate commands to locked layers
Several issues fixed from https://community.aseprite.org/t/750 - Don't apply flip/rotate commands to cels from locked layers - Show a status bar tooltip when all selected layers are locked - Keep the timeline range enabled after the flip/rotate command
This commit is contained in:
parent
7682971acb
commit
21248b96dc
@ -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<<Applying effect...||&Cancel
|
||||
auto_remap = <<<END
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "app/i18n/strings.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui/timeline/timeline.h"
|
||||
#include "app/util/expand_cel_canvas.h"
|
||||
#include "app/util/range_utils.h"
|
||||
@ -67,24 +68,31 @@ void FlipCommand::onExecute(Context* context)
|
||||
Sprite* sprite = writer.sprite();
|
||||
|
||||
{
|
||||
Transaction transaction(writer.context(),
|
||||
m_flipMask ?
|
||||
(m_flipType == doc::algorithm::FlipHorizontal ?
|
||||
"Flip Horizontal":
|
||||
"Flip Vertical"):
|
||||
(m_flipType == doc::algorithm::FlipHorizontal ?
|
||||
"Flip Canvas Horizontal":
|
||||
"Flip Canvas Vertical"));
|
||||
Transaction transaction(writer.context(), friendlyName());
|
||||
DocumentApi api = document->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);
|
||||
|
@ -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<app::Document*>(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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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<Workspace*>(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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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<ObjectId> visited;
|
||||
|
||||
for (Layer* layer : range.selectedLayers()) {
|
||||
if (!layer || !layer->isImage())
|
||||
if (!layer ||
|
||||
!layer->isImage() ||
|
||||
!layer->isEditable())
|
||||
continue;
|
||||
|
||||
LayerImage* layerImage = static_cast<LayerImage*>(layer);
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user