This commit is contained in:
Blaz Kristan 2024-08-05 16:42:21 +02:00
parent d2401a212a
commit e82f38e277
7 changed files with 73 additions and 90 deletions

View File

@ -563,16 +563,16 @@ typedef struct Segment {
// transition functions // transition functions
void startTransition(uint16_t dur); // transition has to start before actual segment values change void startTransition(uint16_t dur); // transition has to start before actual segment values change
void stopTransition(void); // ends transition mode by destroying transition structure void stopTransition(void); // ends transition mode by destroying transition structure (does nothing if not in transition)
void handleTransition(void); inline void handleTransition(void) { if (progress() == 0xFFFFU) stopTransition(); }
#ifndef WLED_DISABLE_MODE_BLEND #ifndef WLED_DISABLE_MODE_BLEND
void swapSegenv(tmpsegd_t &tmpSegD); // copies segment data into specifed buffer, if buffer is not a transition buffer, segment data is overwritten from transition buffer void swapSegenv(tmpsegd_t &tmpSegD); // copies segment data into specifed buffer, if buffer is not a transition buffer, segment data is overwritten from transition buffer
void restoreSegenv(tmpsegd_t &tmpSegD); // restores segment data from buffer, if buffer is not transition buffer, changed values are copied to transition buffer void restoreSegenv(tmpsegd_t &tmpSegD); // restores segment data from buffer, if buffer is not transition buffer, changed values are copied to transition buffer
#endif #endif
uint16_t progress(void); // transition progression between 0-65535 uint16_t progress(void) const; // transition progression between 0-65535
uint8_t currentBri(bool useCct = false); // current segment brightness/CCT (blended while in transition) uint8_t currentBri(bool useCct = false) const; // current segment brightness/CCT (blended while in transition)
uint8_t currentMode(void); // currently active effect/mode (while in transition) uint8_t currentMode(void) const; // currently active effect/mode (while in transition)
uint32_t currentColor(uint8_t slot); // currently active segment color (blended while in transition) uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition)
CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal); CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal);
void setCurrentPalette(void); void setCurrentPalette(void);
@ -587,7 +587,7 @@ typedef struct Segment {
inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); } inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); }
inline void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); } inline void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
#endif #endif
uint32_t getPixelColor(int i); uint32_t getPixelColor(int i) const;
// 1D support functions (some implement 2D as well) // 1D support functions (some implement 2D as well)
void blur(uint8_t, bool smear = false); void blur(uint8_t, bool smear = false);
void fill(uint32_t c); void fill(uint32_t c);
@ -599,8 +599,8 @@ typedef struct Segment {
inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); } inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); }
inline void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); } inline void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); }
inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); } inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); }
uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255); uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const;
uint32_t color_wheel(uint8_t pos); uint32_t color_wheel(uint8_t pos) const;
// 2D matrix // 2D matrix
uint16_t virtualWidth(void) const; // segment width in virtual pixels (accounts for groupping and spacing) uint16_t virtualWidth(void) const; // segment width in virtual pixels (accounts for groupping and spacing)
@ -618,7 +618,7 @@ typedef struct Segment {
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); } inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); }
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); } inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); }
#endif #endif
uint32_t getPixelColorXY(int x, int y); uint32_t getPixelColorXY(int x, int y) const;
// 2D support functions // 2D support functions
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); } inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); }
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); } inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); }
@ -729,15 +729,7 @@ class WS2812FX { // 96 bytes
customMappingSize(0), customMappingSize(0),
_lastShow(0), _lastShow(0),
_segment_index(0), _segment_index(0),
_mainSegment(0), _mainSegment(0)
_queuedChangesSegId(255),
_qStart(0),
_qStop(0),
_qStartY(0),
_qStopY(0),
_qGrouping(0),
_qSpacing(0),
_qOffset(0)
{ {
WS2812FX::instance = this; WS2812FX::instance = this;
_mode.reserve(_modeCount); // allocate memory to prevent initial fragmentation (does not increase size()) _mode.reserve(_modeCount); // allocate memory to prevent initial fragmentation (does not increase size())
@ -945,14 +937,6 @@ class WS2812FX { // 96 bytes
uint8_t _segment_index; uint8_t _segment_index;
uint8_t _mainSegment; uint8_t _mainSegment;
uint8_t _queuedChangesSegId;
uint16_t _qStart, _qStop, _qStartY, _qStopY;
uint8_t _qGrouping, _qSpacing;
uint16_t _qOffset;
/*
void
setUpSegmentFromQueuedChanges(void);
*/
}; };
extern const char JSON_mode_names[]; extern const char JSON_mode_names[];

View File

@ -180,7 +180,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
if (reverse ) x = virtualWidth() - x - 1; if (reverse ) x = virtualWidth() - x - 1;
if (reverse_y) y = virtualHeight() - y - 1; if (reverse_y) y = virtualHeight() - y - 1;
if (transpose) { unsigned t = x; x = y; y = t; } // swap X & Y if segment transposed if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
x *= groupLength(); // expand to physical pixels x *= groupLength(); // expand to physical pixels
y *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels
@ -261,12 +261,12 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
#endif #endif
// returns RGBW values of pixel // returns RGBW values of pixel
uint32_t IRAM_ATTR Segment::getPixelColorXY(int x, int y) { uint32_t IRAM_ATTR Segment::getPixelColorXY(int x, int y) const {
if (!isActive()) return 0; // not active if (!isActive()) return 0; // not active
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit
if (reverse ) x = virtualWidth() - x - 1; if (reverse ) x = virtualWidth() - x - 1;
if (reverse_y) y = virtualHeight() - y - 1; if (reverse_y) y = virtualHeight() - y - 1;
if (transpose) { unsigned t = x; x = y; y = t; } // swap X & Y if segment transposed if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
x *= groupLength(); // expand to physical pixels x *= groupLength(); // expand to physical pixels
y *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels
if (x >= width() || y >= height()) return 0; if (x >= width() || y >= height()) return 0;

View File

@ -327,13 +327,8 @@ void Segment::stopTransition() {
} }
} }
void Segment::handleTransition() {
unsigned _progress = progress();
if (_progress == 0xFFFFU) stopTransition();
}
// transition progression between 0-65535 // transition progression between 0-65535
uint16_t IRAM_ATTR Segment::progress() { uint16_t IRAM_ATTR Segment::progress() const {
if (isInTransition()) { if (isInTransition()) {
unsigned diff = millis() - _t->_start; unsigned diff = millis() - _t->_start;
if (_t->_dur > 0 && diff < _t->_dur) return diff * 0xFFFFU / _t->_dur; if (_t->_dur > 0 && diff < _t->_dur) return diff * 0xFFFFU / _t->_dur;
@ -412,7 +407,7 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
} }
#endif #endif
uint8_t IRAM_ATTR Segment::currentBri(bool useCct) { uint8_t IRAM_ATTR Segment::currentBri(bool useCct) const {
unsigned prog = progress(); unsigned prog = progress();
if (prog < 0xFFFFU) { if (prog < 0xFFFFU) {
unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog; unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog;
@ -422,7 +417,7 @@ uint8_t IRAM_ATTR Segment::currentBri(bool useCct) {
return (useCct ? cct : (on ? opacity : 0)); return (useCct ? cct : (on ? opacity : 0));
} }
uint8_t IRAM_ATTR Segment::currentMode() { uint8_t IRAM_ATTR Segment::currentMode() const {
#ifndef WLED_DISABLE_MODE_BLEND #ifndef WLED_DISABLE_MODE_BLEND
unsigned prog = progress(); unsigned prog = progress();
if (modeBlending && prog < 0xFFFFU) return _t->_modeT; if (modeBlending && prog < 0xFFFFU) return _t->_modeT;
@ -430,7 +425,7 @@ uint8_t IRAM_ATTR Segment::currentMode() {
return mode; return mode;
} }
uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) { uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) const {
if (slot >= NUM_COLORS) slot = 0; if (slot >= NUM_COLORS) slot = 0;
#ifndef WLED_DISABLE_MODE_BLEND #ifndef WLED_DISABLE_MODE_BLEND
return isInTransition() ? color_blend(_t->_segT._colorT[slot], colors[slot], progress(), true) : colors[slot]; return isInTransition() ? color_blend(_t->_segT._colorT[slot], colors[slot], progress(), true) : colors[slot];
@ -685,9 +680,11 @@ uint16_t IRAM_ATTR Segment::virtualLength() const {
vLen = vH; vLen = vH;
break; break;
case M12_pCorner: case M12_pCorner:
case M12_pArc:
vLen = max(vW,vH); // get the longest dimension vLen = max(vW,vH); // get the longest dimension
break; break;
case M12_pArc:
vLen = sqrt16(vH*vH + vW*vW); // use diagonal
break;
case M12_sPinwheel: case M12_sPinwheel:
vLen = getPinwheelLength(vW, vH); vLen = getPinwheelLength(vW, vH);
break; break;
@ -730,12 +727,14 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
if (i==0) if (i==0)
setPixelColorXY(0, 0, col); setPixelColorXY(0, 0, col);
else { else {
float step = HALF_PI / (2.85f*i); float r = i;
for (float rad = 0.0f; rad <= HALF_PI+step/2; rad += step) { float step = HALF_PI / (2.8284f * r + 4); // we only need (PI/4)/(r/sqrt(2)+1) steps
// may want to try float version as well (with or without antialiasing) for (float rad = 0.0f; rad <= (HALF_PI/2)+step/2; rad += step) {
int x = roundf(sin_t(rad) * i); int x = roundf(sin_t(rad) * r);
int y = roundf(cos_t(rad) * i); int y = roundf(cos_t(rad) * r);
// exploit symmetry
setPixelColorXY(x, y, col); setPixelColorXY(x, y, col);
setPixelColorXY(y, x, col);
} }
// Bresenhams Algorithm (may not fill every pixel) // Bresenhams Algorithm (may not fill every pixel)
//int d = 3 - (2*i); //int d = 3 - (2*i);
@ -893,7 +892,7 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa)
} }
#endif #endif
uint32_t IRAM_ATTR Segment::getPixelColor(int i) uint32_t IRAM_ATTR Segment::getPixelColor(int i) const
{ {
if (!isActive()) return 0; // not active if (!isActive()) return 0; // not active
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
@ -1059,7 +1058,7 @@ void Segment::fade_out(uint8_t rate) {
const int rows = virtualHeight(); // will be 1 for 1D const int rows = virtualHeight(); // will be 1 for 1D
rate = (255-rate) >> 1; rate = (255-rate) >> 1;
float mappedRate = float(rate) +1.1f; float mappedRate = 1.0f / (float(rate) + 1.1f);
uint32_t color = colors[1]; // SEGCOLOR(1); // target color uint32_t color = colors[1]; // SEGCOLOR(1); // target color
int w2 = W(color); int w2 = W(color);
@ -1069,15 +1068,16 @@ void Segment::fade_out(uint8_t rate) {
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x); color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x);
if (color == colors[1]) continue; // already at target color
int w1 = W(color); int w1 = W(color);
int r1 = R(color); int r1 = R(color);
int g1 = G(color); int g1 = G(color);
int b1 = B(color); int b1 = B(color);
int wdelta = (w2 - w1) / mappedRate; int wdelta = (w2 - w1) * mappedRate;
int rdelta = (r2 - r1) / mappedRate; int rdelta = (r2 - r1) * mappedRate;
int gdelta = (g2 - g1) / mappedRate; int gdelta = (g2 - g1) * mappedRate;
int bdelta = (b2 - b1) / mappedRate; int bdelta = (b2 - b1) * mappedRate;
// if fade isn't complete, make sure delta is at least 1 (fixes rounding issues) // if fade isn't complete, make sure delta is at least 1 (fixes rounding issues)
wdelta += (w2 == w1) ? 0 : (w2 > w1) ? 1 : -1; wdelta += (w2 == w1) ? 0 : (w2 > w1) ? 1 : -1;
@ -1149,7 +1149,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) {
* The colours are a transition r -> g -> b -> back to r * The colours are a transition r -> g -> b -> back to r
* Inspired by the Adafruit examples. * Inspired by the Adafruit examples.
*/ */
uint32_t Segment::color_wheel(uint8_t pos) { uint32_t Segment::color_wheel(uint8_t pos) const {
if (palette) return color_from_palette(pos, false, true, 0); // perhaps "strip.paletteBlend < 2" should be better instead of "true" if (palette) return color_from_palette(pos, false, true, 0); // perhaps "strip.paletteBlend < 2" should be better instead of "true"
uint8_t w = W(currentColor(0)); uint8_t w = W(currentColor(0));
pos = 255 - pos; pos = 255 - pos;
@ -1173,7 +1173,7 @@ uint32_t Segment::color_wheel(uint8_t pos) {
* @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling) * @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling)
* @returns Single color from palette * @returns Single color from palette
*/ */
uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) { uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) const {
uint32_t color = gamma32(currentColor(mcol)); uint32_t color = gamma32(currentColor(mcol));
// default palette or no RGB support on segment // default palette or no RGB support on segment

View File

@ -11,7 +11,7 @@ uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16)
if (blend == 0) return color1; if (blend == 0) return color1;
unsigned blendmax = b16 ? 0xFFFF : 0xFF; unsigned blendmax = b16 ? 0xFFFF : 0xFF;
if (blend == blendmax) return color2; if (blend == blendmax) return color2;
uint8_t shift = b16 ? 16 : 8; unsigned shift = b16 ? 16 : 8;
uint32_t w1 = W(color1); uint32_t w1 = W(color1);
uint32_t r1 = R(color1); uint32_t r1 = R(color1);
@ -73,22 +73,19 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video)
uint32_t g = G(c1); uint32_t g = G(c1);
uint32_t b = B(c1); uint32_t b = B(c1);
uint32_t w = W(c1); uint32_t w = W(c1);
uint32_t scale = amount + !video; // 32bit for faster calculation
if (video) { if (video) {
uint32_t scale = amount; // 32bit for faster calculation
scaledcolor = (((r * scale) >> 8) << 16) + ((r && scale) ? 1 : 0); scaledcolor = (((r * scale) >> 8) << 16) + ((r && scale) ? 1 : 0);
scaledcolor |= (((g * scale) >> 8) << 8) + ((g && scale) ? 1 : 0); scaledcolor |= (((g * scale) >> 8) << 8) + ((g && scale) ? 1 : 0);
scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0); scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0);
scaledcolor |= (((w * scale) >> 8) << 24) + ((w && scale) ? 1 : 0); scaledcolor |= (((w * scale) >> 8) << 24) + ((w && scale) ? 1 : 0);
return scaledcolor; } else {
}
else {
uint32_t scale = 1 + amount;
scaledcolor = ((r * scale) >> 8) << 16; scaledcolor = ((r * scale) >> 8) << 16;
scaledcolor |= ((g * scale) >> 8) << 8; scaledcolor |= ((g * scale) >> 8) << 8;
scaledcolor |= (b * scale) >> 8; scaledcolor |= (b * scale) >> 8;
scaledcolor |= ((w * scale) >> 8) << 24; scaledcolor |= ((w * scale) >> 8) << 24;
return scaledcolor;
} }
return scaledcolor;
} }
void setRandomColor(byte* rgb) void setRandomColor(byte* rgb)
@ -158,7 +155,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
case 4: // tetradic case 4: // tetradic
harmonics[0] = basehue + 80 + random8(20); harmonics[0] = basehue + 80 + random8(20);
harmonics[1] = basehue + 170 + random8(20); harmonics[1] = basehue + 170 + random8(20);
harmonics[2] = basehue + random8(30)-15; harmonics[2] = basehue - 15 + random8(30);
break; break;
} }
@ -384,13 +381,13 @@ bool colorFromHexString(byte* rgb, const char* in) {
return true; return true;
} }
float minf (float v, float w) static inline float minf(float v, float w)
{ {
if (w > v) return v; if (w > v) return v;
return w; return w;
} }
float maxf (float v, float w) static inline float maxf(float v, float w)
{ {
if (w > v) return w; if (w > v) return w;
return v; return v;

View File

@ -34,7 +34,7 @@
if (d.um_p[0]==-1) d.um_p.shift(); // remove filler if (d.um_p[0]==-1) d.um_p.shift(); // remove filler
d.Sf.SDA.max = d.Sf.SCL.max = d.Sf.MOSI.max = d.Sf.SCLK.max = d.Sf.MISO.max = d.max_gpio; d.Sf.SDA.max = d.Sf.SCL.max = d.Sf.MOSI.max = d.Sf.SCLK.max = d.Sf.MISO.max = d.max_gpio;
//for (let i of d.getElementsByTagName("input")) if (i.type === "number" && i.name.replace("[]","").substr(-3) === "pin") i.max = d.max_gpio; //for (let i of d.getElementsByTagName("input")) if (i.type === "number" && i.name.replace("[]","").substr(-3) === "pin") i.max = d.max_gpio;
pinDropdowns(); // convert INPUT to SELECT for pins pinDD(); // convert INPUT to SELECT for pins
}); });
// error event // error event
scE.addEventListener("error", (ev) => { scE.addEventListener("error", (ev) => {
@ -165,25 +165,25 @@
urows += `<input type="${t==="int"?"number":t}" name="${k}:${f}${a?"[]":""}" ${c} oninput="check(this,'${k.substr(k.indexOf(":")+1)}')"><br>`; urows += `<input type="${t==="int"?"number":t}" name="${k}:${f}${a?"[]":""}" ${c} oninput="check(this,'${k.substr(k.indexOf(":")+1)}')"><br>`;
} }
} }
function pinDropdowns() { function pinDD() {
for (let i of d.Sf.elements) { for (let i of d.Sf.elements) {
if (i.type === "number" && (i.name.includes("pin") || ["SDA","SCL","MOSI","MISO","SCLK"].includes(i.name))) { //select all pin select elements if (i.type === "number" && (i.name.includes("pin") || ["SDA","SCL","MOSI","MISO","SCLK"].includes(i.name))) { //select all pin select elements
let v = parseInt(i.value); let v = parseInt(i.value);
let sel = addDropdown(i.name,0); let sel = addDD(i.name,0);
for (var j = -1; j <= d.max_gpio; j++) { for (var j = -1; j <= d.max_gpio; j++) {
if (d.rsvd.includes(j)) continue; if (d.rsvd.includes(j)) continue;
let foundPin = pins.indexOf(j); let foundPin = pins.indexOf(j);
let txt = (j === -1) ? "unused" : `${j}`; let txt = (j === -1) ? "unused" : `${j}`;
if (foundPin >= 0 && j !== v) txt += ` ${pinO[foundPin]=="if"?"global":pinO[foundPin]}`; // already reserved pin if (foundPin >= 0 && j !== v) txt += ` ${pinO[foundPin]=="if"?"global":pinO[foundPin]}`; // already reserved pin
if (d.ro_gpio.includes(j)) txt += " (R/O)"; if (d.ro_gpio.includes(j)) txt += " (R/O)";
let opt = addOption(sel, txt, j); let opt = addO(sel, txt, j);
if (j === v) opt.selected = true; // this is "our" pin if (j === v) opt.selected = true; // this is "our" pin
else if (pins.includes(j)) opt.disabled = true; // someone else's pin else if (pins.includes(j)) opt.disabled = true; // someone else's pin
} }
let um = i.name.split(":")[0]; let um = i.name.split(":")[0];
d.extra.forEach((o)=>{ d.extra.forEach((o)=>{
if (o[um] && o[um].pin) o[um].pin.forEach((e)=>{ if (o[um] && o[um].pin) o[um].pin.forEach((e)=>{
let opt = addOption(sel,e[0],e[1]); let opt = addO(sel,e[0],e[1]);
if (e[1]==v) opt.selected = true; if (e[1]==v) opt.selected = true;
}); });
}); });
@ -219,7 +219,7 @@
} }
} }
// https://stackoverflow.com/questions/39729741/javascript-change-input-text-to-select-option // https://stackoverflow.com/questions/39729741/javascript-change-input-text-to-select-option
function addDropdown(um,fld) { function addDD(um,fld) {
let sel = d.createElement('select'); let sel = d.createElement('select');
if (typeof(fld) === "string") { // parameter from usermod (field name) if (typeof(fld) === "string") { // parameter from usermod (field name)
if (fld.includes("pin")) sel.classList.add("pin"); if (fld.includes("pin")) sel.classList.add("pin");
@ -255,7 +255,8 @@
} }
return null; return null;
} }
function addOption(sel,txt,val) { var addDropdown = addDD; // backwards compatibility
function addO(sel,txt,val) {
if (sel===null) return; // select object missing if (sel===null) return; // select object missing
let opt = d.createElement("option"); let opt = d.createElement("option");
opt.value = val; opt.value = val;
@ -267,8 +268,9 @@
} }
return opt; return opt;
} }
var addOption = addO; // backwards compatibility
// https://stackoverflow.com/questions/26440494/insert-text-after-this-input-element-with-javascript // https://stackoverflow.com/questions/26440494/insert-text-after-this-input-element-with-javascript
function addInfo(name,el,txt, txt2="") { function addI(name,el,txt, txt2="") {
let obj = d.getElementsByName(name); let obj = d.getElementsByName(name);
if (!obj.length) return; if (!obj.length) return;
if (typeof el === "string" && obj[0]) obj[0].placeholder = el; if (typeof el === "string" && obj[0]) obj[0].placeholder = el;
@ -277,9 +279,10 @@
if (txt2!="") obj[el].insertAdjacentHTML('beforebegin', txt2 + '&nbsp;'); //add pre texts if (txt2!="") obj[el].insertAdjacentHTML('beforebegin', txt2 + '&nbsp;'); //add pre texts
} }
} }
var addInfo = addI; // backwards compatibility
// add Help Button // add Help Button
function addHB(um) { function addHB(um) {
addInfo(um + ':help',0,`<button onclick="location.href='https://kno.wled.ge/usermods/${um}'" type="button">?</button>`); addI(um + ':help',0,`<button onclick="location.href='https://kno.wled.ge/usermods/${um}'" type="button">?</button>`);
} }
// load settings and insert values into DOM // load settings and insert values into DOM
function ldS() { function ldS() {

View File

@ -860,20 +860,19 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
uint16_t spcI = selseg.spacing; uint16_t spcI = selseg.spacing;
pos = req.indexOf(F("&S=")); //segment start pos = req.indexOf(F("&S=")); //segment start
if (pos > 0) { if (pos > 0) {
startI = getNumVal(&req, pos); startI = std::abs(getNumVal(&req, pos));
} }
pos = req.indexOf(F("S2=")); //segment stop pos = req.indexOf(F("S2=")); //segment stop
if (pos > 0) { if (pos > 0) {
stopI = getNumVal(&req, pos); stopI = std::abs(getNumVal(&req, pos));
} }
pos = req.indexOf(F("GP=")); //segment grouping pos = req.indexOf(F("GP=")); //segment grouping
if (pos > 0) { if (pos > 0) {
grpI = getNumVal(&req, pos); grpI = std::max(1,getNumVal(&req, pos));
if (grpI == 0) grpI = 1;
} }
pos = req.indexOf(F("SP=")); //segment spacing pos = req.indexOf(F("SP=")); //segment spacing
if (pos > 0) { if (pos > 0) {
spcI = getNumVal(&req, pos); spcI = std::max(0,getNumVal(&req, pos));
} }
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY); strip.setSegment(selectedSeg, startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY);

View File

@ -148,7 +148,7 @@ void sappends(char stype, const char* key, char* val)
bool oappendi(int i) bool oappendi(int i)
{ {
char s[11]; char s[12]; // 32bit signed number can have 10 digits plus - sign
sprintf(s, "%d", i); sprintf(s, "%d", i);
return oappend(s); return oappend(s);
} }