|
227 | 227 | let gRGBW = false, memu = 0; |
228 | 228 | let busMA = 0; |
229 | 229 | let sLC = 0, sPC = 0, sDI = 0, maxLC = 0; |
230 | | - const abl = d.Sf.ABL.checked; |
231 | | - let setPinConfig = (n,t) => { |
232 | | - let p0d = "GPIO: "; |
233 | | - let p1d = ""; |
234 | | - let off = "Off Refresh"; |
235 | | - switch (gT(t).t.charAt(0)) { |
236 | | - case '2': // 2 pin digital |
237 | | - p1d = "Clock "+p0d; |
238 | | - // fallthrough |
239 | | - case 'D': // digital |
240 | | - p0d = "Data "+p0d; |
241 | | - break; |
242 | | - case 'A': // PWM analog |
243 | | - if (numPins(t) > 1) p0d = "GPIOs: "; |
244 | | - off = "Dithering"; |
245 | | - break; |
246 | | - case 'N': // network |
247 | | - p0d = "IP address: "; |
248 | | - break; |
249 | | - case 'V': // virtual/non-GPIO based |
250 | | - p0d = "Config: " |
251 | | - break; |
252 | | - case 'H': // HUB75 |
253 | | - p0d = "Panel size (width x height), Panel count:" |
254 | | - break; |
255 | | - } |
256 | | - gId("p0d"+n).innerText = p0d; |
257 | | - gId("p1d"+n).innerText = p1d; |
258 | | - gId("off"+n).innerText = off; |
259 | | - // secondary pins show/hide (type string length is equivalent to number of pins used; except for network and on/off) |
260 | | - let pins = Math.max(gT(t).t.length,1) + 3*isNet(t) + 2*isHub75(t); // fixes network pins to 4 |
261 | | - for (let p=1; p<5; p++) { |
262 | | - var LK = d.Sf["L"+p+n]; |
263 | | - if (!LK) continue; |
264 | | - LK.style.display = (p < pins) ? "inline" : "none"; |
265 | | - LK.required = (p < pins); |
266 | | - if (p >= pins) LK.value=""; |
267 | | - } |
268 | | - } |
269 | 230 |
|
270 | 231 | // enable/disable LED fields |
271 | 232 | updateTypeDropdowns(change); |
|
274 | 235 | LTs.forEach((s,i)=>{ |
275 | 236 | var n = s.name.substring(2,3); // bus number (0-Z) |
276 | 237 | var t = parseInt(s.value); |
277 | | - memu += getMem(t, n); // calc memory |
278 | | - dC += (isDig(t) && !isD2P(t)); |
279 | | - setPinConfig(n,t); |
280 | | - gId("abl"+n).style.display = (!abl || !isDig(t)) ? "none" : "inline"; // show/hide individual ABL settings |
281 | | - if (change) { // did we change LED type? |
282 | | - gId("rf"+n).checked = (gId("rf"+n).checked || t == 31); // LEDs require data in off state (mandatory for TM1814) |
283 | | - if (isAna(t)) d.Sf["LC"+n].value = 1; // for sanity change analog count just to 1 LED |
284 | | - d.Sf["LA"+n].min = (!isDig(t) || !abl) ? 0 : 1; // set minimum value for LED mA |
285 | | - d.Sf["MA"+n].min = (!isDig(t)) ? 0 : 250; // set minimum value for PSU mA |
286 | | - } |
287 | | - gId("rf"+n).onclick = mustR(t) ? (()=>{return false}) : (()=>{}); // prevent change change of "Refresh" checkmark when mandatory |
288 | | - gRGBW |= hasW(t); // RGBW checkbox |
289 | | - gId("co"+n).style.display = (isVir(t) || isAna(t) || isHub75(t)) ? "none":"inline"; // hide color order for PWM |
290 | | - gId("dig"+n+"w").style.display = (isDig(t) && hasW(t)) ? "inline":"none"; // show swap channels dropdown |
291 | | - gId("dig"+n+"w").querySelector("[data-opt=CCT]").disabled = !hasCCT(t); // disable WW/CW swapping |
292 | | - if (!(isDig(t) && hasW(t))) d.Sf["WO"+n].value = 0; // reset swapping |
293 | | - gId("dig"+n+"c").style.display = (isAna(t) || isHub75(t)) ? "none":"inline"; // hide count for analog |
294 | | - gId("dig"+n+"r").style.display = (isVir(t)) ? "none":"inline"; // hide reversed for virtual |
295 | | - gId("dig"+n+"s").style.display = (isVir(t) || isAna(t) || isHub75(t)) ? "none":"inline"; // hide skip 1st for virtual & analog |
296 | | - gId("dig"+n+"f").style.display = (isDig(t) || (isPWM(t) && maxL>2048)) ? "inline":"none"; // hide refresh (PWM hijacks reffresh for dithering on ESP32) |
297 | | - gId("dig"+n+"a").style.display = (hasW(t)) ? "inline":"none"; // auto calculate white |
298 | | - gId("dig"+n+"l").style.display = (isD2P(t) || isPWM(t)) ? "inline":"none"; // bus clock speed / PWM speed (relative) (not On/Off) |
299 | | - gId("rev"+n).innerHTML = isAna(t) ? "Inverted output":"Reversed"; // change reverse text for analog else (rotated 180°) |
300 | | - //gId("psd"+n).innerHTML = isAna(t) ? "Index:":"Start:"; // change analog start description |
301 | | - gId("net"+n+"h").style.display = isNet(t) && !is8266() ? "block" : "none"; // show host field for network types except on ESP8266 |
302 | | - if (!isNet(t) || is8266()) d.Sf["HS"+n].value = ""; // cleart host field if not network type or ESP8266 |
| 238 | + memu += getMem(t, n); // calc memory |
| 239 | + dC += isD1P(t); // count digital buses |
| 240 | + gRGBW |= hasW(t); // RGBW checkbox |
303 | 241 | }); |
| 242 | + // enable/disable add/remove buttons |
| 243 | + gId("+").style.display = (LTs.length<36) ? "inline":"none"; // now: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".length |
| 244 | + gId("-").style.display = (LTs.length>1) ? "inline":"none"; |
| 245 | + |
304 | 246 | // display global white channel overrides |
305 | 247 | gId("wc").style.display = (gRGBW) ? 'inline':'none'; |
306 | 248 | if (!gRGBW) { |
|
499 | 441 | </div>`; |
500 | 442 | f.insertAdjacentHTML("beforeend", cn); |
501 | 443 | // fill led types (credit @netmindz) |
502 | | - f.querySelectorAll("select[name^=LT]").forEach((sel,n)=>{ |
503 | | - if (sel.length == 0) { // ignore already updated |
504 | | - for (let type of d.ledTypes) { |
505 | | - let opt = cE("option"); |
506 | | - opt.value = type.i; |
507 | | - opt.text = type.n; |
508 | | - if (type.t != undefined && type.t != "") { |
509 | | - opt.setAttribute('data-type', type.t); |
510 | | - } |
511 | | - sel.appendChild(opt); |
512 | | - } |
| 444 | + let sel = f.lastElementChild.querySelector("select[name^=LT]"); // get recently added LED type select |
| 445 | + for (let type of d.ledTypes) { |
| 446 | + let opt = cE("option"); |
| 447 | + opt.value = type.i; |
| 448 | + opt.text = type.n; |
| 449 | + if (type.t != undefined && type.t != "") { |
| 450 | + opt.setAttribute('data-type', type.t); |
513 | 451 | } |
514 | | - }); |
| 452 | + sel.appendChild(opt); |
| 453 | + } |
515 | 454 | enLA(gN("LL"+s)); // update LED mA |
516 | | - let sel = gN("LT"+s); |
517 | | - sel.selectedIndex = sel.querySelector('option:not([data-type])').index; // select On/Off by default |
| 455 | + if (!init) { |
| 456 | + // we used add button |
| 457 | + sel.selectedIndex = sel.querySelector('option:not([data-type])').index; // select On/Off by default (prevent selecting first type which may be invalid) |
| 458 | + updateTypeDropdowns(true, sel); |
| 459 | + sel.selectedIndex = sel.querySelector('option:not(:disabled)').index; // select 1st valid |
| 460 | + } |
518 | 461 | } |
519 | 462 | if (n==-1) { |
520 | 463 | o[--i].remove(); |
521 | 464 | } |
522 | | - |
523 | | - gId("+").style.display = (i<36) ? "inline":"none"; // was maxB+maxV-1 when virtual buses were limited (now :"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") |
524 | | - gId("-").style.display = (i>1) ? "inline":"none"; |
525 | | - |
526 | 465 | // if called from + or - button, update UI |
527 | | - if (!init) { |
528 | | - UI(); |
529 | | - } |
| 466 | + if (!init) UI(); |
530 | 467 | } |
531 | 468 |
|
532 | 469 | function addCOM(start=0,len=1,co=0) { |
|
835 | 772 | return opt; |
836 | 773 | } |
837 | 774 | // dynamically enforce bus type availability based on current usage |
838 | | - function updateTypeDropdowns(change=false) { // change=true if called from onchange event (reserved for future) |
| 775 | + function updateTypeDropdowns(change=false, sel=undefined) { // change=true if called after a type change |
| 776 | + const abl = d.Sf.ABL.checked; |
839 | 777 | let LTs = d.Sf.querySelectorAll("#mLC select[name^=LT]"); |
840 | 778 | let digitalB = 0, analogB = 0, twopinB = 0, virtB = 0; |
| 779 | + let setPinConfig = (n,t) => { |
| 780 | + let p0d = "GPIO: "; |
| 781 | + let p1d = ""; |
| 782 | + let off = "Off Refresh"; |
| 783 | + switch (gT(t).t.charAt(0)) { |
| 784 | + case '2': // 2 pin digital |
| 785 | + p1d = "Clock "+p0d; |
| 786 | + // fallthrough |
| 787 | + case 'D': // digital |
| 788 | + p0d = "Data "+p0d; |
| 789 | + break; |
| 790 | + case 'A': // PWM analog |
| 791 | + if (numPins(t) > 1) p0d = "GPIOs: "; |
| 792 | + off = "Dithering"; |
| 793 | + break; |
| 794 | + case 'N': // network |
| 795 | + p0d = "IP address: "; |
| 796 | + break; |
| 797 | + case 'V': // virtual/non-GPIO based |
| 798 | + p0d = "Config: " |
| 799 | + break; |
| 800 | + } |
| 801 | + gId("p0d"+n).innerText = p0d; |
| 802 | + gId("p1d"+n).innerText = p1d; |
| 803 | + gId("off"+n).innerText = off; |
| 804 | + // secondary pins show/hide (type string length is equivalent to number of pins used; except for network and on/off) |
| 805 | + let pins = Math.max(gT(t).t.length,1) + 3*isNet(t); // fixes network pins to 4 |
| 806 | + for (let p=1; p<5; p++) { |
| 807 | + var LK = gN("L"+p+n); |
| 808 | + if (!LK) continue; |
| 809 | + LK.style.display = (p < pins) ? "inline" : "none"; |
| 810 | + LK.required = (p < pins); |
| 811 | + if (p >= pins) LK.value=""; |
| 812 | + } |
| 813 | + } |
841 | 814 | // count currently used buses (including last added bus) |
842 | | - LTs.forEach((sel,i) => { |
843 | | - let t = parseInt(sel.value); |
| 815 | + LTs.forEach((s,i) => { |
| 816 | + let t = parseInt(s.value); |
844 | 817 | if (isD1P(t)) digitalB++; |
845 | 818 | if (isPWM(t)) analogB += numPins(t); |
846 | 819 | if (isD2P(t)) twopinB++; |
847 | 820 | if (isVir(t)) virtB++; |
848 | 821 | }); |
849 | 822 | // now enable/disable type options according to limits in dropdowns |
850 | | - LTs.forEach((sel,i) => { |
851 | | - const last = i == LTs.length-1; |
852 | | - const curType = parseInt(sel.value); |
853 | | - const disable = (q) => sel.querySelectorAll(q).forEach(o => o.disabled = true); |
854 | | - const enable = (q) => sel.querySelectorAll(q).forEach(o => o.disabled = false); |
| 823 | + if (sel) LTs = [sel]; // only update the changed one |
| 824 | + LTs.forEach((s,i) => { |
| 825 | + const t = parseInt(s.value); |
| 826 | + const disable = (q) => s.querySelectorAll(q).forEach(o => o.disabled = true); |
| 827 | + const enable = (q) => s.querySelectorAll(q).forEach(o => o.disabled = false); |
855 | 828 | enable('option'); // reset all first |
856 | 829 | // max digital count |
857 | 830 | let maxDB = maxD - ((is32() || isS2() || isS3()) ? (!d.Sf["PR"].checked) * 8 - (!isS3()) : 0); |
858 | 831 | // disallow adding more of a type that has reached its limit |
859 | | - if (digitalB >= maxDB && !isD1P(curType)) disable('option[data-type="D"]'); |
860 | | - if (twopinB >= 2 && !isD2P(curType)) disable('option[data-type="2P"]'); |
| 832 | + if (digitalB >= maxDB && !isD1P(t)) disable('option[data-type="D"]'); |
| 833 | + if (twopinB >= 2 && !isD2P(t)) disable('option[data-type="2P"]'); |
861 | 834 | // determine available analog pins |
862 | | - disable(`option[data-type^="${'A'.repeat(maxA - analogB + (isPWM(curType) ? numPins(curType) : 0) + 1)}"]`); |
863 | | - // if last added bus has an invalid type, change it to first available |
864 | | - if (last && sel.selectedOptions[0].disabled) sel.selectedIndex = sel.querySelector('option:not(:disabled)').index; |
| 835 | + disable(`option[data-type^="${'A'.repeat(maxA - analogB + (isPWM(t) ? numPins(t) : 0) + 1)}"]`); |
| 836 | + // update UI elements |
| 837 | + let n = s.name.substring(2,3); // bus number (0-Z) |
| 838 | + setPinConfig(n,t); |
| 839 | + gId("abl"+n).style.display = (!abl || !isDig(t)) ? "none" : "inline"; // show/hide individual ABL settings |
| 840 | + if (change) { // did we change LED type? |
| 841 | + gId("rf"+n).checked = (gId("rf"+n).checked || t == 31); // LEDs require data in off state (mandatory for TM1814) |
| 842 | + if (isAna(t)) gN("LC"+n).value = 1; // for sanity change analog count just to 1 LED |
| 843 | + gN("LA"+n).min = (!isDig(t) || !abl) ? 0 : 1; // set minimum value for LED mA |
| 844 | + gN("MA"+n).min = (!isDig(t)) ? 0 : 250; // set minimum value for PSU mA |
| 845 | + } |
| 846 | + gId("rf"+n).onclick = mustR(t) ? (()=>{return false}) : (()=>{}); // prevent change change of "Refresh" checkmark when mandatory |
| 847 | + gId("co"+n).style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide color order for PWM |
| 848 | + gId("dig"+n+"w").style.display = (isDig(t) && hasW(t)) ? "inline":"none"; // show swap channels dropdown |
| 849 | + gId("dig"+n+"w").querySelector("[data-opt=CCT]").disabled = !hasCCT(t); // disable WW/CW swapping |
| 850 | + if (!(isDig(t) && hasW(t))) gN("WO"+n).value = 0; // reset swapping |
| 851 | + gId("dig"+n+"c").style.display = (isAna(t)) ? "none":"inline"; // hide count for analog |
| 852 | + gId("dig"+n+"r").style.display = (isVir(t)) ? "none":"inline"; // hide reversed for virtual |
| 853 | + gId("dig"+n+"s").style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide skip 1st for virtual & analog |
| 854 | + gId("dig"+n+"f").style.display = (isDig(t) || (isPWM(t) && maxL>2048)) ? "inline":"none"; // hide refresh (PWM hijacks reffresh for dithering on ESP32) |
| 855 | + gId("dig"+n+"a").style.display = (hasW(t)) ? "inline":"none"; // auto calculate white |
| 856 | + gId("dig"+n+"l").style.display = (isD2P(t) || isPWM(t)) ? "inline":"none"; // bus clock speed / PWM speed (relative) (not On/Off) |
| 857 | + gId("rev"+n).innerHTML = isAna(t) ? "Inverted output":"Reversed"; // change reverse text for analog else (rotated 180°) |
| 858 | + gId("net"+n+"h").style.display = isNet(t) && !is8266() ? "block" : "none"; // show host field for network types except on ESP8266 |
| 859 | + if (!isNet(t) || is8266()) gN("HS"+n).value = ""; // cleart host field if not network type or ESP8266 |
865 | 860 | }); |
866 | 861 | } |
867 | 862 | </script> |
|
0 commit comments