1// Aseprite
2// Copyright (C) 2019-2020 Igara Studio S.A.
3// Copyright (C) 2017-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "app/app.h"
13#include "app/cmd/remove_slice.h"
14#include "app/cmd/set_slice_key.h"
15#include "app/commands/command.h"
16#include "app/context_access.h"
17#include "app/i18n/strings.h"
18#include "app/modules/gui.h"
19#include "app/tx.h"
20#include "app/ui/status_bar.h"
21#include "base/convert_to.h"
22#include "doc/selected_objects.h"
23#include "doc/slice.h"
24#include "doc/sprite.h"
25#include "fmt/format.h"
26#include "ui/alert.h"
27#include "ui/widget.h"
28
29namespace app {
30
31class RemoveSliceCommand : public Command {
32public:
33 RemoveSliceCommand();
34
35protected:
36 void onLoadParams(const Params& params) override;
37 bool onEnabled(Context* context) override;
38 void onExecute(Context* context) override;
39
40private:
41 std::string m_sliceName;
42 ObjectId m_sliceId;
43};
44
45RemoveSliceCommand::RemoveSliceCommand()
46 : Command(CommandId::RemoveSlice(), CmdRecordableFlag)
47{
48}
49
50void RemoveSliceCommand::onLoadParams(const Params& params)
51{
52 m_sliceName = params.get("name");
53
54 std::string id = params.get("id");
55 if (!id.empty())
56 m_sliceId = ObjectId(base::convert_to<doc::ObjectId>(id));
57 else
58 m_sliceId = NullId;
59}
60
61bool RemoveSliceCommand::onEnabled(Context* context)
62{
63 return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
64 ContextFlags::HasActiveSprite |
65 ContextFlags::HasActiveLayer);
66}
67
68void RemoveSliceCommand::onExecute(Context* context)
69{
70 const ContextReader reader(context);
71 const Sprite* sprite = reader.sprite();
72 frame_t frame = reader.frame();
73 SelectedObjects slicesToDelete;
74
75 std::string sliceName;
76 {
77 Slice* slice = nullptr;
78 if (!m_sliceName.empty())
79 slice = sprite->slices().getByName(m_sliceName);
80 else if (m_sliceId != NullId)
81 slice = sprite->slices().getById(m_sliceId);
82
83 if (slice)
84 slicesToDelete.insert(slice->id());
85 else
86 slicesToDelete = reader.site()->selectedSlices();
87 }
88
89 // Nothing to delete
90 if (slicesToDelete.empty())
91 return;
92
93 if (slicesToDelete.size() == 1) {
94 Slice* slice = slicesToDelete.frontAs<Slice>();
95 ASSERT(slice);
96 if (slice)
97 sliceName = slice->name();
98 }
99
100 {
101 ContextWriter writer(reader);
102 Doc* document(writer.document());
103 Sprite* sprite(writer.sprite());
104 Tx tx(writer.context(), "Remove Slice");
105
106 for (auto slice : slicesToDelete.iterateAs<Slice>()) {
107 ASSERT(slice);
108 if (!slice)
109 continue;
110
111 if (slice->size() > 1) {
112 tx(new cmd::SetSliceKey(slice, frame, SliceKey()));
113 }
114 else {
115 tx(new cmd::RemoveSlice(sprite, slice));
116 }
117 }
118
119 tx.commit();
120 document->notifyGeneralUpdate();
121 }
122
123 StatusBar::instance()->invalidate();
124 if (!sliceName.empty())
125 StatusBar::instance()->showTip(
126 1000, fmt::format(Strings::remove_slice_x_removed(), sliceName));
127 else
128 StatusBar::instance()->showTip(
129 1000,
130 fmt::format(Strings::remove_slice_n_slices_removed(),
131 slicesToDelete.size()));
132}
133
134Command* CommandFactory::createRemoveSliceCommand()
135{
136 return new RemoveSliceCommand;
137}
138
139} // namespace app
140