1 
2 
3 #include "toonz/txshlevelcolumn.h"
4 #include "toonz/txshsimplelevel.h"
5 #include "toonz/txshcell.h"
6 #include "toonz/tcolumnfxset.h"
7 #include "toonz/tcolumnfx.h"
8 #include "toonz/txshleveltypes.h"
9 
10 #include "tstream.h"
11 
12 //-----------------------------------------------------------------------------
13 
14 namespace {
qstringToFrameId(QString str)15 TFrameId qstringToFrameId(QString str) {
16   if (str.isEmpty() || str == "-1")
17     return TFrameId::EMPTY_FRAME;
18   else if (str == "-" || str == "-2")
19     return TFrameId::NO_FRAME;
20   TFrameId fid;
21   int s = 0;
22   QString number;
23   char letter(0);
24   for (s = 0; s < str.size(); s++) {
25     QChar c = str.at(s);
26     if (c.isNumber()) number.append(c);
27 #if QT_VERSION >= 0x050500
28     else
29       letter = c.toLatin1();
30 #else
31     else
32       letter = c.toAscii();
33 #endif
34   }
35   return TFrameId(number.toInt(), letter);
36 }
37 }
38 
39 //-----------------------------------------------------------------------------
40 
41 //=============================================================================
42 // TXshLevelColumn
43 
TXshLevelColumn()44 TXshLevelColumn::TXshLevelColumn()
45     : m_fx(new TLevelColumnFx())
46     //, m_iconId("")
47     , m_iconVisible(false) {
48   // updateIcon();
49   m_fx->addRef();
50   m_fx->setColumn(this);
51 }
52 
53 //-----------------------------------------------------------------------------
54 
~TXshLevelColumn()55 TXshLevelColumn::~TXshLevelColumn() {
56   m_fx->setColumn(0);
57   m_fx->release();
58   m_fx = 0;
59 }
60 
61 //-----------------------------------------------------------------------------
62 
getColumnType() const63 TXshColumn::ColumnType TXshLevelColumn::getColumnType() const {
64   return eLevelType;
65 }
66 
67 //----------------------------------------------------------------------------
68 
canSetCell(const TXshCell & cell) const69 bool TXshLevelColumn::canSetCell(const TXshCell &cell) const {
70   if (cell.isEmpty()) return true;
71 
72   TXshSimpleLevel *sl = cell.getSimpleLevel();
73   if (sl) return (sl->getType() & LEVELCOLUMN_XSHLEVEL);
74 
75   return cell.getChildLevel();
76 }
77 
78 //-----------------------------------------------------------------------------
79 
getLevelColumnFx() const80 TLevelColumnFx *TXshLevelColumn::getLevelColumnFx() const { return m_fx; }
81 
82 //-----------------------------------------------------------------------------
83 
getFx() const84 TFx *TXshLevelColumn::getFx() const { return m_fx; }
85 
86 //-----------------------------------------------------------------------------
87 
clone() const88 TXshColumn *TXshLevelColumn::clone() const {
89   TXshLevelColumn *column = new TXshLevelColumn;
90   column->setStatusWord(getStatusWord());
91   column->setOpacity(getOpacity());
92   column->m_cells = m_cells;
93   column->m_first = m_first;
94   column->setColorTag(getColorTag());
95   column->setFilterColorId(getFilterColorId());
96 
97   // column->updateIcon();
98   return column;
99 }
100 
101 //-----------------------------------------------------------------------------
102 
loadData(TIStream & is)103 void TXshLevelColumn::loadData(TIStream &is) {
104   std::string tagName;
105   while (is.openChild(tagName)) {
106     if (tagName == "status") {
107       int status;
108       is >> status;
109       setStatusWord(status);
110       if (status & eCamstandTransparent43) {
111         setOpacity(128);
112         status = status & ~eCamstandTransparent43;
113       }
114     } else if (tagName == "camerastand_opacity") {
115       int opacity;
116       is >> opacity;
117       setOpacity((UCHAR)opacity);
118     } else if (tagName == "filter_color_id") {
119       int id;
120       is >> id;
121       setFilterColorId((TXshColumn::FilterColor)id);
122     } else if (tagName == "cells") {
123       while (is.openChild(tagName)) {
124         if (tagName == "cell") {
125           TPersist *p = 0;
126           QString str;
127           int row = 1, rowCount = 1, increment = 0;
128           TFilePath path;
129           is >> row >> rowCount >> p >> str >> increment;
130           TFrameId fid = qstringToFrameId(str);
131           assert((fid.getLetter() == 0 && rowCount >= 0) ||
132                  (fid.getLetter() != 0 && rowCount == 1));
133           TXshLevel *xshLevel = dynamic_cast<TXshLevel *>(p);
134           if (xshLevel) {
135             int fidNumber = fid.getNumber();
136             for (int i = 0; i < rowCount; i++) {
137               TXshCell cell(xshLevel, fid);
138               setCell(row++, cell);
139               // rowCount>1 => fid has not letter.
140               fidNumber += increment;
141               fid = TFrameId(fidNumber);
142             }
143           }
144         } else
145           throw TException("TXshLevelColumn, unknown tag(2): " + tagName);
146         is.closeChild();
147       }
148     } else if (tagName == "fx") {
149       TPersist *p = 0;
150       is >> p;
151       if (TLevelColumnFx *lcf = dynamic_cast<TLevelColumnFx *>(p)) {
152         lcf->addRef();
153         if (m_fx) m_fx->release();
154         m_fx = lcf;
155         lcf->setColumn(this);
156       }
157     } else if (tagName == "fxnodes")  // per compatibilita' con 1.x e precedenti
158     {
159       TFxSet fxSet;
160       fxSet.loadData(is);
161     } else {
162       throw TException("TXshLevelColumn, unknown tag: " + tagName);
163     }
164     is.closeChild();
165   }
166 }
167 
168 //-----------------------------------------------------------------------------
169 
saveData(TOStream & os)170 void TXshLevelColumn::saveData(TOStream &os) {
171   os.child("status") << getStatusWord();
172   if (getOpacity() < 255) os.child("camerastand_opacity") << (int)getOpacity();
173   if (getFilterColorId() != 0)
174     os.child("filter_color_id") << (int)getFilterColorId();
175   int r0, r1;
176   if (getRange(r0, r1)) {
177     os.openChild("cells");
178     for (int r = r0; r <= r1; r++) {
179       TXshCell cell = getCell(r);
180       if (cell.isEmpty()) continue;
181       TFrameId fid = cell.m_frameId;
182       int n = 1, inc = 0, dr = fid.getNumber();
183       // If fid has not letter save more than one cell and its incrementation;
184       // otherwise save one cell.
185       if (r < r1 && fid.getLetter() == 0) {
186         TXshCell cell2 = getCell(r + 1);
187         TFrameId fid2  = cell2.m_frameId;
188         if (cell2.m_level.getPointer() == cell.m_level.getPointer() &&
189             fid2.getLetter() == 0) {
190           inc = cell2.m_frameId.getNumber() - dr;
191           n++;
192           for (;;) {
193             if (r + n > r1) break;
194             cell2         = getCell(r + n);
195             TFrameId fid2 = cell2.m_frameId;
196             if (cell2.m_level.getPointer() != cell.m_level.getPointer() ||
197                 fid2.getLetter() != 0)
198               break;
199             if (fid2.getNumber() != dr + n * inc) break;
200             n++;
201           }
202         }
203       }
204       os.child("cell") << r << n << cell.m_level.getPointer() << fid.expand()
205                        << inc;
206       r += n - 1;
207     }
208     os.closeChild();
209   }
210   os.child("fx") << m_fx;
211 }
212 
213 //-----------------------------------------------------------------------------
214 // Used in TCellData::getNumbers
setNumbers(int row,int rowCount,const TXshCell cells[])215 bool TXshLevelColumn::setNumbers(int row, int rowCount,
216                                  const TXshCell cells[]) {
217   if (m_cells.empty()) return false;
218   // Check availability.
219   // - if source cells are all empty, do nothing
220   // - also, if source or target cells contain NO_FRAME, do nothing
221   bool isSrcAllEmpty = true;
222   for (int i = 0; i < rowCount; i++) {
223     // checking target cells
224     int currentTgtIndex = row + i - m_first;
225     if (currentTgtIndex < m_cells.size()) {
226       TXshCell tgtCell = m_cells[currentTgtIndex];
227       if (!tgtCell.isEmpty() && tgtCell.m_frameId == TFrameId::NO_FRAME)
228         return false;
229     }
230     // checking source cells
231     TXshCell srcCell = cells[i];
232     if (!srcCell.isEmpty()) {
233       if (srcCell.m_frameId == TFrameId::NO_FRAME) return false;
234       isSrcAllEmpty = false;
235     }
236   }
237   if (isSrcAllEmpty) return false;
238 
239   // Find a level to input.
240   // If the first target cell is empty, search the upper cells, and lower cells
241   // and use a level of firsty-found occupied neighbor cell.
242   TXshLevelP currentLevel;
243   int tmpIndex = std::min(row - m_first, (int)m_cells.size() - 1);
244   // search upper cells
245   while (tmpIndex >= 0) {
246     TXshCell tmpCell = m_cells[tmpIndex];
247     if (!tmpCell.isEmpty() && tmpCell.m_frameId != TFrameId::NO_FRAME) {
248       currentLevel = tmpCell.m_level;
249       break;
250     }
251     tmpIndex--;
252   }
253   // if not found any level in upper cells, then search the lower cells
254   if (!currentLevel) {
255     tmpIndex = std::max(row - m_first, 0);
256     while (tmpIndex < (int)m_cells.size()) {
257       TXshCell tmpCell = m_cells[tmpIndex];
258       if (!tmpCell.isEmpty() && tmpCell.m_frameId != TFrameId::NO_FRAME) {
259         currentLevel = tmpCell.m_level;
260         break;
261       }
262       tmpIndex++;
263     }
264     // in the case any level for input could not be found
265     if (!currentLevel) return false;
266   }
267 
268   // Resize the cell container
269   int ra   = row;
270   int rb   = row + rowCount - 1;
271   int c_rb = m_first + m_cells.size() - 1;
272   if (row > c_rb) {
273     int newCellCount = row - m_first + rowCount;
274     m_cells.resize(newCellCount);
275   } else if (row < m_first) {
276     int delta = m_first - row;
277     m_cells.insert(m_cells.begin(), delta, TXshCell());
278     m_first = row;
279   }
280   if (rb > c_rb) {
281     for (int i = 0; i < rb - c_rb; ++i) m_cells.push_back(TXshCell());
282   }
283 
284   // Paste numbers.
285   for (int i = 0; i < rowCount; i++) {
286     int dstIndex     = row - m_first + i;
287     TXshCell dstCell = m_cells[dstIndex];
288     TXshCell srcCell = cells[i];
289     if (srcCell.isEmpty()) {
290       m_cells[dstIndex] = TXshCell();
291     } else {
292       if (!dstCell.isEmpty()) currentLevel = dstCell.m_level;
293       m_cells[dstIndex] = TXshCell(currentLevel, srcCell.m_frameId);
294     }
295   }
296 
297   // Update the cell container.
298   while (!m_cells.empty() && m_cells.back().isEmpty()) {
299     m_cells.pop_back();
300   }
301   while (!m_cells.empty() && m_cells.front().isEmpty()) {
302     m_cells.erase(m_cells.begin());
303     m_first++;
304   }
305   if (m_cells.empty()) {
306     m_first = 0;
307   }
308   return true;
309 }
310 
311 //-----------------------------------------------------------------------------
312 
313 PERSIST_IDENTIFIER(TXshLevelColumn, "levelColumn")
314