1 #pragma once 2 3 #ifndef XSHEET_INCLUDED 4 #define XSHEET_INCLUDED 5 6 #include <memory> 7 8 // TnzCore includes 9 #include "traster.h" 10 #include "tpersist.h" 11 #include "tsound.h" 12 13 // TnzLib includes 14 #include "toonz/txshcolumn.h" 15 #include "toonz/txshlevel.h" 16 #include "toonz/txsheetcolumnchange.h" 17 18 #include "cellposition.h" 19 20 // STD includes 21 #include <set> 22 23 #undef DVAPI 24 #undef DVVAR 25 #ifdef TOONZLIB_EXPORTS 26 #define DVAPI DV_EXPORT_API 27 #define DVVAR DV_EXPORT_VAR 28 #else 29 #define DVAPI DV_IMPORT_API 30 #define DVVAR DV_IMPORT_VAR 31 #endif 32 33 //============================================================================= 34 35 // Forward declarations 36 37 class TXshLevel; 38 class TXshCell; 39 class TAffine; 40 class TStageObjectId; 41 class TStageObject; 42 class TStageObjectTree; 43 class TStroke; 44 class TVectorImageP; 45 class FxDag; 46 class TControlPointObserver; 47 class TOfflineGL; 48 class ColumnFan; 49 class ToonzScene; 50 class TXshSoundColumn; 51 class TXshNoteSet; 52 class TFrameId; 53 class Orientation; 54 class TXsheetColumnChangeObserver; 55 class ExpressionReferenceMonitor; 56 57 //============================================================================= 58 59 //**************************************************************************************** 60 // TXsheet declaration 61 //**************************************************************************************** 62 63 //! This is the base class for an xsheet. An Xsheet is composed of colums of 64 //! frames. 65 /*! 66 Inherits \b TSmartObject and \b TPersist. 67 68 The class provides a collection of functions that returns xsheet 69 elements, defined in 70 struct \b TXsheetImp, and enables manipulation of these. Most important 71 xsheet elements 72 are: a \b column \b set \b TColumnSetT, a \b pegbar \b tree \b 73 TStageObjectTree, a \b fx 74 \b dag \b FxDag, a \b sound \b track \b TSoundTrack and a \b scene \b 75 ToonzScene. 76 77 For purposes of this class, a Column is a graphics layer, and a 78 row is a frame number. 79 (Whether horizontal or vertial is a matter of displaying). 80 81 A \b column \b set contains all xsheet columns. A collection of 82 functions, concerning column 83 set, allows to manage xsheet column. It's possible to know xsheet column 84 count, 85 getColumnCount(), know first non empty column index, 86 getFirstFreeColumnIndex(), 87 or know if column in datum index is empty, isColumnEmpty(). You can work 88 on single xsheet 89 column, getColumn(), using its indexes: insert and remove a column with 90 insertColumn() 91 and removeColumn() or move column from an index to another using 92 moveColumn(). 93 94 You can manage also column visualization in xsheet, using the xsheet 95 object \b ColumnFan 96 getColumnFan(), and find column icon getColumnIcon(). 97 98 cell positions will be identified by a pair of row+column index, 99 which is a separate class. 100 101 It's possible work on xsheet cells directly, getCell() and setCell() or 102 getCells() and 103 setCells(); cells are identified in xsheet by two index one for row and 104 one for column. 105 You can insert, remove or clear cells using insertCells(), removeCells() 106 or clearCells(); 107 the difference between the remove and the clear function is the shift of 108 remains cells. 109 Also there are functions to manipulate cells reverseCells(), 110 swingCells(), 111 incrementCells(), duplicateCells(), int upTo, stepCells(), eachCells(). 112 113 About \b pegbar \b tree \b TStageObjectTree, it's possible to manage it 114 through the stage object's 115 related functions. 116 117 The \b fx \b dag \b FxDag getFxDag() is not managed with direct 118 functions but is always 119 up to date; in fact same functions update it. For example 120 insertColumn(), if necessary, 121 insert column index in fx dag, the same happen in setCells(). 122 123 The \b sound \b track \b TSoundTrack contain a mixed sound, computed 124 using makeSound(), 125 of all \b TXshSoundColumn present in xsheet. 126 127 It's possible take and know the \b scene \b ToonzScene to which the 128 xsheet refers using 129 getScene() and setScene(). 130 */ 131 132 class DVAPI TXsheet final : public TSmartObject, public TPersist { PERSIST_DECLARATION(TXsheet)133 PERSIST_DECLARATION(TXsheet) 134 135 public: 136 class DVAPI SoundProperties { 137 public: 138 int m_fromFrame; 139 int m_toFrame; 140 int m_frameRate; 141 bool m_isPreview; 142 143 SoundProperties(); 144 ~SoundProperties(); 145 146 inline bool operator==(const SoundProperties &c) const; 147 inline bool operator!=(const SoundProperties &c) const; 148 }; 149 150 private: 151 TSoundOutputDevice *m_player; 152 153 /*! \struct TXsheet::TXsheetImp 154 The TXsheetImp struct provides all objects necessary to define the \b TXsheet 155 class. 156 */ 157 struct TXsheetImp; 158 std::unique_ptr<TXsheetImp> m_imp; 159 TXshNoteSet *m_notes; 160 SoundProperties *m_soundProperties; 161 162 int m_cameraColumnIndex; 163 TXshColumn *m_cameraColumn; 164 165 TXsheetColumnChangeObserver *m_observer; 166 167 DECLARE_CLASS_CODE 168 169 public: 170 TXsheet(); 171 ~TXsheet(); 172 173 //! Returns a unique identifier associated with the xsheet instance. 174 unsigned long id() const; 175 176 /*! Returns max frame number used in xsheet. 177 \sa getMaxFrame() 178 */ 179 int getFrameCount() const; 180 181 /*! Returns true if all cells in rect delimited by first frame \b \e 182 pos0.frame, 183 last frame \b \e pos1.frame and first layer \b \e pos0.layer, last layer \b 184 \e pos1.layer 185 are empty; otherwise, false. 186 */ 187 bool isRectEmpty(const CellPosition &pos0, const CellPosition &pos1) const; 188 189 /*! Returns the \b TXshCell cell in row identified by index \b \e row and 190 column identified by index \b \e col. If column \b TXshColumnP in \b \e col 191 is empty return 192 an empty cell. 193 \sa setCell(), getCells(), setCells() 194 */ 195 const TXshCell &getCell(int row, int col) const; 196 197 const TXshCell &getCell(const CellPosition &pos) const; 198 199 bool setCell(int row, int col, const TXshCell &cell); 200 /*! Set \b \e cells[] to \b \e rowCount cells of column identified by index \b 201 \e col starting from row identified by index \b \e row. If column is empty 202 or is not a \b 203 TXshCellColumn set \b \e cells[] to \b \e rowCount empty cells. 204 \sa getCells(), setCells(), getCell() 205 */ 206 void getCells(int row, int col, int rowCount, TXshCell cells[]) const; 207 /*! If column identified by index \b \e col is a \b TXshCellColumn or is empty 208 and is not 209 locked, this method sets to \b \e cells[] the given \b \e rowCount cells of 210 column \b \e col starting from 211 row \b \e row. If column in \b \e col is empty it creates a new column 212 recalling 213 \b TColumnSetT::touchColumn() and sets the new cells to \b \e cells[], and 214 on creating a new 215 column it adds it to fx dag \b FxDag. 216 If cells in \b \e row and \b \e col are not empty recalls \b 217 TXshCellColumn::setCells(), 218 insert the new cells \b \e cells[] in \b \e row \b \e col and shift old 219 cells. 220 If xsheet change it updates xsheet's frame count. Return false if cannot set 221 cells. 222 \sa getCells(), setCell(), getCell() 223 */ 224 bool setCells(int row, int col, int rowCount, const TXshCell cells[]); 225 /*! If column identified by index \b \e col is not empty, is a \b \e 226 TXshCellColumn and is not locked this method inserts in row identified by 227 index \b \e row \b \e 228 rowCount empty cells, it calls TXshCellColumn::insertEmptyCells(). An 229 update of xsheet's frame count 230 is performed. 231 \sa setCells(), removeCells() 232 */ 233 void insertCells(int row, int col, int rowCount = 1); 234 235 /*! If column identified by index \b \e col is not empty, is a \b 236 TXshCellColumn and is not locked, this method removes \b \e rowCount cells 237 starting from \b \e 238 row, it calls TXshCellColumn::removeCells(). It removes cells without shift 239 remaining cells. An update of xsheet's frame count is performed. 240 \sa clearCells(), insertCells() 241 */ 242 void removeCells(int row, int col, int rowCount = 1); 243 244 /*! If column identified by index \b \e col is not empty, is a \b 245 TXshCellColumn and is not locked, clear \b \e rowCount cells starting from 246 \b \e row and it recalls TXshCellColumn::clearCells(). Clears cells and it 247 shifts remaining cells. Xsheet's frame count is updated. \sa removeCells(), 248 insertCells() 249 */ void clearCells(int row, int col, int rowCount = 1); 250 /*! Clears xsheet. It sets to default values all xsheet elements contained in 251 * struct \b TXsheetImp. 252 */ 253 void clearAll(); 254 /*! Returns cell range of column identified by index \b \e col and set \b \e 255 r0 and \b \e r1 respectively to first and last not empty cell, it then 256 recalls \b 257 TXshCellColumn::getRange(). If column is empty or is not a \b 258 TXshCellColumn this method returns 259 zero and sets 260 \b \e r0 to 0 and \b \e r1 to -1. 261 */ 262 int getCellRange(int col, int &r0, int &r1) const; 263 /*! Returns the max frame number of xsheet column identified by \b \e col and 264 calls \b TXshColumn::getMaxFrame(). 265 \sa getFrameCount() 266 */ 267 int getMaxFrame(int col) const; 268 /*! Returns true if xsheet column identified by \b \e col is empty, it calls 269 \b TXshColumn::isEmpty(), otherwise returns false. 270 */ 271 bool isColumnEmpty(int col) const; 272 /*! Sets the level set \b \e levels with all current xsheet levels used, it 273 includes 274 in \b \e levels sub-xsheet levels too. 275 \sa isLevelUsed() 276 */ 277 void getUsedLevels(std::set<TXshLevel *> &levels) const; 278 /*! Returns true if \b \e level is used in current xsheet or in sub-xsheet, 279 otherwise returns 280 false. It verifies if \b \e level is contained in level set \b 281 getUsedLevels(). 282 */ 283 bool isLevelUsed(TXshLevel *) const; 284 /*! The method retrieves a pegbar \b TStageObject with the passed \b \e id \b 285 TStageObjectId 286 specialization, calling TStageObjectTree::getStageObject(). 287 \sa getStageObjectTree() 288 */ 289 TStageObject *getStageObject(const TStageObjectId &id) const; 290 /*! The method retrieves the pegbar tree \b TStageObjectTree contained in 291 struct \b TXsheetImp. 292 \sa getStageObject() 293 */ 294 TStageObjectTree *getStageObjectTree() const; 295 /*! Returns transformation matrix \b TAffine related to pegbar \b TStageObject 296 with \b \e id 297 \b TStageObjectId specialization in frame \b \e frame, it calls \b 298 TStageObject::getPlacement(). 299 \sa getParentPlacement() 300 */ 301 TAffine getPlacement(const TStageObjectId &id, int frame) const; 302 /*! Returns z value related to pegbar \b TStageObject with \b \e id 303 specialization \b TStageObjectId 304 in frame \b \e frame, it calls \b TStageObject::getZ(). 305 */ 306 double getZ(const TStageObjectId &id, int frame) const; 307 308 double getNoScaleZ(const TStageObjectId &id) const; 309 /*! Returns transformation matrix \b TAffine related to parent of pegbar \b 310 TStageObject with 311 \b \e id \b TStageObjectId specialization in frame \b \e frame, it 312 calls \b TStageObject::getParentPlacement(). 313 \sa getPlacement() 314 */ 315 TAffine getParentPlacement(const TStageObjectId &id, int frame) const; 316 /*! Returns the center related to pegbar \b TStageObject with \b \e id 317 TStageObjectId specialization 318 in frame \b \e frame; it calls \b TStageObject::getCenter(). 319 \sa setCenter() 320 */ 321 TPointD getCenter(const TStageObjectId &id, int frame) const; 322 /*! Sets the center of pegbar \b TStageObject with \b \e id TStageObjectId 323 specialization in frame 324 \b \e frame, to \b \e center; it calls \b TStageObject::setCenter(). 325 \sa getCenter() 326 */ 327 void setCenter(const TStageObjectId &id, int frame, const TPointD ¢er); 328 /*! Returns parent related to pegbar \b TStageObject with \b \e id 329 TStageObjectId specialization; 330 it calls \b TStageObject::getParent(). 331 \sa setStageObjectParent() 332 */ 333 TStageObjectId getStageObjectParent(const TStageObjectId &id); 334 /*! Sets parent of pegbar \b TStageObject with \b \e id TStageObjectId 335 specialization to \b \e parentId; 336 it calls \b TStageObject::setParent(). 337 \sa getStageObjectParent() 338 */ 339 void setStageObjectParent(const TStageObjectId &id, 340 const TStageObjectId &parentId); 341 /*! Returns true if pegbar \b TStageObject with \b \e id TStageObjectId 342 specialization has children, 343 that is if pegbar is a parent of another pegbar; it calls \b 344 TStageObject::hasChildren(). 345 \sa getStageObjectParent() and setStageObjectParent() 346 */ 347 bool hasChildren(const TStageObjectId &id) const; 348 /*! Returns current camera's transformation matrix \b TAffine related to frame 349 \b \e frame, 350 inclusive of zdepth. It Doesn't take care of transformation matrix 351 related to pegbar 352 linked to camera. 353 \note Used only in tab code, "the Tab" has just one camera while 354 "Toonz 5.2 Harlequin" 355 manages several camera. 356 */ 357 TAffine getCameraAff(int frame) const; 358 359 void reverseCells(int r0, int c0, int r1, int c1); 360 /*! The cells, contained in rect delimited by first row \b \e r0, last row \b 361 \e r1 and 362 first column \b \e c0, are appended at the end of the rect in a 363 reversed order. 364 The last cell of rect will not be repeated. 365 */ 366 void swingCells(int r0, int c0, int r1, int c1); 367 /*! If cells is increasingly numbered and belong from same level return true; 368 otherwise return false. 369 \n If returns true, the cells, contained in rect delimited by first row 370 \b \e r0, last row 371 \b \e r1 and first column \b \e c0, are repeated as if filling the 372 numbering gap between 373 two subsequence cell. For example if the command is applied to two 374 cell with 375 \b TFrameId number equal to 2 and 5, the result will be four cells: a 376 cell with 377 \b TFrameId number equal to 2 repeated three times and one cell with 378 \b TFrameId 379 number equal to 5. 380 \n This method inserts in \b \e forUndo vector all the inserted cells, it 381 is useful for the undo process. 382 */ 383 bool incrementCells(int r0, int c0, int r1, int c1, 384 std::vector<std::pair<TRect, TXshCell>> &forUndo); 385 /*! A copy of cells, contained in rect delimited by first row \b \e r0, last 386 row \b \e r1 387 and first column \b \e c0, is made in row cells from \b r1+1 to \b \e 388 upTo. The duplicated 389 cells will be inserted by shifting the other down. 390 */ 391 void duplicateCells(int r0, int c0, int r1, int c1, int upTo); 392 /*! The cells, contained in rect delimited by first row \b \e r0, last row \b 393 \e r1 and 394 first column \b \e c0, are repeated in order to have a step \b \e 395 type. The duplicated 396 cells will be inserted by shifting the other down. 397 */ 398 void stepCells(int r0, int c0, int r1, int c1, int type); 399 /*! For each sequence of frame with same number, contained in rect delimited 400 by first row \b \e r0, last row \b \e r1 and 401 first column \b \e c0, a frame with same number is inserted. 402 */ 403 void increaseStepCells(int r0, int c0, int &r1, int c1); 404 /*! 405 For each sequence of frame with same number, contained in rect delimited by 406 first row \b \e r0, last row \b \e r1 and 407 first column \b \e c0, a frame with same number is removed. 408 */ 409 void decreaseStepCells(int r0, int c0, int &r1, int c1); 410 /*! 411 The cells, contained in rect delimited by first row \b \e r0, last row \b \e r1 412 and 413 first column \b \e c0, are reset in order to have no sequential 414 frame duplication. 415 */ 416 void resetStepCells(int r0, int c0, int r1, int c1); 417 /*! Only one cell each step \b \e type, of the cells, contained in rect 418 delimited by 419 first row \b \e r0, last row \b \e r1 and first column \b \e c0, are 420 preserved, the 421 others are deleted. 422 */ 423 void eachCells(int r0, int c0, int r1, int c1, int type); 424 void rollupCells(int r0, int c0, int r1, int c1); 425 void rolldownCells(int r0, int c0, int r1, int c1); 426 void timeStretch(int r0, int c0, int r1, int c1, int nr); 427 428 // force cells order in n-steps. returns the row amount after process 429 // if withBlank is greater than -1, remove empty cell from its order and 430 // insert blank frames with type*withBlank length at each n-step. 431 int reframeCells(int r0, int r1, int col, int type, int withBlank = -1); 432 433 /*! Exposes level \b \e xl in xsheet starting from cell identified by \b \e 434 row and \b \e col. 435 Returns the number of the inserted cells. 436 */ 437 int exposeLevel(int row, int col, TXshLevel *xl, bool overwrite = false); 438 439 // cutomized exposseLevel used from LoadLevel command 440 int exposeLevel(int row, int col, TXshLevel *xl, std::vector<TFrameId> &fIds_, 441 int xFrom = -1, int xTo = -1, int step = -1, int inc = -1, 442 int frameCount = -1, bool doesFileActuallyExist = true); 443 444 /*! Exposes level \b \e xl \b \e fids in xsheet starting from cell identified 445 * by \b \e row and \b \e col. 446 */ 447 void exposeLevel(int row, int col, TXshLevel *xl, std::vector<TFrameId> fids, 448 bool overwrite); 449 /*! Updates xsheet frame count, find max frame count between all 450 xsheet column, using getMaxFrame(). 451 */ 452 void updateFrameCount(); 453 /*! Clears xsheet calling \b clearAll() and sets all xsheet elements, 454 contained 455 in \b TXsheetImp, to information contained in \b TIStream \b \e is. 456 \sa saveData() 457 */ 458 void loadData(TIStream &is) override; 459 /*! Save all xsheet elements information, contained in \b TXsheetImp, in \b 460 TOStream \b \e os. 461 \sa loadData() 462 */ 463 void saveData(TOStream &os) override; 464 /*! Inserts an empty column in \b \e index calling \b insertColumn(). 465 */ 466 void insertColumn(int index, 467 TXshColumn::ColumnType type = TXshColumn::eLevelType); 468 /*! Insert \b \e column in column \b \e index. Insert column in the column 469 set, in the 470 pegbarTree \b TStageObjectTree contained in TXsheetImp and if column 471 fx \b TFx is 472 not empty in fx dag, calling FxDag::addToXsheet(). 473 \sa removeColumn() 474 */ 475 void insertColumn(int index, TXshColumn *column); // becomes owner 476 /*! Removes column identified by \b \e index from xsheet column. If column in 477 \b \e index 478 is not empty and it has a \b TFx fx, removes column from fx dag, calls 479 FxDag::removeFromXsheet() and disconnects fx column from all output fx \b TFx, 480 than removes column from column set and from pegbarTree \b TStageObjectTree 481 contained 482 in TXsheetImp. 483 \sa insertColumn() 484 */ 485 void removeColumn(int index); 486 /*! Moves column from xsheet column index \b \e srcIndex to \b \e dstIndex, 487 columns between \b \e srcIndex+1 and \b \e dstIndex (included) 488 are shifted of -1. 489 \sa insertColumn() and removeColumn() 490 */ 491 void moveColumn(int srcIndex, int dstIndex); 492 493 /*! Returns a pointer to the \b TXshColumn identified in xsheet by index \b \e 494 * index. 495 */ 496 TXshColumn *getColumn(int index) const; 497 /*! Returns xsheet column count, i.e the number of xsheet column used, it 498 calls 499 \b TColumnSetT::getColumnCount(). 500 \sa getColumn() and getMaxFrame(). 501 */ 502 int getColumnCount() const; 503 /*! Returns first not empty column index in xsheet. 504 */ 505 int getFirstFreeColumnIndex() const; 506 507 TSoundTrack *makeSound(SoundProperties *properties); 508 #ifdef BUTTA 509 /*! Returns \b TSoundTrack with frame rate \b \e frameRate computed calling 510 \b TXshSoundColumn::mixingTogether() of all sound column contained in 511 xsheet. If xsheet doesn't have sound column it returns zero. 512 */ 513 TSoundTrack *makeSound(int frameRate, bool isPreview = true); 514 /*! Utility Function */ 515 TSoundTrack *makeSound(int fromFrame, int toFrame, int frameRate = -1); 516 #endif 517 void scrub(int frame, bool isPreview = false); 518 void stopScrub(); 519 void play(TSoundTrackP soundtrack, int s0, int s1, bool loop); 520 521 /*! Returns a pointer to object \b FxDag contained in \b TXsheetImp, this 522 object 523 allows the user to manage all fx dag, i.e. all element of fx 524 schematic. 525 */ 526 FxDag *getFxDag() const; 527 /*! Returns a pointer to object \b ColumnFan contained in \b TXsheetImp, this 528 object allows the user to manage columns visualization in xsheet. 529 TXsheet maintains one column fan per each orientation. 530 */ 531 ColumnFan *getColumnFan(const Orientation *o) const; 532 /*! Returns a pointer to \b ToonzScene contained in \b TXsheetImp, that is the 533 scene to 534 which the xsheet refers. 535 \sa setScene() 536 */ 537 ToonzScene *getScene() const; 538 /*! Set scene \b ToonzScene contained in \b TXsheetImp to \b scene, change the 539 scene to which the xsheet refers. 540 \sa setScene() 541 */ 542 void setScene(ToonzScene *scene); 543 getNotes()544 TXshNoteSet *getNotes() const { return m_notes; } 545 546 //! Returns true if the \b cellCandidate creates a circular reference. 547 //! A circular reference is obtained when \b cellCandidate is a subXsheet cell 548 //! and contains or matches 549 //! with this XSheet. 550 bool checkCircularReferences(const TXshCell &cellCandidate); 551 552 //! Returns true if the \b columnCandidate creates a circular reference. 553 //! A circular reference is obtained when \b columnCandidate is a subXsheet 554 //! column and contains or matches 555 //! with this XSheet. 556 bool checkCircularReferences(TXshColumn *columnCandidate); 557 558 void invalidateSound(); 559 560 //! Returns the xsheet content's \a camstand bbox at the specified row. 561 TRectD getBBox(int row) const; 562 563 void autoInputCellNumbers(int increment, int interval, int step, int repeat, 564 int from, int to, int r0, int r1, bool isOverwrite, 565 std::vector<int> columnIndices, 566 std::vector<TXshLevelP> levels, int rowsCount); 567 setCameraColumnIndex(int index)568 void setCameraColumnIndex(int index) { m_cameraColumnIndex = index; } getCameraColumnIndex()569 int getCameraColumnIndex() { return m_cameraColumnIndex; } 570 setCameraColumnLocked(bool locked)571 void setCameraColumnLocked(bool locked) { m_cameraColumn->lock(locked); } isCameraColumnLocked()572 bool isCameraColumnLocked() { return m_cameraColumn->isLocked(); } 573 574 ExpressionReferenceMonitor *getExpRefMonitor() const; 575 void setObserver(TXsheetColumnChangeObserver *observer); 576 577 void notify(const TXsheetColumnChange &change); 578 void notifyFxAdded(const std::vector<TFx *> &fxs); 579 void notifyStageObjectAdded(const TStageObjectId id); 580 bool isReferenceManagementIgnored(TDoubleParam *); 581 582 protected: 583 bool checkCircularReferences(TXsheet *childCandidate); 584 585 private: 586 // Not copiable 587 TXsheet(const TXsheet &); 588 TXsheet &operator=(const TXsheet &); 589 590 /*! Return column in index if exists, overwise create a new column; 591 if column exist and is empty check \b isSoundColumn and return right type. 592 */ 593 TXshColumn *touchColumn(int index, 594 TXshColumn::ColumnType = TXshColumn::eLevelType); 595 }; 596 597 //----------------------------------------------------------------------------- 598 599 #ifdef _WIN32 600 template class DVAPI TSmartPointerT<TXsheet>; 601 #endif 602 typedef TSmartPointerT<TXsheet> TXsheetP; 603 604 #endif // XSHEET_INCLUDED 605