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/cmd_transaction.h"
12 
13 #include "app/context.h"
14 #include "app/site.h"
15 
16 #ifdef ENABLE_UI
17 #include "app/app.h"
18 #include "app/ui/timeline/timeline.h"
19 #endif
20 
21 namespace app {
22 
CmdTransaction(const std::string & label,bool changeSavedState,int * savedCounter)23 CmdTransaction::CmdTransaction(const std::string& label,
24                                bool changeSavedState,
25                                int* savedCounter)
26   : m_ranges(nullptr)
27   , m_label(label)
28   , m_changeSavedState(changeSavedState)
29   , m_savedCounter(savedCounter)
30 {
31 }
32 
setNewDocRange(const DocRange & range)33 void CmdTransaction::setNewDocRange(const DocRange& range)
34 {
35 #ifdef ENABLE_UI
36   if (m_ranges)
37     range.write(m_ranges->m_after);
38 #endif
39 }
40 
commit()41 void CmdTransaction::commit()
42 {
43   m_spritePositionAfter = calcSpritePosition();
44 
45   // We cannot capture m_ranges->m_after from the Timeline here
46   // because the document range in the Timeline is updated after the
47   // commit/command (on Timeline::onAfterCommandExecution).
48   //
49   // So m_ranges->m_after is captured explicitly in
50   // setNewDocRange().
51 }
52 
documentRangeBeforeExecute() const53 std::istream* CmdTransaction::documentRangeBeforeExecute() const
54 {
55   if (m_ranges && m_ranges->m_before.tellp() > 0) {
56     m_ranges->m_before.seekg(0);
57     return &m_ranges->m_before;
58   }
59   else
60     return nullptr;
61 }
62 
documentRangeAfterExecute() const63 std::istream* CmdTransaction::documentRangeAfterExecute() const
64 {
65   if (m_ranges && m_ranges->m_after.tellp() > 0) {
66     m_ranges->m_after.seekg(0);
67     return &m_ranges->m_after;
68   }
69   else
70     return nullptr;
71 }
72 
onExecute()73 void CmdTransaction::onExecute()
74 {
75   CmdSequence::onExecute();
76 
77   // The execution of CmdTransaction is called by Transaction at the
78   // very beginning, just to save the current sprite position.
79   m_spritePositionBefore = calcSpritePosition();
80 #ifdef ENABLE_UI
81   if (isDocRangeEnabled()) {
82     m_ranges.reset(new Ranges);
83     calcDocRange().write(m_ranges->m_before);
84   }
85 #endif
86 
87   if (m_changeSavedState)
88     ++(*m_savedCounter);
89 }
90 
onUndo()91 void CmdTransaction::onUndo()
92 {
93   CmdSequence::onUndo();
94 
95   if (m_changeSavedState)
96     --(*m_savedCounter);
97 }
98 
onRedo()99 void CmdTransaction::onRedo()
100 {
101   CmdSequence::onRedo();
102 
103   if (m_changeSavedState)
104     ++(*m_savedCounter);
105 }
106 
onLabel() const107 std::string CmdTransaction::onLabel() const
108 {
109   return m_label;
110 }
111 
onMemSize() const112 size_t CmdTransaction::onMemSize() const
113 {
114   size_t size = CmdSequence::onMemSize();
115   if (m_ranges) {
116     size += (m_ranges->m_before.tellp() +
117              m_ranges->m_after.tellp());
118   }
119   return size;
120 }
121 
calcSpritePosition() const122 SpritePosition CmdTransaction::calcSpritePosition() const
123 {
124   Site site = context()->activeSite();
125   return SpritePosition(site.layer(), site.frame());
126 }
127 
isDocRangeEnabled() const128 bool CmdTransaction::isDocRangeEnabled() const
129 {
130 #ifdef ENABLE_UI
131   if (App::instance()) {
132     Timeline* timeline = App::instance()->timeline();
133     if (timeline && timeline->range().enabled())
134       return true;
135   }
136 #endif
137   return false;
138 }
139 
calcDocRange() const140 DocRange CmdTransaction::calcDocRange() const
141 {
142 #ifdef ENABLE_UI
143   // TODO We cannot use Context::activeSite() because it losts
144   //      important information about the DocRange() (type and
145   //      flags).
146   if (App::instance()) {
147     Timeline* timeline = App::instance()->timeline();
148     if (timeline)
149       return timeline->range();
150   }
151 #endif
152   return DocRange();
153 }
154 
155 } // namespace app
156