1// Aseprite
2// Copyright (C) 2018-2021 Igara Studio S.A.
3// Copyright (C) 2015-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/cmd/set_mask.h"
13#include "app/commands/command.h"
14#include "app/context_access.h"
15#include "app/doc.h"
16#include "app/i18n/strings.h"
17#include "app/modules/editors.h"
18#include "app/modules/gui.h"
19#include "app/snap_to_grid.h"
20#include "app/tx.h"
21#include "app/ui/editor/editor.h"
22#include "doc/mask.h"
23#include "fmt/format.h"
24#include "ui/system.h"
25
26namespace app {
27
28using namespace doc;
29
30class SelectTileCommand : public Command {
31public:
32 SelectTileCommand();
33
34protected:
35 void onLoadParams(const Params& params) override;
36 bool onEnabled(Context* ctx) override;
37 void onExecute(Context* ctx) override;
38 std::string onGetFriendlyName() const override;
39
40private:
41 gen::SelectionMode m_mode;
42};
43
44SelectTileCommand::SelectTileCommand()
45 : Command(CommandId::SelectTile(), CmdRecordableFlag)
46 , m_mode(gen::SelectionMode::DEFAULT)
47{
48}
49
50void SelectTileCommand::onLoadParams(const Params& params)
51{
52 std::string mode = params.get("mode");
53 if (mode == "add")
54 m_mode = gen::SelectionMode::ADD;
55 else if (mode == "subtract")
56 m_mode = gen::SelectionMode::SUBTRACT;
57 else if (mode == "intersect")
58 m_mode = gen::SelectionMode::INTERSECT;
59 else
60 m_mode = gen::SelectionMode::DEFAULT;
61}
62
63bool SelectTileCommand::onEnabled(Context* ctx)
64{
65 return ctx->checkFlags(ContextFlags::ActiveDocumentIsWritable);
66}
67
68void SelectTileCommand::onExecute(Context* ctx)
69{
70 if (!current_editor ||
71 !current_editor->hasMouse())
72 return;
73
74 // Lock sprite
75 ContextWriter writer(ctx);
76 Doc* doc(writer.document());
77
78 std::unique_ptr<Mask> mask(new Mask());
79
80 if (m_mode != gen::SelectionMode::DEFAULT)
81 mask->copyFrom(doc->mask());
82
83 {
84 gfx::Rect gridBounds = writer.site()->gridBounds();
85 gfx::Point pos = current_editor->screenToEditor(current_editor->mousePosInDisplay());
86 pos = snap_to_grid(gridBounds, pos, PreferSnapTo::BoxOrigin);
87 gridBounds.setOrigin(pos);
88
89 switch (m_mode) {
90 case gen::SelectionMode::DEFAULT:
91 case gen::SelectionMode::ADD:
92 mask->add(gridBounds);
93 break;
94 case gen::SelectionMode::SUBTRACT:
95 mask->subtract(gridBounds);
96 break;
97 case gen::SelectionMode::INTERSECT:
98 mask->intersect(gridBounds);
99 break;
100 }
101 }
102
103 // Set the new mask
104 Tx tx(writer.context(),
105 friendlyName(),
106 DoesntModifyDocument);
107 tx(new cmd::SetMask(doc, mask.get()));
108 tx.commit();
109
110 update_screen_for_document(doc);
111}
112
113std::string SelectTileCommand::onGetFriendlyName() const
114{
115 std::string text;
116 switch (m_mode) {
117 case gen::SelectionMode::ADD:
118 text = Strings::commands_SelectTile_Add();
119 break;
120 case gen::SelectionMode::SUBTRACT:
121 text = Strings::commands_SelectTile_Subtract();
122 break;
123 case gen::SelectionMode::INTERSECT:
124 text = Strings::commands_SelectTile_Intersect();
125 break;
126 default:
127 text = getBaseFriendlyName();
128 break;
129 }
130 return text;
131}
132
133Command* CommandFactory::createSelectTileCommand()
134{
135 return new SelectTileCommand;
136}
137
138} // namespace app
139