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个字符

306 行
7.6KB

  1. import GlobalEvents from "/app/js/common/EventCaller.js";
  2. import Utils from "/app/js/common/Utils.js";
  3. import NESPalette from "/app/js/models/NESPalette.js";
  4. const PLI_TEMPLATE = "palette-list-item-template";
  5. const PLI_TITLE = "title";
  6. const PLI_SELECTED = "list-item-selected";
  7. const PLI_BG_COLOR = "pal-bg-color";
  8. const PLI_FG_BASE = "pal-fg-";
  9. const PLI_BG_BASE = "pal-bg-";
  10. const PLI_COLOR_BASE = "nes-color-bg-";
  11. var Palettes = [];
  12. var CurrentPaletteIndex = 0;
  13. var BlockEmits = false;
  14. function HANDLE_PaletteClick(e){
  15. if (!this.hasAttribute("palname")){return;}
  16. var pname = this.getAttribute("palname");
  17. if (Palettes.length > 0){
  18. if (Palettes[CurrentPaletteIndex][0] !== pname || !Palettes[CurrentPaletteIndex][2].classList.contains(PLI_SELECTED)){
  19. var oel = Palettes[CurrentPaletteIndex][2];
  20. oel.classList.remove(PLI_SELECTED);
  21. for (let i=0; i < Palettes.length; i++){
  22. if (Palettes[i][0] === pname){
  23. Palettes[i][2].classList.add(PLI_SELECTED);
  24. CurrentPaletteIndex = i;
  25. GlobalEvents.emit("set_app_palette", Palettes[i][1]);
  26. break;
  27. }
  28. }
  29. }
  30. }
  31. }
  32. function SetElPaletteName(el, pname){
  33. el.setAttribute("palname", pname);
  34. var sel = el.querySelectorAll("." + PLI_TITLE);
  35. if (sel.length === 1){
  36. sel = sel[0];
  37. sel.innerHTML = pname;
  38. }
  39. }
  40. function SetElToColor(el, mode, pi, ci, hex){
  41. var cel = null;
  42. if (ci === 0){
  43. cel = el.querySelectorAll("." + PLI_BG_COLOR);
  44. } else {
  45. cel = el.querySelectorAll("." + ((mode == 0) ? PLI_FG_BASE : PLI_BG_BASE) + pi + "-" + ci);
  46. }
  47. if (cel !== null && cel.length === 1){
  48. cel = cel[0];
  49. var clist = cel.getAttribute("class").split(" ");
  50. for (let i=0; i < clist.length; i++){
  51. if (clist[i].startsWith(PLI_COLOR_BASE)){
  52. cel.classList.remove(clist[i]);
  53. break;
  54. }
  55. }
  56. cel.classList.add(PLI_COLOR_BASE + hex.toUpperCase());
  57. }
  58. }
  59. function ColorElementToPalette(el, palette){
  60. SetElToColor(
  61. el, 0,
  62. 0, 0,
  63. palette.get_palette_syscolor_index(0,0,true)
  64. );
  65. for (let p=0; p < 8; p++){
  66. for (let c=1; c < 4; c++){
  67. SetElToColor(
  68. el, (p >= 4) ? 0 : 1,
  69. p%4, c,
  70. palette.get_palette_syscolor_index(p,c,true)
  71. );
  72. }
  73. }
  74. }
  75. function ConnectElementToPalette(el, palette){
  76. palette.listen("palettes_changed", (e) => {
  77. if (e.type == "ALL"){
  78. if (e.hasOwnProperty("cindex")){
  79. SetElToColor(
  80. el, 0,
  81. 0, 0,
  82. palette.get_palette_syscolor_index(0,0,true)
  83. );
  84. } else {
  85. ColorElementToPalette(el, palette);
  86. }
  87. } else if (e.type == "SPRITE"){
  88. SetElToColor(
  89. el, 0,
  90. e.pindex%4, e.cindex,
  91. palette.get_palette_syscolor_index(e.pindex, e.cindex, true)
  92. );
  93. } else if (e.type == "TILE"){
  94. SetElToColor(
  95. el, 1,
  96. e.pindex, e.cindex,
  97. palette.get_palette_syscolor_index(e.pindex, e.cindex, true)
  98. );
  99. }
  100. });
  101. }
  102. function CreatePaletteDOMEntry(pname, palette){
  103. var oel = document.querySelectorAll("." + PLI_TEMPLATE);
  104. if (oel.length == 1){
  105. var el = oel[0].cloneNode(true);
  106. el.classList.remove(PLI_TEMPLATE);
  107. el.classList.remove("hidden");
  108. ConnectElementToPalette(el, palette);
  109. ColorElementToPalette(el, palette);
  110. SetElPaletteName(el, pname);
  111. el.addEventListener("click", HANDLE_PaletteClick);
  112. oel[0].parentNode.appendChild(el);
  113. return el;
  114. } else {
  115. console.log("WARNING: Multiple templates found. Ambigous state.");
  116. }
  117. return null;
  118. }
  119. class CTRLPalettesStore{
  120. constructor(){
  121. GlobalEvents.listen("palstore-add", (function(e){
  122. if (e.hasOwnProperty("palname")){
  123. this.createPalette(e.palname);
  124. this.activatePalette(e.palname);
  125. }
  126. }).bind(this));
  127. GlobalEvents.listen("palstore-remove", (function(e){
  128. this.removePalette(Palettes[CurrentPaletteIndex][0]);
  129. }).bind(this));
  130. }
  131. get json(){
  132. var d = {
  133. cpi: CurrentPaletteIndex,
  134. pals: []
  135. };
  136. for (let i=0; i < Palettes.length; i++){
  137. d.pals.push([Palettes[i][0], Palettes[i][1].json]);
  138. }
  139. return JSON.stringify(d);
  140. }
  141. set json(j){
  142. try {
  143. var d = JSON.parse(j);
  144. } catch (e) {
  145. throw e;
  146. }
  147. if (d.hasOwnProperty("cpi") && d.hasOwnProperty("pals")){
  148. if (Utils.isInt(d.cpi) && d.pals instanceof Array){
  149. var newPalettes = []
  150. for (let i=0; i < d.pals.length; i++){
  151. if (d.pals[i] instanceof Array){
  152. if (this.getPalette(d.pals[i][0]) === null){
  153. this.createPalette(d.pals[i][0], d.pals[i][1]);
  154. }
  155. }
  156. }
  157. CurrentPaletteIndex = 0
  158. if (Palettes.length > 0){
  159. if (d.cpi >= 0 && d.cpi < Palettes.length){
  160. CurrentPaletteIndex = d.cpi;
  161. }
  162. GlobalEvents.emit("set_app_palette", Palettes[CurrentPaletteIndex][1]);
  163. }
  164. } else {
  165. throw new TypeError("JSON Property Value types invalid.");
  166. }
  167. } else {
  168. throw new TypeError("JSON missing expected properties.");
  169. }
  170. }
  171. initialize(){
  172. if (Palettes.length <= 0)
  173. this.createPalette("Palette");
  174. return this;
  175. }
  176. paletteIndexFromName(name){
  177. for (let i=1; i < Palettes.length; i++){
  178. if (Palettes[i][0] == name){
  179. return i;
  180. }
  181. }
  182. return -1;
  183. }
  184. getPalette(name){
  185. var i = this.paletteIndexFromName(name);
  186. return (i >= 0) ? Palettes[i][1] : null;
  187. }
  188. createPalette(name, pjson){
  189. var palette = this.getPalette(name);
  190. if (palette === null){
  191. palette = new NESPalette();
  192. if (typeof(pjson) === "string"){
  193. try {
  194. palette.json = pjson;
  195. } catch (e) {
  196. console.log("Failed to create palette.", e.toString());
  197. palette = null;
  198. }
  199. } else {
  200. palette.set_palette([
  201. "0F",
  202. "05","06","07",
  203. "09","0A","0B",
  204. "01","02","03",
  205. "0D","00","20",
  206. "15","16","17",
  207. "19","1A","1B",
  208. "11","21","31",
  209. "1D","10","30"
  210. ]);
  211. }
  212. if (palette !== null){
  213. var el = CreatePaletteDOMEntry(name, palette);
  214. Palettes.push([name, palette, el]);
  215. if (Palettes.length <= 1 && !BlockEmits){
  216. //GlobalEvents.emit("set_app_palette", palette);
  217. el.click();
  218. }
  219. }
  220. }
  221. return this;
  222. }
  223. removePalette(name){
  224. for (let i=0; i < Palettes.length; i++){
  225. if (Palettes[i][0] === name){
  226. if (CurrentPaletteIndex === i){
  227. CurrentPaletteIndex = 0;
  228. this.activatePalette(Palettes[0][0]);
  229. }
  230. Palettes[i][2].parentNode.removeChild(Palettes[i][2]);
  231. Palettes.splice(i, 1);
  232. }
  233. }
  234. if (Palettes.length <= 0){
  235. this.createPalette("Palette");
  236. } else {
  237. Palettes[CurrentPaletteIndex][2].click();
  238. }
  239. return this;
  240. }
  241. renamePalette(oldname, newname){
  242. var i = paletteIndexFromName(oldname);
  243. if (i < 0)
  244. throw new ValueError("Failed to find palette named '" + oldname +"'. Cannot rename.");
  245. Palettes[i][0] = newname;
  246. SetElPaletteName(Palettes[i][2], newname);
  247. return this;
  248. }
  249. activatePalette(name){
  250. var i = this.paletteIndexFromName(name);
  251. if (i >= 0 && CurrentPaletteIndex !== i){
  252. Palettes[CurrentPaletteIndex][2].click();
  253. //if (!BlockEmits){
  254. // GlobalEvents.emit("set_app_palette", Palettes[CurrentPaletteIndex][1]);
  255. //}
  256. }
  257. return this;
  258. }
  259. clear(){
  260. for (let i=0; i < Palettes.length; i++){
  261. Palettes[i][2].parentNode.removeChild(Palettes[i][2]);
  262. }
  263. CurrentPaletteIndex = 0;
  264. }
  265. }
  266. const instance = new CTRLPalettesStore();
  267. export default instance;