gcsx_clipboard.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. /* GCSx
  2. ** CLIPBOARD.CPP
  3. **
  4. ** Our internal clipboard, with cross-platform clipboard reading/writing
  5. ** added transparently as code becomes available
  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 "SDL_syswm.h"
  25. #include "all.h"
  26. // Current internal clipboard
  27. ClipboardType clipType = CLIPBOARD_NONE;
  28. string* clipString = NULL;
  29. SDL_Surface* clipImage = NULL;
  30. Uint8* clipColors = NULL;
  31. int clipColorCount = 0;
  32. // (tile layer clipboard)
  33. int clipLayerCount = 0;
  34. int clipLayerWidth = 0;
  35. int clipLayerHeight = 0;
  36. Uint32** clipLayerData = NULL;
  37. Uint32** clipLayerExt = NULL;
  38. Uint32** clipLayerFx = NULL;
  39. const void** clipLayerTileSet = NULL;
  40. // (spawn clipboard)
  41. int clipSpawnCount = 0;
  42. int clipSpawnCountLayers = 0;
  43. SpawnEdit** clipSpawnData = NULL;
  44. int* clipSpawnLayers = NULL;
  45. ClipboardType typeInClipboard() { start_func
  46. return clipType;
  47. }
  48. int canConvertClipboard(ClipboardType type) { start_func
  49. // Text type
  50. #ifdef WIN32
  51. // WINDOWS CLIPBOARD
  52. if ((type == CLIPBOARD_TEXT_LINE) || (type == CLIPBOARD_TEXT_MULTI)) {
  53. if ((IsClipboardFormatAvailable(CF_TEXT)) || (IsClipboardFormatAvailable(CF_OEMTEXT))) return 1;
  54. return 0;
  55. }
  56. #else
  57. if ((type == CLIPBOARD_TEXT_LINE) && (clipType == CLIPBOARD_TEXT_MULTI)) return 1;
  58. if ((type == CLIPBOARD_TEXT_MULTI) && (clipType == CLIPBOARD_TEXT_LINE)) return 1;
  59. #endif
  60. // Other types
  61. if (type == clipType) return 1;
  62. return 0;
  63. }
  64. void clipboardClear() { start_func
  65. clipType = CLIPBOARD_NONE;
  66. delete clipString;
  67. clipString = NULL;
  68. delete[] clipColors;
  69. clipColors = NULL;
  70. clipColorCount = 0;
  71. if (clipImage) {
  72. SDL_FreeSurface(clipImage);
  73. clipImage = NULL;
  74. }
  75. if (clipLayerCount) {
  76. for (int pos = 0; pos < clipLayerCount; ++pos) {
  77. delete[] clipLayerData[pos];
  78. delete[] clipLayerExt[pos];
  79. delete[] clipLayerFx[pos];
  80. }
  81. delete[] clipLayerData;
  82. delete[] clipLayerExt;
  83. delete[] clipLayerFx;
  84. delete[] clipLayerTileSet;
  85. clipLayerData = NULL;
  86. clipLayerExt = NULL;
  87. clipLayerFx = NULL;
  88. clipLayerTileSet = NULL;
  89. clipLayerCount = 0;
  90. }
  91. if (clipSpawnCount) {
  92. for (int pos = 0; pos < clipSpawnCount; ++pos) {
  93. delete clipSpawnData[pos];
  94. }
  95. delete[] clipSpawnData;
  96. delete[] clipSpawnLayers;
  97. clipSpawnData = NULL;
  98. clipSpawnLayers = NULL;
  99. clipSpawnCount = 0;
  100. clipSpawnCountLayers = 0;
  101. }
  102. }
  103. void clipboardClearTileset(const void* tileset) { start_func
  104. if (clipType == CLIPBOARD_LAYER) {
  105. for (int pos = 0; pos < clipLayerCount; ++pos) {
  106. if (clipLayerTileSet[pos] == tileset) clipLayerTileSet[pos] = NULL;
  107. }
  108. }
  109. // @TODO: Spawns
  110. }
  111. void clipboardCopy(const string& text) { start_func
  112. // (clear any other types)
  113. clipboardClear();
  114. #ifdef WIN32
  115. // WINDOWS CLIPBOARD
  116. SDL_SysWMinfo wmInfo;
  117. SDL_VERSION(&wmInfo.version);
  118. SDL_GetWMInfo(&wmInfo);
  119. if (OpenClipboard(wmInfo.window)) {
  120. // Add \r before every \n
  121. string data = text;
  122. string::size_type pos = 0;
  123. while ((pos = data.find('\n', pos)) != string::npos) {
  124. data.insert(pos, 1, '\r');
  125. pos += 2;
  126. }
  127. EmptyClipboard();
  128. HGLOBAL hClipboardData;
  129. hClipboardData = GlobalAlloc(GMEM_DDESHARE, data.size() + 1);
  130. char* pchData = (char*)GlobalLock(hClipboardData);
  131. strcpy(pchData, data.c_str());
  132. GlobalUnlock(hClipboardData);
  133. SetClipboardData(CF_TEXT, hClipboardData);
  134. CloseClipboard();
  135. }
  136. #else
  137. // Store string
  138. delete clipString;
  139. clipString = NULL;
  140. clipString = new string(text);
  141. // Multiline?
  142. if (clipString->find_first_of('\n', 0) == string::npos) clipType = CLIPBOARD_TEXT_MULTI;
  143. else clipType = CLIPBOARD_TEXT_LINE;
  144. #endif
  145. }
  146. void clipboardCopy(SDL_Surface* surface, int x, int y, int width, int height) { start_func
  147. assert(surface);
  148. assert(width > 0);
  149. assert(height > 0);
  150. // (clear any other types)
  151. clipboardClear();
  152. // Attempt to allocate surface
  153. clipImage = createSurface32(width, height);
  154. // Blit
  155. blit(x, y, surface, 0, 0, clipImage, width, height);
  156. clipType = CLIPBOARD_IMAGE;
  157. }
  158. void clipboardCopy(const Uint8* colors, int count) { start_func
  159. assert(count);
  160. assert(colors);
  161. // (clear any other types)
  162. clipboardClear();
  163. // Attempt to allocate memory
  164. clipColors = new Uint8[count * 4];
  165. // Copy
  166. memcpy(clipColors, colors, count * 4);
  167. clipType = CLIPBOARD_RGBA;
  168. clipColorCount = count;
  169. }
  170. void clipboardCopy(const vector<SpawnEdit const*>& spawns, const vector<int>& layers) { start_func
  171. assert(!spawns.empty());
  172. assert(!layers.empty());
  173. assert(spawns.size() == layers.size());
  174. // (clear any other types)
  175. clipboardClear();
  176. // Prepare memory
  177. clipSpawnCount = spawns.size();
  178. clipSpawnData = new SpawnEdit*[clipSpawnCount];
  179. clipSpawnLayers = new int[clipSpawnCount];
  180. // Loop through twice- first to determine range of layers and x/y positions
  181. int baseX = 0;
  182. int baseY = 0;
  183. set<int> layersUsed;
  184. vector<SpawnEdit const*>::const_iterator sPos = spawns.begin();
  185. vector<SpawnEdit const*>::const_iterator sEnd = spawns.end();
  186. vector<int>::const_iterator lPos = layers.begin();
  187. vector<int>::const_iterator lEnd = layers.end();
  188. for (; sPos != sEnd; ++sPos, ++lPos) {
  189. if (sPos == spawns.begin()) {
  190. baseX = (*sPos)->getX();
  191. baseY = (*sPos)->getY();
  192. }
  193. else {
  194. if ((*sPos)->getX() < baseX) baseX = (*sPos)->getX();
  195. if ((*sPos)->getY() < baseY) baseY = (*sPos)->getY();
  196. }
  197. layersUsed.insert(*lPos);
  198. }
  199. // Prepare for normalization of layer numbers to be zero-based
  200. map<int, int> layerMap;
  201. int layerNormalized = 0;
  202. for (set<int>::iterator pos = layersUsed.begin(); pos != layersUsed.end(); ++pos) {
  203. layerMap[*pos] = layerNormalized++;
  204. }
  205. clipSpawnCountLayers = layerNormalized;
  206. // Second loop, to copy to clipboard as normalized data
  207. sPos = spawns.begin();
  208. lPos = layers.begin();
  209. for (int pos = 0; sPos != sEnd; ++pos, ++sPos, ++lPos) {
  210. SpawnEdit* newSpawn = new SpawnEdit(*sPos, NULL);
  211. // Normalize position
  212. newSpawn->setPos(newSpawn->getX() - baseX, newSpawn->getY() - baseY, 1);
  213. clipSpawnData[pos] = newSpawn;
  214. // Normalize layer
  215. clipSpawnLayers[pos] = layerMap[*lPos];
  216. }
  217. clipType = CLIPBOARD_SPAWN;
  218. }
  219. void clipboardCopy(int numLayers, const void* const* tileset, const Uint32* const* data, const Uint32* const* dataExt, const Uint32* const* dataFx, int x, int y, int width, int height, int pitch) { start_func
  220. assert(numLayers);
  221. assert(data);
  222. assert(width);
  223. assert(height);
  224. assert(pitch);
  225. // (clear any other types)
  226. clipboardClear();
  227. // Attempt to allocate arrays
  228. clipLayerData = new Uint32*[numLayers];
  229. clipLayerExt = new Uint32*[numLayers];
  230. clipLayerFx = new Uint32*[numLayers];
  231. clipLayerTileSet = new const void*[numLayers];
  232. // Fill arrays with NULL
  233. for (int pos = 0; pos < numLayers; ++pos) {
  234. assert(data[pos]);
  235. clipLayerData[pos] = NULL;
  236. clipLayerExt[pos] = NULL;
  237. clipLayerFx[pos] = NULL;
  238. clipLayerTileSet[pos] = NULL;
  239. }
  240. // Copy each layer
  241. for (int pos = 0; pos < numLayers; ++pos) {
  242. // Tileset
  243. if (tileset) clipLayerTileSet[pos] = tileset[pos];
  244. // Allocate data space and copy
  245. clipLayerData[pos] = new Uint32[width * height];
  246. matrixCopy(data[pos] + x + y * pitch, clipLayerData[pos], width * 4, height, pitch * 4, width * 4);
  247. // If applicable, allocate ext space and copy
  248. if ((dataExt) && (dataExt[pos])) {
  249. clipLayerExt[pos] = new Uint32[width * height];
  250. matrixCopy(dataExt[pos] + x + y * pitch, clipLayerExt[pos], width * 4, height, pitch * 4, width * 4);
  251. }
  252. // If applicable, allocate fx space and copy
  253. if ((dataFx) && (dataFx[pos])) {
  254. clipLayerFx[pos] = new Uint32[width * height];
  255. matrixCopy(dataFx[pos] + x + y * pitch, clipLayerFx[pos], width * 4, height, pitch * 4, width * 4);
  256. }
  257. }
  258. // Store layer stats
  259. clipLayerCount = numLayers;
  260. clipLayerWidth = width;
  261. clipLayerHeight = height;
  262. clipType = CLIPBOARD_LAYER;
  263. }
  264. void clipboardPasteTextLine(string& paste) { start_func
  265. #ifdef WIN32
  266. // WINDOWS CLIPBOARD
  267. SDL_SysWMinfo wmInfo;
  268. SDL_VERSION(&wmInfo.version);
  269. SDL_GetWMInfo(&wmInfo);
  270. if (OpenClipboard(wmInfo.window)) {
  271. if ((IsClipboardFormatAvailable(CF_TEXT)) || (IsClipboardFormatAvailable(CF_OEMTEXT))) {
  272. HANDLE hClipboardData = GetClipboardData(CF_TEXT);
  273. char *pchData = (char*)GlobalLock(hClipboardData);
  274. string data = pchData;
  275. GlobalUnlock(hClipboardData);
  276. CloseClipboard();
  277. // (cut at first \n or \r)
  278. string::size_type pos = data.find_first_of("\r\n", 0);
  279. if (pos == string::npos) paste = data;
  280. else paste = data.substr(0, pos);
  281. }
  282. else paste = blankString;
  283. }
  284. else paste = blankString;
  285. #else
  286. if (clipType == CLIPBOARD_TEXT_LINE) {
  287. assert(clipString);
  288. paste = *clipString;
  289. }
  290. else if (clipType == CLIPBOARD_TEXT_MULTI) {
  291. assert(clipString);
  292. // (cut at first \n)
  293. string::size_type pos = clipString->find_first_of('\n', 0);
  294. if (pos == string::npos) paste = *clipString;
  295. else paste = clipString->substr(0, pos);
  296. }
  297. else paste = blankString;
  298. #endif
  299. }
  300. void clipboardPasteTextMulti(string& paste) { start_func
  301. #ifdef WIN32
  302. // WINDOWS CLIPBOARD
  303. SDL_SysWMinfo wmInfo;
  304. SDL_VERSION(&wmInfo.version);
  305. SDL_GetWMInfo(&wmInfo);
  306. if (OpenClipboard(wmInfo.window)) {
  307. if ((IsClipboardFormatAvailable(CF_TEXT)) || (IsClipboardFormatAvailable(CF_OEMTEXT))) {
  308. HANDLE hClipboardData = GetClipboardData(CF_TEXT);
  309. char *pchData = (char*)GlobalLock(hClipboardData);
  310. string data = pchData;
  311. GlobalUnlock(hClipboardData);
  312. CloseClipboard();
  313. // (remove all \r)
  314. string::size_type pos = 0;
  315. while ((pos = data.find('\r', pos)) != string::npos) {
  316. data.erase(pos, 1);
  317. }
  318. paste = data;
  319. }
  320. else paste = blankString;
  321. }
  322. else paste = blankString;
  323. #else
  324. if ((clipType == CLIPBOARD_TEXT_LINE) || (clipType == CLIPBOARD_TEXT_MULTI)) {
  325. assert(clipString);
  326. paste = *clipString;
  327. }
  328. else paste = blankString;
  329. #endif
  330. }
  331. void clipboardPasteImageSize(int* width, int* height) { start_func
  332. assert(width);
  333. assert(height);
  334. if (clipType == CLIPBOARD_IMAGE) {
  335. assert(clipImage);
  336. *width = clipImage->w;
  337. *height = clipImage->h;
  338. }
  339. else {
  340. *width = 0;
  341. *height = 0;
  342. }
  343. }
  344. void clipboardPasteImage(SDL_Surface* dest, int x, int y) { start_func
  345. assert(dest);
  346. if (clipType == CLIPBOARD_IMAGE) {
  347. blit(0, 0, clipImage, x, y, dest, clipImage->w, clipImage->h);
  348. }
  349. }
  350. int clipboardPasteColor(Uint8* dest, int count) { start_func
  351. assert(dest);
  352. if (clipType == CLIPBOARD_RGBA) {
  353. if (count > clipColorCount) count = clipColorCount;
  354. memcpy(dest, clipColors, count * 4);
  355. return count;
  356. }
  357. return 0;
  358. }
  359. void clipboardPasteLayerInfo(int* numLayers, int* width, int* height) { start_func
  360. assert(numLayers);
  361. assert(width);
  362. assert(height);
  363. if (clipType == CLIPBOARD_LAYER) {
  364. *numLayers = clipLayerCount;
  365. *width = clipLayerWidth;
  366. *height = clipLayerHeight;
  367. }
  368. else {
  369. *numLayers = 0;
  370. *width = 0;
  371. *height = 0;
  372. }
  373. }
  374. void clipboardPasteLayerInfoDetails(int layer, const void** tileset, int* hasExt, int* hasFx) { start_func
  375. assert(tileset);
  376. assert(hasFx);
  377. if (clipType == CLIPBOARD_LAYER) {
  378. assert(layer >= 0);
  379. assert(layer < clipLayerCount);
  380. *tileset = clipLayerTileSet[layer];
  381. *hasExt = clipLayerExt[layer] ? 1 : 0;
  382. *hasFx = clipLayerFx[layer] ? 1 : 0;
  383. }
  384. else {
  385. *tileset = NULL;
  386. *hasExt = 0;
  387. *hasFx = 0;
  388. }
  389. }
  390. void clipboardPasteLayer(int layer, Uint32* data, Uint32* dataExt, Uint32* dataFx, int x, int y, int width, int height, int pitch, Uint32 defaultData, Uint32 defaultExt, Uint32 defaultFx) { start_func
  391. assert(data);
  392. assert(pitch);
  393. assert(width);
  394. assert(height);
  395. if (clipType == CLIPBOARD_LAYER) {
  396. assert(layer >= 0);
  397. assert(layer < clipLayerCount);
  398. // First, main data
  399. matrixCopy(clipLayerData[layer], data + x + y * pitch, min(width, clipLayerWidth) * 4, min(height, clipLayerHeight), clipLayerWidth * 4, pitch * 4);
  400. // Next, ext?
  401. if (dataExt) {
  402. // Copy or fill?
  403. if (clipLayerExt[layer]) {
  404. matrixCopy(clipLayerExt[layer], dataExt + x + y * pitch, min(width, clipLayerWidth) * 4, min(height, clipLayerHeight), clipLayerWidth * 4, pitch * 4);
  405. }
  406. else {
  407. for (int row = min(height, clipLayerHeight); row > 0; --row) {
  408. memSet32(dataExt + x + (y + row) * pitch, defaultExt, min(width, clipLayerWidth));
  409. }
  410. }
  411. }
  412. // Next, fx?
  413. if (dataFx) {
  414. // Copy or fill?
  415. if (clipLayerFx[layer]) {
  416. matrixCopy(clipLayerFx[layer], dataFx + x + y * pitch, min(width, clipLayerWidth) * 4, min(height, clipLayerHeight), clipLayerWidth * 4, pitch * 4);
  417. }
  418. else {
  419. for (int row = min(height, clipLayerHeight); row > 0; --row) {
  420. memSet32(dataFx + x + (y + row) * pitch, defaultFx, min(width, clipLayerWidth));
  421. }
  422. }
  423. }
  424. }
  425. }
  426. void clipboardPasteSpawnInfo(int* numSpawns, int* numLayers) { start_func
  427. assert(numSpawns);
  428. assert(numLayers);
  429. if (clipType == CLIPBOARD_SPAWN) {
  430. *numSpawns = clipSpawnCount;
  431. *numLayers = clipSpawnCountLayers;
  432. }
  433. else {
  434. *numSpawns = 0;
  435. *numLayers = 0;
  436. }
  437. }
  438. void clipboardPasteSpawn(int spawnNum, SpawnEdit* newSpawn, int* layerNum, int baseX, int baseY) { start_func
  439. assert(clipType == CLIPBOARD_SPAWN);
  440. assert(newSpawn);
  441. assert(layerNum);
  442. assert(spawnNum >= 0);
  443. assert(spawnNum < clipSpawnCount);
  444. *layerNum = clipSpawnLayers[spawnNum];
  445. newSpawn->setPos(clipSpawnData[spawnNum]->getX() + baseX, clipSpawnData[spawnNum]->getY() + baseY);
  446. newSpawn->setName(clipSpawnData[spawnNum]->getName());
  447. newSpawn->setScript(clipSpawnData[spawnNum]->getScript());
  448. newSpawn->setSprite(clipSpawnData[spawnNum]->getAnimgroup(), clipSpawnData[spawnNum]->getTileset(),
  449. clipSpawnData[spawnNum]->getSubid());
  450. }