A pixel art painter geared specifically at NES pixel art. Includes export for .chr binary file as well as palette and namespace data.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

213 行
5.1KB

  1. import GlobalEvents from "/app/js/common/EventCaller.js";
  2. import Utils from "/app/js/common/Utils.js";
  3. import Renderer from "/app/js/ui/Renderer.js";
  4. import NESBank from "/app/js/models/NESBank.js";
  5. import NESPalette from "/app/js/models/NESPalette.js";
  6. const BLI_TEMPLATE = "bank-list-item-template";
  7. const BLI_CANVAS = "bank-img";
  8. const BLI_TITLE = "title";
  9. const BLI_SELECTED = "list-item-selected";
  10. var Banks = {};
  11. var CurrentBank = "";
  12. function HANDLE_BankClick(e){
  13. var name = this.getAttribute("bankname");
  14. if (name !== CurrentBank){
  15. if (CurrentBank !== "")
  16. Banks[CurrentBank].el.classList.remove(BLI_SELECTED);
  17. CurrentBank = name;
  18. Banks[CurrentBank].el.classList.add(BLI_SELECTED);
  19. GlobalEvents.emit("change_surface", Banks[CurrentBank].bank);
  20. }
  21. }
  22. function SetElBankName(el, name){
  23. el.setAttribute("bankname", name);
  24. var sel = el.querySelector("." + BLI_TITLE);
  25. if (sel){
  26. sel.innerHTML = name;
  27. }
  28. }
  29. var RenderBankToEl = Utils.throttle(function(el, bank){
  30. var cnv = el.querySelector("." + BLI_CANVAS);
  31. var ctx = cnv.getContext("2d");
  32. Renderer.renderToFit(bank, ctx);
  33. }, 500); // Only update twice a second.
  34. function HANDLE_BankDataChange(bank, e){
  35. RenderBankToEl(this, bank);
  36. }
  37. function ConnectElementToBank(el, bank){
  38. bank.listen("data_changed", HANDLE_BankDataChange.bind(el, bank));
  39. }
  40. function CreateBankDOMEntry(name, bank){
  41. var baseel = document.querySelector("." + BLI_TEMPLATE);
  42. if (!baseel){
  43. console.log("WARNING: Failed to find bank list item template.");
  44. return null;
  45. }
  46. var el = baseel.cloneNode(true);
  47. el.classList.remove(BLI_TEMPLATE);
  48. el.classList.remove("hidden");
  49. el.setAttribute("bankname", name);
  50. ConnectElementToBank(el, bank);
  51. SetElBankName(el, name);
  52. el.addEventListener("click", HANDLE_BankClick);
  53. baseel.parentNode.appendChild(el);
  54. setTimeout(()=>{
  55. RenderBankToEl(el, bank);
  56. }, 500); // Make the render call in about a half second. Allow DOM time to catch up?
  57. return el;
  58. }
  59. class CTRLBanksStore{
  60. constructor(){
  61. var HANDLE_ChangeSurface = function(surf){
  62. if (!(surf instanceof NESBank)){
  63. if (CurrentBank !== ""){
  64. Banks[CurrentBank].el.classList.remove(BLI_SELECTED);
  65. CurrentBank = "";
  66. }
  67. } else {
  68. if (Banks.length <= 0 || (CurrentBank !== "" && Banks[CurrentBank].bank !== surf)){
  69. console.log("WARNING: Bank object being set outside of Bank Store.");
  70. }
  71. }
  72. }
  73. GlobalEvents.listen("change_surface", HANDLE_ChangeSurface);
  74. GlobalEvents.listen("bankstore-add", (function(e){
  75. if (e.hasOwnProperty("bankname")){
  76. this.createBank(e.bankname);
  77. this.activateBank(e.bankname);
  78. }
  79. }).bind(this));
  80. GlobalEvents.listen("bankstore-remove", (function(e){
  81. if (CurrentBank !== "")
  82. this.removeBank(CurrentBank);
  83. }).bind(this));
  84. }
  85. get length(){
  86. return Object.keys(Banks).length;
  87. }
  88. get json(){
  89. var data = [];
  90. Object.keys(Banks).forEach((key) => {
  91. if (Banks.hasOwnProperty(key)){
  92. data.push({name:key, data:Banks[key].bank.base64});
  93. }
  94. });
  95. return JSON.stringify(data);
  96. }
  97. initialize(){
  98. if (this.length <= 0){
  99. this.createBank("Bank");
  100. }
  101. return this;
  102. }
  103. createBank(name, bbase64){
  104. if (!(name in Banks)){
  105. var bank = new NESBank();
  106. if (typeof(bbase64) === "string"){
  107. try {
  108. bank.base64 = bbase64;
  109. } catch (e) {
  110. console.log("Failed to create Bank. " + e.toString());
  111. bank = null;
  112. }
  113. }
  114. if (bank !== null){
  115. var el = CreateBankDOMEntry(name, bank);
  116. if (el){
  117. Banks[name] = {bank:bank, el:el};
  118. //Banks.push([name, bank, el]);
  119. if (this.length <= 1){
  120. Banks[name].el.click();
  121. //GlobalEvents.emit("change_surface", bank);
  122. }
  123. }
  124. }
  125. }
  126. return this;
  127. }
  128. removeBank(name){
  129. if (name in Banks){
  130. if (name === CurrentBank){
  131. var keys = Object.keys(Banks);
  132. if (keys.length > 1){
  133. CurrentBank = (keys[0] !== name) ? keys[0] : keys[1];
  134. } else {
  135. CurrentBank = "";
  136. }
  137. }
  138. Banks[name].el.parentNode.removeChild(Banks[name].el);
  139. delete Banks[name];
  140. if (CurrentBank !== ""){
  141. Banks[CurrentBank].el.click();
  142. } else {
  143. GlobalEvents.emit("change_surface", null);
  144. }
  145. }
  146. return this;
  147. }
  148. renameBank(name, newname){
  149. if ((name in Banks) && !(newname in Banks)){
  150. Banks[newname] = Banks[name];
  151. delete Banks[name];
  152. SetElBankName(Banks[newname].el, newname);
  153. }
  154. return this;
  155. }
  156. activateBank(name){
  157. if (CurrentBank !== name && (name in Banks)){
  158. Banks[name].el.click();
  159. //CurrentBank = name;
  160. //GlobalEvents.emit("change_surface", Banks[CurrentBank].bank);
  161. }
  162. return this;
  163. }
  164. clear(){
  165. Object.keys(Banks).forEach((item) => {
  166. item.el.parentNode.removeChild(item.el);
  167. });
  168. Banks = {};
  169. if (CurrentBank !== "")
  170. GlobalEvents.emit("change_surface", null);
  171. CurrentBank = "";
  172. }
  173. }
  174. const instance = new CTRLBanksStore();
  175. export default instance;