gcsx_editor.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /* GCSx
  2. ** EDITOR.CPP
  3. **
  4. ** Game editor module- basic init, menubar, other top-level functionality
  5. */
  6. /*****************************************************************************
  7. ** Copyright (C) 2003-2006 Janson
  8. **
  9. ** This program is free software; you can redistribute it and/or modify
  10. ** it under the terms of the GNU General Public License as published by
  11. ** the Free Software Foundation; either version 2 of the License, or
  12. ** (at your option) any later version.
  13. **
  14. ** This program is distributed in the hope that it will be useful,
  15. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ** GNU General Public License for more details.
  18. **
  19. ** You should have received a copy of the GNU General Public License
  20. ** along with this program; if not, write to the Free Software
  21. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
  22. *****************************************************************************/
  23. #include "all.h"
  24. // Icon surface
  25. SDL_Surface* iconSurface = NULL;
  26. const string resourceError("Error loading resource/editoricon.bmp");
  27. SDL_Surface* getIconSurface() { start_func
  28. static int error = 0;
  29. if ((!iconSurface) && (!error)) {
  30. string iconFile;
  31. createFilename(resourceDir->c_str(), FILENAME_EDITORICONS, iconFile);
  32. iconSurface = SDL_LoadBMP(iconFile.c_str());
  33. if (iconSurface == NULL) {
  34. guiErrorBox(resourceError, errorTitleResourceLoad);
  35. error = 1;
  36. }
  37. else {
  38. // Copy to a surface32 with clear BK
  39. SDL_Surface* icon32 = createSurface32(iconSurface->w, iconSurface->h);
  40. sge_FilledRect(icon32, 0, 0, icon32->w, icon32->h, mapColor32(0, 0, 0, 0));
  41. SDL_SetAlpha(icon32, SDL_SRCALPHA, 255);
  42. SDL_SetColorKey(iconSurface, SDL_SRCCOLORKEY, SDL_MapRGB(iconSurface->format, 255, 0, 0));
  43. blit(0, 0, iconSurface, 0, 0, icon32);
  44. SDL_FreeSurface(iconSurface);
  45. iconSurface = icon32;
  46. }
  47. }
  48. return iconSurface;
  49. }
  50. // Menu tree for editor
  51. PopupMenu::PopupGen editorMenuTree[] = {
  52. { MENU_SUB, "\tWorld", 0 },
  53. { FILE_NEW, "\tNew", 0 },
  54. { FILE_OPENEXIST, "\tOpen...", 0 },
  55. { MENU_SEP, NULL, 0 },
  56. { FILE_SAVE, "\tSave", 1 },
  57. { FILE_SAVEAS, "Save \tas...", 1 },
  58. { FILE_SAVEALL, "Sa\tve all", 0 },
  59. { MENU_SEP, NULL, 0 },
  60. { FILE_CLOSE, "\tClose", 1 },
  61. { FILE_CLOSEALL, "C\tlose all", 0 },
  62. { MENU_SEP, NULL, 0 },
  63. { FILE_QUIT, "\tQuit editor", 0 },
  64. { FILE_EXIT, "E\txit", 0 },
  65. { 0, NULL, 0 },
  66. { MENU_SUB, "\tNew", 0 },
  67. { NEW_ANIM, "Animation Group...", 0 },
  68. { NEW_FONT, "Font...", 0 },
  69. { NEW_LIBRARY, "Function Library...", 0 },
  70. { NEW_IMAGE, "Image/Tile Set...", 0 },
  71. { NEW_NOTES, "Notes...", 0 },
  72. { NEW_SCENE, "Scene...", 0 },
  73. { NEW_SCRIPT, "Script...", 0 },
  74. { MENU_SEP, NULL, 0 },
  75. { MENU_SUB, "Import", 0 },
  76. { NEW_IMPORT_IMAGE, "Image/Tile Set...", 0 },
  77. { NEW_IMPORT_FONT, "Font...", 0 },
  78. { 0, NULL, 0 },
  79. { MENU_SEP, NULL, 0 },
  80. { NEW_FOLDER, "Folder...", 0 },
  81. // @TODO: Layer
  82. // @TODO: World?
  83. { 0, NULL, 0 },
  84. { MENU_SUB, "\tEdit", 0 },
  85. { EDIT_UNDO, "\tUndo", 1 },
  86. { EDIT_REDO, "\tRedo", 1 },
  87. { MENU_SEP, NULL, 0 },
  88. { EDIT_CUT, "Cu\tt", 1 },
  89. { EDIT_COPY, "\tCopy", 1 },
  90. { EDIT_PASTE, "\tPaste", 1 },
  91. { EDIT_DELETE, "\tDelete", 1 },
  92. { MENU_SEP, NULL, 0 },
  93. /* Not completed yet
  94. { EDIT_FLIP, "Flip", 1 },
  95. { EDIT_MIRROR, "Mirror", 1 },
  96. { EDIT_SIZEROTATE, "Resize/rotate...", 1 },
  97. { EDIT_COLORIZE, "Colorize...", 1 },
  98. { EDIT_FILTER, "Filter...", 1 },
  99. { MENU_SEP, NULL, 0 },
  100. */
  101. { EDIT_SELECTALL, "\tSelect all", 1 },
  102. { EDIT_DESELECTALL, "\tDeselect all", 1 },
  103. { MENU_SEP, NULL, 0 },
  104. { EDIT_GRADIENT, "Create gradient", 1 },
  105. { EDIT_SETGLYPHWIDTH, "Set \tglyph width", 1 },
  106. { 0, NULL, 0 },
  107. { MENU_SUB, "\tTools", 0 },
  108. { MODE_EDITTILES, "Edit \ttile images", 1 },
  109. { MODE_EDITCOLLISION, "Edit \tcollision maps", 1 },
  110. { MODE_EDITASSIGN, "\tAssign maps to tiles", 1 },
  111. { TOOLS_CHOOSE, "\tChoose...", 1 },
  112. { TOOLS_CHOOSER, "C\thoose right-click...", 1 },
  113. { MENU_SEP, NULL, 0 },
  114. { MENU_SUB, "Settin\tgs", TOOLS_SETTINGS },
  115. { TOOLS_NEXTIMAGE, "\tNext image", 1 },
  116. { TOOLS_PREVIMAGE, "\tPrevious image", 1 },
  117. { TOOLS_NEXTCOLOR, "\tNext color", 1 },
  118. { TOOLS_PREVCOLOR, "\tPrevious color", 1 },
  119. { TOOLS_EDITCOLOR, "\tEdit color", 1 },
  120. { MENU_SEP, NULL, 0 },
  121. { TOOLS_ANTIALIAS, "\tSmoothing (anti-alias)", 1 },
  122. { TOOLS_CONTIGUOUS, "\tContiguous", 1 },
  123. { MENU_SEP, NULL, 0 },
  124. { TOOLS_BLENDUP, "\tIncrease blend", 1 },
  125. { TOOLS_BLENDDOWN, "\tDecrease blend", 1 },
  126. { MENU_SEP, NULL, 0 },
  127. { TOOLS_TOLERANCEUP, "Inc\trease tolerance", 1 },
  128. { TOOLS_TOLERANCEDOWN, "Decre\tase tolerance", 1 },
  129. { 0, NULL, 0 },
  130. { MENU_SEP, NULL, 0 },
  131. { TOOLS_PEN, "\tPen", 1 },
  132. { TOOLS_LINE, "\tLine", 1 },
  133. { TOOLS_RECT, "Recta\tngle", 1 },
  134. { TOOLS_RECTFILL, "Filled \trectangle", 1 },
  135. { TOOLS_ELLIPSE, "\tEllipse", 1 },
  136. { TOOLS_ELLIPSEFILL, "F\tilled ellipse", 1 },
  137. { TOOLS_FILL, "\tFlood fill", 1 },
  138. { MENU_SEP, NULL, 0 },
  139. { TOOLS_SELECT, "\tSelect", 1 },
  140. { TOOLS_SELECTELLIPSE, "Selec\tt ellipse", 1 },
  141. { TOOLS_WAND, "Magic \twand", 1 },
  142. { MENU_SEP, NULL, 0 },
  143. { TOOLS_DROPPER, "\tDropper", 1 },
  144. // @TODO: some new tools (sprites)
  145. { 0, NULL, 0 },
  146. { MENU_SUB, "\tView", 0 },
  147. { VIEW_ZOOMIN, "Zoom \tin", 1 },
  148. { VIEW_ZOOMOUT, "Zoom \tout", 1 },
  149. { MENU_SEP, NULL, 0 },
  150. { VIEW_PREV, "\tPrevious", 1 },
  151. { VIEW_NEXT, "\tNext", 1 },
  152. { MENU_SEP, NULL, 0 },
  153. { VIEW_ALLLAYER, "\tShow all layers", 1 },
  154. { VIEW_DIMLAYER, "\tDim other layers", 1 },
  155. { VIEW_NOLAYER, "\tHide other layers", 1 },
  156. { MENU_SEP, NULL, 0 },
  157. { VIEW_GRID, "Show \tgrid", 1 },
  158. { MENU_SUB, "Show \tdots", VIEW_DOTS_CHOOSE },
  159. { VIEW_DOTS_NONE, "\tNo dots", 1 },
  160. { VIEW_DOTS_TRANS, "\tTransparent as dots", 1 },
  161. { VIEW_DOTS_ALPHA, "\tAlpha dots", 1 },
  162. { 0, NULL, 0 },
  163. { MENU_SEP, NULL, 0 },
  164. { VIEW_BROWSER, "\tWorld browser", 1 },
  165. { VIEW_CONSOLE, "\tConsole", 1 },
  166. /* Removed (not currently working)
  167. { MENU_SEP, NULL, 0 },
  168. { VIEW_TOOLPANEL, "\tTool panel", 1 },
  169. { VIEW_TOOLBAR, "Tool \tbar", 1 },
  170. */
  171. { 0, NULL, 0 },
  172. /* Removed (only had one item)
  173. { MENU_SUB, "\tConfig", 0 },
  174. { 0, NULL, 0 },
  175. */
  176. { MENU_SUB, "W\tindow", 0 },
  177. { WINDOW_NEXT, "\tNext", 1 },
  178. { WINDOW_PREV, "\tPrevious", 1 },
  179. { MENU_SEP, NULL, 0 },
  180. { WINDOW_MIN, "\tMinimize", 1 },
  181. { WINDOW_MAX, "Ma\tximize", 1 },
  182. { WINDOW_CLOSE, "\tClose", 1 },
  183. { WINDOW_CLOSEALL, "Close \tall", 1 },
  184. { WINDOW_CLOSEALLBUT, "Close all \tbut current", 1 },
  185. { MENU_SEP, NULL, 0 },
  186. { WINDOW_TILEHORIZ, "Tile \thorizontally", 1 },
  187. { WINDOW_TILEVERT, "Tile \tvertically", 1 },
  188. { WINDOW_CASCADE, "Casca\tde", 1 },
  189. /* Removed (not currently working)
  190. { MENU_SEP, NULL, 0 },
  191. { WINDOW_SWITCHPANEL, "\tSwitch panel", 1 },
  192. */
  193. { MENU_SEP, NULL, 0 },
  194. { CONFIG_RESOLUTION, "\tResolution..." },
  195. { 0, NULL, 0 },
  196. { 0, NULL, 0 }
  197. };
  198. // World browser
  199. TreeView* worldBrowser = NULL;
  200. // Menu handler for editor
  201. Window::CommandSupport editorCommandSupport(int code) { start_func
  202. switch (code) {
  203. case VIEW_BROWSER:
  204. return (Window::CommandSupport)((worldBrowser->isOpen() ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_ENABLE);
  205. case VIEW_CONSOLE:
  206. return (Window::CommandSupport)((debugWindow()->isOpen() ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_ENABLE);
  207. }
  208. return Window::COMMAND_HIDE;
  209. }
  210. // Command handler for editor
  211. int editorHandleGlobalEvents(const SDL_Event* event) { start_func
  212. WorldEdit* newWorld = NULL;
  213. string myFile;
  214. switch (event->type) {
  215. case SDL_SPECIAL:
  216. if (event->user.code == SDL_PREQUIT) {
  217. // Any modified worlds?
  218. if (!WorldEdit::modifiedAll()) desktop->cancelQuit();
  219. return 1;
  220. }
  221. if (event->user.code == SDL_IDLETIMEOUTSHORT) {
  222. config->performSave();
  223. return 1;
  224. }
  225. break;
  226. case SDL_COMMAND:
  227. switch (event->user.code) {
  228. case FILE_NEW:
  229. // (this line doesn't currently throw)
  230. newWorld = new WorldEdit();
  231. try {
  232. // If not OK, cancel creation of world
  233. if (!newWorld->propertiesDialog()) {
  234. delete newWorld;
  235. return 1;
  236. }
  237. // Can't undo creation of a new world
  238. newWorld->undo.clearUndo();
  239. }
  240. catch (UndoException& e) {
  241. delete newWorld;
  242. return 1;
  243. }
  244. newWorld->addToBrowser(worldBrowser);
  245. if (!worldBrowser->isOnDesktop()) {
  246. worldBrowser->runWindowed();
  247. }
  248. return 1;
  249. case FILE_OPENEXIST:
  250. try {
  251. if (fileOpen(FILETYPE_WORLD, 1, myFile)) {
  252. // (exception point)
  253. newWorld = new WorldEdit(myFile.c_str());
  254. newWorld->addToBrowser(worldBrowser);
  255. if (!worldBrowser->isOnDesktop()) {
  256. worldBrowser->runWindowed();
  257. }
  258. }
  259. }
  260. catch (FileException& e) {
  261. guiErrorBox(string(e.details), errorTitleFile);
  262. }
  263. return 1;
  264. case FILE_SAVEALL:
  265. WorldEdit::saveAll();
  266. return 1;
  267. case FILE_CLOSEALL:
  268. WorldEdit::closeAll();
  269. return 1;
  270. case FILE_EXIT:
  271. desktop->broadcastEvent(SDL_QUIT, 0);
  272. return 1;
  273. case FILE_QUIT:
  274. desktop->broadcastEvent(SDL_SPECIAL, SDL_QUITTOFRONT);
  275. return 1;
  276. case CONFIG_RESOLUTION:
  277. ResolutionDialog::create()->chooseResolution();
  278. return 1;
  279. case VIEW_BROWSER:
  280. if (worldBrowser->isOnDesktop()) {
  281. worldBrowser->closeWindow();
  282. }
  283. else {
  284. worldBrowser->runWindowed();
  285. }
  286. return 1;
  287. case VIEW_CONSOLE:
  288. if (debugWindow()->isOpen()) {
  289. debugWindow()->closeWindow();
  290. }
  291. else {
  292. debugWindow()->runWindowed();
  293. }
  294. return 1;
  295. }
  296. break;
  297. }
  298. return 0;
  299. }
  300. int gcsxEditor() { start_func
  301. PopupMenu* editorMenu = NULL;
  302. int quitType = 0;
  303. SDL_Surface* bk;
  304. try {
  305. // In the editor, we need unicode translation and repeating keys
  306. SDL_EnableUNICODE(1);
  307. SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
  308. // Our event handlers
  309. desktop->setEventHandler(editorHandleGlobalEvents);
  310. desktop->setSupportsHandler(editorCommandSupport);
  311. // Set up items for the "View" menu
  312. worldBrowser = new TreeView("Browse Worlds", NULL, 0, NULL, 1);
  313. // Set up our menus
  314. editorMenu = PopupMenu::compileMenu(editorMenuTree, 1);
  315. editorMenu->menubar(1);
  316. // Background (error results in quietly having no bk image)
  317. string bkFile;
  318. createFilename(resourceDir->c_str(), FILENAME_BKEDITOR, bkFile);
  319. bk = IMG_Load(bkFile.c_str());
  320. desktop->setBackground(bk, COLOR_EDITORDESKTOP);
  321. // Enter main event loop
  322. SDL_WM_SetCaption(PRODUCT_NAME " - Editor", PRODUCT_NAME " - Editor");
  323. quitType = desktop->eventLoop();
  324. // Close all windows
  325. desktop->closeAllWindows();
  326. // Close all worlds
  327. WorldEdit::closeAll(1);
  328. // Cleanup
  329. // @TODO: Standardize 3 sets of cleanup into one (don't run beginExitStage() here!)
  330. desktop->setBackground(NULL, COLOR_EDITORDESKTOP);
  331. if (iconSurface) {
  332. SDL_FreeSurface(iconSurface);
  333. iconSurface = NULL;
  334. }
  335. SDL_FreeSurface(bk);
  336. delete worldBrowser;
  337. worldBrowser = NULL;
  338. delete editorMenu;
  339. editorMenu = NULL;
  340. desktop->setSupportsHandler(NULL);
  341. desktop->setEventHandler(NULL);
  342. desktop->initEventCleanup();
  343. SDL_EnableKeyRepeat(0, 0);
  344. SDL_EnableUNICODE(0);
  345. clearEvents();
  346. }
  347. // Any exceptions
  348. catch (...) {
  349. try {
  350. beginExitStage();
  351. // @TODO: Attempt to recovery-save?
  352. // Cleanup
  353. desktop->deleteAllWindows();
  354. desktop->setBackground(NULL, COLOR_EDITORDESKTOP);
  355. if (iconSurface) {
  356. SDL_FreeSurface(iconSurface);
  357. iconSurface = NULL;
  358. }
  359. SDL_FreeSurface(bk);
  360. delete worldBrowser;
  361. worldBrowser = NULL;
  362. delete editorMenu;
  363. desktop->setSupportsHandler(NULL);
  364. desktop->setEventHandler(NULL);
  365. desktop->initEventCleanup();
  366. SDL_EnableKeyRepeat(0, 0);
  367. SDL_EnableUNICODE(0);
  368. clearEvents();
  369. }
  370. catch (...) {
  371. }
  372. // Pass it on
  373. throw;
  374. }
  375. return quitType == SDL_QUITTOFRONT;
  376. }