1// Aseprite
2// Copyright (C) 2001-2018 David Capello
3//
4// This program is distributed under the terms of
5// the End-User License Agreement for Aseprite.
6
7#ifdef HAVE_CONFIG_H
8#include "config.h"
9#endif
10
11#include "app/app.h"
12#include "app/cmd/add_tag.h"
13#include "app/cmd/remove_tag.h"
14#include "app/cmd/set_tag_range.h"
15#include "app/commands/command.h"
16#include "app/commands/commands.h"
17#include "app/commands/params.h"
18#include "app/context_access.h"
19#include "app/loop_tag.h"
20#include "app/tx.h"
21#include "app/ui/timeline/timeline.h"
22#include "doc/tag.h"
23
24namespace app {
25
26class SetLoopSectionCommand : public Command {
27public:
28 enum class Action { Auto, On, Off };
29
30 SetLoopSectionCommand();
31
32protected:
33 void onLoadParams(const Params& params) override;
34 bool onEnabled(Context* context) override;
35 void onExecute(Context* context) override;
36
37 Action m_action;
38 doc::frame_t m_begin, m_end;
39};
40
41SetLoopSectionCommand::SetLoopSectionCommand()
42 : Command(CommandId::SetLoopSection(), CmdRecordableFlag)
43 , m_action(Action::Auto)
44 , m_begin(0)
45 , m_end(0)
46{
47}
48
49void SetLoopSectionCommand::onLoadParams(const Params& params)
50{
51 std::string action = params.get("action");
52 if (action == "on") m_action = Action::On;
53 else if (action == "off") m_action = Action::Off;
54 else m_action = Action::Auto;
55
56 std::string begin = params.get("begin");
57 std::string end = params.get("end");
58
59 m_begin = frame_t(strtol(begin.c_str(), NULL, 10));
60 m_end = frame_t(strtol(end.c_str(), NULL, 10));
61}
62
63bool SetLoopSectionCommand::onEnabled(Context* ctx)
64{
65 return ctx->checkFlags(ContextFlags::HasActiveDocument);
66}
67
68void SetLoopSectionCommand::onExecute(Context* ctx)
69{
70 Doc* doc = ctx->activeDocument();
71 if (!doc)
72 return;
73
74 doc::Sprite* sprite = doc->sprite();
75 doc::frame_t begin = m_begin;
76 doc::frame_t end = m_end;
77 bool on = false;
78
79 switch (m_action) {
80
81 case Action::Auto: {
82 auto range = App::instance()->timeline()->range();
83 if (range.enabled() && (range.frames() > 1)) {
84 begin = range.selectedFrames().firstFrame();
85 end = range.selectedFrames().lastFrame();
86 on = true;
87 }
88 else {
89 on = false;
90 }
91 break;
92 }
93
94 case Action::On:
95 on = true;
96 break;
97
98 case Action::Off:
99 on = false;
100 break;
101
102 }
103
104 doc::Tag* loopTag = get_loop_tag(sprite);
105 if (on) {
106 if (!loopTag) {
107 loopTag = create_loop_tag(begin, end);
108
109 ContextWriter writer(ctx);
110 Tx tx(writer.context(), "Add Loop");
111 tx(new cmd::AddTag(sprite, loopTag));
112 tx.commit();
113 }
114 else if (loopTag->fromFrame() != begin ||
115 loopTag->toFrame() != end) {
116 ContextWriter writer(ctx);
117 Tx tx(writer.context(), "Set Loop Range");
118 tx(new cmd::SetTagRange(loopTag, begin, end));
119 tx.commit();
120 }
121 else {
122 Command* cmd = Commands::instance()->byId(CommandId::FrameTagProperties());
123 ctx->executeCommand(cmd);
124 }
125 }
126 else {
127 if (loopTag) {
128 ContextWriter writer(ctx);
129 Tx tx(writer.context(), "Remove Loop");
130 tx(new cmd::RemoveTag(sprite, loopTag));
131 tx.commit();
132 }
133 }
134
135 App::instance()->timeline()->invalidate();
136}
137
138Command* CommandFactory::createSetLoopSectionCommand()
139{
140 return new SetLoopSectionCommand;
141}
142
143} // namespace app
144