From 05f5aaaeca5628197cd65c7da5f076bf594a490e Mon Sep 17 00:00:00 2001 From: cschwinne Date: Wed, 19 Feb 2020 15:53:42 +0100 Subject: [PATCH 1/3] Refactoring --- wled00/const.h | 26 ++++++++++++++++++++++++++ wled00/wled00.ino | 23 ++++++----------------- wled00/wled05_init.ino | 10 +++++----- 3 files changed, 37 insertions(+), 22 deletions(-) create mode 100644 wled00/const.h diff --git a/wled00/const.h b/wled00/const.h new file mode 100644 index 000000000..15345c7ca --- /dev/null +++ b/wled00/const.h @@ -0,0 +1,26 @@ +#ifndef wled_const_h +#define wled_const_h + +//Access point behavior +#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot +#define AP_BEHAVIOR_NO_CONN 1 //Open when no connection +#define AP_BEHAVIOR_ALWAYS 2 //Always open +#define AP_BEHAVIOR_BUTTON_ONLY 3 //Only when button pressed for 6 sec + +//realtime modes +#define REALTIME_MODE_INACTIVE 0 +#define REALTIME_MODE_GENERIC 1 +#define REALTIME_MODE_UDP 2 +#define REALTIME_MODE_HYPERION 3 +#define REALTIME_MODE_E131 4 +#define REALTIME_MODE_ADALIGHT 5 + +//E1.31 DMX modes +#define DMX_MODE_DISABLED 0 //not used +#define DMX_MODE_SINGLE_RGB 1 //all LEDs same RGB color (3 channels) +#define DMX_MODE_SINGLE_DRGB 2 //all LEDs same RGB color and master dimmer (4 channels) +#define DMX_MODE_EFFECT 3 //trigger standalone effects of WLED (11 channels) +#define DMX_MODE_MULTIPLE_RGB 4 //every LED is addressed with its own RGB (ledCount * 3 channels) +#define DMX_MODE_MULTIPLE_DRGB 5 //every LED is addressed with its own RGB and share a master dimmer (ledCount * 3 + 1 channels) + +#endif diff --git a/wled00/wled00.ino b/wled00/wled00.ino index 89f08a5d2..6d0bae61b 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -75,6 +75,7 @@ #include "html_other.h" #include "FX.h" #include "ir_codes.h" +#include "const.h" #if IR_PIN < 0 @@ -90,7 +91,7 @@ #endif //version code in format yymmddb (b = daily build) -#define VERSION 2002181 +#define VERSION 2002191 char versionString[] = "0.9.1"; @@ -115,7 +116,7 @@ char cmDNS[33] = "x"; //mDNS address (placeholder, will char apSSID[33] = ""; //AP off by default (unless setup) byte apChannel = 1; //2.4GHz WiFi AP channel (1-13) byte apHide = 0; //hidden AP SSID -byte apBehavior = 0; //0: Open AP when no connection after boot 1: Open when no connection 2: Always open 3: Only when button pressed for 6 sec +byte apBehavior = AP_BEHAVIOR_BOOT_NO_CONN; //access point opens when no connection after boot by default IPAddress staticIP(0, 0, 0, 0); //static IP of ESP IPAddress staticGateway(0, 0, 0, 0); //gateway (router) IP IPAddress staticSubnet(255, 255, 255, 0); //most common subnet in home networks @@ -178,14 +179,8 @@ bool arlsDisableGammaCorrection = true; //activate if gamma correction is bool arlsForceMaxBri = false; //enable to force max brightness if source has very dark colors that would be black uint16_t e131Universe = 1; //settings for E1.31 (sACN) protocol (only DMX_MODE_MULTIPLE_* can span over consequtive universes) -#define DMX_MODE_DISABLED 0 //not used -#define DMX_MODE_SINGLE_RGB 1 //all LEDs same RGB color (3 channels) -#define DMX_MODE_SINGLE_DRGB 2 //all LEDs same RGB color and master dimmer (4 channels) -#define DMX_MODE_EFFECT 3 //trigger standalone effects of WLED (11 channels) -#define DMX_MODE_MULTIPLE_RGB 4 //every LED is addressed with its own RGB (ledCount * 3 channels) -#define DMX_MODE_MULTIPLE_DRGB 5 //every LED is addressed with its own RGB and share a master dimmer (ledCount * 3 + 1 channels) -uint8_t DMXMode; //DMX mode (s.a.) -uint16_t DMXAddress; //DMX start address of fixture, a.k.a. first Channel [for E1.31 (sACN) protocol] +uint8_t DMXMode = DMX_MODE_MULTIPLE_RGB; //DMX mode (s.a.) +uint16_t DMXAddress = 1; //DMX start address of fixture, a.k.a. first Channel [for E1.31 (sACN) protocol] uint8_t DMXOldDimmer = 0; //only update brightness on change uint8_t e131LastSequenceNumber = 0; //to detect packet loss bool e131Multicast = false; //multicast or unicast @@ -362,13 +357,7 @@ bool presetApplyBri = false, presetApplyCol = true, presetApplyFx = true; bool saveCurrPresetCycConf = false; //realtime -#define REALTIME_MODE_INACTIVE 0 -#define REALTIME_MODE_GENERIC 1 -#define REALTIME_MODE_UDP 2 -#define REALTIME_MODE_HYPERION 3 -#define REALTIME_MODE_E131 4 -#define REALTIME_MODE_ADALIGHT 5 -byte realtimeMode = 0; +byte realtimeMode = REALTIME_MODE_INACTIVE; IPAddress realtimeIP = (0,0,0,0); unsigned long realtimeTimeout = 0; diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino index 0cc6ac7ec..b26358cb3 100644 --- a/wled00/wled05_init.ino +++ b/wled00/wled05_init.ino @@ -121,7 +121,7 @@ void beginStrip() void initAP(bool resetAP=false){ - if (apBehavior == 3 && !resetAP) return; + if (apBehavior == AP_BEHAVIOR_BUTTON_ONLY && !resetAP) return; if (!apSSID[0] || resetAP) strcpy(apSSID, "WLED-AP"); if (resetAP) strcpy(apPass,"wled1234"); @@ -172,7 +172,7 @@ void initConnection() if (!apActive) initAP(); //instantly go to ap mode return; } else if (!apActive) { - if (apBehavior == 2) + if (apBehavior == AP_BEHAVIOR_ALWAYS) { initAP(); } else @@ -246,7 +246,7 @@ uint32_t lastHeap; unsigned long heapTime = 0; void handleConnection() { - if (millis() < 2000 && (!WLED_WIFI_CONFIGURED || apBehavior == 2)) return; + if (millis() < 2000 && (!WLED_WIFI_CONFIGURED || apBehavior == AP_BEHAVIOR_ALWAYS)) return; if (lastReconnectAttempt == 0) initConnection(); //reconnect WiFi to clear stale allocations if heap gets too low @@ -297,7 +297,7 @@ void handleConnection() { initConnection(); } if (millis() - lastReconnectAttempt > ((stac) ? 300000 : 20000) && WLED_WIFI_CONFIGURED) initConnection(); - if (!apActive && millis() - lastReconnectAttempt > 12000 && (!wasConnected || apBehavior == 1)) initAP(); + if (!apActive && millis() - lastReconnectAttempt > 12000 && (!wasConnected || apBehavior == AP_BEHAVIOR_NO_CONN)) initAP(); } else if (!interfacesInited) { //newly connected DEBUG_PRINTLN(""); DEBUG_PRINT("Connected! IP address: "); @@ -306,7 +306,7 @@ void handleConnection() { userConnected(); //shut down AP - if (apBehavior != 2 && apActive) + if (apBehavior != AP_BEHAVIOR_ALWAYS && apActive) { dnsServer.stop(); WiFi.softAPdisconnect(true); From d4c0542c84b6dd3a967cc2d2abf0bb227f81ec32 Mon Sep 17 00:00:00 2001 From: huggy-d1 Date: Wed, 19 Feb 2020 13:24:56 -0500 Subject: [PATCH 2/3] Update readme.md Minor spelling change --- usermods/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usermods/readme.md b/usermods/readme.md index 8cd2d486f..350212fb8 100644 --- a/usermods/readme.md +++ b/usermods/readme.md @@ -8,11 +8,11 @@ In order for other people to be able to have fun with your usermod, please keep - Create a folder in this folder with a descriptive name (for example `usermod_ds18b20_temp_sensor_mqtt`) - Include your custom `wled06_usermod.ino` file -- If your usermod requieres changes to other WLED files, please write a `readme.md` outlining the steps one has to take to use the usermod +- If your usermod requires changes to other WLED files, please write a `readme.md` outlining the steps one has to take to use the usermod - Create a pull request! - If your feature is useful for the majority of WLED users, I will consider adding it to the base code! While I do my best to not break too much, keep in mind that as WLED is being updated, usermods might break. I am not actively maintaining any usermod in this directory, that is your responsibility as the creator of the usermod. -Thank you for your help :) \ No newline at end of file +Thank you for your help :) From 65a32b4166832d8c627db1dc89fde995d17d9175 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Thu, 20 Feb 2020 00:45:09 +0100 Subject: [PATCH 3/3] Added new auto white modes (related to #573 ) --- wled00/FX.h | 4 +- wled00/FX_fcn.cpp | 21 +- wled00/const.h | 9 +- wled00/data/index.htm | 1970 ++++++++++++------------- wled00/html_settings.h | 10 +- wled00/html_ui.h | 2987 +++++++++++++++++++------------------- wled00/wled00.ino | 3 +- wled00/wled01_eeprom.ino | 4 +- wled00/wled02_xml.ino | 4 +- wled00/wled03_set.ino | 2 +- wled00/wled08_led.ino | 2 +- wled00/wled14_colors.ino | 2 +- wled00/wled19_json.ino | 2 +- 13 files changed, 2526 insertions(+), 2494 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index abfc11d31..9f1fda411 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -28,6 +28,7 @@ #define WS2812FX_h #include "NpbWrapper.h" +#include "const.h" #define FASTLED_INTERNAL //remove annoying pragma messages #include "FastLED.h" @@ -426,6 +427,7 @@ class WS2812FX { uint8_t mainSegment = 0, + rgbwMode = RGBW_MODE_DUAL, paletteFade = 0, paletteBlend = 0, colorOrder = 0, @@ -589,7 +591,7 @@ class WS2812FX { void fill(uint32_t); bool - _rgbwMode, + _useRgbw = false, _cronixieMode, _cronixieBacklightEnabled, _skipFirstMode, diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index c1ee11afa..73ddbf794 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -32,9 +32,9 @@ void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst) { - if (supportWhite == _rgbwMode && countPixels == _length) return; + if (supportWhite == _useRgbw && countPixels == _length) return; RESET_RUNTIME; - _rgbwMode = supportWhite; + _useRgbw = supportWhite; _skipFirstMode = skipFirst; _length = countPixels; @@ -65,6 +65,7 @@ void WS2812FX::service() { { if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary { + if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check _virtualSegmentLength = SEGMENT.virtualLength(); doShow = true; handle_palette(); @@ -106,6 +107,20 @@ uint16_t WS2812FX::realPixelIndex(uint16_t i) { void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) { + //auto calculate white channel value if enabled + if (_useRgbw) { + if (rgbwMode == RGBW_MODE_AUTO_BRIGHTER || (w == 0 && (rgbwMode == RGBW_MODE_DUAL || rgbwMode == RGBW_MODE_LEGACY))) + { + //white value is set to lowest RGB channel + //thank you to @Def3nder! + w = r < g ? (r < b ? r : b) : (g < b ? g : b); + } else if (rgbwMode == RGBW_MODE_AUTO_ACCURATE && w == 0) + { + w = r < g ? (r < b ? r : b) : (g < b ? g : b); + r -= w; g -= w; b -= w; + } + } + RgbwColor col; switch (colorOrder) { @@ -256,7 +271,7 @@ void WS2812FX::show(void) { } - if (_rgbwMode) //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less + if (_useRgbw) //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less { powerSum *= 3; powerSum = powerSum >> 2; //same as /= 4 diff --git a/wled00/const.h b/wled00/const.h index 15345c7ca..1308bf5fe 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -3,10 +3,17 @@ //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot -#define AP_BEHAVIOR_NO_CONN 1 //Open when no connection +#define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost) #define AP_BEHAVIOR_ALWAYS 2 //Always open #define AP_BEHAVIOR_BUTTON_ONLY 3 //Only when button pressed for 6 sec +//RGB to RGBW conversion mode +#define RGBW_MODE_MANUAL_ONLY 0 //No automatic white channel calculation. Manual white channel slider +#define RGBW_MODE_AUTO_BRIGHTER 1 //New algorithm. Adds as much white as the darkest RGBW channel +#define RGBW_MODE_AUTO_ACCURATE 2 //New algorithm. Adds as much white as the darkest RGBW channel and subtracts this amount from each RGB channel +#define RGBW_MODE_DUAL 3 //Manual slider + auto calculation. Automatically calculates only if manual slider is set to off (0) +#define RGBW_MODE_LEGACY 4 //Old floating algorithm. Too slow for realtime and palette support + //realtime modes #define REALTIME_MODE_INACTIVE 0 #define REALTIME_MODE_GENERIC 1 diff --git a/wled00/data/index.htm b/wled00/data/index.htm index d9d1ccc95..3446f7ceb 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -1,668 +1,668 @@ - - - - - -WLED - + + + + + + WLED + @@ -672,144 +672,144 @@ display: none;
-
-
- - - - - - -
-
-

