1// Aseprite
2// Copyright (C) 2018 Igara Studio S.A.
3// Copyright (C) 2001-2017 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/commands/command.h"
14#include "app/commands/params.h"
15#include "app/context.h"
16#include "app/doc.h"
17#include "app/i18n/strings.h"
18#include "app/pref/preferences.h"
19#include "app/ui_context.h"
20#include "app/ui/context_bar.h"
21#include "app/modules/gui.h"
22
23namespace app {
24
25class SymmetryModeCommand : public Command {
26public:
27 SymmetryModeCommand();
28
29protected:
30 void onLoadParams(const Params& params) override;
31 bool onEnabled(Context* context) override;
32 bool onChecked(Context* context) override;
33 void onExecute(Context* context) override;
34 std::string onGetFriendlyName() const override;
35
36private:
37 app::gen::SymmetryMode m_mode = app::gen::SymmetryMode::NONE;
38};
39
40SymmetryModeCommand::SymmetryModeCommand()
41 : Command(CommandId::SymmetryMode(), CmdUIOnlyFlag)
42{
43}
44
45std::string SymmetryModeCommand::onGetFriendlyName() const
46{
47 switch (m_mode) {
48 case app::gen::SymmetryMode::HORIZONTAL:
49 return Strings::symmetry_toggle_horizontal();
50 case app::gen::SymmetryMode::VERTICAL:
51 return Strings::symmetry_toggle_vertical();
52 default:
53 return Strings::symmetry_toggle();
54 }
55}
56
57void SymmetryModeCommand::onLoadParams(const Params& params)
58{
59 std::string mode = params.get("orientation");
60 if (mode == "vertical") m_mode = app::gen::SymmetryMode::VERTICAL;
61 else if (mode == "horizontal") m_mode = app::gen::SymmetryMode::HORIZONTAL;
62 else m_mode = app::gen::SymmetryMode::NONE;
63}
64
65bool SymmetryModeCommand::onEnabled(Context* ctx)
66{
67 return ctx->checkFlags(ContextFlags::ActiveDocumentIsWritable |
68 ContextFlags::HasActiveSprite);
69}
70
71bool SymmetryModeCommand::onChecked(Context* ctx)
72{
73 return Preferences::instance().symmetryMode.enabled();
74}
75
76void SymmetryModeCommand::onExecute(Context* ctx)
77{
78 auto& enabled = Preferences::instance().symmetryMode.enabled;
79 // When the m_mode is NONE, it toggles the whole symmetry controls in
80 // the context bar.
81 if (m_mode == app::gen::SymmetryMode::NONE) {
82 enabled(!enabled());
83 }
84 // In other case it toggles the specific document symmetry specified
85 // in m_mode.
86 else {
87 Doc* doc = ctx->activeDocument();
88 DocumentPreferences& docPref = Preferences::instance().document(doc);
89 const app::gen::SymmetryMode actual = docPref.symmetry.mode();
90
91 // If the symmetry options are hidden, we'll always show them and
92 // activate the m_mode symmetry. We cannot just toggle the
93 // symmetry when the options aren't visible in the context bar,
94 // because if m_mode is checked, this would cause to show the
95 // symmetry options in the context bar but with a unchecked m_mode
96 // symmetry.
97 if (!enabled()) {
98 docPref.symmetry.mode(app::gen::SymmetryMode(int(m_mode) | int(actual)));
99 enabled(true);
100 }
101 // If the symmetry options are visible, we just switch the m_mode
102 // symmetry.
103 else {
104 docPref.symmetry.mode(app::gen::SymmetryMode(int(m_mode) ^ int(actual)));
105 }
106
107 // Redraw all editors
108 //
109 // TODO It looks like only the current editor shows the symmetry,
110 // so it's not necessary to invalidate all editors (only the
111 // current one).
112 doc->notifyGeneralUpdate();
113
114 // Redraw the buttons in the context bar.
115 //
116 // TODO Same with context bar, in the future the context bar could
117 // be listening the DocPref changes to be automatically
118 // invalidated (like it already does with symmetryMode.enabled)
119 App::instance()->contextBar()->updateForActiveTool();
120 }
121}
122
123Command* CommandFactory::createSymmetryModeCommand()
124{
125 return new SymmetryModeCommand;
126}
127
128} // namespace app
129