Dual mode 2D + 1D with auto segment creation. (#3060)
* Dual mode 2D + 1D with auto segment creation. * Bugfix. - stop when seglen
This commit is contained in:
parent
6be9317fd7
commit
dca8a47da8
@ -393,8 +393,8 @@ void Segment::set(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t o
|
||||
markForReset();
|
||||
return;
|
||||
}
|
||||
if (i1 < Segment::maxWidth) start = i1; // Segment::maxWidth equals strip.getLengthTotal() for 1D
|
||||
stop = i2 > Segment::maxWidth ? Segment::maxWidth : MAX(1,i2);
|
||||
if (i1 < Segment::maxWidth || (i1 >= Segment::maxWidth*Segment::maxHeight && i1 < strip.getLengthTotal())) start = i1; // Segment::maxWidth equals strip.getLengthTotal() for 1D
|
||||
stop = i2 > Segment::maxWidth*Segment::maxHeight ? MIN(i2,strip.getLengthTotal()) : (i2 > Segment::maxWidth ? Segment::maxWidth : MAX(1,i2));
|
||||
startY = 0;
|
||||
stopY = 1;
|
||||
#ifndef WLED_DISABLE_2D
|
||||
@ -600,6 +600,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
|
||||
}
|
||||
return;
|
||||
} else if (Segment::maxHeight!=1 && (width()==1 || height()==1)) {
|
||||
if (start < Segment::maxWidth*Segment::maxHeight) {
|
||||
// we have a vertical or horizontal 1D segment (WARNING: virtual...() may be transposed)
|
||||
int x = 0, y = 0;
|
||||
if (virtualHeight()>1) y = i;
|
||||
@ -607,6 +608,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
|
||||
setPixelColorXY(x, y, col);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (leds) leds[i] = col;
|
||||
@ -1412,6 +1414,20 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
|
||||
_segments[i].spacing = 0;
|
||||
_mainSegment = i;
|
||||
}
|
||||
// do we have LEDs after the matrix? (ignore buses)
|
||||
if (autoSegments && _length > Segment::maxWidth*Segment::maxHeight /*&& getActiveSegmentsNum() == 2*/) {
|
||||
if (_segments.size() == getLastActiveSegmentId()+1)
|
||||
_segments.push_back(Segment(Segment::maxWidth*Segment::maxHeight, _length));
|
||||
else {
|
||||
size_t i = getLastActiveSegmentId() + 1;
|
||||
_segments[i].start = Segment::maxWidth*Segment::maxHeight;
|
||||
_segments[i].stop = _length;
|
||||
_segments[i].startY = 0;
|
||||
_segments[i].stopY = 1;
|
||||
_segments[i].grouping = 1;
|
||||
_segments[i].spacing = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if (autoSegments) { //make one segment per bus
|
||||
uint16_t segStarts[MAX_NUM_SEGMENTS] = {0};
|
||||
@ -1435,6 +1451,7 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
|
||||
s++;
|
||||
}
|
||||
_segments.clear();
|
||||
_segments.reserve(s); // prevent reallocations
|
||||
for (size_t i = 0; i < s; i++) {
|
||||
Segment seg = Segment(segStarts[i], segStops[i]);
|
||||
seg.selected = true;
|
||||
@ -1482,8 +1499,7 @@ bool WS2812FX::checkSegmentAlignment() {
|
||||
//After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply)
|
||||
//Note: If called in an interrupt (e.g. JSON API), original segment must be restored,
|
||||
//otherwise it can lead to a crash on ESP32 because _segment_index is modified while in use by the main thread
|
||||
uint8_t WS2812FX::setPixelSegment(uint8_t n)
|
||||
{
|
||||
uint8_t WS2812FX::setPixelSegment(uint8_t n) {
|
||||
uint8_t prevSegId = _segment_index;
|
||||
if (n < _segments.size()) {
|
||||
_segment_index = n;
|
||||
@ -1492,8 +1508,7 @@ uint8_t WS2812FX::setPixelSegment(uint8_t n)
|
||||
return prevSegId;
|
||||
}
|
||||
|
||||
void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col)
|
||||
{
|
||||
void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) {
|
||||
if (i2 >= i)
|
||||
{
|
||||
for (uint16_t x = i; x <= i2; x++) setPixelColor(x, col);
|
||||
@ -1503,14 +1518,12 @@ void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col)
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::setTransitionMode(bool t)
|
||||
{
|
||||
void WS2812FX::setTransitionMode(bool t) {
|
||||
for (segment &seg : _segments) if (!seg.transitional) seg.startTransition(t ? _transitionDur : 0);
|
||||
}
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
void WS2812FX::printSize()
|
||||
{
|
||||
void WS2812FX::printSize() {
|
||||
size_t size = 0;
|
||||
for (const Segment &seg : _segments) size += seg.getSize();
|
||||
DEBUG_PRINTF("Segments: %d -> %uB\n", _segments.size(), size);
|
||||
@ -1521,8 +1534,7 @@ void WS2812FX::printSize()
|
||||
}
|
||||
#endif
|
||||
|
||||
void WS2812FX::loadCustomPalettes()
|
||||
{
|
||||
void WS2812FX::loadCustomPalettes() {
|
||||
byte tcp[72]; //support gradient palettes with up to 18 entries
|
||||
CRGBPalette16 targetPalette;
|
||||
customPalettes.clear(); // start fresh
|
||||
|
@ -713,7 +713,7 @@ function populateSegments(s)
|
||||
let rvXck = `<label class="check revchkl">Reverse ${isM?'':'direction'}<input type="checkbox" id="seg${i}rev" onchange="setRev(${i})" ${inst.rev?"checked":""}><span class="checkmark"></span></label>`;
|
||||
let miXck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mi" onchange="setMi(${i})" ${inst.mi?"checked":""}><span class="checkmark"></span></label>`;
|
||||
let rvYck = "", miYck ="";
|
||||
if (isM) {
|
||||
if (isM && staX<mw*mh) {
|
||||
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>`;
|
||||
}
|
||||
@ -749,19 +749,19 @@ function populateSegments(s)
|
||||
<input type="text" class="ptxt noslide" id="seg${i}t" autocomplete="off" maxlength=32 value="${inst.n?inst.n:""}" placeholder="Enter name..."/>
|
||||
<table class="infot segt">
|
||||
<tr>
|
||||
<td>${isM?'Start X':'Start LED'}</td>
|
||||
<td>${isM?(cfg.comp.seglen?"Width":"Stop X"):(cfg.comp.seglen?"LED count":"Stop LED")}</td>
|
||||
<td>${isM?'':'Offset'}</td>
|
||||
<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="noslide segn" id="seg${i}s" type="number" min="0" max="${(isM?mw:ledCount)-1}" value="${staX}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
|
||||
<td><input class="noslide segn" id="seg${i}e" type="number" min="0" max="${(isM?mw:ledCount)-(cfg.comp.seglen?staX:0)}" value="${stoX-(cfg.comp.seglen?staX:0)}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
|
||||
<td style="text-align:revert;">${isM?miXck+'<br>'+rvXck:''}<input class="noslide segn ${isM?'hide':''}" id="seg${i}of" type="number" value="${inst.of}" oninput="updateLen(${i})"></td>
|
||||
<td><input class="noslide 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="noslide 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="noslide segn ${isM&&staX<mw*mh?'hide':''}" id="seg${i}of" type="number" value="${inst.of}" oninput="updateLen(${i})"></td>
|
||||
</tr>
|
||||
${isM ? '<tr><td>Start Y</td><td>'+(cfg.comp.seglen?'Height':'Stop Y')+'</td><td></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="noslide segn" id="seg'+i+'sY" type="number" min="0" max="'+(mh-1)+'" value="'+staY+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
|
||||
'<td><input class="noslide segn" id="seg'+i+'eY" type="number" min="0" max="'+(mh-(cfg.comp.seglen?staY:0))+'" value="'+(stoY-(cfg.comp.seglen?staY:0))+'" oninput="updateLen('+i+')" onkeydown="segEnter('+i+')"></td>'+
|
||||
'<td><input class="noslide 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>
|
||||
@ -772,16 +772,17 @@ function populateSegments(s)
|
||||
<tr>
|
||||
<td><input class="noslide segn" id="seg${i}grp" type="number" min="1" max="255" value="${inst.grp}" oninput="updateLen(${i})" onkeydown="segEnter(${i})"></td>
|
||||
<td><input class="noslide 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:left;"><button class="btn btn-xs" onclick="setSeg(${i})"><i class="icons btn-icon" id="segc${i}"></i></button></td>
|
||||
<td style="text-align:revert;"><button class="btn btn-xs" onclick="setSeg(${i})"><i class="icons btn-icon" id="segc${i}"></i></button></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="h bp" id="seg${i}len"></div>
|
||||
${!isM?rvXck:''}
|
||||
${isM&&stoY-staY>1&&stoX-staX>1?map2D:''}
|
||||
${!(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?'Transpose':'Mirror effect'}
|
||||
<input type="checkbox" id="seg${i}${isM?'tp':'mi'}" onchange="${(isM?'setTp(':'setMi(')+i})" ${isM?(inst.tp?"checked":""):(inst.mi?"checked":"")}>
|
||||
${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">
|
||||
@ -1049,10 +1050,30 @@ function updateLen(s)
|
||||
var start = parseInt(gId(`seg${s}s`).value);
|
||||
var stop = parseInt(gId(`seg${s}e`).value) + (cfg.comp.seglen?start:0);
|
||||
var len = stop - start;
|
||||
let sY = gId(`seg${s}sY`);
|
||||
let eY = gId(`seg${s}eY`);
|
||||
let sX = gId(`seg${s}s`);
|
||||
let eX = gId(`seg${s}e`);
|
||||
let of = gId(`seg${s}of`);
|
||||
let mySH = gId("mkSYH");
|
||||
let mySD = gId("mkSYD");
|
||||
if (isM) {
|
||||
// do we have 1D segment *after* the matrix?
|
||||
if (start >= mw*mh) {
|
||||
if (sY) { sY.value = 0; sY.max = 0; sY.min = 0; }
|
||||
if (eY) { eY.value = 1; eY.max = 1; eY.min = 0; }
|
||||
sX.min = mw*mh; sX.max = ledCount-1;
|
||||
eX.min = mw*mh+1; eX.max = ledCount;
|
||||
if (mySH) mySH.classList.add("hide");
|
||||
if (mySD) mySD.classList.add("hide");
|
||||
if (of) of.classList.remove("hide");
|
||||
} else {
|
||||
// matrix setup
|
||||
let startY = parseInt(gId(`seg${s}sY`).value);
|
||||
let stopY = parseInt(gId(`seg${s}eY`).value) + (cfg.comp.seglen?startY:0);
|
||||
if (mySH) mySH.classList.remove("hide");
|
||||
if (mySD) mySD.classList.remove("hide");
|
||||
if (of) of.classList.add("hide");
|
||||
let startY = parseInt(sY.value);
|
||||
let stopY = parseInt(eY.value) + (cfg.comp.seglen?startY:0);
|
||||
len *= (stopY-startY);
|
||||
let tPL = gId(`seg${s}lbtm`);
|
||||
if (stop-start>1 && stopY-startY>1) {
|
||||
@ -1075,6 +1096,7 @@ function updateLen(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var out = "(delete)";
|
||||
if (len > 1) {
|
||||
out = `${len} LEDs`;
|
||||
@ -1090,6 +1112,7 @@ function updateLen(s)
|
||||
var virt = Math.ceil(len/(grp + spc));
|
||||
if (!isNaN(virt) && (grp > 1 || spc > 0)) out += ` (${virt} virtual)`;
|
||||
}
|
||||
if (isM && start >= mw*mh) out += " [strip]";
|
||||
|
||||
gId(`seg${s}len`).innerHTML = out;
|
||||
}
|
||||
@ -1692,11 +1715,11 @@ function makeSeg()
|
||||
<td><input class="noslide 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}"></i></button></td>
|
||||
</tr>
|
||||
${isM ? '<tr><td>Start Y</td><td>'+(cfg.comp.seglen?'Height':'Stop Y')+'</td></tr>'+
|
||||
'<tr>'+
|
||||
'<td><input class="noslide segn" id="seg'+lu+'sY" type="number" min="0" max="'+(mh-1)+'" value="'+0+'" oninput="updateLen('+lu+')" onkeydown="segEnter('+lu+')"></td>'+
|
||||
'<td><input class="noslide segn" id="seg'+lu+'eY" type="number" min="0" max="'+mh+'" value="'+mh+'" oninput="updateLen('+lu+')" onkeydown="segEnter('+lu+')"></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="noslide segn" id="seg${lu}sY" type="number" min="0" max="${mh-1}" value="0" oninput="updateLen(${lu})" onkeydown="segEnter(${lu})"></td>
|
||||
<td><input class="noslide 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>
|
||||
@ -2026,25 +2049,26 @@ function setSeg(s)
|
||||
let sX = gId(`seg${s}s`);
|
||||
let eX = gId(`seg${s}e`);
|
||||
var start = parseInt(sX.value);
|
||||
var stop = parseInt(eX.value);
|
||||
var stop = parseInt(eX.value) + (cfg.comp.seglen?start:0);
|
||||
if (start<sX.min || start>sX.max) {sX.value=sX.min; return;} // prevent out of bounds
|
||||
if (stop<eX.min || stop>eX.max) {eX.value=eX.max; return;} // prevent out of bounds
|
||||
if (stop<eX.min || stop-(cfg.comp.seglen?start:0)>eX.max) {eX.value=eX.max; return;} // prevent out of bounds
|
||||
if ((cfg.comp.seglen && stop == 0) || (!cfg.comp.seglen && stop <= start)) {delSeg(s); return;}
|
||||
var obj = {"seg": {"id": s, "n": name, "start": start, "stop": (cfg.comp.seglen?start:0)+stop}};
|
||||
if (isM) {
|
||||
var obj = {"seg": {"id": s, "n": name, "start": start, "stop": stop}};
|
||||
if (isM && start<mw*mh) {
|
||||
let sY = gId(`seg${s}sY`);
|
||||
let eY = gId(`seg${s}eY`);
|
||||
var startY = parseInt(sY.value);
|
||||
var stopY = parseInt(eY.value);
|
||||
var stopY = parseInt(eY.value) + (cfg.comp.seglen?startY:0);
|
||||
if (startY<sY.min || startY>sY.max) {sY.value=sY.min; return;} // prevent out of bounds
|
||||
if (stopY<eY.min || stopY>eY.max) {eY.value=eY.max; return;} // prevent out of bounds
|
||||
obj.seg.startY = startY;
|
||||
obj.seg.stopY = (cfg.comp.seglen?startY:0)+stopY;
|
||||
obj.seg.stopY = stopY;
|
||||
}
|
||||
if (gId(`seg${s}grp`)) { // advanced options, not present in new segment dialog (makeSeg())
|
||||
var grp = parseInt(gId(`seg${s}grp`).value);
|
||||
var spc = parseInt(gId(`seg${s}spc`).value);
|
||||
var ofs = parseInt(gId(`seg${s}of` ).value);
|
||||
let g = gId(`seg${s}grp`);
|
||||
if (g) { // advanced options, not present in new segment dialog (makeSeg())
|
||||
let grp = parseInt(g.value);
|
||||
let spc = parseInt(gId(`seg${s}spc`).value);
|
||||
let ofs = parseInt(gId(`seg${s}of` ).value);
|
||||
obj.seg.grp = grp;
|
||||
obj.seg.spc = spc;
|
||||
obj.seg.of = ofs;
|
||||
|
3836
wled00/html_ui.h
3836
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2301240
|
||||
#define VERSION 2301290
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
|
Loading…
Reference in New Issue
Block a user