Merge branch 'main' into cpal

This commit is contained in:
Blaz Kristan 2023-04-14 17:16:20 +02:00
commit 3efee4a855
12 changed files with 2244 additions and 2212 deletions

View File

@ -1,5 +1,12 @@
## WLED changelog
#### Build 2304090
- updated Arduino ESP8266 core to 4.1.0 (newer compiler)
- updated NeoPixelBus to 2.7.3 (with support for UCS890x chipset)
- better support for ESP32-C3, ESP32-S2 and ESP32-S3 (Arduino ESP32 core 5.2.0)
- iPad/tablet with 1024 pixels width in landscape orientation PC mode support (#3153)
- fix for Pixel Art Converter (#3155)
#### Build 2303240
- Peek scaling of large 2D matrices
- Added 0D (1 pixel) metadata for effects & enhance 0D (analog strip) UI handling

View File

@ -234,7 +234,7 @@ default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
lib_deps =
${env.lib_deps}
https://github.com/lorol/LITTLEFS.git
makuna/NeoPixelBus @ 2.6.9
makuna/NeoPixelBus @ 2.7.3
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0
@ -247,6 +247,7 @@ lib_deps =
platform = espressif32@5.2.0
platform_packages =
build_flags = -g
-Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one
-DARDUINO_ARCH_ESP32 -DESP32
#-DCONFIG_LITTLEFS_FOR_IDF_3_2
-D CONFIG_ASYNC_TCP_USE_WDT=0
@ -314,7 +315,7 @@ build_flags = -g
lib_deps =
${env.lib_deps}
;; NeoPixelBus 2.7.1 is the first that has official support for ESP32-S3
makuna/NeoPixelBus @ ~2.7.3
makuna/NeoPixelBus @ 2.7.3
https://github.com/pbolduc/AsyncTCP.git @ 1.2.0

View File

@ -4653,8 +4653,8 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so
byte ysteps = abs8(x2 - y2) + 1;
byte steps = xsteps >= ysteps ? xsteps : ysteps;
//Draw gradient line
for (size_t i = 1; i <= steps; i++) {
uint8_t rate = i * 255 / steps;
for (size_t j = 1; j <= steps; j++) {
uint8_t rate = j * 255 / steps;
byte dx = lerp8by8(x1, y1, rate);
byte dy = lerp8by8(x2, y2, rate);
//SEGMENT.setPixelColorXY(dx, dy, grad ? color.nscale8_video(255-rate) : color); // use addPixelColorXY for different look

View File

@ -1181,12 +1181,12 @@ void WS2812FX::estimateCurrentAndLimitBri() {
uint32_t powerSum = 0;
for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
Bus *bus = busses.getBus(b);
for (uint_fast8_t bNum = 0; bNum < busses.getNumBusses(); bNum++) {
Bus *bus = busses.getBus(bNum);
if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses
uint16_t len = bus->getLength();
uint32_t busPowerSum = 0;
for (uint16_t i = 0; i < len; i++) { //sum up the usage of each LED
for (uint_fast16_t i = 0; i < len; i++) { //sum up the usage of each LED
uint32_t c = bus->getPixelColor(i);
byte r = R(c), g = G(c), b = B(c), w = W(c);

View File

@ -184,9 +184,9 @@
//APA102
#ifdef WLED_USE_ETHERNET
// fix for #2542 (by @BlackBird77)
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarEsp32DmaHspi5MhzMethod> //hardware HSPI with DMA (ESP32 only)
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarHspi5MhzMethod> //hardware HSPI (was DotStarEsp32DmaHspi5MhzMethod in NPB 2.6.9)
#else
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarSpi5MhzMethod> //hardware HSPI
#define B_HS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarSpi5MhzMethod> //hardware VSPI
#endif
#define B_SS_DOT_3 NeoPixelBrightnessBus<DotStarBgrFeature, DotStarMethod> //soft SPI

View File

@ -151,7 +151,7 @@ button {
}
.segt TD {
padding: 2px !important;
padding: 2px 0 !important;
text-align: center;
/*text-transform: uppercase;*/
}
@ -174,7 +174,10 @@ button {
}
.slider-icon {
transform: translate(3px,3px);
/*transform: translate(3px,3px);*/
position: absolute;
left: 8px;
bottom: 5px;
}
.e-icon {
@ -314,14 +317,17 @@ button {
overflow: auto;
height: 100%;
overscroll-behavior: none;
padding: 0 4px;
}
#Effects {
-webkit-overflow-scrolling: touch;
}
#segutil, #segutil2, #segcont, #putil, #pcont, #pql {
width: 280px;
#segutil, #segutil2, #segcont, #putil, #pcont, #pql, #fx, #palw,
.fnd {
max-width: 280px;
font-size: 19px;
}
#putil, #segutil, #segutil2 {
@ -333,7 +339,8 @@ button {
padding-top: 12px;
}
#pql, #segcont, #pcont {
#fx, #pql, #segcont, #pcont, #sliders, #picker, #qcs-w, #hexw, #pall, #ledmap,
.slider, .filter, .option, .segname, .pname, .fnd {
margin: 0 auto;
}
@ -380,8 +387,7 @@ button {
}
#sliders {
width: 300px;
margin: 0 auto;
position: -webkit-sticky;
position: sticky;
bottom: 0;
}
@ -393,32 +399,44 @@ button {
.slider {
max-width: 300px;
min-width: 260px;
margin: 0 auto; /* add 5px; if you want some vertical space but looks ugly */
/* margin: 5px auto; add 5px; if you want some vertical space but looks ugly */
border-radius: 24px;
position: relative;
padding-bottom: 2px;
}
/* Slider wrapper div */
.sliderwrap {
height: 30px;
width: 230px;
max-width: 230px;
position: relative;
z-index: 0;
}
#sliders .slider, #info .slider {
background-color: var(--c-2);
}
#sliders .sliderwrap, .sbs .sliderwrap {
left: 16px; /* offset for icon */
}
.filter, .option {
background-color: var(--c-4);
border-radius: 26px;
height: 26px;
margin: 0 auto; /* add 4-8px if you want space at the bottom */
max-width: 300px;
/* margin: 0 auto 4px; add 4-8px if you want space at the bottom */
padding: 4px 2px;
position: relative;
z-index: 1;
opacity: 1;
transition: opacity 0.5s linear, height 0.5s, transform 0.5s;
transform: scaleY(1);
overflow: hidden;
}
.option {
z-index: unset;
.filter {
z-index: 1;
}
/* Tooltip text */
@ -530,6 +548,7 @@ button {
}
.close {
position: -webkit-sticky;
position: sticky;
top: 0;
float: right;
@ -596,14 +615,9 @@ button {
}
#info #imgw {
/*display: inline-block;*/
margin: 8px auto;
}
/*
#kv, #kn {
display: inline-block;
}
*/
#lv {
max-width: 600px;
display: inline-block;
@ -668,6 +682,7 @@ img {
transition: visibility 0.25s ease, opacity 0.25s ease;
opacity: 0;
visibility: hidden;
left: 8px;
}
output.sliderbubbleshow {
@ -725,16 +740,7 @@ input[type=range]::-moz-range-thumb {
border: 2px solid var(--c-1);
}
/* Slider wrapper div */
.sliderwrap {
height: 30px;
width: 230px;
position: relative;
z-index: 0;
}
#Colors .sliderwrap {
width: 260px;
margin: 4px 0 0;
}
@ -748,18 +754,14 @@ input[type=range]::-moz-range-thumb {
}
#briwrap {
min-width: 267px;
float: right;
margin-top: var(--bmt);
}
#picker, #qcs-w, #hexw, #pall, #ledmap {
margin: 0 auto;
width: 260px;
/*background-color: unset;*/
}
#picker {
margin-top: -10px !important;
max-width: 260px;
}
/* buttons */
@ -994,14 +996,12 @@ textarea {
.segname, .pname {
white-space: nowrap;
/*cursor: pointer;*/
text-align: center;
overflow: clip;
text-overflow: ellipsis;
line-height: 24px;
padding: 8px 24px;
max-width: 170px;
margin: 0 auto;
position: relative;
}
@ -1012,7 +1012,7 @@ textarea {
/* segment power wrapper */
.sbs {
padding: 4px 0 4px 8px;
padding: 1px 0 1px 20px;
display: var(--sgp);
}
@ -1208,10 +1208,7 @@ TD .checkmark, TD .radiomark {
border: 0px solid var(--c-f);
text-align: left;
transition: background-color 0.5s;
/*filter: brightness(1);*/
font-size: 19px;
border-radius: 21px;
/*min-width: 264px;*/
}
.seg {
@ -1254,10 +1251,8 @@ TD .checkmark, TD .radiomark {
/* list wrapper */
.list {
position: relative;
width: 280px;
transition: background-color 0.5s;
margin: auto auto 10px;
font-size: 19px;
line-height: 24px;
}
@ -1267,6 +1262,7 @@ TD .checkmark, TD .radiomark {
cursor: pointer;
background-color: var(--c-2);
overflow: hidden;
position: -webkit-sticky;
position: sticky;
border-radius: 21px;
margin: 13px auto 0;
@ -1303,6 +1299,7 @@ TD .checkmark, TD .radiomark {
.lstI.selected {
top: 0;
bottom: 0;
border: 1px solid var(--c-4);
}
.lstI.sticky,
@ -1358,8 +1355,6 @@ TD .checkmark, TD .radiomark {
/* find/search element */
.fnd {
width: 280px;
margin: 0 auto;
position: relative;
}
@ -1391,7 +1386,6 @@ TD .checkmark, TD .radiomark {
.presin {
padding: 8px;
position: relative;
width: 264px;
}
.btn-s,
@ -1469,6 +1463,16 @@ TD .checkmark, TD .radiomark {
}
}
@media all and (max-width: 1023px) {
.top button {
width: 8%;
padding: 10px 0 8px 0;
}
#buttonPcm {
display: none;
}
}
@media all and (max-width: 335px) {
.sliderbubble {
display: none;
@ -1487,38 +1491,84 @@ TD .checkmark, TD .radiomark {
}
}
@media all and (max-width: 540px) {
.top button {
width: 16.6%;
padding: 8px 0 4px 0;
}
}
@media all and (min-width: 541px) and (max-width: 719px) {
.top button {
width: 14.2%;
padding: 8px 0 4px 0;
}
}
@media all and (max-width: 719px) {
.hd {
display: none !important;
}
#briwrap {
margin-top: 0px !important;
float: none;
}
}
@media all and (max-width: 798px) {
@media all and (max-width: 420px) {
#buttonNodes {
display: none;
}
}
@media all and (max-width: 1249px) {
#buttonPcm {
@media all and (max-width: 639px) {
.top button {
width: 16.6%;
padding: 8px 0 4px 0;
}
#briwrap {
margin: 0 auto !important;
float: none;
display: inline-block;
}
.hd {
display: none !important;
}
}
@media all and (min-width: 420px) and (max-width: 639px) {
.top button {
width: 14.28%;
padding: 8px 0 4px 0;
}
}
@media all and (min-width: 640px) and (max-width: 767px) {
#buttonNodes {
display: none;
}
}
/* small screen & tablet "PC mode" support */
@media all and (min-width: 1024px) and (max-width: 1249px) {
#segutil, #segutil2, #segcont, #putil, #pcont, #pql, #fx, #palw, #psFind, #sliders {
width: 100%;
max-width: 280px;
font-size: 18px;
}
#picker {
width: 230px;
}
#putil .btn-s {
width: 114px;
}
#sliders .sliderbubble {
display: none;
}
.sliderwrap {
width: calc(100% - 28px);
}
#sliders .sliderwrap {
left: 12px;
}
.segname {
padding: 8px 16px;
max-width: 140px;
}
.segname, .pname {
max-width: 134px;
}
.segt TD {
padding: 0 !important;
}
input[type="number"], input[type=text], select, textarea {
font-size: 18px;
}
input[type="number"] {
width: 32px;
}
.lstIcontent {
padding-left: 8px;
}
.revchkl {
max-width: 183px;
text-overflow: ellipsis;
overflow-x: clip;
}
}

View File

@ -72,8 +72,8 @@
</div>
<div id="briwrap">
<p class="hd">Brightness</p>
<div class="il">
<i class="icons slider-icon" onclick="tglTheme()">&#xe2a6;</i>
<div class="slider" style="left:24px;">
<i class="icons slider-icon" onclick="tglTheme()" style="transform: translate(-32px,5px);">&#xe2a6;</i>
<div class="sliderwrap il">
<input id="sliderBri" onchange="setBri()" oninput="updateTrail(this)" max="255" min="1" type="range" value="128" />
<div class="sliderdisplay"></div>
@ -231,6 +231,10 @@
<input type="checkbox" data-flt="&#x1F3A8;" onchange="filterFx(this)">
<span class="checkmark"></span>
</label>
<label id="filter0D" class="check fchkl hide">&#8226;
<input type="checkbox" data-flt="&#8226;" onchange="filterFx(this)">
<span class="checkmark"></span>
</label>
<label id="filter1D" class="check fchkl">&#8942;
<input type="checkbox" data-flt="&#8942;" onchange="filterFx(this)">
<span class="checkmark"></span>
@ -249,7 +253,7 @@
</label>
</div>
<div id="slider0" class="slider">
<i class="icons slider-icon" style="cursor: pointer;" onclick="tglFreeze()">&#xe325;</i>
<i class="icons slider-icon" onclick="tglFreeze()">&#xe325;</i>
<div class="sliderwrap il">
<input id="sliderSpeed" class="noslide" onchange="setSpeed()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
<div class="sliderdisplay"></div>
@ -258,7 +262,7 @@
<span id="sliderLabel0" class="tooltiptext">Effect speed</span>
</div>
<div id="slider1" class="slider">
<i class="icons slider-icon" style="cursor: pointer;" onclick="tglLabels()">&#xe409;</i>
<i class="icons slider-icon" onclick="tglLabels()">&#xe409;</i>
<div class="sliderwrap il">
<input id="sliderIntensity" class="noslide" onchange="setIntensity()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
<div class="sliderdisplay"></div>

View File

@ -214,6 +214,7 @@ function onLoad()
resetPUtil();
if (localStorage.getItem('pcm') == "true" || (!/Mobi/.test(navigator.userAgent) && localStorage.getItem('pcm') == null)) togglePcMode(true);
applyCfg();
if (cfg.comp.hdays) { //load custom holiday list
fetch((loc?`http://${locip}`:'.') + "/holidays.json", { // may be loaded from external source
@ -258,9 +259,8 @@ function onLoad()
resetUtil();
d.addEventListener("visibilitychange", handleVisibilityChange, false);
size();
//size();
gId("cv").style.opacity=0;
if (localStorage.getItem('pcm') == "true" || (!/Mobi/.test(navigator.userAgent) && localStorage.getItem('pcm') == null)) togglePcMode(true);
var sls = d.querySelectorAll('input[type="range"]');
for (var sl of sls) {
sl.addEventListener('touchstart', toggleBubble);
@ -603,14 +603,19 @@ function parseInfo(i) {
syncTglRecv = i.str;
maxSeg = i.leds.maxseg;
pmt = i.fs.pmt;
gId('buttonNodes').style.display = lastinfo.ndc > 0 ? null:"none";
// do we have a matrix set-up
mw = i.leds.matrix ? i.leds.matrix.w : 0;
mh = i.leds.matrix ? i.leds.matrix.h : 0;
isM = mw>0 && mh>0;
if (!isM) {
gId("filter0D").classList.remove('hide');
gId("filter1D").classList.add('hide');
//gId("filter2D").classList.add('hide');
hideModes("2D");
gId("filter2D").classList.add('hide');
} else {
gId("filter0D").classList.add('hide');
gId("filter1D").classList.remove('hide');
gId("filter2D").classList.remove('hide');
}
// if (i.noaudio) {
// gId("filterVol").classList.add("hide");
@ -638,7 +643,7 @@ function parseInfo(i) {
function populateInfo(i)
{
var cn="";
var heap = i.freeheap/1000;
var heap = i.freeheap/1024;
heap = heap.toFixed(1);
var pwr = i.leds.pwr;
var pwru = "Not calculated";
@ -697,13 +702,13 @@ function populateSegments(s)
let sg = gId(`seg${i}`);
let exp = sg ? (sg.classList.contains('expanded') || (i===0 && cfg.comp.segexp)) : false;
let segp = `<div id="segp${i}" class="sbs">
<i class="icons e-icon pwr ${inst.on ? "act":""}" id="seg${i}pwr" onclick="setSegPwr(${i})">&#xe08f;</i>
<div class="sliderwrap il">
<input id="seg${i}bri" class="noslide" onchange="setSegBri(${i})" oninput="updateTrail(this)" max="255" min="1" type="range" value="${inst.bri}" />
<div class="sliderdisplay"></div>
</div>
</div>`;
let segp = `<div id="segp${i}" class="sbs">`+
`<i class="icons slider-icon pwr ${inst.on ? "act":""}" id="seg${i}pwr" onclick="setSegPwr(${i})">&#xe08f;</i>`+
`<div class="sliderwrap il">`+
`<input id="seg${i}bri" class="noslide" onchange="setSegBri(${i})" oninput="updateTrail(this)" max="255" min="1" type="range" value="${inst.bri}" />`+
`<div class="sliderdisplay"></div>`+
`</div>`+
`</div>`;
let staX = inst.start;
let stoX = inst.stop;
let staY = inst.startY;
@ -715,81 +720,81 @@ function populateSegments(s)
rvYck = `<label class="check revchkl">Reverse<input type="checkbox" id="seg${i}rY" onchange="setRevY(${i})" ${inst.rY?"checked":""}><span class="checkmark"></span></label>`;
miYck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mY" onchange="setMiY(${i})" ${inst.mY?"checked":""}><span class="checkmark"></span></label>`;
}
let map2D = `<div id="seg${i}map2D" data-map="map2D" class="lbl-s hide">Expand 1D FX<br>
<div class="sel-p"><select class="sel-p" id="seg${i}m12" onchange="setM12(${i})">
<option value="0" ${inst.m12==0?' selected':''}>Pixels</option>
<option value="1" ${inst.m12==1?' selected':''}>Bar</option>
<option value="2" ${inst.m12==2?' selected':''}>Arc</option>
<option value="3" ${inst.m12==3?' selected':''}>Corner</option>
</select></div>
</div>`;
let sndSim = `<div data-snd="si" class="lbl-s hide">Sound sim<br>
<div class="sel-p"><select class="sel-p" id="seg${i}si" onchange="setSi(${i})">
<option value="0" ${inst.si==0?' selected':''}>BeatSin</option>
<option value="1" ${inst.si==1?' selected':''}>WeWillRockYou</option>
<option value="2" ${inst.si==2?' selected':''}>U10_3</option>
<option value="3" ${inst.si==3?' selected':''}>U14_3</option>
</select></div>
</div>`;
cn += `<div class="seg lstI ${i==s.mainseg ? 'selected' : ''} ${exp ? "expanded":""}" id="seg${i}">
<label class="check schkl">
<input type="checkbox" id="seg${i}sel" onchange="selSeg(${i})" ${inst.sel ? "checked":""}>
<span class="checkmark"></span>
</label>
<i class="icons e-icon frz" id="seg${i}frz" onclick="event.preventDefault();tglFreeze(${i});">&#x${inst.frz ? (li.live && li.liveseg==i?'e410':'e0e8') : 'e325'};</i>
<div class="segname" onclick="selSegEx(${i})">
${inst.n ? inst.n : "Segment "+i}
<i class="icons edit-icon flr" id="seg${i}nedit" onclick="tglSegn(${i})">&#xe2c6;</i>
</div>
<i class="icons e-icon flr" id="sege${i}" onclick="expand(${i})">&#xe395;</i>
${cfg.comp.segpwr?segp:''}
<div class="segin" id="seg${i}in">
<input type="text" class="ptxt" id="seg${i}t" autocomplete="off" maxlength=32 value="${inst.n?inst.n:""}" placeholder="Enter name..."/>
<table class="infot segt">
<tr>
<td>${isM&&staX<mw*mh?'Start X':'Start LED'}</td>
<td>${isM&&staX<mw*mh?(cfg.comp.seglen?"Width":"Stop X"):(cfg.comp.seglen?"LED count":"Stop LED")}</td>
<td>${isM&&staX<mw*mh?'':'Offset'}</td>
</tr>
<tr>
<td><input class="segn" id="seg${i}s" type="number" min="0" max="${(isM&&staX<mw*mh?mw:ledCount)-1}" value="${staX}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
<td><input class="segn" id="seg${i}e" type="number" min="0" max="${(isM&&staX<mw*mh?mw:ledCount)}" value="${stoX-(cfg.comp.seglen?staX:0)}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
<td style="text-align:revert;">${isM&&staX<mw*mh?miXck+'<br>'+rvXck:''}<input class="segn ${isM&&staX<mw*mh?'hide':''}" id="seg${i}of" type="number" value="${inst.of}" oninput="updateLen(${i})"></td>
</tr>
${isM&&staX<mw*mh ? '<tr><td>Start Y</td><td>'+(cfg.comp.seglen?'Height':'Stop Y')+'</td><td></td></tr>'+
let map2D = `<div id="seg${i}map2D" data-map="map2D" class="lbl-s hide">Expand 1D FX<br>`+
`<div class="sel-p"><select class="sel-p" id="seg${i}m12" onchange="setM12(${i})">`+
`<option value="0" ${inst.m12==0?' selected':''}>Pixels</option>`+
`<option value="1" ${inst.m12==1?' selected':''}>Bar</option>`+
`<option value="2" ${inst.m12==2?' selected':''}>Arc</option>`+
`<option value="3" ${inst.m12==3?' selected':''}>Corner</option>`+
`</select></div>`+
`</div>`;
let sndSim = `<div data-snd="si" class="lbl-s hide">Sound sim<br>`+
`<div class="sel-p"><select class="sel-p" id="seg${i}si" onchange="setSi(${i})">`+
`<option value="0" ${inst.si==0?' selected':''}>BeatSin</option>`+
`<option value="1" ${inst.si==1?' selected':''}>WeWillRockYou</option>`+
`<option value="2" ${inst.si==2?' selected':''}>U10_3</option>`+
`<option value="3" ${inst.si==3?' selected':''}>U14_3</option>`+
`</select></div>`+
`</div>`;
cn += `<div class="seg lstI ${i==s.mainseg ? 'selected' : ''} ${exp ? "expanded":""}" id="seg${i}">`+
`<label class="check schkl">`+
`<input type="checkbox" id="seg${i}sel" onchange="selSeg(${i})" ${inst.sel ? "checked":""}>`+
`<span class="checkmark"></span>`+
`</label>`+
`<i class="icons e-icon frz" id="seg${i}frz" onclick="event.preventDefault();tglFreeze(${i});">&#x${inst.frz ? (li.live && li.liveseg==i?'e410':'e0e8') : 'e325'};</i>`+
`<div class="segname" onclick="selSegEx(${i})">`+
(inst.n ? inst.n : "Segment "+i) +
`<i class="icons edit-icon flr" id="seg${i}nedit" onclick="tglSegn(${i})">&#xe2c6;</i>`+
`</div>`+
`<i class="icons e-icon flr" id="sege${i}" onclick="expand(${i})">&#xe395;</i>`+
(cfg.comp.segpwr ? segp : '') +
`<div class="segin" id="seg${i}in">`+
`<input type="text" class="ptxt" id="seg${i}t" autocomplete="off" maxlength=32 value="${inst.n?inst.n:""}" placeholder="Enter name..."/>`+
`<table class="infot segt">`+
`<tr>`+
`<td>${isM&&staX<mw*mh?'Start X':'Start LED'}</td>`+
`<td>${isM&&staX<mw*mh?(cfg.comp.seglen?"Width":"Stop X"):(cfg.comp.seglen?"LED count":"Stop LED")}</td>`+
`<td>${isM&&staX<mw*mh?'':'Offset'}</td>`+
`</tr>`+
`<tr>`+
`<td><input class="segn" id="seg${i}s" type="number" min="0" max="${(isM&&staX<mw*mh?mw:ledCount)-1}" value="${staX}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>`+
`<td><input class="segn" id="seg${i}e" type="number" min="0" max="${(isM&&staX<mw*mh?mw:ledCount)}" value="${stoX-(cfg.comp.seglen?staX:0)}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>`+
`<td style="text-align:revert;">${isM&&staX<mw*mh?miXck+'<br>'+rvXck:''}<input class="segn ${isM&&staX<mw*mh?'hide':''}" id="seg${i}of" type="number" value="${inst.of}" oninput="updateLen(${i})"></td>`+
`</tr>`+
(isM && staX<mw*mh ? '<tr><td>Start Y</td><td>'+(cfg.comp.seglen?'Height':'Stop Y')+'</td><td></td></tr>'+
'<tr>'+
'<td><input class="segn" id="seg'+i+'sY" type="number" min="0" max="'+(mh-1)+'" value="'+staY+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
'<td><input class="segn" id="seg'+i+'eY" type="number" min="0" max="'+mh+'" value="'+(stoY-(cfg.comp.seglen?staY:0))+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
'<td style="text-align:revert;">'+miYck+'<br>'+rvYck+'</td>'+
'</tr>':''}
<tr>
<td>Grouping</td>
<td>Spacing</td>
<td></td>
</tr>
<tr>
<td><input class="segn" id="seg${i}grp" type="number" min="1" max="255" value="${inst.grp}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
<td><input class="segn" id="seg${i}spc" type="number" min="0" max="255" value="${inst.spc}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
<td style="text-align:revert;"><button class="btn btn-xs" onclick="setSeg(${i})"><i class="icons btn-icon" id="segc${i}">&#xe390;</i></button></td>
</tr>
</table>
<div class="h bp" id="seg${i}len"></div>
${!(isM&&staX<mw*mh)?rvXck:''}
${isM&&staX<mw*mh&&stoY-staY>1&&stoX-staX>1?map2D:''}
${s.AudioReactive && s.AudioReactive.on ? "" : sndSim}
<label class="check revchkl" id="seg${i}lbtm">
${isM&&staX<mw*mh?'Transpose':'Mirror effect'}${isM&&staX<mw*mh?
'</tr>' : '') +
`<tr>`+
`<td>Grouping</td>`+
`<td>Spacing</td>`+
`<td></td>`+
`</tr>`+
`<tr>`+
`<td><input class="segn" id="seg${i}grp" type="number" min="1" max="255" value="${inst.grp}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>`+
`<td><input class="segn" id="seg${i}spc" type="number" min="0" max="255" value="${inst.spc}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>`+
`<td style="text-align:revert;"><button class="btn btn-xs" onclick="setSeg(${i})"><i class="icons btn-icon" id="segc${i}">&#xe390;</i></button></td>`+
`</tr>`+
`</table>`+
`<div class="h bp" id="seg${i}len"></div>`+
(!(isM&&staX<mw*mh) ? rvXck : '') +
(isM&&staX<mw*mh&&stoY-staY>1&&stoX-staX>1 ? map2D : '') +
(s.AudioReactive && s.AudioReactive.on ? "" : sndSim) +
`<label class="check revchkl" id="seg${i}lbtm">`+
(isM&&staX<mw*mh?'Transpose':'Mirror effect') + (isM&&staX<mw*mh ?
'<input type="checkbox" id="seg'+i+'tp" onchange="setTp('+i+')" '+(inst.tp?"checked":"")+'>':
'<input type="checkbox" id="seg'+i+'mi" onchange="setMi('+i+')" '+(inst.mi?"checked":"")+'>'}
<span class="checkmark"></span>
</label>
<div class="del">
<button class="btn btn-xs" id="segr${i}" title="Repeat until end" onclick="rptSeg(${i})"><i class="icons btn-icon">&#xe22d;</i></button>
<button class="btn btn-xs" id="segd${i}" title="Delete" onclick="delSeg(${i})"><i class="icons btn-icon">&#xe037;</i></button>
</div>
</div>
${cfg.comp.segpwr?'':segp}
</div>`;
'<input type="checkbox" id="seg'+i+'mi" onchange="setMi('+i+')" '+(inst.mi?"checked":"")+'>') +
`<span class="checkmark"></span>`+
`</label>`+
`<div class="del">`+
`<button class="btn btn-xs" id="segr${i}" title="Repeat until end" onclick="rptSeg(${i})"><i class="icons btn-icon">&#xe22d;</i></button>`+
`<button class="btn btn-xs" id="segd${i}" title="Delete" onclick="delSeg(${i})"><i class="icons btn-icon">&#xe037;</i></button>`+
`</div>`+
`</div>`+
(cfg.comp.segpwr ? '' : segp) +
`</div>`;
}
gId('segcont').innerHTML = cn;
@ -960,18 +965,16 @@ function genPalPrevCss(id)
function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', effectPar = '')
{
return `<div class="lstI${id==0?' sticky':''}" data-id="${id}" ${effectPar===''?'':'data-opt="'+effectPar+'"'}onClick="${clickAction}(${id})">
<label class="radio schkl" onclick="event.preventDefault()">
<input type="radio" value="${id}" name="${listName}">
<span class="radiomark"></span>
<div class="lstIcontent">
<span class="lstIname">
${name}
</span>
</div>
</label>
${extraHtml}
</div>`;
return `<div class="lstI${id==0?' sticky':''}" data-id="${id}" ${effectPar===''?'':'data-opt="'+effectPar+'"'}onClick="${clickAction}(${id})">`+
`<label class="radio schkl" onclick="event.preventDefault()">`+
`<input type="radio" value="${id}" name="${listName}">`+
`<span class="radiomark"></span>`+
`<div class="lstIcontent">`+
`<span class="lstIname">${name}</span>`+
`</div>`+
`</label>`+
extraHtml +
`</div>`;
}
function btype(b)
@ -1160,7 +1163,6 @@ function updateUI()
gId('buttonPower').className = (isOn) ? 'active':'';
gId('buttonNl').className = (nlA) ? 'active':'';
gId('buttonSync').className = (syncSend) ? 'active':'';
showNodes();
updateSelectedFx();
updateSelectedPalette(selectedPal); // must be after updateSelectedFx() to un-hide color slots for * palettes
@ -1244,7 +1246,7 @@ function updateSelectedFx()
if (fx.dataset.id>0) {
if (segLmax==0) fx.classList.add('hide'); // none of the segments selected (hide all effects)
else {
if (segLmax==1 && (!opts[3] || opts[3].indexOf("0")<0)) fx.classList.add('hide');
if ((segLmax==1 && (!opts[3] || opts[3].indexOf("0")<0)) || (!isM && opts[3] && ((opts[3].indexOf("2")>=0 && opts[3].indexOf("1")<0)))) fx.classList.add('hide');
else fx.classList.remove('hide');
}
}
@ -1295,7 +1297,6 @@ function makeWS() {
var i = json.info;
if (i) {
parseInfo(i);
showNodes();
if (isInfo) populateInfo(i);
} else
i = lastinfo;
@ -1720,29 +1721,29 @@ function makeSeg()
behavior: 'smooth',
block: 'start',
});
var cn = `<div class="seg lstI expanded">
<div class="segin">
<input type="text" id="seg${lu}t" autocomplete="off" maxlength=32 value="" placeholder="New segment ${lu}"/>
<table class="segt">
<tr>
<td width="38%">${isM?'Start X':'Start LED'}</td>
<td width="38%">${isM?(cfg.comp.seglen?"Width":"Stop X"):(cfg.comp.seglen?"LED count":"Stop LED")}</td>
</tr>
<tr>
<td><input class="segn" id="seg${lu}s" type="number" min="0" max="${isM?mw-1:ledCount-1}" value="${ns}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
<td><input class="segn" id="seg${lu}e" type="number" min="0" max="${ct}" value="${ct}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
<td><button class="btn btn-xs" onclick="setSeg(${lu});"><i class="icons bth-icon" id="segc${lu}">&#xe390;</i></button></td>
</tr>
<tr id="mkSYH" class="${isM?"":"hide"}"><td>Start Y</td><td>${cfg.comp.seglen?'Height':'Stop Y'}</td></tr>
<tr id="mkSYD" class="${isM?"":"hide"}">
<td><input class="segn" id="seg${lu}sY" type="number" min="0" max="${mh-1}" value="0" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
<td><input class="segn" id="seg${lu}eY" type="number" min="0" max="${mh}" value="${isM?mh:1}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
</tr>
</table>
<div class="h" id="seg${lu}len">${ledCount - ns} LEDs</div>
<div class="c"><button class="btn btn-p" onclick="resetUtil()">Cancel</button></div>
</div>
</div>`;
var cn = `<div class="seg lstI expanded">`+
`<div class="segin">`+
`<input type="text" id="seg${lu}t" autocomplete="off" maxlength=32 value="" placeholder="New segment ${lu}"/>`+
`<table class="segt">`+
`<tr>`+
`<td width="38%">${isM?'Start X':'Start LED'}</td>`+
`<td width="38%">${isM?(cfg.comp.seglen?"Width":"Stop X"):(cfg.comp.seglen?"LED count":"Stop LED")}</td>`+
`</tr>`+
`<tr>`+
`<td><input class="segn" id="seg${lu}s" type="number" min="0" max="${isM?mw-1:ledCount-1}" value="${ns}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>`+
`<td><input class="segn" id="seg${lu}e" type="number" min="0" max="${ct}" value="${ct}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>`+
`<td><button class="btn btn-xs" onclick="setSeg(${lu});"><i class="icons bth-icon" id="segc${lu}">&#xe390;</i></button></td>`+
`</tr>`+
`<tr id="mkSYH" class="${isM?"":"hide"}"><td>Start Y</td><td>${cfg.comp.seglen?'Height':'Stop Y'}</td></tr>`+
`<tr id="mkSYD" class="${isM?"":"hide"}">`+
`<td><input class="segn" id="seg${lu}sY" type="number" min="0" max="${mh-1}" value="0" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>`+
`<td><input class="segn" id="seg${lu}eY" type="number" min="0" max="${mh}" value="${isM?mh:1}" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>`+
`</tr>`+
`</table>`+
`<div class="h" id="seg${lu}len">${ledCount - ns} LEDs</div>`+
`<div class="c"><button class="btn btn-p" onclick="resetUtil()">Cancel</button></div>`+
`</div>`+
`</div>`;
gId('segutil').innerHTML = cn;
}
@ -2619,7 +2620,7 @@ function getPalettesData(page, callback)
showToast(error, true);
});
}
/*
function hideModes(txt)
{
for (let e of (gId('fxlist').querySelectorAll('.lstI')||[])) {
@ -2630,7 +2631,7 @@ function hideModes(txt)
if (f) e.classList.add('hide'); //else e.classList.remove('hide');
}
}
*/
function search(f,l=null)
{
f.nextElementSibling.style.display=(f.value!=='')?'block':'none';
@ -2795,20 +2796,16 @@ function move(e)
x0 = null;
}
function showNodes() {
gId('buttonNodes').style.display = (lastinfo.ndc > 0 && (wW > 797 || (wW > 539 && wW < 720))) ? "block":"none";
}
function size()
{
wW = window.innerWidth;
showNodes();
var h = gId('top').clientHeight;
sCol('--th', h + "px");
sCol('--bh', gId('bot').clientHeight + "px");
if (isLv) h -= 4;
sCol('--tp', h + "px");
togglePcMode();
lastw = wW;
}
function togglePcMode(fromB = false)
@ -2816,19 +2813,16 @@ function togglePcMode(fromB = false)
if (fromB) {
pcModeA = !pcModeA;
localStorage.setItem('pcm', pcModeA);
pcMode = pcModeA;
}
if (wW < 1250 && !pcMode) return;
if (!fromB && ((wW < 1250 && lastw < 1250) || (wW >= 1250 && lastw >= 1250))) return;
pcMode = (wW >= 1024) && pcModeA;
if (cpick) cpick.resize(pcMode && wW>1023 && wW<1250 ? 230 : 260); // for tablet in landscape
if (!fromB && ((wW < 1024 && lastw < 1024) || (wW >= 1024 && lastw >= 1024))) return; // no change in size and called from size()
openTab(0, true);
if (wW < 1250) {pcMode = false;}
else if (pcModeA && !fromB) pcMode = pcModeA;
updateTablinks(0);
gId('buttonPcm').className = (pcMode) ? "active":"";
gId('bot').style.height = (pcMode && !cfg.comp.pcmbot) ? "0":"auto";
sCol('--bh', gId('bot').clientHeight + "px");
_C.style.width = (pcMode)?'100%':'400%';
lastw = wW;
}
function mergeDeep(target, ...sources)
@ -2852,7 +2846,7 @@ function mergeDeep(target, ...sources)
size();
_C.style.setProperty('--n', N);
window.addEventListener('resize', size, false);
window.addEventListener('resize', size, true);
_C.addEventListener('mousedown', lock, false);
_C.addEventListener('touchstart', lock, false);

File diff suppressed because it is too large Load Diff

View File

@ -300,10 +300,10 @@ byte PinManagerClass::allocateLedc(byte channels)
if (ca >= channels) { //enough free channels
byte in = (i + 1) - ca;
for (byte j = 0; j < ca; j++) {
byte b = in + j;
byte by = b >> 3;
byte bi = b - 8*by;
bitWrite(ledcAlloc[by], bi, true);
byte bChan = in + j;
byte byChan = bChan >> 3;
byte biChan = bChan - 8*byChan;
bitWrite(ledcAlloc[byChan], biChan, true);
}
return in;
}

View File

@ -821,9 +821,9 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8
}
}
byte buffer[ART_NET_HEADER_SIZE];
memcpy_P(buffer, ART_NET_HEADER, ART_NET_HEADER_SIZE);
ddpUdp.write(buffer, ART_NET_HEADER_SIZE); // This doesn't change. Hard coded ID, OpCode, and protocol version.
byte header_buffer[ART_NET_HEADER_SIZE];
memcpy_P(header_buffer, ART_NET_HEADER, ART_NET_HEADER_SIZE);
ddpUdp.write(header_buffer, ART_NET_HEADER_SIZE); // This doesn't change. Hard coded ID, OpCode, and protocol version.
ddpUdp.write(sequenceNumber & 0xFF); // sequence number. 1..255
ddpUdp.write(0x00); // physical - more an FYI, not really used for anything. 0..3
ddpUdp.write((currentPacket) & 0xFF); // Universe LSB. 1 full packet == 1 full universe, so just use current packet number.

View File

@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2303240
#define VERSION 2304090
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG