1// Aseprite
2// Copyright (C) 2019 Igara Studio S.A.
3// Copyright (C) 2001-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/commands/commands.h"
15#include "app/context_access.h"
16#include "app/modules/gui.h"
17#include "app/tx.h"
18#include "doc/image.h"
19#include "doc/mask.h"
20#include "doc/primitives.h"
21#include "doc/sprite.h"
22
23namespace app {
24
25class InvertMaskCommand : public Command {
26public:
27 InvertMaskCommand();
28
29protected:
30 bool onEnabled(Context* context) override;
31 void onExecute(Context* context) override;
32};
33
34InvertMaskCommand::InvertMaskCommand()
35 : Command(CommandId::InvertMask(), CmdRecordableFlag)
36{
37}
38
39bool InvertMaskCommand::onEnabled(Context* context)
40{
41 return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
42 ContextFlags::HasActiveSprite);
43}
44
45void InvertMaskCommand::onExecute(Context* context)
46{
47 bool hasMask = false;
48 {
49 const ContextReader reader(context);
50 if (reader.document()->isMaskVisible())
51 hasMask = true;
52 }
53
54 // without mask?...
55 if (!hasMask) {
56 // so we select all
57 Command* mask_all_cmd =
58 Commands::instance()->byId(CommandId::MaskAll());
59 context->executeCommand(mask_all_cmd);
60 }
61 // invert the current mask
62 else {
63 ContextWriter writer(context);
64 Doc* document(writer.document());
65 Sprite* sprite(writer.sprite());
66
67 // Select all the sprite area
68 std::unique_ptr<Mask> mask(new Mask());
69 mask->replace(sprite->bounds());
70
71 // Remove in the new mask the current sprite marked region
72 const gfx::Rect& maskBounds = document->mask()->bounds();
73 doc::fill_rect(mask->bitmap(),
74 maskBounds.x, maskBounds.y,
75 maskBounds.x + maskBounds.w-1,
76 maskBounds.y + maskBounds.h-1, 0);
77
78 Mask* curMask = document->mask();
79 if (curMask->bitmap()) {
80 // Copy the inverted region in the new mask (we just modify the
81 // document's mask temporaly here)
82 curMask->freeze();
83 curMask->invert();
84 doc::copy_image(mask->bitmap(),
85 curMask->bitmap(),
86 curMask->bounds().x,
87 curMask->bounds().y);
88 curMask->invert();
89 curMask->unfreeze();
90 }
91
92 // We need only need the area inside the sprite
93 mask->intersect(sprite->bounds());
94
95 // Set the new mask
96 Tx tx(writer.context(), "Mask Invert", DoesntModifyDocument);
97 tx(new cmd::SetMask(document, mask.get()));
98 tx.commit();
99
100 update_screen_for_document(document);
101 }
102}
103
104Command* CommandFactory::createInvertMaskCommand()
105{
106 return new InvertMaskCommand;
107}
108
109} // namespace app
110