Skip to content

Commit

Permalink
Add ability to edit multiple slices
Browse files Browse the repository at this point in the history
Related to aseprite#721 and aseprite#1651, still need more work to give a better UX to
edit static and animated slices.
  • Loading branch information
dacap committed May 2, 2019
1 parent 40957c1 commit 73de6c8
Show file tree
Hide file tree
Showing 19 changed files with 612 additions and 167 deletions.
15 changes: 8 additions & 7 deletions data/widgets/slice_properties.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Aseprite -->
<!-- Copyright (C) 2017-2018 by David Capello -->
<!-- Copyright (C) 2019 Igara Studio S.A. -->
<!-- Copyright (C) 2017-2018 David Capello -->
<gui>
<window id="slice_properties" text="@.title">
<grid columns="2">
Expand Down Expand Up @@ -30,16 +31,16 @@

<check text="@.center" id="center" />
<hbox homogeneous="true">
<expr id="center_x" text="0" />
<expr id="center_y" text="0" />
<expr id="center_w" text="0" />
<expr id="center_h" text="0" />
<expr id="center_x" />
<expr id="center_y" />
<expr id="center_w" />
<expr id="center_h" />
</hbox>

<check text="@.pivot" id="pivot" />
<hbox>
<expr id="pivot_x" text="0" />
<expr id="pivot_y" text="0" />
<expr id="pivot_x" />
<expr id="pivot_y" />
</hbox>

<separator horizontal="true" cell_hspan="2" />
Expand Down
35 changes: 30 additions & 5 deletions src/app/cmd/add_slice.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2017 David Capello
//
// This program is distributed under the terms of
Expand All @@ -10,6 +11,8 @@

#include "app/cmd/add_slice.h"

#include "app/doc.h"
#include "app/doc_event.h"
#include "doc/slice.h"
#include "doc/slice_io.h"
#include "doc/sprite.h"
Expand Down Expand Up @@ -42,23 +45,45 @@ void AddSlice::onUndo()
write_slice(m_stream, slice);
m_size = size_t(m_stream.tellp());

sprite->slices().remove(slice);
sprite->incrementVersion();
delete slice;
removeSlice(sprite, slice);
}

void AddSlice::onRedo()
{
Sprite* sprite = this->sprite();
Slice* slice = read_slice(m_stream);

sprite->slices().add(slice);
sprite->incrementVersion();
addSlice(sprite, slice);

m_stream.str(std::string());
m_stream.clear();
m_size = 0;
}

void AddSlice::addSlice(Sprite* sprite, Slice* slice)
{
sprite->slices().add(slice);
sprite->incrementVersion();

Doc* doc = static_cast<Doc*>(sprite->document());
DocEvent ev(doc);
ev.sprite(sprite);
ev.slice(slice);
doc->notify_observers<DocEvent&>(&DocObserver::onAddSlice, ev);
}

void AddSlice::removeSlice(Sprite* sprite, Slice* slice)
{
Doc* doc = static_cast<Doc*>(sprite->document());
DocEvent ev(doc);
ev.sprite(sprite);
ev.slice(slice);
doc->notify_observers<DocEvent&>(&DocObserver::onRemoveSlice, ev);

sprite->slices().remove(slice);
sprite->incrementVersion();
delete slice;
}

} // namespace cmd
} // namespace app
4 changes: 4 additions & 0 deletions src/app/cmd/add_slice.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2017 David Capello
//
// This program is distributed under the terms of
Expand Down Expand Up @@ -33,6 +34,9 @@ namespace cmd {
}

private:
void addSlice(Sprite* sprite, Slice* slice);
void removeSlice(Sprite* sprite, Slice* slice);

size_t m_size;
std::stringstream m_stream;
};
Expand Down
57 changes: 41 additions & 16 deletions src/app/commands/cmd_remove_slice.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2017-2018 David Capello
//
// This program is distributed under the terms of
Expand All @@ -14,9 +15,10 @@
#include "app/commands/command.h"
#include "app/context_access.h"
#include "app/modules/gui.h"
#include "app/ui/status_bar.h"
#include "app/tx.h"
#include "app/ui/status_bar.h"
#include "base/convert_to.h"
#include "doc/selected_objects.h"
#include "doc/slice.h"
#include "doc/sprite.h"
#include "ui/alert.h"
Expand Down Expand Up @@ -66,40 +68,63 @@ void RemoveSliceCommand::onExecute(Context* context)
const ContextReader reader(context);
const Sprite* sprite = reader.sprite();
frame_t frame = reader.frame();
const Slice* foundSlice = nullptr;
SelectedObjects slicesToDelete;

