mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-17 08:43:11 +00:00
Add support to remove several layers & frames at once
This commit is contained in:
parent
ccb24cad35
commit
cb11fb3458
@ -20,10 +20,13 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/document_api.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "app/undo_transaction.h"
|
||||
#include "raster/sprite.h"
|
||||
#include "ui/ui.h"
|
||||
@ -63,7 +66,21 @@ void RemoveFrameCommand::onExecute(Context* context)
|
||||
Sprite* sprite(writer.sprite());
|
||||
{
|
||||
UndoTransaction undoTransaction(writer.context(), "Remove Frame");
|
||||
document->getApi().removeFrame(sprite, writer.frame());
|
||||
|
||||
// TODO the range of selected frames should be in the DocumentLocation.
|
||||
Timeline::Range range = App::instance()->getMainWindow()->getTimeline()->range();
|
||||
if (range.enabled()) {
|
||||
for (FrameNumber frame = range.frameEnd(),
|
||||
begin = range.frameBegin().previous();
|
||||
frame != begin;
|
||||
frame = frame.previous()) {
|
||||
document->getApi().removeFrame(sprite, frame);
|
||||
}
|
||||
}
|
||||
else {
|
||||
document->getApi().removeFrame(sprite, writer.frame());
|
||||
}
|
||||
|
||||
undoTransaction.commit();
|
||||
}
|
||||
update_screen_for_document(document);
|
||||
|
@ -20,12 +20,15 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/app.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/document_api.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "app/undo_transaction.h"
|
||||
#include "raster/layer.h"
|
||||
#include "raster/sprite.h"
|
||||
@ -52,8 +55,11 @@ RemoveLayerCommand::RemoveLayerCommand()
|
||||
|
||||
bool RemoveLayerCommand::onEnabled(Context* context)
|
||||
{
|
||||
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
||||
ContextFlags::HasActiveLayer);
|
||||
ContextWriter writer(context);
|
||||
Sprite* sprite(writer.sprite());
|
||||
return
|
||||
sprite &&
|
||||
sprite->countLayers() > 1;
|
||||
}
|
||||
|
||||
void RemoveLayerCommand::onExecute(Context* context)
|
||||
@ -65,17 +71,32 @@ void RemoveLayerCommand::onExecute(Context* context)
|
||||
{
|
||||
UndoTransaction undoTransaction(writer.context(), "Remove Layer");
|
||||
|
||||
layer_name = layer->getName();
|
||||
// TODO the range of selected layer should be in the DocumentLocation.
|
||||
Timeline::Range range = App::instance()->getMainWindow()->getTimeline()->range();
|
||||
if (range.enabled()) {
|
||||
Sprite* sprite = writer.sprite();
|
||||
|
||||
// TODO indexes in timeline are inverted!! fix that for a future release
|
||||
for (LayerIndex layer = sprite->countLayers() - LayerIndex(range.layerBegin()+1),
|
||||
end = sprite->countLayers() - LayerIndex(range.layerEnd()+2);
|
||||
layer != end; --layer) {
|
||||
document->getApi().removeLayer(sprite->indexToLayer(layer));
|
||||
}
|
||||
}
|
||||
else {
|
||||
layer_name = layer->getName();
|
||||
document->getApi().removeLayer(layer);
|
||||
}
|
||||
|
||||
document->getApi().removeLayer(layer);
|
||||
undoTransaction.commit();
|
||||
}
|
||||
update_screen_for_document(document);
|
||||
|
||||
StatusBar::instance()->invalidate();
|
||||
StatusBar::instance()
|
||||
->showTip(1000, "Layer `%s' removed",
|
||||
layer_name.c_str());
|
||||
if (!layer_name.empty())
|
||||
StatusBar::instance()->showTip(1000, "Layer `%s' removed", layer_name.c_str());
|
||||
else
|
||||
StatusBar::instance()->showTip(1000, "Layers removed");
|
||||
}
|
||||
|
||||
Command* CommandFactory::createRemoveLayerCommand()
|
||||
|
@ -253,11 +253,13 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
if (m_space_pressed) m_space_pressed = false;
|
||||
break;
|
||||
|
||||
case kMouseDownMessage:
|
||||
case kMouseDownMessage: {
|
||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
|
||||
if (!m_document)
|
||||
break;
|
||||
|
||||
if (static_cast<MouseMessage*>(msg)->middle() || m_space_pressed) {
|
||||
if (mouseMsg->middle() || m_space_pressed) {
|
||||
captureMouse();
|
||||
m_state = STATE_SCROLLING;
|
||||
return true;
|
||||
@ -268,12 +270,13 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
m_clk_layer = m_hot_layer;
|
||||
m_clk_frame = m_hot_frame;
|
||||
|
||||
captureMouse();
|
||||
|
||||
switch (m_hot_part) {
|
||||
case A_PART_NOTHING:
|
||||
// Do nothing.
|
||||
break;
|
||||
case A_PART_SEPARATOR:
|
||||
captureMouse();
|
||||
m_state = STATE_MOVING_SEPARATOR;
|
||||
break;
|
||||
case A_PART_HEADER_GEAR:
|
||||
@ -282,46 +285,52 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
case A_PART_HEADER_LAYER:
|
||||
// Do nothing.
|
||||
break;
|
||||
case A_PART_HEADER_FRAME:
|
||||
setFrame(m_clk_frame);
|
||||
captureMouse();
|
||||
if (msg->ctrlPressed())
|
||||
m_state = STATE_MOVING_FRAME;
|
||||
else {
|
||||
m_state = STATE_SELECTING_FRAMES;
|
||||
startRange(getLayerIndex(m_layer), m_clk_frame);
|
||||
case A_PART_HEADER_FRAME: {
|
||||
bool selectFrame = (mouseMsg->left() || !isFrameActive(m_clk_frame));
|
||||
|
||||
if (selectFrame) {
|
||||
setFrame(m_clk_frame);
|
||||
if (msg->ctrlPressed())
|
||||
m_state = STATE_MOVING_FRAME;
|
||||
else {
|
||||
m_state = STATE_SELECTING_FRAMES;
|
||||
m_range.startRange(getLayerIndex(m_layer), m_clk_frame);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case A_PART_LAYER_TEXT: {
|
||||
const DocumentReader document(const_cast<Document*>(m_document));
|
||||
const Sprite* sprite = m_sprite;
|
||||
int old_layer = getLayerIndex(m_layer);
|
||||
bool selectLayer = (mouseMsg->left() || !isLayerActive(m_layers[m_clk_layer]));
|
||||
FrameNumber frame = m_frame;
|
||||
|
||||
// Did the user select another layer?
|
||||
if (old_layer != m_clk_layer) {
|
||||
setLayer(m_layers[m_clk_layer]);
|
||||
invalidate();
|
||||
if (selectLayer) {
|
||||
// Did the user select another layer?
|
||||
if (old_layer != m_clk_layer) {
|
||||
setLayer(m_layers[m_clk_layer]);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// Change the scroll to show the new selected layer/cel.
|
||||
showCel(m_clk_layer, m_frame);
|
||||
|
||||
if (msg->ctrlPressed()) {
|
||||
m_state = STATE_MOVING_LAYER;
|
||||
if (selectLayer) {
|
||||
if (msg->ctrlPressed()) {
|
||||
m_state = STATE_MOVING_LAYER;
|
||||
}
|
||||
else {
|
||||
m_state = STATE_SELECTING_LAYERS;
|
||||
m_range.startRange(m_clk_layer, m_frame);
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_state = STATE_SELECTING_LAYERS;
|
||||
startRange(m_clk_layer, m_frame);
|
||||
}
|
||||
captureMouse();
|
||||
break;
|
||||
}
|
||||
case A_PART_LAYER_EYE_ICON:
|
||||
captureMouse();
|
||||
break;
|
||||
case A_PART_LAYER_PADLOCK_ICON:
|
||||
captureMouse();
|
||||
break;
|
||||
case A_PART_CEL: {
|
||||
const DocumentReader document(const_cast<Document*>(m_document));
|
||||
@ -331,7 +340,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
|
||||
// Select the new clicked-part.
|
||||
if (old_layer != m_clk_layer ||
|
||||
old_frame != m_clk_frame) {
|
||||
old_frame != m_clk_frame) {
|
||||
setLayer(m_layers[m_clk_layer]);
|
||||
setFrame(m_clk_frame);
|
||||
invalidate();
|
||||
@ -340,14 +349,11 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
// Change the scroll to show the new selected cel.
|
||||
showCel(m_clk_layer, m_frame);
|
||||
|
||||
// Capture the mouse (to move the cel).
|
||||
captureMouse();
|
||||
|
||||
if (msg->ctrlPressed())
|
||||
m_state = STATE_MOVING_CEL;
|
||||
else {
|
||||
m_state = STATE_SELECTING_CELS;
|
||||
startRange(m_clk_layer, m_clk_frame);
|
||||
m_range.startRange(m_clk_layer, m_clk_frame);
|
||||
invalidate();
|
||||
}
|
||||
break;
|
||||
@ -357,6 +363,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
// Redraw the new clicked part (header, layer or cel).
|
||||
invalidatePart(m_clk_part, m_clk_layer, m_clk_frame);
|
||||
break;
|
||||
}
|
||||
|
||||
case kMouseMoveMessage: {
|
||||
if (!m_document)
|
||||
@ -451,14 +458,14 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
switch (m_state) {
|
||||
case STATE_SELECTING_LAYERS: {
|
||||
if (m_layer != m_layers[hot_layer]) {
|
||||
updateRange(hot_layer, m_frame);
|
||||
m_range.endRange(hot_layer, m_frame);
|
||||
setLayer(m_layers[m_clk_layer = hot_layer]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case STATE_SELECTING_FRAMES: {
|
||||
updateRange(getLayerIndex(m_layer), hot_frame);
|
||||
m_range.endRange(getLayerIndex(m_layer), hot_frame);
|
||||
setFrame(m_clk_frame = hot_frame);
|
||||
break;
|
||||
}
|
||||
@ -466,7 +473,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
case STATE_SELECTING_CELS:
|
||||
if ((m_layer != m_layers[hot_layer])
|
||||
|| (m_frame != hot_frame)) {
|
||||
updateRange(hot_layer, hot_frame);
|
||||
m_range.endRange(hot_layer, hot_frame);
|
||||
setLayer(m_layers[m_clk_layer = hot_layer]);
|
||||
setFrame(m_clk_frame = hot_frame);
|
||||
}
|
||||
@ -881,7 +888,7 @@ void Timeline::onFrameChanged(Editor* editor)
|
||||
setFrame(editor->getFrame());
|
||||
|
||||
if (!hasCapture())
|
||||
disableRange();
|
||||
m_range.disableRange();
|
||||
|
||||
showCurrentCel();
|
||||
}
|
||||
@ -891,7 +898,7 @@ void Timeline::onLayerChanged(Editor* editor)
|
||||
setLayer(editor->getLayer());
|
||||
|
||||
if (!hasCapture())
|
||||
disableRange();
|
||||
m_range.disableRange();
|
||||
|
||||
showCurrentCel();
|
||||
}
|
||||
@ -1258,25 +1265,6 @@ void Timeline::regenerateLayers()
|
||||
m_layers[c] = m_sprite->indexToLayer(LayerIndex(nlayers-c-1));
|
||||
}
|
||||
|
||||
void Timeline::startRange(int layer, FrameNumber frame)
|
||||
{
|
||||
m_range.enabled = true;
|
||||
m_range.layerBegin = m_range.layerEnd = layer;
|
||||
m_range.frameBegin = m_range.frameEnd = frame;
|
||||
}
|
||||
|
||||
void Timeline::updateRange(int layer, FrameNumber frame)
|
||||
{
|
||||
ASSERT(m_range.enabled);
|
||||
m_range.layerEnd = layer;
|
||||
m_range.frameEnd = frame;
|
||||
}
|
||||
|
||||
void Timeline::disableRange()
|
||||
{
|
||||
m_range.enabled = false;
|
||||
}
|
||||
|
||||
void Timeline::hotThis(int hot_part, int hot_layer, FrameNumber hot_frame)
|
||||
{
|
||||
// If the part, layer or frame change.
|
||||
@ -1403,20 +1391,37 @@ bool Timeline::isFrameActive(FrameNumber frame) const
|
||||
return m_range.inRange(frame);
|
||||
}
|
||||
|
||||
void Timeline::Range::startRange(int layer, FrameNumber frame)
|
||||
{
|
||||
m_enabled = true;
|
||||
m_layerBegin = m_layerEnd = layer;
|
||||
m_frameBegin = m_frameEnd = frame;
|
||||
}
|
||||
|
||||
void Timeline::Range::endRange(int layer, FrameNumber frame)
|
||||
{
|
||||
ASSERT(m_enabled);
|
||||
m_layerEnd = layer;
|
||||
m_frameEnd = frame;
|
||||
}
|
||||
|
||||
void Timeline::Range::disableRange()
|
||||
{
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
bool Timeline::Range::inRange(int layer) const
|
||||
{
|
||||
if (enabled)
|
||||
return ((layer >= layerBegin && layer <= layerEnd)
|
||||
|| (layer >= layerEnd && layer <= layerBegin));
|
||||
if (m_enabled)
|
||||
return (layer >= layerBegin() && layer <= layerEnd());
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Timeline::Range::inRange(FrameNumber frame) const
|
||||
{
|
||||
if (enabled)
|
||||
return ((frame >= frameBegin && frame <= frameEnd)
|
||||
|| (frame >= frameEnd && frame <= frameBegin));
|
||||
if (m_enabled)
|
||||
return (frame >= frameBegin() && frame <= frameEnd());
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -63,6 +63,31 @@ namespace app {
|
||||
STATE_MOVING_FRAME,
|
||||
};
|
||||
|
||||
struct Range {
|
||||
Range() : m_enabled(false) { }
|
||||
|
||||
bool enabled() const { return m_enabled; }
|
||||
int layerBegin() const { return MIN(m_layerBegin, m_layerEnd); }
|
||||
int layerEnd() const { return MAX(m_layerBegin, m_layerEnd); }
|
||||
FrameNumber frameBegin() const { return MIN(m_frameBegin, m_frameEnd); }
|
||||
FrameNumber frameEnd() const { return MAX(m_frameBegin, m_frameEnd); }
|
||||
|
||||
bool inRange(int layer) const;
|
||||
bool inRange(FrameNumber frame) const;
|
||||
bool inRange(int layer, FrameNumber frame) const;
|
||||
|
||||
void startRange(int layer, FrameNumber frame);
|
||||
void endRange(int layer, FrameNumber frame);
|
||||
void disableRange();
|
||||
|
||||
private:
|
||||
bool m_enabled;
|
||||
int m_layerBegin;
|
||||
int m_layerEnd;
|
||||
FrameNumber m_frameBegin;
|
||||
FrameNumber m_frameEnd;
|
||||
};
|
||||
|
||||
Timeline();
|
||||
~Timeline();
|
||||
|
||||
@ -79,6 +104,8 @@ namespace app {
|
||||
State getState() const { return m_state; }
|
||||
bool isMovingCel() const;
|
||||
|
||||
Range range() const { return m_range; }
|
||||
|
||||
protected:
|
||||
bool onProcessMessage(ui::Message* msg) OVERRIDE;
|
||||
void onPreferredSize(ui::PreferredSizeEvent& ev) OVERRIDE;
|
||||
@ -121,9 +148,6 @@ namespace app {
|
||||
gfx::Rect getPartBounds(int part, int layer = 0, FrameNumber frame = FrameNumber(0)) const;
|
||||
void invalidatePart(int part, int layer, FrameNumber frame);
|
||||
void regenerateLayers();
|
||||
void startRange(int layer, FrameNumber frame);
|
||||
void updateRange(int layer, FrameNumber frame);
|
||||
void disableRange();
|
||||
void hotThis(int hot_part, int hot_layer, FrameNumber hotFrame);
|
||||
void centerCel(int layer, FrameNumber frame);
|
||||
void showCel(int layer, FrameNumber frame);
|
||||
@ -134,20 +158,6 @@ namespace app {
|
||||
bool isLayerActive(const Layer* layer) const;
|
||||
bool isFrameActive(FrameNumber frame) const;
|
||||
|
||||
struct Range {
|
||||
bool enabled;
|
||||
int layerBegin;
|
||||
int layerEnd;
|
||||
FrameNumber frameBegin;
|
||||
FrameNumber frameEnd;
|
||||
|
||||
Range() : enabled(false) { }
|
||||
|
||||
bool inRange(int layer) const;
|
||||
bool inRange(FrameNumber frame) const;
|
||||
bool inRange(int layer, FrameNumber frame) const;
|
||||
};
|
||||
|
||||
skin::Style* m_timelineStyle;
|
||||
skin::Style* m_timelineBoxStyle;
|
||||
skin::Style* m_timelineOpenEyeStyle;
|
||||
|
Loading…
x
Reference in New Issue
Block a user