gcsx_animgroupedit.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /* GCSx
  2. ** ANIMGROUPEDIT.CPP
  3. **
  4. ** Animation group support
  5. ** Expands basic AnimGroup to include editor functionality
  6. */
  7. /*****************************************************************************
  8. ** Copyright (C) 2003-2006 Janson
  9. **
  10. ** This program is free software; you can redistribute it and/or modify
  11. ** it under the terms of the GNU General Public License as published by
  12. ** the Free Software Foundation; either version 2 of the License, or
  13. ** (at your option) any later version.
  14. **
  15. ** This program is distributed in the hope that it will be useful,
  16. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. ** GNU General Public License for more details.
  19. **
  20. ** You should have received a copy of the GNU General Public License
  21. ** along with this program; if not, write to the Free Software
  22. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
  23. *****************************************************************************/
  24. #include "all.h"
  25. AnimGroupEdit::AnimGroupEdit(WorldEdit* myWorld, int myId) : AnimGroup(myWorld, myId) { start_func
  26. assert(myWorld);
  27. // Find an unused "Untitled" name
  28. if (myId) {
  29. string findName("animations");
  30. int pos = 1;
  31. while (myWorld->findAnimGroup(findName)) {
  32. findName = "animations ";
  33. findName += intToStr(++pos);
  34. }
  35. findName[0] = toupper(findName[0]);
  36. name = findName;
  37. headerModified = contentModified = 1;
  38. }
  39. else headerModified = contentModified = 0;
  40. nameL = name;
  41. toLower(nameL);
  42. browserNode = NULL;
  43. disassociated = 0;
  44. desktop->broadcastObjChange(OBJ_ANIMGROUP | OBJMOD_CREATE, this, 0, 0);
  45. }
  46. AnimGroupEdit::~AnimGroupEdit() { start_func
  47. // @TODO: doesn't appear to be needed; no way to delete accidentally
  48. // if (!disassociated) desktop->broadcastObjChange(OBJ_ANIMGROUP | OBJMOD_DELETE, this, 0, 0);
  49. // World should be the one deleting us, which will delete our node also
  50. }
  51. void AnimGroupEdit::disassociate() throw_File { start_func
  52. // Ensure not cached- our exception point
  53. cacheLoad();
  54. // Drop browser node
  55. dropBrowser();
  56. // Notify objects
  57. desktop->broadcastObjChange(OBJ_ANIMGROUP | OBJMOD_DELETE, this, 0, 0);
  58. disassociated = 1;
  59. }
  60. void AnimGroupEdit::reassociate(TreeView* node) { start_func
  61. assert(disassociated);
  62. // Notify objects
  63. desktop->broadcastObjChange(OBJ_ANIMGROUP | OBJMOD_CREATE, this, 0, 0);
  64. // Browser node
  65. addToBrowser(node, 0);
  66. // Ensure written to file
  67. headerModified = contentModified = 1;
  68. disassociated = 0;
  69. }
  70. void AnimGroupEdit::setHeaderModified() { start_func
  71. if (!headerModified) headerModified = 1;
  72. }
  73. void AnimGroupEdit::setContentModified() { start_func
  74. if (!contentModified) {
  75. contentModified = 1;
  76. // No possibility of returning to cache
  77. delete cacheFile;
  78. cacheFile = NULL;
  79. }
  80. }
  81. void AnimGroupEdit::dropBrowser() { start_func
  82. browserNode = NULL;
  83. }
  84. void AnimGroupEdit::addToBrowser(TreeView* node, int makeCurrent) { start_func
  85. browserNode = new TreeView(name, this, 0, treeviewEventWrap);
  86. browserNode->setIcon(7);
  87. node->insert(browserNode, makeCurrent);
  88. }
  89. int AnimGroupEdit::treeviewEvent(int code, int command, int check) { start_func
  90. if (check) {
  91. if (command == EDIT_DELETE) return Window::COMMAND_ENABLE;
  92. return Window::COMMAND_HIDE;
  93. }
  94. switch (command) {
  95. case LV_SELECT:
  96. openBrowseWindow();
  97. return 1;
  98. case LV_RCLICK:
  99. // @TODO: Should actually be a popup with this as an item
  100. propertiesDialog(desktop->findPreviousFocusWindow());
  101. return 1;
  102. case EDIT_DELETE:
  103. case LV_DELETE:
  104. // Handles any error conditions/cancellation for us
  105. getWorldEdit()->deleteAnimGroup(this, desktop->findPreviousFocusWindow());
  106. return 1;
  107. }
  108. return 0;
  109. }
  110. int AnimGroupEdit::treeviewEventWrap(void* ptr, int code, int command, int check) { start_func
  111. return ((AnimGroupEdit*)ptr)->treeviewEvent(code, command, check);
  112. }
  113. void AnimGroupEdit::setSize(int newCount, Window* srcWin, Window* exWin) throw_Undo { start_func
  114. // @TODO: Undo (already in throw def), update events
  115. if (newCount != numAnim) {
  116. setHeaderModified();
  117. setContentModified();
  118. AnimSequence* newAnims = NULL;
  119. if (newCount) {
  120. newAnims = new AnimSequence[newCount];
  121. // Copy existing
  122. for (int pos = min(numAnim, newCount) - 1; pos >= 0; --pos) {
  123. newAnims[pos] = anims[pos];
  124. }
  125. // (any empty spaces initialized already)
  126. }
  127. delete[] anims;
  128. anims = newAnims;
  129. numAnim = newCount;
  130. }
  131. }
  132. void AnimGroupEdit::setName(const string& newName, Window* srcWin, Window* exWin) throw_Undo { start_func
  133. if (name != newName) {
  134. setHeaderModified();
  135. if (world) {
  136. getWorldEdit()->undo.storeUndoName(UndoBuffer::UNDO_ANIMGROUPNAME, id, name, newName, srcWin);
  137. world->deindexAnimGroup(this);
  138. }
  139. name = newName;
  140. nameL = newName;
  141. toLower(nameL);
  142. if (world) world->indexAnimGroup(this);
  143. if (browserNode) browserNode->changeName(newName);
  144. desktop->broadcastObjChange(OBJ_TILESET | OBJMOD_NAME, this, 0, 0, exWin);
  145. }
  146. }
  147. void AnimGroupEdit::openEditWindow(int subid) { start_func
  148. try {
  149. if (!numAnim) return;
  150. if (subid < 1) subid = 1;
  151. else if (subid > numAnim) subid = numAnim;
  152. new AnimGroupPaint(this, subid); // Exception point
  153. }
  154. catch (FileException& e) {
  155. guiErrorBox(string(e.details), errorTitleFile);
  156. }
  157. }
  158. void AnimGroupEdit::openBrowseWindow() { start_func
  159. try {
  160. //@TODO: new window
  161. //@TODO: add anim requires at least one tileset
  162. }
  163. catch (FileException& e) {
  164. guiErrorBox(string(e.details), errorTitleFile);
  165. }
  166. }
  167. void AnimGroupEdit::loadAnim(int id, AnimSequence* copyAnim) { start_func
  168. assert(id > 0);
  169. assert(id <= numAnim);
  170. *copyAnim = anims[id - 1];
  171. }
  172. void AnimGroupEdit::saveAnim(int id, const AnimSequence* newAnim, Window* exWin) { start_func
  173. assert(id > 0);
  174. assert(id <= numAnim);
  175. anims[id - 1] = *newAnim;
  176. desktop->broadcastObjChange(OBJ_ANIMGROUP | OBJMOD_ANIM, this, id, 0, exWin);
  177. }
  178. void AnimGroupEdit::loadAnimName(int id, string* copyName) { start_func
  179. assert(id > 0);
  180. assert(id <= numAnim);
  181. *copyName = anims[id - 1].name;
  182. }
  183. void AnimGroupEdit::saveAnimName(int id, const string* newName, Window* exWin) { start_func
  184. assert(id > 0);
  185. assert(id <= numAnim);
  186. if (anims[id - 1].name != *newName) {
  187. anims[id - 1].name = *newName;
  188. desktop->broadcastObjChange(OBJ_ANIMGROUP | OBJMOD_NAME, this, id - 1, 0, exWin);
  189. }
  190. }
  191. int AnimGroupEdit::propertiesDialog(Window* srcWin, Window* exWin) { start_func
  192. string newName = name;
  193. if (AnimGroupPropertiesDialog::create()->run(&newName, this)) {
  194. try {
  195. markLock();
  196. }
  197. catch (FileException& e) {
  198. guiErrorBox(string(e.details), errorTitleFile);
  199. return 0;
  200. }
  201. try {
  202. getWorldEdit()->undo.preUndoBlock();
  203. setName(newName, srcWin, exWin);
  204. getWorldEdit()->undo.postUndoBlock();
  205. }
  206. catch (UndoException& e) {
  207. markUnlock();
  208. return 0;
  209. }
  210. markUnlock();
  211. return 1;
  212. }
  213. return 0;
  214. }
  215. int AnimGroupEdit::isHeaderModified() const { start_func
  216. return headerModified;
  217. }
  218. int AnimGroupEdit::isContentModified() const { start_func
  219. return contentModified;
  220. }
  221. Uint32 AnimGroupEdit::saveHeader(FileWrite* file) throw_File { start_func
  222. file->writeStr(name);
  223. file->writeInt(id);
  224. file->writeInt(defWidth);
  225. file->writeInt(defHeight);
  226. file->writeInt(numAnim);
  227. return 1;
  228. }
  229. void AnimGroupEdit::saveContent(FileWrite* file) throw_File { start_func
  230. // (our data shouldn't be empty unless we have none
  231. assert(anims || !numAnim);
  232. if (numAnim) {
  233. for (int pos = 0; pos < numAnim; ++pos) {
  234. file->writeStr(anims[pos].name);
  235. file->writeInt(anims[pos].count);
  236. file->writeInt(anims[pos].width);
  237. file->writeInt(anims[pos].height);
  238. file->writeInt8(anims[pos].loopType);
  239. // Frames
  240. for (int subpos = 0; subpos < anims[pos].count; ++subpos) {
  241. file->writeInt(anims[pos].frames[subpos].count);
  242. file->writeInt16(anims[pos].frames[subpos].xOrigin);
  243. file->writeInt16(anims[pos].frames[subpos].yOrigin);
  244. file->writeInt16(anims[pos].frames[subpos].xOffs);
  245. file->writeInt16(anims[pos].frames[subpos].yOffs);
  246. file->writeInt8(anims[pos].frames[subpos].delay);
  247. // Components
  248. for (int subsubpos = 0; subsubpos < anims[pos].frames[subpos].count; ++subsubpos) {
  249. file->writeInt(anims[pos].frames[subpos].comps[subsubpos].tileset->getId());
  250. file->writeInt16(anims[pos].frames[subpos].comps[subsubpos].index);
  251. file->writeInt16(anims[pos].frames[subpos].comps[subsubpos].x);
  252. file->writeInt16(anims[pos].frames[subpos].comps[subsubpos].y);
  253. file->writeInt8(anims[pos].frames[subpos].comps[subsubpos].r);
  254. file->writeInt8(anims[pos].frames[subpos].comps[subsubpos].g);
  255. file->writeInt8(anims[pos].frames[subpos].comps[subsubpos].b);
  256. file->writeInt8(anims[pos].frames[subpos].comps[subsubpos].alpha);
  257. file->writeInt8(anims[pos].frames[subpos].comps[subsubpos].effects);
  258. }
  259. }
  260. }
  261. }
  262. }
  263. void AnimGroupEdit::saveSuccess() { start_func
  264. headerModified = 0;
  265. contentModified = 0;
  266. }
  267. void AnimGroupEdit::cachedContent(FileRead* file, int oldData) { start_func
  268. // If already cached..
  269. if (cached) {
  270. delete cacheFile;
  271. cacheFile = file;
  272. }
  273. else if (oldData) {
  274. delete file;
  275. }
  276. else {
  277. // Cache ourselves?
  278. if (!lockCount) {
  279. delete cacheFile;
  280. cacheFile = file;
  281. delete[] anims;
  282. anims = NULL;
  283. cached = 1;
  284. }
  285. else {
  286. delete file;
  287. }
  288. }
  289. }