1 module editorevents; 2 3 import document; 4 import clipboard; 5 6 public import pixelperfectengine.concrete.eventchainsystem; 7 public import pixelperfectengine.graphics.layers; 8 public import pixelperfectengine.map.mapformat; 9 10 import pixelperfectengine.system.file; 11 12 import std.stdio; 13 import std.conv : to; 14 import sdlang; 15 16 public class WriteToMapVoidFill : UndoableEvent { 17 ITileLayer target; 18 Coordinate area; 19 MappingElement me; 20 MappingElement[] original; 21 public this(ITileLayer target, Coordinate area, MappingElement me){ 22 this.target = target; 23 this.area = area; 24 this.me = me; 25 //mask.length = area.area; 26 } 27 public void redo() { 28 original.length = 0; 29 original.reserve(area.area); 30 for (int y = area.top ; y <= area.bottom ; y++) { 31 for (int x = area.left ; x <= area.right ; x++) { 32 MappingElement o = target.readMapping(x,y); 33 original ~= o; 34 if (o.tileID == 0xFFFF) 35 target.writeMapping(x,y,me); 36 } 37 } 38 } 39 public void undo() { 40 size_t pos; 41 for (int y = area.top ; y <= area.bottom ; y++) { 42 for (int x = area.left ; x <= area.right ; x++) { 43 target.writeMapping(x,y,original[pos]); 44 pos++; 45 } 46 } 47 } 48 } 49 50 public class WriteToMapOverwrite : UndoableEvent { 51 ITileLayer target; 52 Coordinate area; 53 MappingElement me; 54 MappingElement[] original; 55 public this(ITileLayer target, Coordinate area, MappingElement me){ 56 this.target = target; 57 this.area = area; 58 this.me = me; 59 //original.length = (area.width + 1) * (area.height + 1); 60 } 61 public void redo() { 62 original.length = 0; 63 original.reserve(area.area); 64 for(int y = area.top ; y <= area.bottom ; y++){ 65 for(int x = area.left ; x <= area.right ; x++){ 66 original ~= target.readMapping(x,y); 67 target.writeMapping(x,y,me); 68 } 69 } 70 } 71 public void undo() { 72 size_t pos; 73 for (int y = area.top ; y <= area.bottom ; y++) { 74 for (int x = area.left ; x <= area.right ; x++) { 75 target.writeMapping(x,y,original[pos]); 76 pos++; 77 } 78 } 79 } 80 } 81 82 public class WriteToMapSingle : UndoableEvent { 83 ITileLayer target; 84 int x; 85 int y; 86 MappingElement me; 87 MappingElement original; 88 public this(ITileLayer target, int x, int y, MappingElement me) { 89 this.target = target; 90 this.x = x; 91 this.y = y; 92 this.me = me; 93 } 94 public void redo() { 95 original = target.readMapping(x,y); 96 target.writeMapping(x,y,me); 97 /*debug { 98 import std.stdio : writeln; 99 writeln("Layer was written at position ", x, ";", y," with values ", target.readMapping(x,y)); 100 }*/ 101 } 102 public void undo() { 103 target.writeMapping(x,y,original); 104 } 105 } 106 107 public class CreateTileLayerEvent : UndoableEvent { 108 TileLayer creation; 109 MapDocument target; 110 int tX; 111 int tY; 112 int mX; 113 int mY; 114 int pri; 115 string name; 116 string file; 117 bool embed; 118 Tag backup; 119 120 public this(MapDocument target, int tX, int tY, int mX, int mY, dstring name, string file, bool embed) { 121 import std.utf : toUTF8; 122 creation = new TileLayer(tX, tY); 123 creation.setRenderingMode(RenderingMode.Copy); 124 this.target = target; 125 //this.md = md; 126 this.tX = tX; 127 this.tY = tY; 128 this.mX = mX; 129 this.mY = mY; 130 this.name = toUTF8(name); 131 this.file = file; 132 this.embed = embed; 133 //this.imageReturnFunc = imageReturnFunc; 134 } 135 public void redo() { 136 import std.file : exists, isFile; 137 import std.path : baseName; 138 import std.utf : toUTF8; 139 import pixelperfectengine.system.etc : intToHex; 140 if (backup) { //If a backup exists, then re-add that to the document, then return. 141 target.mainDoc.addNewLayer(pri, backup, creation); 142 //target.outputWindow.addLayer(pri); 143 return; 144 } 145 try { 146 const int nextLayer = target.nextLayerNumber; 147 148 //handle the following instances for mapping: 149 //file == null AND embed 150 //file == existing file AND embed 151 //file == existing file AND !embed 152 //file == nonexisting file 153 if ((!exists(file) || !isFile(file)) && embed) { //create new instance for the map by embedding data into the SDLang file 154 //selDoc.mainDoc.tld[nextLayer] = new 155 MappingElement[] me; 156 me.length = mX * mY; 157 creation.loadMapping(mX, mY, me); 158 target.mainDoc.addNewTileLayer(nextLayer, tX, tY, mX, mY, name, creation); 159 target.mainDoc.addEmbeddedMapData(nextLayer, me); 160 } else if (!exists(file)) { //Create empty file 161 File f = File(file, "wb"); 162 MappingElement[] me; 163 me.length = mX * mY; 164 creation.loadMapping(mX, mY, me); 165 target.mainDoc.addNewTileLayer(nextLayer, tX, tY, mX, mY, name, creation); 166 saveMapFile(MapDataHeader(mX, mY), me, f); 167 target.mainDoc.addMapDataFile(nextLayer, file); 168 } else { //load mapping, embed data into current file if needed 169 MapDataHeader mdh; 170 MappingElement[] me = loadMapFile(File(file), mdh); 171 creation.loadMapping(mdh.sizeX, mdh.sizeY, me); 172 target.mainDoc.addNewTileLayer(nextLayer, tX, tY, mX, mY, name, creation); 173 if (embed) 174 target.mainDoc.addEmbeddedMapData(nextLayer, me); 175 else 176 target.mainDoc.addMapDataFile(nextLayer, file); 177 } 178 179 //handle the following instances for materials: 180 //res == image file 181 //TODO: check if material resource file has any embedded resource data 182 //TODO: enable importing from SDLang map files (*.xmf) 183 //TODO: generate dummy tiles for nonexistent material 184 /+if (exists(res)) { 185 //load the resource file and test if it's the correct size (through an exception) 186 source = loadImage(File(res)); 187 ABitmap[] tilesheet; 188 switch (source.getBitdepth()) { 189 case 4: 190 Bitmap4Bit[] output = loadBitmapSheetFromImage!Bitmap4Bit(source, tX, tY); 191 foreach(p; output) 192 tilesheet ~= p; 193 break; 194 case 8: 195 Bitmap8Bit[] output = loadBitmapSheetFromImage!Bitmap8Bit(source, tX, tY); 196 foreach(p; output) 197 tilesheet ~= p; 198 break; 199 case 16: 200 Bitmap16Bit[] output = loadBitmapSheetFromImage!Bitmap16Bit(source, tX, tY); 201 foreach(p; output) 202 tilesheet ~= p; 203 break; 204 case 32: 205 Bitmap32Bit[] output = loadBitmapSheetFromImage!Bitmap32Bit(source, tX, tY); 206 foreach(p; output) 207 tilesheet ~= p; 208 break; 209 default: 210 throw new Exception("Unsupported bitdepth!"); 211 212 } 213 if (tilesheet.length == 0) throw new Exception("No tiles were imported!"); 214 target.addTileSet(nextLayer, tilesheet); 215 target.mainDoc.addsourceFile(nextLayer, res); 216 { 217 TileInfo[] idList; 218 string nameBase = baseName(res); 219 for (int id ; id < tilesheet.length ; id++) { 220 idList ~= TileInfo(cast(wchar)id, id, nameBase ~ "0x" ~ intToHex(id, 4)); 221 //writeln(idList); 222 } 223 target.mainDoc.addTileInfo(nextLayer, idList, res); 224 } 225 if (source.isIndexed) { 226 Color[] palette; 227 /*foreach (color ; source.palette) { 228 palette ~= Color(color.a, color.r, color.g, color.b); 229 debug writeln(color); 230 }*/ 231 auto sourcePalette = source.palette; 232 palette.reserve(sourcePalette.length); 233 for (ushort i ; i < sourcePalette.length ; i++){ 234 const auto origC = sourcePalette[i]; 235 const Color c = Color(origC.a, origC.r, origC.g, origC.b); 236 palette ~= c; 237 } 238 target.mainDoc.addPaletteFile(res, "", cast(int)target.outputWindow.palette.length); 239 target.outputWindow.palette = target.outputWindow.palette ~ palette; 240 //debug writeln(target.outputWindow.palette); 241 } 242 243 }+/ 244 //target.outputWindow.addLayer(nextLayer); 245 target.selectedLayer = nextLayer; 246 pri = nextLayer; 247 target.updateLayerList(); 248 target.updateMaterialList(); 249 } catch (Exception e) { 250 writeln(e); 251 } 252 } 253 public void undo() { 254 //Just remove the added layer from the layerlists 255 //target.outputWindow.removeLayer(pri); 256 backup = target.mainDoc.removeLayer(pri); 257 target.updateLayerList(); 258 target.updateMaterialList(); 259 } 260 } 261 public class ResizeTileMapEvent : UndoableEvent { 262 MappingElement[] backup, destMap; 263 int mX, mY, offsetX, offsetY, newX, newY; 264 MapDocument targetDoc; 265 int layer; 266 bool patternRepeat; 267 this(int[6] params, MapDocument targetDoc, int layer, bool patternRepeat) { 268 mX = params[0]; 269 mY = params[1]; 270 offsetX = params[2]; 271 offsetY = params[3]; 272 newX = params[4]; 273 newY = params[5]; 274 this.targetDoc = targetDoc; 275 this.layer = layer; 276 this.patternRepeat = patternRepeat; 277 } 278 public void redo() { 279 //backup current layer data 280 ITileLayer targetLayer = cast(ITileLayer)targetDoc.mainDoc.layeroutput[layer]; 281 backup = targetLayer.getMapping(); 282 destMap.length = newX * newY; 283 //writeln(destMap.length); 284 if(patternRepeat) { 285 int sX = offsetX % mX, sY = offsetY % mY; 286 for (int iY ; iY < newY ; iY++) { 287 for (int iX ; iX < newX ; iX++) { 288 destMap[iX + (iY * newX)] = backup[sX + (sY * mX)]; 289 sX++; 290 if (sX >= mX) sX = 0; 291 } 292 sY++; 293 if (sY >= mY) sY = 0; 294 } 295 } else { 296 for (int iY ; iY < mY ; iY++) { 297 //Do a boundscheck, if falls outside of it do nothing. If inside, copy. 298 if (iY + offsetY < newY && iY + offsetY >= 0) { 299 for (int iX ; iX < mX ; iX++) { 300 //Do a boundscheck, if falls outside of it do nothing. If inside, copy. 301 if (iX + offsetX < newX && iX + offsetX >= 0) { 302 destMap[iX + offsetX + ((iY + offsetY) * newY)] = backup[iX + (iY * mY)]; 303 } else if (iX + offsetX >= newX) break; 304 } 305 } else if (iY + offsetY >= newY) break; 306 } 307 } 308 targetLayer.loadMapping(newX, newY, destMap); 309 targetDoc.mainDoc.alterTileLayerInfo(layer, 4, newX); 310 targetDoc.mainDoc.alterTileLayerInfo(layer, 5, newY); 311 } 312 public void undo() { 313 ITileLayer targetLayer = cast(ITileLayer)targetDoc.mainDoc.layeroutput[layer]; 314 targetLayer.loadMapping(mX, mY, backup); 315 targetDoc.mainDoc.alterTileLayerInfo(layer, 4, mX); 316 targetDoc.mainDoc.alterTileLayerInfo(layer, 5, mY); 317 } 318 } 319 public class AddTileSheetEvent : UndoableEvent { 320 Image source; 321 MapDocument targetDoc; 322 int layer; 323 int paletteOffset; 324 int paletteShift; 325 string preName, afterName, fileName; 326 int numFrom; 327 uint numStyle; ///0: decimal, 1: hex, 2: octal 328 Tag backup; 329 this(Image source, MapDocument targetDoc, int layer, int paletteOffset, int paletteShift, string[3] name, int numFrom, 330 uint numStyle) { 331 this.source = source; 332 this.targetDoc = targetDoc; 333 this.layer = layer; 334 this.paletteOffset = paletteOffset; 335 this.paletteShift = paletteShift; 336 preName = name[0]; 337 afterName = name[1]; 338 fileName = name[2]; 339 this.numFrom = numFrom; 340 this.numStyle = numStyle; 341 } 342 public void redo() { 343 import pixelperfectengine.system.etc : intToHex, intToOct; 344 //Copy palette if exists (-1 means no palette or do not import palette) 345 if (paletteOffset >= 0) { 346 //Color[] targetPalette = targetDoc.outputWindow.paletteLocal; 347 Color[] importedPalette = loadPaletteFromImage(source); 348 assert(importedPalette.length); 349 const ushort offset = cast(ushort)(paletteOffset << paletteShift); 350 targetDoc.outputWindow.loadPaletteChunk(importedPalette, offset); 351 targetDoc.mainDoc.addPaletteFile(fileName, "", paletteOffset << paletteShift, paletteShift); 352 } 353 if (backup is null) { 354 //TODO: check if material resource file has any embedded resource data 355 //TODO: enable importing from SDLang map files (*.xmf) 356 //TODO: generate dummy tiles for nonexistent material 357 358 //load the resource file and test if it's the correct size (through an exception) 359 //source = loadImage(File(res)); 360 ITileLayer itl = cast(ITileLayer)targetDoc.mainDoc.layeroutput[layer]; 361 const int tX = itl.getTileWidth, tY = itl.getTileHeight; 362 ABitmap[] tilesheet; 363 switch (source.getBitdepth()) { 364 case 4: 365 Bitmap4Bit[] output = loadBitmapSheetFromImage!Bitmap4Bit(source, tX, tY); 366 foreach(p; output) 367 tilesheet ~= p; 368 break; 369 case 8: 370 Bitmap8Bit[] output = loadBitmapSheetFromImage!Bitmap8Bit(source, tX, tY); 371 foreach(p; output) 372 tilesheet ~= p; 373 break; 374 case 16: 375 Bitmap16Bit[] output = loadBitmapSheetFromImage!Bitmap16Bit(source, tX, tY); 376 foreach(p; output) 377 tilesheet ~= p; 378 break; 379 case 32: 380 Bitmap32Bit[] output = loadBitmapSheetFromImage!Bitmap32Bit(source, tX, tY); 381 foreach(p; output) 382 tilesheet ~= p; 383 break; 384 default: 385 throw new Exception("Unsupported bitdepth!"); 386 } 387 if (tilesheet.length == 0) throw new Exception("No tiles were imported!"); 388 targetDoc.addTileSet(layer, tilesheet); 389 targetDoc.mainDoc.addTileSourceFile(layer, fileName, null, 0); 390 { 391 TileInfo[] idList; 392 for (int id ; id < tilesheet.length ; id++) { 393 //idList ~= TileInfo(cast(wchar)id, id, nameBase ~ "0x" ~ intToHex(id, 4)); 394 string tilename = preName; 395 switch(numStyle & 0x3) { 396 case 1: 397 tilename ~= intToHex(id + numFrom, numStyle>>>8); 398 break; 399 case 2: 400 tilename ~= intToOct(id + numFrom, numStyle>>>8); 401 break; 402 default: 403 string num = to!string(id); 404 for (int i ; i < (numStyle>>>8) - num.length ; i++) { 405 tilename ~= '0'; 406 } 407 tilename ~= num; 408 break; 409 } 410 tilename ~= afterName; 411 idList ~= TileInfo(cast(wchar)id, cast(ushort)paletteShift, id, tilename); 412 //writeln(idList); 413 } 414 targetDoc.mainDoc.addTileInfo(layer, idList, fileName, null); 415 } 416 } else { 417 418 } 419 } 420 public void undo() { 421 //remove palette if exists 422 if (paletteOffset >= 0) { 423 const ushort offset = cast(ushort)(paletteOffset << paletteShift); 424 targetDoc.outputWindow.clearPaletteChunk(cast(ushort)source.palette.length, offset); 425 } 426 427 } 428 } 429 /** 430 * Cuts a selected portion of tiles out from a tilelayer. 431 */ 432 public class CutFromTileLayerEvent : UndoableEvent { 433 ITileLayer target; 434 Coordinate area; 435 MappingElement[] original; 436 public this(ITileLayer target, Coordinate area){ 437 this.target = target; 438 this.area = area; 439 } 440 public void redo() { 441 original.length = 0; 442 original.reserve(area.area); 443 for (int y = area.top ; y < area.bottom ; y++) { 444 for (int x = area.left ; x < area.right ; x++) { 445 MappingElement o = target.readMapping(x,y); 446 original ~= o; 447 target.writeMapping(x,y,MappingElement.init); 448 } 449 } 450 } 451 public void undo() { 452 size_t pos; 453 for (int y = area.top ; y < area.bottom ; y++) { 454 for (int x = area.left ; x < area.right ; x++) { 455 target.writeMapping(x,y,original[pos]); 456 pos++; 457 } 458 } 459 } 460 } 461 /** 462 * Pastes a copied area to a given tilelayer. 463 */ 464 public class PasteIntoTileLayerEvent : UndoableEvent { 465 MapClipboard.Item item; 466 ITileLayer target; 467 Point position; 468 MappingElement[] original; 469 bool overwrite; 470 public this (MapClipboard.Item item, ITileLayer target, Point position, bool overwrite = true) { 471 this.item = item; 472 this.target = target; 473 this.position = position; 474 this.overwrite = overwrite; 475 } 476 477 public void redo() { 478 original.length = 0; 479 original.reserve(item.width * item.height); 480 if (overwrite) { 481 for (int y = position.y, y0 ; y0 < item.height ; y++, y0++) { 482 for (int x = position.x, x0 ; x0 < item.width ; x++, x0++) { 483 MappingElement o = target.readMapping(x,y); 484 original ~= o; 485 target.writeMapping(x,y,item.map[x0 + (y0 * item.width)]); 486 } 487 } 488 } else { 489 for (int y = position.y, y0 ; y0 < item.height ; y++, y0++) { 490 for (int x = position.x, x0 ; x0 < item.width ; x++, x0++) { 491 MappingElement o = target.readMapping(x,y), n = item.map[x0 + (y0 * item.width)]; 492 original ~= o; 493 if (n.tileID != 0xFFFF) 494 target.writeMapping(x,y,n); 495 } 496 } 497 } 498 } 499 500 public void undo() { 501 size_t pos; 502 for (int y = position.y ; y < position.y + item.height ; y++) { 503 for (int x = position.x ; x < position.x + item.width ; x++) { 504 target.writeMapping(x,y,original[pos]); 505 pos++; 506 } 507 } 508 } 509 } 510 /** 511 * Removes a single tile. 512 */ 513 public class RemoveTile : UndoableEvent { 514 int id; 515 MapDocument targetDoc; 516 int layer; 517 Tag infobackup; 518 ABitmap bitmapbackup; 519 string source, dpkSource; 520 this (int id, MapDocument targetDoc, int layer) { 521 this.id = id; 522 this.targetDoc = targetDoc; 523 this.layer = layer; 524 } 525 526 public void redo() { 527 infobackup = targetDoc.mainDoc.removeTile(layer, id, source, dpkSource); 528 TileLayer tl = cast(TileLayer)targetDoc.mainDoc.layeroutput[layer]; 529 bitmapbackup = tl.getTile(cast(wchar)id); 530 tl.removeTile(cast(wchar)id); 531 targetDoc.updateMaterialList(); 532 } 533 534 public void undo() { 535 targetDoc.mainDoc.addTile(layer, infobackup, source, dpkSource); 536 Tag t = targetDoc.mainDoc.getTileSourceTag(layer, source, dpkSource); 537 TileLayer tl = cast(TileLayer)targetDoc.mainDoc.layeroutput[layer]; 538 tl.addTile(bitmapbackup, cast(wchar)id, cast(ubyte)(t.getAttribute!int("palShift"))); 539 targetDoc.updateMaterialList(); 540 } 541 } 542 /** 543 * Renames a single tile 544 */ 545 public class RenameTile : UndoableEvent { 546 int id; 547 MapDocument targetDoc; 548 int layer; 549 string oldName, newName; 550 551 this (int id, MapDocument targetDoc, int layer, string newName) { 552 this.id = id; 553 this.targetDoc = targetDoc; 554 this.layer = layer; 555 this.newName = newName; 556 } 557 558 public void redo() { 559 oldName = targetDoc.mainDoc.renameTile(layer, id, newName); 560 targetDoc.updateMaterialList(); 561 } 562 563 public void undo() { 564 targetDoc.mainDoc.renameTile(layer, id, oldName); 565 targetDoc.updateMaterialList(); 566 } 567 } 568 /** 569 * Removes a layer. 570 */ 571 public class RemoveLayer : UndoableEvent { 572 MapDocument targetDoc; 573 int layer; 574 Tag infobackup; 575 Layer databackup; 576 this (MapDocument targetDoc, int layer) { 577 this.targetDoc = targetDoc; 578 this.layer = layer; 579 } 580 581 public void redo() { 582 infobackup = targetDoc.mainDoc.layerData.remove(layer); 583 databackup = targetDoc.mainDoc.layeroutput.remove(layer); 584 targetDoc.updateLayerList(); 585 } 586 587 public void undo() { 588 targetDoc.mainDoc.layerData[layer] = infobackup; 589 targetDoc.mainDoc.layeroutput[layer] = databackup; 590 targetDoc.updateLayerList(); 591 } 592 } 593 /** 594 * Renames a layer. 595 */ 596 public class RenameLayer : UndoableEvent { 597 MapDocument targetDoc; 598 int layer; 599 string oldName, newName; 600 this (MapDocument targetDoc, int layer, string newName) { 601 this.targetDoc = targetDoc; 602 this.layer = layer; 603 this.newName = newName; 604 } 605 606 public void redo() { 607 try { 608 Tag t = targetDoc.mainDoc.layerData[layer]; 609 oldName = t.values[0].get!string(); 610 t.values[0] = Value(newName); 611 } catch (DOMException e) { 612 debug writeln(e); 613 } catch (Exception e) { 614 debug writeln(e); 615 } 616 targetDoc.updateLayerList(); 617 } 618 619 public void undo() { 620 try { 621 Tag t = targetDoc.mainDoc.layerData[layer]; 622 //newName = t.values[0].get!string(); 623 t.values[0] = Value(oldName); 624 } catch (DOMException e) { 625 debug writeln(e); 626 } catch (Exception e) { 627 debug writeln(e); 628 } 629 targetDoc.updateLayerList(); 630 } 631 } 632 /** 633 * Moves a layer in the priority list. 634 */ 635 public class ChangeLayerPriority : UndoableEvent { 636 MapDocument targetDoc; 637 int layer; 638 int newPri; 639 this (MapDocument targetDoc, int layer, int newPri) { 640 this.targetDoc = targetDoc; 641 this.layer = layer; 642 this.newPri = newPri; 643 } 644 645 public void redo() { 646 targetDoc.mainDoc.layerData[newPri] = targetDoc.mainDoc.layerData.remove(layer); 647 targetDoc.mainDoc.layeroutput[newPri] = targetDoc.mainDoc.layeroutput.remove(layer); 648 targetDoc.mainDoc.layerData[newPri].values[1] = Value(newPri); 649 targetDoc.selectedLayer = newPri; 650 targetDoc.updateLayerList(); 651 } 652 653 public void undo() { 654 targetDoc.mainDoc.layerData[layer] = targetDoc.mainDoc.layerData.remove(newPri); 655 targetDoc.mainDoc.layeroutput[layer] = targetDoc.mainDoc.layeroutput.remove(newPri); 656 targetDoc.mainDoc.layerData[layer].values[1] = Value(layer); 657 targetDoc.selectedLayer = layer; 658 targetDoc.updateLayerList(); 659 } 660 } 661 /** 662 * Flips all selected tiles horizontally. 663 */ 664 public class FlipSelTilesH : UndoableEvent { 665 ITileLayer target; 666 Box area; 667 MappingElement[] backup; 668 669 this (ITileLayer target, Box area) { 670 this.target = target; 671 this.area = area; 672 backup.length = area.area; 673 int i; 674 for (int y = area.top ; y <= area.bottom ; y++) { 675 for (int x = area.left ; x <= area.right ; x++, i++) { 676 MappingElement w = target.readMapping(x, y); 677 backup[i] = w; 678 } 679 } 680 } 681 682 public void redo() { 683 for (int y = area.top ; y <= area.bottom ; y++) { 684 for (int x = area.left ; x <= area.right ; x++) { 685 MappingElement w = target.readMapping(x, y); 686 w.attributes.horizMirror = !w.attributes.horizMirror; 687 target.writeMapping(x, y, w); 688 } 689 } 690 } 691 692 public void undo() { 693 int i; 694 for (int y = area.top ; y <= area.bottom ; y++) { 695 for (int x = area.left ; x <= area.right ; x++, i++) { 696 target.writeMapping(x, y, backup[i]); 697 } 698 } 699 } 700 } 701 /** 702 * Flips all selected tiles vertically. 703 */ 704 public class FlipSelTilesV : UndoableEvent { 705 ITileLayer target; 706 Box area; 707 MappingElement[] backup; 708 709 this (ITileLayer target, Box area) { 710 this.target = target; 711 this.area = area; 712 backup.length = area.area; 713 int i; 714 for (int y = area.top ; y <= area.bottom ; y++) { 715 for (int x = area.left ; x <= area.right ; x++, i++) { 716 MappingElement w = target.readMapping(x, y); 717 backup[i] = w; 718 } 719 } 720 } 721 722 public void redo() { 723 for (int y = area.top ; y <= area.bottom ; y++) { 724 for (int x = area.left ; x <= area.right ; x++) { 725 MappingElement w = target.readMapping(x, y); 726 w.attributes.vertMirror = !w.attributes.vertMirror; 727 target.writeMapping(x, y, w); 728 } 729 } 730 } 731 732 public void undo() { 733 int i; 734 for (int y = area.top ; y <= area.bottom ; y++) { 735 for (int x = area.left ; x <= area.right ; x++, i++) { 736 target.writeMapping(x, y, backup[i]); 737 } 738 } 739 } 740 } 741 /** 742 * Mirrors selection horizontally. (Tile Layer) 743 */ 744 public class MirrorSelHTL : UndoableEvent { 745 ITileLayer target; 746 Box area; 747 MappingElement[] backup; 748 749 this (ITileLayer target, Box area) { 750 this.target = target; 751 this.area = area; 752 int i; 753 backup.length = area.area; 754 for (int y = area.top ; y <= area.bottom ; y++) { 755 for (int x = area.left ; x <= area.right ; x++, i++) { 756 backup[i] = target.readMapping(x, y); 757 } 758 } 759 } 760 761 public void redo() { 762 for (int y0 = area.top ; y0 <= area.bottom ; y0++) { 763 for (int x0 = area.left, x1 = area.right ; x0 < x1 ; x0++, x1--) { 764 MappingElement w = target.readMapping(x0, y0); 765 target.writeMapping(x0, y0, target.readMapping(x1, y0)); 766 target.writeMapping(x1, y0, w); 767 } 768 } 769 } 770 771 public void undo() { 772 int i; 773 for (int y = area.top ; y <= area.bottom ; y++) { 774 for (int x = area.left ; x <= area.right ; x++, i++) { 775 target.writeMapping(x, y, backup[i]); 776 } 777 } 778 } 779 } 780 /** 781 * Mirrors selection vertically. (Tile Layer) 782 */ 783 public class MirrorSelVTL : UndoableEvent { 784 ITileLayer target; 785 Box area; 786 MappingElement[] backup; 787 788 this (ITileLayer target, Box area) { 789 this.target = target; 790 this.area = area; 791 int i; 792 backup.length = area.area; 793 for (int y = area.top ; y <= area.bottom ; y++) { 794 for (int x = area.left ; x <= area.right ; x++, i++) { 795 backup[i] = target.readMapping(x, y); 796 } 797 } 798 } 799 800 public void redo() { 801 for (int y0 = area.top, y1 = area.bottom ; y0 < y1 ; y0++, y1--) { 802 for (int x0 = area.left ; x0 <= area.right ; x0++) { 803 MappingElement w = target.readMapping(x0, y0); 804 target.writeMapping(x0, y0, target.readMapping(x0, y1)); 805 target.writeMapping(x0, y1, w); 806 } 807 } 808 } 809 810 public void undo() { 811 int i; 812 for (int y = area.top ; y <= area.bottom ; y++) { 813 for (int x = area.left ; x <= area.right ; x++, i++) { 814 target.writeMapping(x, y, backup[i++]); 815 } 816 } 817 } 818 } 819 /** 820 * Mirrors selection both horizontally and vertically. (Tile Layer) 821 */ 822 public class MirrorSelBTL : UndoableEvent { 823 ITileLayer target; 824 Box area; 825 MappingElement[] backup; 826 827 this (ITileLayer target, Box area) { 828 this.target = target; 829 this.area = area; 830 int i; 831 backup.length = area.area; 832 for (int y = area.top ; y <= area.bottom ; y++) { 833 for (int x = area.left ; x <= area.right ; x++, i++) { 834 backup[i] = target.readMapping(x, y); 835 } 836 } 837 } 838 839 public void redo() { 840 for (int y0 = area.top, y1 = area.bottom ; y0 < y1 ; y0++, y1--) { 841 for (int x0 = area.left, x1 = area.right ; x0 < x1 ; x0++, x1--) { 842 MappingElement w = target.readMapping(x0, y0); 843 target.writeMapping(x0, y0, target.readMapping(x1, y1)); 844 target.writeMapping(x1, y1, w); 845 } 846 } 847 } 848 849 public void undo() { 850 int i; 851 for (int y = area.top ; y <= area.bottom ; y++) { 852 for (int x = area.left ; x <= area.right ; x++, i++) { 853 target.writeMapping(x, y, backup[i]); 854 } 855 } 856 } 857 } 858 /** 859 * Imports mapping data to a layer. 860 */ 861 public class ImportLayerData : UndoableEvent { 862 ITileLayer target; 863 Tag dataTarget; 864 MappingElement[] newData; 865 MappingElement[] backup; 866 int width, height; 867 int buw, buh; 868 869 this(ITileLayer target, Tag dataTarget, MappingElement[] newData, int width, int height) { 870 this.target = target; 871 this.dataTarget = dataTarget; 872 this.newData = newData; 873 this.width = width; 874 this.height = height; 875 buw = target.getMX(); 876 buh = target.getMY(); 877 backup = target.getMapping(); 878 } 879 880 public void redo() { 881 dataTarget.values[4] = Value(width); 882 dataTarget.values[5] = Value(height); 883 target.loadMapping(width, height, newData); 884 } 885 886 public void undo() { 887 dataTarget.values[4] = Value(buw); 888 dataTarget.values[5] = Value(buh); 889 target.loadMapping(buw, buh, backup); 890 } 891 }