Brightness

-
- -
- -
-
-
-
- -
+
+
+ + + + + + +
+
+

Brightness

+
+ +
+ +
+
+
+
+ +
-
-
-
-

White channel

-
- -
-
-
-
-
-
-
-
-
-

-
-
-
-
-
R
-
-
- - - -
-

Color palette

-
- - -
-
+
+
+
+

White channel

+
+ +
+
+
+
+
+
+
+
+
+

+
+
+
+
+
R
+
+
+ + + +
+

Color palette

+
+ + +
+
-
-

Effect speed

-
- -
- -
-
-
-

Effect intensity

-
- -
- -
-
-
-

Effect mode

-
- -
-
-Loading... -
-
-
+
+

Effect speed

+
+ +
+ +
+
+
+

Effect intensity

+
+ +
+ +
+
+
+

Effect mode

+
+ +
+
+ Loading... +
+
+
+ +
+
+ Loading... +
+
+ +
+
-
-
-Loading... -
-
- -
-
- -
-

Load from slot

- - - -
- - - -
- - - -
- - - -
-
-Slot 16 can save all segments.

-
-First preset:
-Last preset:
-Time per preset: s
-Transition: s -
+
+

Load from slot

+ + + +
+ + + +
+ + + +
+ + + +
+
+ Slot 16 can save all segments.