if (!m_sliceName.empty())
foundSlice = sprite->slices().getByName(m_sliceName);
else if (m_sliceId != NullId)
foundSlice = sprite->slices().getById(m_sliceId);
std::string sliceName;
{
Slice* slice = nullptr;
if (!m_sliceName.empty())
slice = sprite->slices().getByName(m_sliceName);
else if (m_sliceId != NullId)
slice = sprite->slices().getById(m_sliceId);

if (slice)
slicesToDelete.insert(slice->id());
else
slicesToDelete = reader.site()->selectedSlices();
}

if (!foundSlice)
// Nothing to delete
if (slicesToDelete.empty())
return;

std::string sliceName = foundSlice->name();
if (slicesToDelete.size() == 1) {
Slice* slice = slicesToDelete.frontAs<Slice>();
ASSERT(slice);
if (slice)
sliceName = slice->name();
}

{
ContextWriter writer(reader, 500);
Doc* document(writer.document());
Sprite* sprite(writer.sprite());
Tx tx(writer.context(), "Remove Slice");
Slice* slice = const_cast<Slice*>(foundSlice);

if (slice->size() > 1) {
tx(new cmd::SetSliceKey(slice, frame, SliceKey()));
}
else {
tx(new cmd::RemoveSlice(sprite, slice));
for (auto slice : slicesToDelete.iterateAs<Slice>()) {
ASSERT(slice);
if (!slice)
continue;

if (slice->size() > 1) {
tx(new cmd::SetSliceKey(slice, frame, SliceKey()));
}
else {
tx(new cmd::RemoveSlice(sprite, slice));
}
}

tx.commit();
document->notifyGeneralUpdate();
}

StatusBar::instance()->invalidate();
if (!sliceName.empty())
StatusBar::instance()->showTip(1000, "Slice '%s' removed", sliceName.c_str());
StatusBar::instance()->showTip(
1000, "Slice '%s' removed", sliceName.c_str());
else
StatusBar::instance()->showTip(1000, "Slice removed");
StatusBar::instance()->showTip(
1000, "%d slice(s) removed", slicesToDelete.size());
}

Command* CommandFactory::createRemoveSliceCommand()
Expand Down
84 changes: 58 additions & 26 deletions src/app/commands/cmd_slice_properties.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2017-2018 David Capello
//
// This program is distributed under the terms of
Expand Down Expand Up @@ -64,45 +65,76 @@ void SlicePropertiesCommand::onExecute(Context* context)
const ContextReader reader(context);
const Sprite* sprite = reader.sprite();
frame_t frame = reader.frame();
const Slice* foundSlice = nullptr;
SelectedObjects slices;

if (!m_sliceName.empty())
foundSlice = sprite->slices().getByName(m_sliceName);
else if (m_sliceId != NullId)
foundSlice = sprite->slices().getById(m_sliceId);

if (!foundSlice)
return;
{
Slice* slice = nullptr;
if (!m_sliceName.empty())
slice = sprite->slices().getByName(m_sliceName);
else if (m_sliceId != NullId)
slice = sprite->slices().getById(m_sliceId);

if (slice)
slices.insert(slice->id());
else
slices = reader.site()->selectedSlices();
}

const doc::SliceKey* key = foundSlice->getByFrame(frame);
if (!key)
// Nothing to delete
if (slices.empty())
return;

SliceWindow window(sprite, foundSlice, frame);
SliceWindow window(sprite, slices, frame);
if (!window.show())
return;

