Pin dropdowns POC.
NeoPixelBusGammaMethod POC. PixelMagic POC. Button reassign POC.
This commit is contained in:
parent
21387b9a83
commit
3ca58ee65f
@ -222,6 +222,7 @@ writeHtmlGzipped("wled00/data/index.htm", "wled00/html_ui.h", 'index');
|
||||
writeHtmlGzipped("wled00/data/simple.htm", "wled00/html_simple.h", 'simple');
|
||||
writeHtmlGzipped("wled00/data/pixart/pixart.htm", "wled00/html_pixart.h", 'pixart');
|
||||
writeHtmlGzipped("wled00/data/cpal/cpal.htm", "wled00/html_cpal.h", 'cpal');
|
||||
//writeHtmlGzipped("wled00/data/pxmagic.htm", "wled00/html_pxmagic.h", 'pxmagic');
|
||||
/*
|
||||
writeChunks(
|
||||
"wled00/data",
|
||||
|
@ -122,6 +122,9 @@
|
||||
#define I_SS_LPO_3 48
|
||||
|
||||
|
||||
// In the following NeoGammaNullMethod can be replaced with NeoGammaWLEDMethod to perform Gamma correction implicitly
|
||||
// unfortunately that may apply Gamma correction to pre-calculated palettes which is undesired
|
||||
|
||||
/*** ESP8266 Neopixel methods ***/
|
||||
#ifdef ESP8266
|
||||
//RGB
|
||||
|
@ -338,7 +338,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
if (light_gc_col > 1.0f) gammaCorrectCol = true;
|
||||
else gammaCorrectCol = false;
|
||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) {
|
||||
if (gammaCorrectVal != 2.8f) calcGammaTable(gammaCorrectVal);
|
||||
if (gammaCorrectVal != 2.8f) NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
||||
} else {
|
||||
gammaCorrectVal = 1.0f; // no gamma correction
|
||||
gammaCorrectBri = false;
|
||||
|
@ -302,7 +302,7 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) {
|
||||
}
|
||||
|
||||
//gamma 2.8 lookup table used for color correction
|
||||
static byte gammaT[] = {
|
||||
uint8_t NeoGammaWLEDMethod::gammaT[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||
@ -320,27 +320,22 @@ static byte gammaT[] = {
|
||||
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
||||
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
||||
|
||||
uint8_t gamma8_cal(uint8_t b, float gamma)
|
||||
{
|
||||
return (int)(powf((float)b / 255.0f, gamma) * 255.0f + 0.5f);
|
||||
}
|
||||
|
||||
// re-calculates & fills gamma table
|
||||
void calcGammaTable(float gamma)
|
||||
void NeoGammaWLEDMethod::calcGammaTable(float gamma)
|
||||
{
|
||||
for (uint16_t i = 0; i < 256; i++) {
|
||||
gammaT[i] = gamma8_cal(i, gamma);
|
||||
for (size_t i = 0; i < 256; i++) {
|
||||
gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
// used for individual channel or brightness gamma correction
|
||||
uint8_t gamma8(uint8_t b)
|
||||
uint8_t NeoGammaWLEDMethod::Correct(uint8_t value)
|
||||
{
|
||||
return gammaT[b];
|
||||
if (!gammaCorrectCol) return value;
|
||||
return gammaT[value];
|
||||
}
|
||||
|
||||
// used for color gamma correction
|
||||
uint32_t gamma32(uint32_t color)
|
||||
uint32_t NeoGammaWLEDMethod::Correct32(uint32_t color)
|
||||
{
|
||||
if (!gammaCorrectCol) return color;
|
||||
uint8_t w = W(color);
|
||||
|
1064
wled00/data/pxmagic.htm
Normal file
1064
wled00/data/pxmagic.htm
Normal file
File diff suppressed because one or more lines are too long
@ -10,7 +10,7 @@
|
||||
d.um_p = [];
|
||||
d.rsvd = [];
|
||||
d.ro_gpio = [];
|
||||
d.max_gpio = 39;
|
||||
d.max_gpio = 50;
|
||||
var customStarts=false,startsDirty=[],maxCOOverrides=5;
|
||||
var loc = false, locip, locproto = "http:";
|
||||
function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");}
|
||||
@ -28,6 +28,7 @@
|
||||
scE.addEventListener("load", () => {
|
||||
GetV();checkSi();setABL();
|
||||
if (d.um_p[0]==-1) d.um_p.shift();
|
||||
pinDropdowns();
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
@ -546,6 +547,62 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
||||
}
|
||||
}
|
||||
}
|
||||
function pinDropdowns() {
|
||||
let fields = ["IR","RL"]; // IR & relay
|
||||
gId("btns").querySelectorAll('input[type="number"]').forEach((e)=>{fields.push(e.name);}) // buttons
|
||||
for (let i of d.Sf.elements) {
|
||||
if (i.type === "number" && fields.includes(i.name)) { //select all pin select elements
|
||||
let v = parseInt(i.value);
|
||||
let sel = addDropdown(i.name,0);
|
||||
for (var j = -1; j <= d.max_gpio; j++) {
|
||||
if (d.rsvd.includes(j)) continue;
|
||||
let foundPin = d.um_p.indexOf(j);
|
||||
let txt = (j === -1) ? "unused" : `${j}`;
|
||||
if (foundPin >= 0 && j !== v) txt += ` used`; // already reserved pin
|
||||
if (d.ro_gpio.includes(j)) txt += " (R/O)";
|
||||
let opt = addOption(sel, txt, j);
|
||||
if (j === v) opt.selected = true; // this is "our" pin
|
||||
else if (d.um_p.includes(j)) opt.disabled = true; // someone else's pin
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// https://stackoverflow.com/questions/39729741/javascript-change-input-text-to-select-option
|
||||
function addDropdown(field) {
|
||||
let sel = d.createElement('select');
|
||||
sel.classList.add("pin");
|
||||
let inp = d.getElementsByName(field)[0];
|
||||
if (inp && inp.tagName === "INPUT" && (inp.type === "text" || inp.type === "number")) { // may also use nodeName
|
||||
let v = inp.value;
|
||||
let n = inp.name;
|
||||
// copy the existing input element's attributes to the new select element
|
||||
for (var i = 0; i < inp.attributes.length; ++ i) {
|
||||
var att = inp.attributes[i];
|
||||
// type and value don't apply, so skip them
|
||||
// ** you might also want to skip style, or others -- modify as needed **
|
||||
if (att.name != 'type' && att.name != 'value' && att.name != 'class' && att.name != 'style') {
|
||||
sel.setAttribute(att.name, att.value);
|
||||
}
|
||||
}
|
||||
sel.setAttribute("data-val", v);
|
||||
// finally, replace the old input element with the new select element
|
||||
inp.parentElement.replaceChild(sel, inp);
|
||||
return sel;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function addOption(sel,txt,val) {
|
||||
if (sel===null) return; // select object missing
|
||||
let opt = d.createElement("option");
|
||||
opt.value = val;
|
||||
opt.text = txt;
|
||||
sel.appendChild(opt);
|
||||
for (let i=0; i<sel.childNodes.length; i++) {
|
||||
let c = sel.childNodes[i];
|
||||
if (c.value == sel.dataset.val) sel.selectedIndex = i;
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
function S() {
|
||||
let l = window.location;
|
||||
if (l.protocol == "file:") {
|
||||
|
@ -7,7 +7,7 @@
|
||||
<title>Usermod Settings</title>
|
||||
<script>
|
||||
var d = document;
|
||||
d.max_gpio = 39;
|
||||
d.max_gpio = 50;
|
||||
d.um_p = [];
|
||||
d.rsvd = [];
|
||||
d.ro_gpio = [];
|
||||
@ -39,6 +39,7 @@
|
||||
d.Sf.MISO.max = d.max_gpio;
|
||||
let inp = d.getElementsByTagName("input");
|
||||
for (let i of inp) if (i.type === "number" && i.name.replace("[]","").substr(-3) === "pin") i.max = d.max_gpio;
|
||||
pinDropdowns();
|
||||
});
|
||||
// error event
|
||||
scE.addEventListener("error", (ev) => {
|
||||
@ -103,8 +104,10 @@
|
||||
if (isO(o)) {
|
||||
for (const [k,v] of Object.entries(o)) {
|
||||
if (isO(v)) {
|
||||
let oldO = owner; // keep parent name
|
||||
owner = k;
|
||||
getPins(v);
|
||||
owner = oldO;
|
||||
continue;
|
||||
}
|
||||
if (k.replace("[]","").substr(-3)=="pin") {
|
||||
@ -163,11 +166,67 @@
|
||||
urows += `<input type="${t==="int"?"number":t}" name="${k}:${f}${a?"[]":""}" ${c} oninput="check(this,'${k.substr(k.indexOf(":")+1)}')"><br>`;
|
||||
}
|
||||
}
|
||||
function pinDropdowns() {
|
||||
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
|
||||
let v = parseInt(i.value);
|
||||
let sel = addDropdown(i.name,0);
|
||||
for (var j = -1; j <= d.max_gpio; j++) {
|
||||
if (d.rsvd.includes(j)) continue;
|
||||
let foundPin = pins.indexOf(j);
|
||||
let txt = (j === -1) ? "unused" : `${j}`;
|
||||
if (foundPin >= 0 && j !== v) txt += ` ${pinO[foundPin]=="if"?"global":pinO[foundPin]}`; // already reserved pin
|
||||
if (d.ro_gpio.includes(j)) txt += " (R/O)";
|
||||
let opt = addOption(sel, txt, j);
|
||||
if (j === v) opt.selected = true; // this is "our" pin
|
||||
else if (pins.includes(j)) opt.disabled = true; // someone else's pin
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function UI(e) {
|
||||
// update changed select options across all usermods
|
||||
let oldV = parseInt(e.dataset.val);
|
||||
e.dataset.val = e.value;
|
||||
let txt = e.name.split(":")[e.name.split(":").length-2];
|
||||
let selects = d.Sf.querySelectorAll("select[class='pin']");
|
||||
for (let sel of selects) {
|
||||
if (sel == e) continue
|
||||
Array.from(sel.options).forEach((i)=>{
|
||||
if (!(i.value==oldV || i.value==e.value)) return;
|
||||
if (i.value == -1) {
|
||||
i.text = "unused";
|
||||
return
|
||||
}
|
||||
i.text = i.value;
|
||||
if (i.value==oldV) {
|
||||
i.disabled = false;
|
||||
}
|
||||
if (i.value==e.value) {
|
||||
i.disabled = true;
|
||||
i.text += ` ${txt}`;
|
||||
}
|
||||
if (d.ro_gpio.includes(parseInt(i.value))) i.text += " (R/O)";
|
||||
});
|
||||
}
|
||||
}
|
||||
// https://stackoverflow.com/questions/39729741/javascript-change-input-text-to-select-option
|
||||
function addDropdown(um,fld) {
|
||||
let sel = d.createElement('select');
|
||||
let arr = d.getElementsByName(um+":"+fld);
|
||||
let inp = arr[1]; // assume 1st field to be hidden (type)
|
||||
if (typeof(fld) === "string") { // parameter from usermod (field name)
|
||||
if (fld.includes("pin")) sel.classList.add("pin");
|
||||
um += ":"+fld;
|
||||
} else if (typeof(fld) === "number") sel.classList.add("pin"); // a hack to add a class
|
||||
let arr = d.getElementsByName(um);
|
||||
let idx = arr[0].type==="hidden"?1:0; // ignore hidden field
|
||||
if (arr.length > 2) {
|
||||
// we have array of values (usually pins)
|
||||
for (let i of arr) {
|
||||
if (i.type === "number") break;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
let inp = arr[idx];
|
||||
if (inp && inp.tagName === "INPUT" && (inp.type === "text" || inp.type === "number")) { // may also use nodeName
|
||||
let v = inp.value;
|
||||
let n = inp.name;
|
||||
@ -181,8 +240,10 @@
|
||||
}
|
||||
}
|
||||
sel.setAttribute("data-val", v);
|
||||
sel.setAttribute("onchange", "UI(this)");
|
||||
// finally, replace the old input element with the new select element
|
||||
inp.parentElement.replaceChild(sel, inp);
|
||||
if (arr[0].type==="hidden") arr[0].parentElement.removeChild(arr[0]); // remove hidden element from DOM
|
||||
return sel;
|
||||
}
|
||||
return null;
|
||||
@ -197,6 +258,7 @@
|
||||
let c = sel.childNodes[i];
|
||||
if (c.value == sel.dataset.val) sel.selectedIndex = i;
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
// https://stackoverflow.com/questions/26440494/insert-text-after-this-input-element-with-javascript
|
||||
function addInfo(name,el,txt, txt2="") {
|
||||
@ -208,6 +270,10 @@
|
||||
if (txt2!="") obj[el].insertAdjacentHTML('beforebegin', txt2 + ' '); //add pre texts
|
||||
}
|
||||
}
|
||||
// add Help Button
|
||||
function addHB(um) {
|
||||
addInfo(um + ':help',0,`<button onclick="location.href='https://kno.wled.ge/usermods/${um}'" type="button">?</button>`);
|
||||
}
|
||||
// load settings and insert values into DOM
|
||||
function ldS() {
|
||||
fetch(getURL('/cfg.json'), {
|
||||
|
@ -61,6 +61,9 @@ button.sml {
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
.err {
|
||||
color: #f00;
|
||||
}
|
||||
.warn {
|
||||
color: #fa0;
|
||||
}
|
||||
@ -117,6 +120,10 @@ select {
|
||||
font-family: Verdana, sans-serif;
|
||||
border: 0.5ch solid #333;
|
||||
}
|
||||
select.pin {
|
||||
max-width: 120px;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
tr {
|
||||
line-height: 100%;
|
||||
}
|
||||
|
@ -50,6 +50,18 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau
|
||||
|
||||
|
||||
//colors.cpp
|
||||
// similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod)
|
||||
class NeoGammaWLEDMethod {
|
||||
public:
|
||||
static uint8_t Correct(uint8_t value); // apply Gamma to single channel
|
||||
static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB)
|
||||
static void calcGammaTable(float gamma); // re-calculates & fills gamma table
|
||||
static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB)
|
||||
private:
|
||||
static uint8_t gammaT[];
|
||||
};
|
||||
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
|
||||
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
|
||||
uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
|
||||
uint32_t color_add(uint32_t,uint32_t);
|
||||
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||
@ -63,10 +75,6 @@ bool colorFromHexString(byte* rgb, const char* in);
|
||||
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
||||
uint16_t approximateKelvinFromRGB(uint32_t rgb);
|
||||
void setRandomColor(byte* rgb);
|
||||
uint8_t gamma8_cal(uint8_t b, float gamma);
|
||||
void calcGammaTable(float gamma);
|
||||
uint8_t gamma8(uint8_t b);
|
||||
uint32_t gamma32(uint32_t);
|
||||
|
||||
//dmx.cpp
|
||||
void initDMX();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -455,6 +455,29 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
}
|
||||
}
|
||||
|
||||
// accepting config changes (not permanent, unless config is saved)
|
||||
JsonObject cfg = root["cfg"];
|
||||
if (!cfg.isNull()) {
|
||||
// reconfigure button presets (on the fly)
|
||||
JsonVariant btn = cfg["btn"];
|
||||
if (btn.is<JsonObject>()) {
|
||||
uint8_t btn_id = btn["id"] | 0;
|
||||
macroButton[btn_id] = btn["s"] | macroButton[btn_id];
|
||||
macroLongPress[btn_id] = btn["l"] | macroLongPress[btn_id];
|
||||
macroDoublePress[btn_id] = btn["d"] | macroDoublePress[btn_id];
|
||||
} else {
|
||||
uint8_t btn_id = 0;
|
||||
for (JsonObject _btn : btn.as<JsonArray>()) {
|
||||
btn_id = _btn["id"] | btn_id;
|
||||
if (btn_id >= WLED_MAX_BUTTONS) continue;
|
||||
macroButton[btn_id] = _btn["s"] | macroButton[btn_id];
|
||||
macroLongPress[btn_id] = _btn["l"] | macroLongPress[btn_id];
|
||||
macroDoublePress[btn_id] = _btn["d"] | macroDoublePress[btn_id];
|
||||
btn_id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stateUpdated(callMode);
|
||||
if (presetToRestore) currentPreset = presetToRestore;
|
||||
|
||||
|
@ -37,8 +37,8 @@ void applyValuesToSelectedSegs()
|
||||
|
||||
if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;}
|
||||
if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
|
||||
if (effectPalette != selsegPrev.palette) {seg.palette = effectPalette; stateChanged = true;}
|
||||
if (effectCurrent != selsegPrev.mode) {strip.setMode(i, effectCurrent); stateChanged = true;}
|
||||
if (effectPalette != selsegPrev.palette) {seg.setPalette(effectPalette); stateChanged = true;}
|
||||
if (effectCurrent != selsegPrev.mode) {seg.setMode(effectCurrent); stateChanged = true;}
|
||||
uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
|
||||
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0); stateChanged = true;}
|
||||
|
@ -233,7 +233,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
gammaCorrectCol = request->hasArg(F("GC"));
|
||||
gammaCorrectVal = request->arg(F("GV")).toFloat();
|
||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3)
|
||||
calcGammaTable(gammaCorrectVal);
|
||||
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
||||
else {
|
||||
gammaCorrectVal = 1.0f; // no gamma correction
|
||||
gammaCorrectBri = false;
|
||||
|
@ -197,7 +197,7 @@ void appendGPIOinfo() {
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
oappend(SET_F("d.rsvd=[11,12,13,14,15,16,17"));
|
||||
#elif defined(ESP32)
|
||||
oappend(SET_F("d.rsvd=[6,7,8,9,10,11,24,28,29,30,31"));
|
||||
oappend(SET_F("d.rsvd=[6,7,8,9,10,11,24,28,29,30,31,37,38"));
|
||||
#else
|
||||
oappend(SET_F("d.rsvd=[6,7,8,9,10,11"));
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user