Searchable presets.

Inline sin_gap().
Prevent live timeout.
This commit is contained in:
Blaz Kristan 2022-03-10 22:36:09 +01:00
parent 06fe7323eb
commit 841a9f8082
8 changed files with 4263 additions and 4223 deletions

View File

@ -670,9 +670,13 @@ class WS2812FX {
setPixelSegment(uint8_t n), setPixelSegment(uint8_t n),
gamma8(uint8_t), gamma8(uint8_t),
gamma8_cal(uint8_t, float), gamma8_cal(uint8_t, float),
sin_gap(uint16_t),
get_random_wheel_index(uint8_t); get_random_wheel_index(uint8_t);
inline uint8_t sin_gap(uint16_t in) {
if (in & 0x100) return 0;
return sin8(in + 192); //correct phase shift of sine so that it starts and stops at 0
}
int8_t int8_t
tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec); tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec);

View File

@ -931,12 +931,6 @@ uint16_t IRAM_ATTR WS2812FX::triwave16(uint16_t in)
return 0xFFFF - (in - 0x8000)*2; return 0xFFFF - (in - 0x8000)*2;
} }
uint8_t IRAM_ATTR WS2812FX::sin_gap(uint16_t in) {
if (in & 0x100) return 0;
//if (in > 255) return 0;
return sin8(in + 192); //correct phase shift of sine so that it starts and stops at 0
}
/* /*
* Generates a tristate square wave w/ attac & decay * Generates a tristate square wave w/ attac & decay
* @param x input value 0-255 * @param x input value 0-255

View File

@ -139,19 +139,21 @@ button {
} }
.segt TD { .segt TD {
padding: 2px !important;
text-align: center; text-align: center;
/*text-transform: uppercase;*/ /*text-transform: uppercase;*/
} }
.segt TD, .plentry TD { .segt TD, .plentry TD {
font-size: 14px; font-size: 13px;
padding: 0; padding: 0;
vertical-align: middle; vertical-align: middle;
} }
/*
.segt TD.h, .plentry TD.h { .segt TD.h, .plentry TD.h {
font-size: 13px; font-size: 13px;
padding: 2px 0 0; padding: 2px 0 0;
} }
*/
.keytd { .keytd {
text-align: left; text-align: left;
} }
@ -317,6 +319,20 @@ button {
margin: 10px 0; margin: 10px 0;
} }
#pcont {
margin-bottom: 10px;
}
#putil {
padding: 0 0 10px;
margin: 0 auto;
}
#putil .btn-n, #putil .btn-s {
/*box-shadow: 0 0 0 5px var(--c-1);*/
margin-bottom: 10px;
}
.smooth { transition: transform calc(var(--f, 1)*.5s) ease-out } .smooth { transition: transform calc(var(--f, 1)*.5s) ease-out }
.tab-label { .tab-label {
@ -386,7 +402,7 @@ button {
color: var(--c-f); color: var(--c-f);
text-align: center; text-align: center;
border-radius: 5px; border-radius: 5px;
padding: 16px; padding: 22px;
position: fixed; position: fixed;
z-index: 5; z-index: 5;
left: 50%; left: 50%;
@ -655,8 +671,8 @@ input[type=range]::-moz-range-thumb {
transform:translate3d(0,0,0); transform:translate3d(0,0,0);
overflow: clip; overflow: clip;
text-overflow: clip; text-overflow: clip;
border: 1px solid var(--c-2); border: 1px solid var(--c-3);
background-color: var(--c-2); background-color: var(--c-3);
} }
.btn:hover { .btn:hover {
border: 1px solid var(--c-5); border: 1px solid var(--c-5);
@ -680,12 +696,16 @@ input[type=range]::-moz-range-thumb {
margin: 5px 0; margin: 5px 0;
} }
.btn-xs, .btn-pl-del, .btn-pl-add { .btn-xs, .btn-pl-del, .btn-pl-add {
width: 42px; width: 42px !important;
height: 42px; height: 42px !important;
} }
.btn-xs { .btn-xs {
margin: 2px 0 0 0; margin: 2px 0 0 0;
} }
#putil .btn-xs {
margin: 0;
}
.btn-pl-del, .btn-pl-add { .btn-pl-del, .btn-pl-add {
margin: 0; margin: 0;
white-space: nowrap; white-space: nowrap;
@ -762,11 +782,10 @@ input[type=number], input[type=text] {
border: 0px solid var(--c-2); border: 0px solid var(--c-2);
border-radius: 5px; border-radius: 5px;
padding: 8px; padding: 8px;
margin: 6px 6px 6px 0; /*margin: 6px 6px 6px 0;*/
font-size: 19px; font-size: 19px;
transition: background-color 0.2s; transition: background-color 0.2s;
outline: none; outline: none;
width: 50px;
-webkit-appearance: textfield; -webkit-appearance: textfield;
-moz-appearance: textfield; -moz-appearance: textfield;
appearance: textfield; appearance: textfield;
@ -774,12 +793,13 @@ input[type=number], input[type=text] {
input[type=number] { input[type=number] {
text-align: right; text-align: right;
width: 50px;
} }
textarea { textarea {
background: var(--c-2); background: var(--c-2);
color: var(--c-f); color: var(--c-f);
width: 250px; /* +padding=260px */ width: calc(100% - 14px); /* +padding=260px */
height: 90px; height: 90px;
border-radius: 5px; border-radius: 5px;
border: 2px solid var(--c-5); border: 2px solid var(--c-5);
@ -789,17 +809,21 @@ textarea {
padding: 5px; padding: 5px;
} }
.apitxt {
height: 7em;
}
::selection { ::selection {
background: var(--c-b); background: var(--c-b);
} }
input[type=text] { input[type=text] {
width: 100px; width: calc(100% - 24px);
text-align: center; text-align: center;
} }
.ptxt { .ptxt {
width: 240px !important; /*width: 236px !important;*/
margin: 0 4px 4px !important; margin: 0 4px 4px !important;
} }
@ -836,9 +860,9 @@ input[type=number]::-webkit-outer-spin-button {
.pid { .pid {
position: absolute; position: absolute;
top: 2px; top: 8px;
left: 0px; left: 12px;
padding: 12px 0px 0px 12px; /*padding: 10px 0 0 12px;*/
font-size: 16px; font-size: 16px;
text-align: center; text-align: center;
color: var(--c-b); color: var(--c-b);
@ -1044,9 +1068,7 @@ input[type=number]::-webkit-outer-spin-button {
} }
#segcont .seg:hover:not([class*="expanded"]), #segcont .seg:hover:not([class*="expanded"]),
#pcont .pres:hover:not([class*="expanded"]), .lstI:hover:not([class*="expanded"]) {
#pcont .selected:hover:not([class*="expanded"]),
.lstI:hover {
background: var(--c-5); background: var(--c-5);
} }
@ -1065,6 +1087,11 @@ input[type=number]::-webkit-outer-spin-button {
.lstI.sticky, .lstI.selected { .lstI.sticky, .lstI.selected {
z-index: 1; z-index: 1;
} }
#pcont .selected {
bottom: 114px;
top: 40px;
}
/* calculated in index.js /* calculated in index.js
#fxlist .lstI.selected { #fxlist .lstI.selected {
top: 142px; top: 142px;
@ -1085,8 +1112,8 @@ input[type=number]::-webkit-outer-spin-button {
.lstIcontent { .lstIcontent {
/*width: 100%; /*width: 100%;
vertical-align: middle; vertical-align: middle;*/
padding: 0 20px 0 5px; padding: 0; /*20px 0 5px;
text-align: left; text-align: left;
display: inline-block;*/ display: inline-block;*/
position: relative; position: relative;
@ -1110,6 +1137,8 @@ input[type=number]::-webkit-outer-spin-button {
.fnd { .fnd {
width: 280px; width: 280px;
margin: 0 auto; margin: 0 auto;
/*border-radius: 25px;
box-shadow: 0 0 0 5px var(--c-1);*/
} }
input[type="text"].fnd { input[type="text"].fnd {
@ -1133,22 +1162,29 @@ input[type="text"].fnd:hover {
} }
.segin { .segin {
padding: 8px; padding: 8px 8px 0;
display: none; }
.presin {
padding: 8px 0 0;
} }
.modal .btn, .segin .btn { .btn-s, .btn-n {
border: 1px solid var(--c-3); border: 1px solid var(--c-2);
background-color: var(--c-3); background-color: var(--c-2);
} }
.modal .btn:hover, .segin .btn:hover { .modal .btn:hover, .segin .btn:hover {
border: 1px solid var(--c-5); border: 1px solid var(--c-5);
background-color: var(--c-5); background-color: var(--c-5);
} }
/* must be after .expanded */
.pres .lstIcontent, .segin {
display: none;
}
.check input:checked ~ .checkmark:after, .radio input:checked ~ .radiomark:after, .check input:checked ~ .checkmark:after, .radio input:checked ~ .radiomark:after,
.expanded, .expanded .segin { .expanded {
display: block; display: block !important;
} }
.c { .c {

View File

@ -182,50 +182,52 @@
</div> </div>
<div id="Effects" class="tabcontent"> <div id="Effects" class="tabcontent">
<p class="labels" id="sliderLabel0">Effect speed</p> <div id="sliders">
<div class="staytop" id="slider0"> <p class="labels" id="sliderLabel0">Effect speed</p>
<i class="icons slider-icon" style="cursor: pointer;" onclick="tglFreeze()">&#xe325;</i> <div class="staytop" id="slider0">
<div class="sliderwrap il"> <i class="icons slider-icon" style="cursor: pointer;" onclick="tglFreeze()">&#xe325;</i>
<input id="sliderSpeed" class="noslide" onchange="setSpeed()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" /> <div class="sliderwrap il">
<div class="sliderdisplay"></div> <input id="sliderSpeed" class="noslide" onchange="setSpeed()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
<div class="sliderdisplay"></div>
</div>
<output class="sliderbubble"></output>
</div> </div>
<output class="sliderbubble"></output> <p class="labels" id="sliderLabel1">Effect intensity</p>
</div> <div class="staytop" id="slider1">
<p class="labels" id="sliderLabel1">Effect intensity</p> <i class="icons slider-icon" style="cursor: pointer;" onclick="tglLabels()">&#xe409;</i>
<div class="staytop" id="slider1"> <div class="sliderwrap il">
<i class="icons slider-icon" style="cursor: pointer;" onclick="tglLabels()">&#xe409;</i> <input id="sliderIntensity" class="noslide" onchange="setIntensity()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" />
<div class="sliderwrap il"> <div class="sliderdisplay"></div>
<input id="sliderIntensity" class="noslide" onchange="setIntensity()" oninput="updateTrail(this)" max="255" min="0" type="range" value="128" /> </div>
<div class="sliderdisplay"></div> <output class="sliderbubble"></output>
</div> </div>
<output class="sliderbubble"></output> <p class="labels" id="sliderLabel2">Custom 1</p>
</div> <div class="staytop" id="slider2">
<p class="labels" id="sliderLabel2">Custom 1</p> <i class="icons slider-icon">&#xe410;</i>
<div class="staytop" id="slider2"> <div class="sliderwrap il">
<i class="icons slider-icon">&#xe410;</i> <input id="sliderC1" class="noslide" onchange="setFFT1()" oninput="updateTrail(this)" max="255" min="0" type="range" value="6" />
<div class="sliderwrap il"> <div class="sliderdisplay"></div>
<input id="sliderC1" class="noslide" onchange="setFFT1()" oninput="updateTrail(this)" max="255" min="0" type="range" value="6" /> </div>
<div class="sliderdisplay"></div> <output class="sliderbubble"></output>
</div> </div>
<output class="sliderbubble"></output> <p class="labels" id="sliderLabel3">Custom 2</p>
</div> <div class="staytop" id="slider3">
<p class="labels" id="sliderLabel3">Custom 2</p> <i class="icons slider-icon">&#xe410;</i>
<div class="staytop" id="slider3"> <div class="sliderwrap il">
<i class="icons slider-icon">&#xe410;</i> <input id="sliderC2" class="noslide" onchange="setFFT2()" oninput="updateTrail(this)" max="255" min="0" type="range" value="6" />
<div class="sliderwrap il"> <div class="sliderdisplay"></div>
<input id="sliderC2" class="noslide" onchange="setFFT2()" oninput="updateTrail(this)" max="255" min="0" type="range" value="6" /> </div>
<div class="sliderdisplay"></div> <output class="sliderbubble"></output>
</div> </div>
<output class="sliderbubble"></output> <p class="labels" id="sliderLabel4">Custom 3</p>
</div> <div class="staytop" id="slider4">
<p class="labels" id="sliderLabel4">Custom 3</p> <i class="icons slider-icon">&#xe410;</i>
<div class="staytop" id="slider4"> <div class="sliderwrap il">
<i class="icons slider-icon">&#xe410;</i> <input id="sliderC3" class="noslide" onchange="setFFT3()" oninput="updateTrail(this)" max="255" min="0" type="range" value="6" />
<div class="sliderwrap il"> <div class="sliderdisplay"></div>
<input id="sliderC3" class="noslide" onchange="setFFT3()" oninput="updateTrail(this)" max="255" min="0" type="range" value="6" /> </div>
<div class="sliderdisplay"></div> <output class="sliderbubble"></output>
</div> </div>
<output class="sliderbubble"></output>
</div> </div>
<div class="il"> <div class="il">
<p class="labels hd" id="modeLabel">Effect mode</p> <p class="labels hd" id="modeLabel">Effect mode</p>
@ -235,7 +237,15 @@
<i class="icons search-icon">&#xe0a1;</i> <i class="icons search-icon">&#xe0a1;</i>
</div> </div>
<div id="fxlist" class="list"> <div id="fxlist" class="list">
Loading... <div class="lstI">
<label class="radio schkl" onclick="loadFX()">
<div class="lstIcontent">
<span class="lstIname">
Loading...
</span>
</div>
</label>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -253,13 +263,19 @@
</div> </div>
<div id="Presets" class="tabcontent"> <div id="Presets" class="tabcontent">
<div id="putil" class="staytop">
</div>
<div id="pql"> <div id="pql">
</div> </div>
<div id="pcont"> <p class="labels hd">Presets</p>
<div class="staytop fnd" id="psFind">
<input type="text" class="fnd" placeholder="Search" oninput="search(this,'pcont')" onfocus="search(this,'pcont')" />
<i class="icons clear-icon" onclick="clean(this);">&#xe38f;</i>
<i class="icons search-icon">&#xe0a1;</i>
</div>
<div id="pcont" class="list">
<span onclick="loadPresets()">Loading...</span> <span onclick="loadPresets()">Loading...</span>
</div> </div>
<div id="putil" class="staybot">
</div>
</div> </div>
</div> </div>
@ -271,7 +287,7 @@
</div> </div>
<div id="connind"></div> <div id="connind"></div>
<div id="toast"></div> <div id="toast" onclick="clearErrorToast(100);"></div>
<div id="namelabel" onclick="toggleNodes()"></div> <div id="namelabel" onclick="toggleNodes()"></div>
<div id="info" class="modal"> <div id="info" class="modal">
<div id="imgw"> <div id="imgw">

View File

@ -294,6 +294,7 @@ function showToast(text, error = false)
{ {
if (error) gId('connind').style.backgroundColor = "var(--c-r)"; if (error) gId('connind').style.backgroundColor = "var(--c-r)";
var x = gId("toast"); var x = gId("toast");
if (error) text += '<i class="icons btn-icon" style="transform:rotate(45deg);position:absolute;top:10px;right:0px;" onclick="clearErrorToast(100);">&#xe18a;</i>';
x.innerHTML = text; x.innerHTML = text;
x.classList.add(error ? "error":"show"); x.classList.add(error ? "error":"show");
clearTimeout(timeout); clearTimeout(timeout);
@ -307,7 +308,7 @@ function showErrorToast()
showToast('Connection to light failed!', true); showToast('Connection to light failed!', true);
} }
function clearErrorToast() function clearErrorToast(n=10000)
{ {
var x = gId("toast"); var x = gId("toast");
if (x.classList.contains("error")) { if (x.classList.contains("error")) {
@ -315,7 +316,7 @@ function clearErrorToast()
timeout = setTimeout(()=>{ timeout = setTimeout(()=>{
x.classList.remove("show"); x.classList.remove("show");
x.classList.remove("error"); x.classList.remove("error");
}, 10000); }, n);
} }
} }
@ -401,7 +402,7 @@ function presetError(empty)
if (bckstr.length > 10) hasBackup = true; if (bckstr.length > 10) hasBackup = true;
} catch (e) {} } catch (e) {}
var cn = `<div class="seg c" style="padding:8px;">`; var cn = `<div class="pres c" ${empty?'style="padding:8px;"':'onclick="loadPresets()" style="cursor:pointer;padding:8px;"'}>`;
if (empty) if (empty)
cn += `You have no presets yet!`; cn += `You have no presets yet!`;
else else
@ -436,8 +437,6 @@ function loadPresets(callback = null)
// afterwards // afterwards
if (!callback && pmt == pmtLast) return; if (!callback && pmt == pmtLast) return;
pmtLast = pmt;
var url = (loc?`http://${locip}`:'') + '/presets.json'; var url = (loc?`http://${locip}`:'') + '/presets.json';
fetch(url, { fetch(url, {
@ -449,6 +448,7 @@ function loadPresets(callback = null)
}) })
.then(json => { .then(json => {
pJson = json; pJson = json;
pmtLast = pmt;
populatePresets(); populatePresets();
}) })
.catch((e)=>{ .catch((e)=>{
@ -477,7 +477,6 @@ function loadPalettes(callback = null)
}) })
.catch((e)=>{ .catch((e)=>{
showToast(e, true); showToast(e, true);
presetError(false);
}) })
.finally(()=>{ .finally(()=>{
if (callback) callback(); if (callback) callback();
@ -502,7 +501,6 @@ function loadFX(callback = null)
}) })
.catch((e)=>{ .catch((e)=>{
showToast(e, true); showToast(e, true);
presetError(false);
}) })
.finally(()=>{ .finally(()=>{
if (callback) callback(); if (callback) callback();
@ -556,7 +554,7 @@ function populatePresets(fromls)
if (fromls) pJson = JSON.parse(localStorage.getItem("wledP")); if (fromls) pJson = JSON.parse(localStorage.getItem("wledP"));
if (!pJson) {setTimeout(loadPresets,250); return;} if (!pJson) {setTimeout(loadPresets,250); return;}
delete pJson["0"]; delete pJson["0"];
var cn = `<p class="labels hd">All presets</p>`; var cn = "";
var arr = Object.entries(pJson); var arr = Object.entries(pJson);
arr.sort(cmpP); arr.sort(cmpP);
pQL = []; pQL = [];
@ -570,11 +568,11 @@ function populatePresets(fromls)
if (qll) pQL.push([i, qll, pName(i)]); if (qll) pQL.push([i, qll, pName(i)]);
is.push(i); is.push(i);
cn += `<div class="pres" id="p${i}o">`; cn += `<div class="pres lstI" id="p${i}o">`;
if (cfg.comp.pid) cn += `<div class="pid">${i}</div>`; if (cfg.comp.pid) cn += `<div class="pid">${i}</div>`;
cn += `<div class="pname" onclick="setPreset(${i})">${isPlaylist(i)?"<i class='icons btn-icon'>&#xe139;</i>":""}${pName(i)}</div> cn += `<div class="pname lstIname" onclick="setPreset(${i})">${isPlaylist(i)?"<i class='icons btn-icon'>&#xe139;</i>":""}${pName(i)}</div>
<i class="icons e-icon flr ${expanded[i+100] ? "exp":""}" id="sege${i+100}" onclick="expand(${i+100})">&#xe395;</i> <i class="icons e-icon flr ${expanded[i+100] ? "exp":""}" id="sege${i+100}" onclick="expand(${i+100})">&#xe395;</i>
<div class="segin" id="seg${i+100}"></div> <div class="presin lstIcontent" id="seg${i+100}"></div>
</div>`; </div>`;
pNum++; pNum++;
} }
@ -1263,7 +1261,7 @@ function setSliderAndColorControl(idx, applyDef=false)
var obj = {"seg":{}}; var obj = {"seg":{}};
// set html slider items on/off // set html slider items on/off
var nSliders = Math.min(5,Math.floor((gId("Effects").children.length - 1) / 2)); // p (label) & div for each slider + FX list var nSliders = Math.min(5,Math.floor((gId("sliders").children.length - 1) / 2)); // p (label) & div for each slider + FX list
for (let i=0; i<nSliders; i++) { for (let i=0; i<nSliders; i++) {
var slider = gId("slider" + i); var slider = gId("slider" + i);
var label = gId("sliderLabel" + i); var label = gId("sliderLabel" + i);
@ -1703,11 +1701,6 @@ ${(i>0)? ('<div class="h">ID ' +i+ '</div>'):""}`;
function makePUtil() function makePUtil()
{ {
gId('putil').classList.remove("staytop");
gId('putil').scrollIntoView({
behavior: 'smooth',
block: 'start',
});
gId('putil').innerHTML = `<div class="pres"><div class="segin expanded">${makeP(0)}</div></div>`; gId('putil').innerHTML = `<div class="pres"><div class="segin expanded">${makeP(0)}</div></div>`;
} }
@ -1724,9 +1717,9 @@ function makePlEntry(p,i) {
<td class="c"><button class="btn btn-pl-add" onclick="addPl(${p},${i})"><i class="icons btn-icon">&#xe18a;</i></button></td> <td class="c"><button class="btn btn-pl-add" onclick="addPl(${p},${i})"><i class="icons btn-icon">&#xe18a;</i></button></td>
</tr> </tr>
<tr> <tr>
<td class="h">Duration</td> <td class="c">Duration</td>
<td class="h">Transition</td> <td class="c">Transition</td>
<td class="h">#${i+1}</td> <td class="c">#${i+1}</td>
</tr> </tr>
<tr> <tr>
<td class="c" width="40%"><input class="noslide segn" type="number" placeholder="Duration" max=6553.0 min=0.2 step=0.1 oninput="pleDur(${p},${i},this)" value="${plJson[p].dur[i]/10.0}">s</td> <td class="c" width="40%"><input class="noslide segn" type="number" placeholder="Duration" max=6553.0 min=0.2 step=0.1 oninput="pleDur(${p},${i},this)" value="${plJson[p].dur[i]/10.0}">s</td>
@ -1743,21 +1736,14 @@ function makePlUtil()
showToast("You need at least 2 presets to make a playlist!"); //return; showToast("You need at least 2 presets to make a playlist!"); //return;
} }
if (plJson[0].transition[0] < 0) plJson[0].transition[0] = tr; if (plJson[0].transition[0] < 0) plJson[0].transition[0] = tr;
gId('putil').classList.remove("staytop");
gId('putil').scrollIntoView({
behavior: 'smooth',
block: 'start',
});
gId('putil').innerHTML = `<div class="pres"><div class="segin expanded" id="seg100">${makeP(0,true)}</div></div>`; gId('putil').innerHTML = `<div class="pres"><div class="segin expanded" id="seg100">${makeP(0,true)}</div></div>`;
refreshPlE(0); refreshPlE(0);
} }
function resetPUtil() function resetPUtil()
{ {
gId('putil').classList.add("staytop"); gId('putil').innerHTML = `<button class="btn btn-s" onclick="makePUtil()"><i class="icons btn-icon">&#xe18a;</i>New&nbsp;preset</button><br>`+
var cn = `<button class="btn btn-n" onclick="makePUtil()"><i class="icons btn-icon">&#xe18a;</i>New&nbsp;preset</button>`+ `<button class="btn btn-s" onclick="makePlUtil()"><i class="icons btn-icon">&#xe139;</i>New&nbsp;playlist</button>`;
`<button class="btn btn-xs" onclick="makePlUtil()"><i class="icons btn-icon">&#xe139;</i></button>`;
gId('putil').innerHTML = cn;
} }
function tglCs(i) function tglCs(i)
@ -2160,12 +2146,8 @@ function setColor(sr)
cdd.b = b = hasRGB ? col.b : w; cdd.b = b = hasRGB ? col.b : w;
cdd.w = w; cdd.w = w;
setCSL(cd[csel]); setCSL(cd[csel]);
var obj = {"seg": {"col": [[r, g, b, w],[],[]]}}; var obj = {"seg": {"col": [[],[],[]]}};
if (csel == 1) { obj.seg.col[csel] = [r, g, b, w];
obj = {"seg": {"col": [[],[r, g, b, w],[]]}};
} else if (csel == 2) {
obj = {"seg": {"col": [[],[],[r, g, b, w]]}};
}
requestJson(obj); requestJson(obj);
} }
@ -2353,11 +2335,13 @@ function expand(i, c=false)
tglCs(p); tglCs(p);
} else } else
seg.innerHTML = ""; seg.innerHTML = "";
} else {
gId('seg' +i +'in').classList.toggle("expanded");
} }
seg.parentElement.scrollIntoView({ seg.parentElement.scrollIntoView({
behavior: 'smooth', behavior: 'smooth',
block: (expanded[i]?'start':'center'), block: /*(expanded[i]?'start':*/'center'/*)*/,
}); });
} }

File diff suppressed because it is too large Load Diff

View File

@ -148,8 +148,10 @@ void realtimeLock(uint32_t timeoutMs, byte md)
} }
} }
realtimeTimeout = millis() + timeoutMs; if (realtimeTimeout != UINT32_MAX) {
if (timeoutMs == 255001 || timeoutMs == 65000) realtimeTimeout = UINT32_MAX; realtimeTimeout = millis() + timeoutMs;
if (timeoutMs == 255001 || timeoutMs == 65000) realtimeTimeout = UINT32_MAX;
}
// if strip is off (bri==0) and not already in RTM // if strip is off (bri==0) and not already in RTM
if (bri == 0 && !realtimeMode) { if (bri == 0 && !realtimeMode) {
strip.setBrightness(scaledBri(briLast)); strip.setBrightness(scaledBri(briLast));

View File

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