{
const SliceWindow::Mods mods = window.modifiedFields();
ContextWriter writer(reader, 500);
Tx tx(writer.context(), "Slice Properties");
Slice* slice = const_cast<Slice*>(foundSlice);

std::string name = window.nameValue();

if (slice->name() != name)
tx(new cmd::SetSliceName(slice, name));

if (slice->userData() != window.userDataValue())
tx(new cmd::SetUserData(slice, window.userDataValue()));
for (Slice* slice : slices.iterateAs<Slice>()) {
// Change name
if (mods & SliceWindow::kName) {
std::string name = window.nameValue();
if (slice->name() != name)
tx(new cmd::SetSliceName(slice, name));
}

// Change user data
if ((mods & SliceWindow::kUserData) &&
slice->userData() != window.userDataValue()) {
tx(new cmd::SetUserData(slice, window.userDataValue()));
}

// Change slice properties
const doc::SliceKey* key = slice->getByFrame(frame);
if (!key)
continue;

if (key->bounds() != window.boundsValue() ||
key->center() != window.centerValue() ||
key->pivot() != window.pivotValue()) {
SliceKey newKey = *key;
newKey.setBounds(window.boundsValue());
newKey.setCenter(window.centerValue());
newKey.setPivot(window.pivotValue());
tx(new cmd::SetSliceKey(slice, frame, newKey));
gfx::Rect newBounds = newKey.bounds();
gfx::Rect newCenter = newKey.center();
gfx::Point newPivot = newKey.pivot();
if (mods & SliceWindow::kBoundsX) newBounds.x = window.boundsValue().x;
if (mods & SliceWindow::kBoundsY) newBounds.y = window.boundsValue().y;
if (mods & SliceWindow::kBoundsW) newBounds.w = window.boundsValue().w;
if (mods & SliceWindow::kBoundsH) newBounds.h = window.boundsValue().h;
if (mods & SliceWindow::kCenterX) newCenter.x = window.centerValue().x;
if (mods & SliceWindow::kCenterY) newCenter.y = window.centerValue().y;
if (mods & SliceWindow::kCenterW) newCenter.w = window.centerValue().w;
if (mods & SliceWindow::kCenterH) newCenter.h = window.centerValue().h;
if (mods & SliceWindow::kPivotX) newPivot.x = window.pivotValue().x;
if (mods & SliceWindow::kPivotY) newPivot.y = window.pivotValue().y;
newKey.setBounds(newBounds);
newKey.setCenter(newCenter);
newKey.setPivot(newPivot);

if (key->bounds() != newKey.bounds() ||
key->center() != newKey.center() ||
key->pivot() != newKey.pivot()) {
tx(new cmd::SetSliceKey(slice, frame, newKey));
}
}

tx.commit();
Expand Down
9 changes: 8 additions & 1 deletion src/app/doc_event.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Aseprite
// Copyright (c) 2001-2018 David Capello
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
Expand All @@ -17,6 +18,7 @@ namespace doc {
class Image;
class Layer;
class LayerImage;
class Slice;
class Sprite;
}

Expand All @@ -35,6 +37,8 @@ namespace app {
, m_image(NULL)
, m_imageIndex(-1)
, m_frame(0)
, m_frameTag(nullptr)
, m_slice(nullptr)
, m_targetLayer(NULL)
, m_targetFrame(0) {
}
Expand All @@ -48,6 +52,7 @@ namespace app {
int imageIndex() const { return m_imageIndex; }
frame_t frame() const { return m_frame; }
FrameTag* frameTag() const { return m_frameTag; }
Slice* slice() const { return m_slice; }
const gfx::Region& region() const { return m_region; }

void sprite(Sprite* sprite) { m_sprite = sprite; }
Expand All @@ -57,6 +62,7 @@ namespace app {
void imageIndex(int imageIndex) { m_imageIndex = imageIndex; }
void frame(frame_t frame) { m_frame = frame; }
void frameTag(FrameTag* frameTag) { m_frameTag = frameTag; }
void slice(Slice* slice) { m_slice = slice; }
void region(const gfx::Region& rgn) { m_region = rgn; }

// Destination of the operation.
Expand All @@ -75,6 +81,7 @@ namespace app {
int m_imageIndex;
frame_t m_frame;
FrameTag* m_frameTag;
Slice* m_slice;
gfx::Region m_region;

// For copy/move commands, the m_layer/m_frame are source of the
Expand Down
6 changes: 4 additions & 2 deletions src/app/doc_observer.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Aseprite
// Copyright (C) 2018 Igara Studio S.A.
// Copyright (c) 2001-2018 David Capello
// Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
Expand Down Expand Up @@ -30,6 +30,7 @@ namespace app {
virtual void onAddLayer(DocEvent& ev) { }
virtual void onAddFrame(DocEvent& ev) { }
virtual void onAddCel(DocEvent& ev) { }
virtual void onAddSlice(DocEvent& ev) { }
virtual void onAddFrameTag(DocEvent& ev) { }

virtual void onBeforeRemoveLayer(DocEvent& ev) { }
Expand All @@ -40,6 +41,7 @@ namespace app {
virtual void onRemoveFrame(DocEvent& ev) { }
virtual void onRemoveFrameTag(DocEvent& ev) { }
virtual void onRemoveCel(DocEvent& ev) { }
virtual void onRemoveSlice(DocEvent& ev) { }

virtual void onSpriteSizeChanged(DocEvent& ev) { }
virtual void onSpriteTransparentColorChanged(DocEvent& ev) { }
Expand Down
Loading

0 comments on commit 73de6c8

Please sign in to comment.