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文字以内のものにしてください。

232 行
5.6KB

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