+
+ First preset:
+ Last preset:
+ Time per preset: s
+ Transition: s +
- - - - + + + +
@@ -817,16 +817,16 @@ Transition: /*! -* iro.js v4.4.0 -* 2016-2019 James Daniel -* Licensed under MPL 2.0 -* github.com/jaames/iro.js -*/ + * iro.js v4.4.0 + * 2016-2019 James Daniel + * Licensed under MPL 2.0 + * github.com/jaames/iro.js + */ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.iro=e()}(this,function(){"use strict";var c=function(){},i={},h=[],u=[];function p(t,e){var o,n,r,i,s=arguments,a=u;for(i=arguments.length;2t){var n=function(e){var t="".concat(e).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);return t?Math.max(0,(t[1]?t[1].length:0)-(t[2]?+t[2]:0)):0}(t);return parseFloat(e.toFixed(n))}return Math.round(e/t)*t}return function(){function n(e,r){(function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")})(this,n),l.element(e)?this.element=e:l.string(e)&&(this.element=document.querySelector(e)),l.element(this.element)&&l.empty(this.element.rangeTouch)&&(this.config=Object.assign({},t,r),this.init())}return r=n,i=[{key:"setup",value:function(e){var r=1(t=100/c.width*(u.clientX-c.left))?t=0:100t?t-=(100-2*t)*f:50 3000) { -requestJson({}, true); -} + if (!document.hidden && new Date () - lastUpdate > 3000) { + requestJson({}, true); + } } function onLoad() { -size(); - -var cd = d.getElementById('csl').children; -for (i = 0; i < cd.length; i++) { -cd[i].style.backgroundColor = "rgb(0, 0, 0)"; -} -selectSlot(0); -updateTablinks(0); -resetUtil(); -cpick.on("input:end", function() { -setColor(true); -}); -setTimeout(requestJson, 25); -d.addEventListener("visibilitychange", handleVisibilityChange, false); - -d.getElementById("cv").style.opacity=0; + size(); + + var cd = d.getElementById('csl').children; + for (i = 0; i < cd.length; i++) { + cd[i].style.backgroundColor = "rgb(0, 0, 0)"; + } + selectSlot(0); + updateTablinks(0); + resetUtil(); + cpick.on("input:end", function() { + setColor(true); + }); + setTimeout(requestJson, 25); + d.addEventListener("visibilitychange", handleVisibilityChange, false); + + d.getElementById("cv").style.opacity=0; } function updateTablinks(tabI) { -tablinks = d.getElementsByClassName("tablinks"); -for (i = 0; i < tablinks.length; i++) { -tablinks[i].className = tablinks[i].className.replace(" active", ""); -} -if (pcMode) return; -tablinks[tabI].className += " active"; + tablinks = d.getElementsByClassName("tablinks"); + for (i = 0; i < tablinks.length; i++) { + tablinks[i].className = tablinks[i].className.replace(" active", ""); + } + if (pcMode) return; + tablinks[tabI].className += " active"; } function openTab(tabI) { -if (pcMode) return; -var i, tabcontent, tablinks; -iSlide = tabI; -_C.classList.toggle('smooth', false); -_C.style.setProperty('--i', iSlide); -updateTablinks(tabI); + if (pcMode) return; + var i, tabcontent, tablinks; + iSlide = tabI; + _C.classList.toggle('smooth', false); + _C.style.setProperty('--i', iSlide); + updateTablinks(tabI); } var timeout; function showToast(text, error = false) { -var x = d.getElementById("toast"); -x.innerHTML = text; -x.className = error ? "error":"show"; -clearTimeout(timeout); -x.style.animation = 'none'; -x.offsetHeight; -x.style.animation = null; -timeout = setTimeout(function(){ x.className = x.className.replace("show", ""); }, 2900); + var x = d.getElementById("toast"); + x.innerHTML = text; + x.className = error ? "error":"show"; + clearTimeout(timeout); + x.style.animation = 'none'; + x.offsetHeight; + x.style.animation = null; + timeout = setTimeout(function(){ x.className = x.className.replace("show", ""); }, 2900); } function showErrorToast() { -showToast('Connection to light failed. Please refresh the page. If the issue persists, reboot your ESP.', true); + showToast('Connection to light failed. Please refresh the page. If the issue persists, reboot your ESP.', true); } function clearErrorToast() { -d.getElementById("toast").className = d.getElementById("toast").className.replace("error", ""); + d.getElementById("toast").className = d.getElementById("toast").className.replace("error", ""); } function populateSegments(s) { -var cn = ""; -segCount = 0, lowestUnused = 0; + var cn = ""; + segCount = 0, lowestUnused = 0; + + for (y in s.seg) + { + segCount++; + + var inst=s.seg[y]; + var i = parseInt(inst.id); + if (i == lowestUnused) lowestUnused = i+1; + + cn += `
+ + +
+ + + + + + + + + +
Start LEDStop LED
+ + + + + + + + + +
GroupingSpacing
+
${inst.stop - inst.start} LED${inst.stop - inst.start > 1 ? "s":""} (${Math.ceil((inst.stop - inst.start)/(inst.grp + inst.spc))} virtual)
+ + + +
+

`; + } -for (y in s.seg) -{ -segCount++; - -var inst=s.seg[y]; -var i = parseInt(inst.id); -if (i == lowestUnused) lowestUnused = i+1; - -cn += `
- - -
- - - - - - - - - -
Start LEDStop LED
- - - - - - - - - -
GroupingSpacing
-
${inst.stop - inst.start} LED${inst.stop - inst.start > 1 ? "s":""} (${Math.ceil((inst.stop - inst.start)/(inst.grp + inst.spc))} virtual)
- - - -
-

`; -} - -d.getElementById('segcont').innerHTML = cn; -if (lowestUnused >= maxSeg) { -d.getElementById('segutil').innerHTML = 'Maximum number of segments reached.'; -noNewSegs = true; -} else if (noNewSegs) { -resetUtil(); -noNewSegs = false; -} + d.getElementById('segcont').innerHTML = cn; + if (lowestUnused >= maxSeg) { + d.getElementById('segutil').innerHTML = 'Maximum number of segments reached.'; + noNewSegs = true; + } else if (noNewSegs) { + resetUtil(); + noNewSegs = false; + } } function updateTrail(e) { -var progress = e.value *100 /255; -progress = parseInt(progress); -var val = `linear-gradient(90deg, white ${progress}%, #444 ${progress}%)`; -e.parentNode.getElementsByClassName('sliderdisplay')[0].style.background = val; + var progress = e.value *100 /255; + progress = parseInt(progress); + var val = `linear-gradient(90deg, white ${progress}%, #444 ${progress}%)`; + e.parentNode.getElementsByClassName('sliderdisplay')[0].style.background = val; } function updateLen(s) { -var start = parseInt(d.getElementById(`seg${s}s`).value); -var stop = parseInt(d.getElementById(`seg${s}e`).value); -var len = stop - start; -var out = "(delete)" -if (len > 1) { -out = `${len} LEDs`; -} else if (len == 1) { -out = "1 LED" -} - -if (d.getElementById(`seg${s}grp`) != null) -{ -var grp = parseInt(d.getElementById(`seg${s}grp`).value); -var spc = parseInt(d.getElementById(`seg${s}spc`).value); -if (grp == 0) grp = 1; -var virt = Math.ceil(len/(grp + spc)); -if (!isNaN(virt) && (grp > 1 || spc > 0)) out += ` (${virt} virtual)`; -} - -d.getElementById(`seg${s}len`).innerHTML = out; + var start = parseInt(d.getElementById(`seg${s}s`).value); + var stop = parseInt(d.getElementById(`seg${s}e`).value); + var len = stop - start; + var out = "(delete)" + if (len > 1) { + out = `${len} LEDs`; + } else if (len == 1) { + out = "1 LED" + } + + if (d.getElementById(`seg${s}grp`) != null) + { + var grp = parseInt(d.getElementById(`seg${s}grp`).value); + var spc = parseInt(d.getElementById(`seg${s}spc`).value); + if (grp == 0) grp = 1; + var virt = Math.ceil(len/(grp + spc)); + if (!isNaN(virt) && (grp > 1 || spc > 0)) out += ` (${virt} virtual)`; + } + + d.getElementById(`seg${s}len`).innerHTML = out; } function updateUI() { -d.getElementById('buttonPower').className = (isOn) ? "active":""; -d.getElementById('buttonNl').className = (nlA) ? "active":""; -d.getElementById('buttonSync').className = (syncSend) ? "active":""; + d.getElementById('buttonPower').className = (isOn) ? "active":""; + d.getElementById('buttonNl').className = (nlA) ? "active":""; + d.getElementById('buttonSync').className = (syncSend) ? "active":""; -d.getElementById('fxb' + selectedFx).style.backgroundColor = "#666"; -updateTrail(d.getElementById('sliderBri')); -updateTrail(d.getElementById('sliderSpeed')); -updateTrail(d.getElementById('sliderIntensity')); -updateTrail(d.getElementById('sliderW')); -if (isRgbw) d.getElementById('wwrap').style.display = "block"; + d.getElementById('fxb' + selectedFx).style.backgroundColor = "#666"; + updateTrail(d.getElementById('sliderBri')); + updateTrail(d.getElementById('sliderSpeed')); + updateTrail(d.getElementById('sliderIntensity')); + updateTrail(d.getElementById('sliderW')); + if (isRgbw) d.getElementById('wwrap').style.display = "block"; + + var btns = document.getElementsByClassName("psts"); + for (i = 0; i < btns.length; i++) { + btns[i].className = btns[i].className.replace(" active", ""); + if ((savedPresets >> i) & 0x01) btns[i].className += " stored"; + } + if (currentPreset > 0 && currentPreset <= btns.length) btns[currentPreset -1].className += " active"; -var btns = document.getElementsByClassName("psts"); -for (i = 0; i < btns.length; i++) { -btns[i].className = btns[i].className.replace(" active", ""); -if ((savedPresets >> i) & 0x01) btns[i].className += " stored"; -} -if (currentPreset > 0 && currentPreset <= btns.length) btns[currentPreset -1].className += " active"; - -spal = d.getElementById("selectPalette"); -spal.style.backgroundColor = (spal.selectedIndex > 0) ? "#666":"#333"; + spal = d.getElementById("selectPalette"); + spal.style.backgroundColor = (spal.selectedIndex > 0) ? "#666":"#333"; } function compare(a, b) { -if (a.name < b.name){ -return -1; -} -return 1; + if (a.name < b.name){ + return -1; + } + return 1; } var jsonTimeout; function requestJson(command, verbose = true) { -lastUpdate = new Date(); -if (!jsonTimeout) jsonTimeout = setTimeout(showErrorToast, 3000); -var req = null; -e1 = d.getElementById('fxlist'); -e2 = d.getElementById('selectPalette'); + lastUpdate = new Date(); + if (!jsonTimeout) jsonTimeout = setTimeout(showErrorToast, 3000); + var req = null; + e1 = d.getElementById('fxlist'); + e2 = d.getElementById('selectPalette'); -url = command ? '/json/state':'/json'; + url = command ? '/json/state':'/json'; + + type = command ? 'post':'get'; + if (command) + { + command.v = verbose; + req = JSON.stringify(command); + } + fetch + (url, { + method: type, + headers: { + "Content-type": "application/json; charset=UTF-8" + }, + body: req + }) + .then(res => { + if (!res.ok) { + showErrorToast(); + } + return res.json(); + }) + .then(json => { + clearTimeout(jsonTimeout); + jsonTimeout = null; + clearErrorToast(); + if (!json) showToast('Empty response', true); + if (json.success) return; + var s = json; + if (!command) { + var x='',y=''; + json.effects.shift(); //remove solid + for (i in json.effects) json.effects[i] = {"id": parseInt(i)+1, "name":json.effects[i]}; + json.effects.sort(compare); + for (i in json.effects) { + x += '
'; + } -type = command ? 'post':'get'; -if (command) -{ -command.v = verbose; -req = JSON.stringify(command); -} -fetch -(url, { -method: type, -headers: { -"Content-type": "application/json; charset=UTF-8" -}, -body: req -}) -.then(res => { -if (!res.ok) { -showErrorToast(); -} -return res.json(); -}) -.then(json => { -clearTimeout(jsonTimeout); -jsonTimeout = null; -clearErrorToast(); -if (!json) showToast('Empty response', true); -if (json.success) return; -var s = json; -if (!command) { -var x='',y=''; -json.effects.shift(); //remove solid -for (i in json.effects) json.effects[i] = {"id": parseInt(i)+1, "name":json.effects[i]}; -json.effects.sort(compare); -for (i in json.effects) { -x += '
'; -} + json.palettes.shift(); //remove default + for (i in json.palettes) json.palettes[i] = {"id": parseInt(i)+1, "name":json.palettes[i]}; + json.palettes.sort(compare); + for (i in json.palettes) { + y += ''; + } + e1.innerHTML=x; e2.innerHTML=y; + var info = json.info; + var name = info.name; + d.getElementById('namelabel').innerHTML = name; + if (name === "Dinnerbone") d.documentElement.style.transform = "rotate(180deg)"; + if (info.live) name = "(Live) " + name; + d.title = name; + isRgbw = info.leds.wv; + ledCount = info.leds.count; + syncTglRecv = info.str; + maxSeg = info.leds.maxseg; + s = json.state; + } + isOn = s.on; + d.getElementById('sliderBri').value= s.bri; + nlA = s.nl.on; + nlDur = s.nl.dur; + syncSend = s.udpn.send; + savedPresets = s.pss; + currentPreset = s.ps; + d.getElementById('cyToggle').checked = (s.pl < 0) ? false : true; + d.getElementById('cycs').value = s.ccnf.min; + d.getElementById('cyce').value = s.ccnf.max; + d.getElementById('cyct').value = s.ccnf.time /10; + d.getElementById('cyctt').value = s.transition /10; + + var selc=0; var ind=0; + populateSegments(s); + for (i in s.seg) + { + if(s.seg[i].sel) {selc = ind; break;} ind++; + } + var i=s.seg[selc]; + if (!i) { + showToast('No Segments!', true); + updateUI(); + return; + } + var cd = d.getElementById('csl').children; + for (e = 2; e >= 0; e--) + { + cd[e].style.backgroundColor = "rgb(" + i.col[e][0] + "," + i.col[e][1] + "," + i.col[e][2] + ")"; + if (isRgbw) whites[e] = i.col[e][3]; + selectSlot(csel); + } + d.getElementById('sliderSpeed').value = whites[csel]; -json.palettes.shift(); //remove default -for (i in json.palettes) json.palettes[i] = {"id": parseInt(i)+1, "name":json.palettes[i]}; -json.palettes.sort(compare); -for (i in json.palettes) { -y += ''; -} -e1.innerHTML=x; e2.innerHTML=y; -var info = json.info; -var name = info.name; -d.getElementById('namelabel').innerHTML = name; -if (name === "Dinnerbone") d.documentElement.style.transform = "rotate(180deg)"; -if (info.live) name = "(Live) " + name; -d.title = name; -isRgbw = info.leds.wv; -ledCount = info.leds.count; -syncTglRecv = info.str; -maxSeg = info.leds.maxseg; -s = json.state; -} -isOn = s.on; -d.getElementById('sliderBri').value= s.bri; -nlA = s.nl.on; -nlDur = s.nl.dur; -syncSend = s.udpn.send; -savedPresets = s.pss; -currentPreset = s.ps; -d.getElementById('cyToggle').checked = (s.pl < 0) ? false : true; -d.getElementById('cycs').value = s.ccnf.min; -d.getElementById('cyce').value = s.ccnf.max; -d.getElementById('cyct').value = s.ccnf.time /10; -d.getElementById('cyctt').value = s.transition /10; + d.getElementById('sliderSpeed').value = i.sx; + d.getElementById('sliderIntensity').value = i.ix; -var selc=0; var ind=0; -populateSegments(s); -for (i in s.seg) -{ -if(s.seg[i].sel) {selc = ind; break;} ind++; -} -var i=s.seg[selc]; -if (!i) { -showToast('No Segments!', true); -updateUI(); -return; -} -var cd = d.getElementById('csl').children; -for (e = 2; e >= 0; e--) -{ -cd[e].style.backgroundColor = "rgb(" + i.col[e][0] + "," + i.col[e][1] + "," + i.col[e][2] + ")"; -if (isRgbw) whites[e] = i.col[e][3]; -selectSlot(csel); -} -d.getElementById('sliderSpeed').value = whites[csel]; + d.getElementById('fxb' + selectedFx).style.backgroundColor = "#333"; + selectedFx = i.fx; + e2.value = i.pal; + if (!command) d.getElementById('Effects').scrollTop = d.getElementById('fxb' + selectedFx).offsetTop - d.getElementById('Effects').clientHeight/1.8; -d.getElementById('sliderSpeed').value = i.sx; -d.getElementById('sliderIntensity').value = i.ix; - -d.getElementById('fxb' + selectedFx).style.backgroundColor = "#333"; -selectedFx = i.fx; -e2.value = i.pal; -if (!command) d.getElementById('Effects').scrollTop = d.getElementById('fxb' + selectedFx).offsetTop - d.getElementById('Effects').clientHeight/1.8; - -if (s.error) showToast('WLED error ' + s.error, true); -updateUI(); -}) -.catch(function (error) { -showToast(error, true); -}) + if (s.error) showToast('WLED error ' + s.error, true); + updateUI(); + }) + .catch(function (error) { + showToast(error, true); + }) } function togglePower() { -isOn = !isOn; -var obj = {"on": isOn}; -obj.transition = parseInt(d.getElementById('cyctt').value*10); -requestJson(obj); + isOn = !isOn; + var obj = {"on": isOn}; + obj.transition = parseInt(d.getElementById('cyctt').value*10); + requestJson(obj); } function toggleNl() { -nlA = !nlA; -if (nlA) -{ -showToast('Nightlight active. Your light will turn off after ' + nlDur + ' minutes.'); -} else { -showToast('Nightlight deactivated.'); -} -var obj = {"nl": {"on": nlA}}; -requestJson(obj); + nlA = !nlA; + if (nlA) + { + showToast('Nightlight active. Your light will turn off after ' + nlDur + ' minutes.'); + } else { + showToast('Nightlight deactivated.'); + } + var obj = {"nl": {"on": nlA}}; + requestJson(obj); } function toggleSync() { -syncSend = !syncSend; -if (syncSend) -{ -showToast('Other lights in the network will now sync to this one.'); -} else { -showToast('This light and other lights in the network will no longer sync.'); -} -var obj = {"udpn": {"send": syncSend}}; -if (syncTglRecv) obj.udpn.recv = syncSend; -requestJson(obj); + syncSend = !syncSend; + if (syncSend) + { + showToast('Other lights in the network will now sync to this one.'); + } else { + showToast('This light and other lights in the network will no longer sync.'); + } + var obj = {"udpn": {"send": syncSend}}; + if (syncTglRecv) obj.udpn.recv = syncSend; + requestJson(obj); } function toggleLiveview() { -isLv = !isLv; -d.getElementById('liveview').style.display = (isLv) ? "block":"none"; -d.getElementById('liveview').src = (isLv) ? "/liveview":"about:blank"; -d.getElementById('buttonSr').className = (isLv) ? "active":""; + isLv = !isLv; + d.getElementById('liveview').style.display = (isLv) ? "block":"none"; + d.getElementById('liveview').src = (isLv) ? "/liveview":"about:blank"; + d.getElementById('buttonSr').className = (isLv) ? "active":""; } function makeSeg() { -var ns = 0; -if (lowestUnused > 0) { -var pend = d.getElementById(`seg${lowestUnused -1}e`).value; -if (pend < ledCount) ns = pend; -} -var cn = `
- -
- - - - - - - - - -
Start LEDStop LED
-
${ledCount - ns} LEDs
- -
-
`; -d.getElementById('segutil').innerHTML = cn; + var ns = 0; + if (lowestUnused > 0) { + var pend = d.getElementById(`seg${lowestUnused -1}e`).value; + if (pend < ledCount) ns = pend; + } + var cn = `
+ +
+ + + + + + + + + +
Start LEDStop LED
+
${ledCount - ns} LEDs
+ +
+
`; + d.getElementById('segutil').innerHTML = cn; } function resetUtil() { -var cn = `
`; -d.getElementById('segutil').innerHTML = cn; + var cn = `
`; + d.getElementById('segutil').innerHTML = cn; } function selSeg(s){ -var sel = d.getElementById(`seg${s}sel`).checked; -var obj = {"seg": {"id": s, "sel": sel}}; -requestJson(obj); + var sel = d.getElementById(`seg${s}sel`).checked; + var obj = {"seg": {"id": s, "sel": sel}}; + requestJson(obj); } function setSeg(s){ -var start = parseInt(d.getElementById(`seg${s}s`).value); -var stop = parseInt(d.getElementById(`seg${s}e`).value); -if (stop <= start) {delSeg(s); return;}; -var obj = {"seg": {"id": s, "start": start, "stop": stop}}; -if (d.getElementById(`seg${s}grp`)) -{ -var grp = parseInt(d.getElementById(`seg${s}grp`).value); -var spc = parseInt(d.getElementById(`seg${s}spc`).value); -obj.seg.grp = grp; -obj.seg.spc = spc; -} -requestJson(obj); + var start = parseInt(d.getElementById(`seg${s}s`).value); + var stop = parseInt(d.getElementById(`seg${s}e`).value); + if (stop <= start) {delSeg(s); return;}; + var obj = {"seg": {"id": s, "start": start, "stop": stop}}; + if (d.getElementById(`seg${s}grp`)) + { + var grp = parseInt(d.getElementById(`seg${s}grp`).value); + var spc = parseInt(d.getElementById(`seg${s}spc`).value); + obj.seg.grp = grp; + obj.seg.spc = spc; + } + requestJson(obj); } function delSeg(s){ -if (segCount < 2) { -showToast("You need to have multiple segments in order to delete one."); -return; -} -expanded[s] = false; -segCount--; -var obj = {"seg": {"id": s, "stop": 0}}; -requestJson(obj); + if (segCount < 2) { + showToast("You need to have multiple segments in order to delete one."); + return; + } + expanded[s] = false; + segCount--; + var obj = {"seg": {"id": s, "stop": 0}}; + requestJson(obj); } function setRev(s){ -var rev = d.getElementById(`seg${s}rev`).checked; -var obj = {"seg": {"id": s, "rev": rev}}; -requestJson(obj); + var rev = d.getElementById(`seg${s}rev`).checked; + var obj = {"seg": {"id": s, "rev": rev}}; + requestJson(obj); } function setX(ind) { -var obj = {"seg": {"fx": parseInt(ind)}}; -requestJson(obj); + var obj = {"seg": {"fx": parseInt(ind)}}; + requestJson(obj); } function setPalette() { -var obj = {"seg": {"pal": parseInt(d.getElementById('selectPalette').value)}}; -requestJson(obj); + var obj = {"seg": {"pal": parseInt(d.getElementById('selectPalette').value)}}; + requestJson(obj); } function setBri() { -var obj = {"bri": parseInt(d.getElementById('sliderBri').value)}; -obj.transition = parseInt(d.getElementById('cyctt').value*10); -requestJson(obj); + var obj = {"bri": parseInt(d.getElementById('sliderBri').value)}; + obj.transition = parseInt(d.getElementById('cyctt').value*10); + requestJson(obj); } function setSpeed() { -var obj = {"seg": {"sx": parseInt(d.getElementById('sliderSpeed').value)}}; -requestJson(obj); + var obj = {"seg": {"sx": parseInt(d.getElementById('sliderSpeed').value)}}; + requestJson(obj); } function setIntensity() { -var obj = {"seg": {"ix": parseInt(d.getElementById('sliderIntensity').value)}}; -requestJson(obj); + var obj = {"seg": {"ix": parseInt(d.getElementById('sliderIntensity').value)}}; + requestJson(obj); } function toggleCY() { -var obj = {"pl" : -1}; -if (d.getElementById('cyToggle').checked) -{ -obj = {"pl": 0, "ccnf": {"min": parseInt(d.getElementById('cycs').value), "max": parseInt(d.getElementById('cyce').value), "time": parseInt(d.getElementById('cyct').value*10)}}; -obj.transition = parseInt(d.getElementById('cyctt').value*10); -} - -requestJson(obj); + var obj = {"pl" : -1}; + if (d.getElementById('cyToggle').checked) + { + obj = {"pl": 0, "ccnf": {"min": parseInt(d.getElementById('cycs').value), "max": parseInt(d.getElementById('cyce').value), "time": parseInt(d.getElementById('cyct').value*10)}}; + obj.transition = parseInt(d.getElementById('cyctt').value*10); + } + + requestJson(obj); } function togglePS() { -ps = !ps; - -var btns = document.getElementsByClassName("psts"); -for (i = 0; i < btns.length; i++) { -if (ps) { -btns[i].className += " saving"; -} else { -btns[i].className = btns[i].className.replace(" saving", ""); -} -} - -d.getElementById("psLabel").innerHTML = (ps) ? "Save to slot":"Load from slot"; + ps = !ps; + + var btns = document.getElementsByClassName("psts"); + for (i = 0; i < btns.length; i++) { + if (ps) { + btns[i].className += " saving"; + } else { + btns[i].className = btns[i].className.replace(" saving", ""); + } + } + + d.getElementById("psLabel").innerHTML = (ps) ? "Save to slot":"Load from slot"; } function setPreset(i) { -var obj = {"ps": i} -if ((savedPresets >> (i-1)) & 0x01) { -showToast("Loading config from slot " + i +"."); -} else { -showToast("Slot " + i +" is empty! Use saving mode to save the current config to it."); -} -if (ps) { -obj = {"psave": i}; -showToast("Saving config to slot " + i +"."); -} -requestJson(obj); + var obj = {"ps": i} + if ((savedPresets >> (i-1)) & 0x01) { + showToast("Loading config from slot " + i +"."); + } else { + showToast("Slot " + i +" is empty! Use saving mode to save the current config to it."); + } + if (ps) { + obj = {"psave": i}; + showToast("Saving config to slot " + i +"."); + } + requestJson(obj); } function selectSlot(b) { -csel = b; -var cd = d.getElementById('csl').children; -for (i = 0; i < cd.length; i++) { -cd[i].style.border="2px solid white"; -cd[i].style.margin="5px"; -cd[i].style.width="42px"; -} -cd[csel].style.border="5px solid white"; -cd[csel].style.margin="2px"; -cd[csel].style.width="50px"; -if (cpick.color.rgbString !== cd[csel].style.backgroundColor) { -cpick.color.set(cd[csel].style.backgroundColor); -} -d.getElementById('sliderW').value = whites[csel]; -updateTrail(d.getElementById('sliderW')); + csel = b; + var cd = d.getElementById('csl').children; + for (i = 0; i < cd.length; i++) { + cd[i].style.border="2px solid white"; + cd[i].style.margin="5px"; + cd[i].style.width="42px"; + } + cd[csel].style.border="5px solid white"; + cd[csel].style.margin="2px"; + cd[csel].style.width="50px"; + if (cpick.color.rgbString !== cd[csel].style.backgroundColor) { + cpick.color.set(cd[csel].style.backgroundColor); + } + d.getElementById('sliderW').value = whites[csel]; + updateTrail(d.getElementById('sliderW')); } var lasth = 0; function pC(col) { -if (col == "rnd") -{ -col = {h: 0, s: 0, v: 100}; -col.s = Math.floor((Math.random() * 50) + 50); -do { -col.h = Math.floor(Math.random() * 360); -} while (Math.abs(col.h - lasth) < 50); -lasth = col.h; -} -cpick.color.set(col); -setColor(false); + if (col == "rnd") + { + col = {h: 0, s: 0, v: 100}; + col.s = Math.floor((Math.random() * 50) + 50); + do { + col.h = Math.floor(Math.random() * 360); + } while (Math.abs(col.h - lasth) < 50); + lasth = col.h; + } + cpick.color.set(col); + setColor(false); } function setColor(fromPicker) { -var cd = d.getElementById('csl').children; -if (fromPicker && cd[csel].style.backgroundColor == 'rgb(0, 0, 0)') cpick.color.setChannel('hsv', 'v', 100); -cd[csel].style.backgroundColor = cpick.color.rgbString; -whites[csel] = d.getElementById('sliderW').value; -var col = cpick.color.rgb; -var obj = {"seg": {"col": [[col.r, col.g, col.b, whites[csel]],[],[]]}}; -if (csel == 1) { -obj = {"seg": {"col": [[],[col.r, col.g, col.b, whites[csel]],[]]}}; -} else if (csel == 2) { -obj = {"seg": {"col": [[],[],[col.r, col.g, col.b, whites[csel]]]}}; -} -obj.transition = parseInt(d.getElementById('cyctt').value*10); -if (d.getElementById('selectPalette').value > 5) { -d.getElementById('selectPalette').value = 0; -obj.seg.pal = 0; -} -requestJson(obj); + var cd = d.getElementById('csl').children; + if (fromPicker && cd[csel].style.backgroundColor == 'rgb(0, 0, 0)') cpick.color.setChannel('hsv', 'v', 100); + cd[csel].style.backgroundColor = cpick.color.rgbString; + whites[csel] = d.getElementById('sliderW').value; + var col = cpick.color.rgb; + var obj = {"seg": {"col": [[col.r, col.g, col.b, whites[csel]],[],[]]}}; + if (csel == 1) { + obj = {"seg": {"col": [[],[col.r, col.g, col.b, whites[csel]],[]]}}; + } else if (csel == 2) { + obj = {"seg": {"col": [[],[],[col.r, col.g, col.b, whites[csel]]]}}; + } + obj.transition = parseInt(d.getElementById('cyctt').value*10); + if (d.getElementById('selectPalette').value > 5) { + d.getElementById('selectPalette').value = 0; + obj.seg.pal = 0; + } + requestJson(obj); } function expand(i) { -expanded[i] = !expanded[i]; -d.getElementById('seg' +i).style.display = (expanded[i]) ? "block":"none"; -d.getElementById('sege' +i).style.transform = (expanded[i]) ? "rotate(180deg)":"rotate(0deg)" + expanded[i] = !expanded[i]; + d.getElementById('seg' +i).style.display = (expanded[i]) ? "block":"none"; + d.getElementById('sege' +i).style.transform = (expanded[i]) ? "rotate(180deg)":"rotate(0deg)" } function unfocusSliders() { -d.getElementById("sliderBri").blur(); -d.getElementById("sliderSpeed").blur(); -d.getElementById("sliderIntensity").blur(); + d.getElementById("sliderBri").blur(); + d.getElementById("sliderSpeed").blur(); + d.getElementById("sliderIntensity").blur(); } //sliding UI @@ -1404,67 +1404,67 @@ let iSlide = 0, x0 = null, y0 = null, scrollS = 0, locked = false, w; function unify(e) { return e.changedTouches ? e.changedTouches[0] : e } function lock(e) { -if (pcMode) return; -var l = e.target.classList; -if (l.contains('noslide') || l.contains('iro__wheel__saturation') || l.contains('iro__slider__value') || l.contains('iro__slider')) return; -x0 = unify(e).clientX; -y0 = unify(e).clientY; -scrollS = d.getElementsByClassName("tabcontent")[iSlide].scrollTop; + if (pcMode) return; + var l = e.target.classList; + if (l.contains('noslide') || l.contains('iro__wheel__saturation') || l.contains('iro__slider__value') || l.contains('iro__slider')) return; + x0 = unify(e).clientX; + y0 = unify(e).clientY; + scrollS = d.getElementsByClassName("tabcontent")[iSlide].scrollTop; -_C.classList.toggle('smooth', !(locked = true)) + _C.classList.toggle('smooth', !(locked = true)) } function drag(e) { -if (!locked || pcMode) return; -if (d.getElementsByClassName("tabcontent")[iSlide].scrollTop != scrollS) { -move(e); return; -} - -//if (Math.abs(unify(e).clientX - x0) > Math.abs(unify(e).clientY - y0)) { -//if (e.cancelable) e.preventDefault(); -//} - -_C.style.setProperty('--tx', `${Math.round(unify(e).clientX - x0)}px`) + if (!locked || pcMode) return; + if (d.getElementsByClassName("tabcontent")[iSlide].scrollTop != scrollS) { + move(e); return; + } + + //if (Math.abs(unify(e).clientX - x0) > Math.abs(unify(e).clientY - y0)) { + //if (e.cancelable) e.preventDefault(); + //} + + _C.style.setProperty('--tx', `${Math.round(unify(e).clientX - x0)}px`) } function move(e) { -if(!locked || pcMode) return; -var dx = unify(e).clientX - x0, s = Math.sign(dx), -f = +(s*dx/w).toFixed(2); + if(!locked || pcMode) return; + var dx = unify(e).clientX - x0, s = Math.sign(dx), + f = +(s*dx/w).toFixed(2); -if((iSlide > 0 || s < 0) && (iSlide < N - 1 || s > 0) && f > .12) { -_C.style.setProperty('--i', iSlide -= s); -f = 1 - f; -updateTablinks(iSlide); -} - -_C.style.setProperty('--tx', '0px'); -_C.style.setProperty('--f', f); -_C.classList.toggle('smooth', !(locked = false)); -x0 = null + if((iSlide > 0 || s < 0) && (iSlide < N - 1 || s > 0) && f > .12) { + _C.style.setProperty('--i', iSlide -= s); + f = 1 - f; + updateTablinks(iSlide); + } + + _C.style.setProperty('--tx', '0px'); + _C.style.setProperty('--f', f); + _C.classList.toggle('smooth', !(locked = false)); + x0 = null } function size() { -w = window.innerWidth; -_C.style.setProperty('--tp', d.getElementById('top').clientHeight + "px"); -_C.style.setProperty('--bt', d.getElementById('bot').clientHeight + "px"); -if (w < 1250) togglePcMode(); + w = window.innerWidth; + _C.style.setProperty('--tp', d.getElementById('top').clientHeight + "px"); + _C.style.setProperty('--bt', d.getElementById('bot').clientHeight + "px"); + if (w < 1250) togglePcMode(); } function togglePcMode() { -if (w < 1250 && !pcMode) return; -openTab(0); -pcMode = !pcMode; -if (w < 1250) pcMode = false; -updateTablinks(0); -d.getElementById('buttonPcm').className = (pcMode) ? "active":""; -if (pcMode) -{ -_C.style.width = '100%'; -} else { -_C.style.width = '400%'; -} + if (w < 1250 && !pcMode) return; + openTab(0); + pcMode = !pcMode; + if (w < 1250) pcMode = false; + updateTablinks(0); + d.getElementById('buttonPcm').className = (pcMode) ? "active":""; + if (pcMode) + { + _C.style.width = '100%'; + } else { + _C.style.width = '400%'; + } } size(); diff --git a/wled00/html_settings.h b/wled00/html_settings.h index 5fe0e919e..07e49ceab 100644 --- a/wled00/html_settings.h +++ b/wled00/html_settings.h @@ -118,7 +118,15 @@ LED voltage (Max. current for a single LED):

LEDs are 4-channel type (RGBW):
-Auto-calculate white channel from RGB:
+Auto-calculate white channel from RGB:
+ +
Color order: