Add CustomEffects as usermod: step 2: ui works
This commit is contained in:
12
usermods/customeffects/customeffects.css
Normal file
12
usermods/customeffects/customeffects.css
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.ceTextarea {
|
||||||
|
width: 90%;
|
||||||
|
height: 300px;
|
||||||
|
resize: none;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kceEditor {
|
||||||
|
max-width: 490px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
154
usermods/customeffects/customeffects.js
Normal file
154
usermods/customeffects/customeffects.js
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
|
||||||
|
var isCEEditor = false;
|
||||||
|
|
||||||
|
function toggleCEEditor(name, segID) {
|
||||||
|
if (isInfo) toggleInfo();
|
||||||
|
if (isNodes) toggleNodes();
|
||||||
|
isCEEditor = !isCEEditor;
|
||||||
|
if (isCEEditor) populateCEEditor(name, segID);
|
||||||
|
d.getElementById('ceEditor').style.transform = (isCEEditor) ? "translateY(0px)":"translateY(100%)";
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchAndExecute(url, name, callback)
|
||||||
|
{
|
||||||
|
fetch
|
||||||
|
(url+name, {
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (!res.ok) {
|
||||||
|
showToast("File " + name + " not found", true);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return res.text();
|
||||||
|
})
|
||||||
|
.then(text => {
|
||||||
|
callback(text);
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
showToast("Error getting " + name, true);
|
||||||
|
// showToast(error, true);
|
||||||
|
// console.log(error);
|
||||||
|
presetError(false);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
// if (callback) setTimeout(callback,99);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadLogFile(name, attempt) {
|
||||||
|
var ceLogArea = d.getElementById("ceLogArea");
|
||||||
|
fetchAndExecute((loc?`http://${locip}`:'.') + "/", name , function(logtext)
|
||||||
|
{
|
||||||
|
if (logtext == "") {
|
||||||
|
if (attempt < 10) {
|
||||||
|
ceLogArea.value = ("...........").substring(0, attempt + 1);
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
loadLogFile(name, attempt + 1);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ceLogArea.value = "log not found after 10 seconds";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ceLogArea.value = logtext;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveCE(name, segID) {
|
||||||
|
showToast("Saving " + name);
|
||||||
|
|
||||||
|
var ceProgramArea = d.getElementById("ceProgramArea");
|
||||||
|
|
||||||
|
uploadFileWithText("/" + name, ceProgramArea.value);
|
||||||
|
|
||||||
|
var obj = {"seg": {"id": segID, "reset": true}};
|
||||||
|
requestJson(obj);
|
||||||
|
|
||||||
|
var ceLogArea = d.getElementById("ceLogArea");
|
||||||
|
ceLogArea.value = ".";
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
loadLogFile(name + ".log", 1);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function populateCEEditor(name, segID)
|
||||||
|
{
|
||||||
|
fetchAndExecute((loc?`http://${locip}`:'.') + "/", name + ".wled", function(text)
|
||||||
|
{
|
||||||
|
var cn=`Custom Effects Editor<br>
|
||||||
|
<i>${name}.wled</i><br>
|
||||||
|
<textarea class="ceTextarea" id="ceProgramArea">${text}</textarea><br>
|
||||||
|
<button class="btn infobtn" onclick="toggleCEEditor()">Close</button>
|
||||||
|
<button class="btn infobtn" onclick="saveCE('${name}.wled', ${segID})">Save and Run</button><br>
|
||||||
|
<button class="btn infobtn" onclick="downloadCEFile('${name}.wled')">Download ${name}.wled</button>
|
||||||
|
<button class="btn infobtn" onclick="loadCETemplate('${name}')">Load template</button><br>
|
||||||
|
<button class="btn infobtn" onclick="downloadCEFile('wled.json')">Download wled.json</button>
|
||||||
|
<button class="btn infobtn" onclick="downloadCEFile('presets.json')">Download presets.json</button><br>
|
||||||
|
<a href="https://github.com/MoonModules/WLED-Effects/tree/master/CustomEffects/wled" target="_blank">Custom Effects Library</a><br>
|
||||||
|
<a href="https://github.com/atuline/WLED/wiki/WLED-Custom-effects" target="_blank">Custom Effects Help</a><br>
|
||||||
|
<br><i>Compile and Run Log</i><br>
|
||||||
|
<textarea class="ceTextarea" id="ceLogArea"></textarea><br>
|
||||||
|
<i>Run log > 3 seconds is send to Serial Ouput.</i>`;
|
||||||
|
|
||||||
|
d.getElementById('kceEditor').innerHTML = cn;
|
||||||
|
|
||||||
|
var ceLogArea = d.getElementById("ceLogArea");
|
||||||
|
ceLogArea.value = ".";
|
||||||
|
loadLogFile(name + ".wled.log", 1);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadCEFile(name) {
|
||||||
|
var url = "https://raw.githubusercontent.com/MoonModules/WLED-Effects/master/CustomEffects/wled/";
|
||||||
|
|
||||||
|
fetchAndExecute(url, name, function(text) {
|
||||||
|
console.log(text);
|
||||||
|
if (name == "wled.json" || name == "presets.json") {
|
||||||
|
if (!confirm('Are you sure to download/overwrite ' + name + '?'))
|
||||||
|
return;
|
||||||
|
uploadFileWithText("/" + name, text);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var ceProgramArea = d.getElementById("ceProgramArea");
|
||||||
|
ceProgramArea.value = text;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.onload = function() {
|
||||||
|
if (name == "wled.json" || name == "presets.json") {
|
||||||
|
if (!confirm('Are you sure to download ' + name + '?'))
|
||||||
|
return;
|
||||||
|
uploadFileWithText("/" + name, request.response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var ceProgramArea = d.getElementById("ceProgramArea");
|
||||||
|
ceProgramArea.value = request.response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.open("GET", url);
|
||||||
|
request.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadCETemplate(name) {
|
||||||
|
var ceProgramArea = d.getElementById("ceProgramArea");
|
||||||
|
ceProgramArea.value = `/*
|
||||||
|
Custom Effects Template
|
||||||
|
*/
|
||||||
|
program ${name}
|
||||||
|
{
|
||||||
|
function renderFrame()
|
||||||
|
{
|
||||||
|
setPixelColor(counter, colorFromPalette(counter, counter))
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -100,10 +100,16 @@ class CustomEffectsUserMod : public Usermod {
|
|||||||
unsigned long lastTime = 0; //will be used to download new forecast every hour
|
unsigned long lastTime = 0; //will be used to download new forecast every hour
|
||||||
char errorMessage[100] = "";
|
char errorMessage[100] = "";
|
||||||
|
|
||||||
|
bool enabled = false;
|
||||||
|
bool initDone = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
strip.addEffect(255, &mode_customEffect, _data_FX_MODE_CUSTOMEFFECT);
|
if (!initDone)
|
||||||
|
strip.addEffect(255, &mode_customEffect, _data_FX_MODE_CUSTOMEFFECT);
|
||||||
|
initDone = true;
|
||||||
|
enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void connected() {
|
void connected() {
|
||||||
@@ -140,6 +146,12 @@ class CustomEffectsUserMod : public Usermod {
|
|||||||
void addToJsonState(JsonObject& root)
|
void addToJsonState(JsonObject& root)
|
||||||
{
|
{
|
||||||
//root["user0"] = userVar0;
|
//root["user0"] = userVar0;
|
||||||
|
if (!initDone) return; // prevent crash on boot applyPreset()
|
||||||
|
JsonObject usermod = root[FPSTR(_name)];
|
||||||
|
if (usermod.isNull()) {
|
||||||
|
usermod = root.createNestedObject(FPSTR(_name));
|
||||||
|
}
|
||||||
|
usermod["on"] = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -196,4 +208,4 @@ class CustomEffectsUserMod : public Usermod {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
const char CustomEffectsUserMod::_name[] PROGMEM = "Custom Effects";
|
const char CustomEffectsUserMod::_name[] PROGMEM = "CustomEffects";
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
setTimeout(()=>{h.appendChild(l)},100);
|
setTimeout(()=>{h.appendChild(l)},100);
|
||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" href="index.css">
|
<link rel="stylesheet" href="index.css">
|
||||||
|
<link rel="stylesheet" href="../../usermods/customeffects/customeffects.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
@@ -365,6 +366,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- WLEDSR Custom Effects -->
|
||||||
|
<div id="ceEditor" class="modal">
|
||||||
|
<div id="kceEditor">Loading...</div><br>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="mliveview2D" class="modal">
|
<div id="mliveview2D" class="modal">
|
||||||
<div id="kliveview2D" style="width:100%; height:100%">Loading...</div><br>
|
<div id="kliveview2D" style="width:100%; height:100%">Loading...</div><br>
|
||||||
</div>
|
</div>
|
||||||
@@ -380,5 +386,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<i id="roverstar" class="icons huge" onclick="setLor(0)"></i><br>
|
<i id="roverstar" class="icons huge" onclick="setLor(0)"></i><br>
|
||||||
<script src="index.js"></script>
|
<script src="index.js"></script>
|
||||||
|
<script src="../../usermods/customeffects/customeffects.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -684,7 +684,11 @@ function populateSegments(s)
|
|||||||
let li = lastinfo;
|
let li = lastinfo;
|
||||||
segCount = 0; lowestUnused = 0; lSeg = 0;
|
segCount = 0; lowestUnused = 0; lSeg = 0;
|
||||||
|
|
||||||
|
console.log(s);
|
||||||
|
|
||||||
for (var inst of (s.seg||[])) {
|
for (var inst of (s.seg||[])) {
|
||||||
|
console.log(inst);
|
||||||
|
|
||||||
segCount++;
|
segCount++;
|
||||||
|
|
||||||
let i = parseInt(inst.id);
|
let i = parseInt(inst.id);
|
||||||
@@ -728,6 +732,7 @@ function populateSegments(s)
|
|||||||
<option value="3" ${inst.ssim==3?' selected':''}>U14_3</option>
|
<option value="3" ${inst.ssim==3?' selected':''}>U14_3</option>
|
||||||
</select></div>
|
</select></div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
let cusEff = `<button class="btn" onclick="toggleCEEditor('${inst.n?inst.n:"default"}', ${i})">Custom Effect Editor</button><br>`;
|
||||||
cn += `<div class="seg lstI ${i==s.mainseg ? 'selected' : ''} ${exp ? "expanded":""}" id="seg${i}">
|
cn += `<div class="seg lstI ${i==s.mainseg ? 'selected' : ''} ${exp ? "expanded":""}" id="seg${i}">
|
||||||
<label class="check schkl">
|
<label class="check schkl">
|
||||||
<input type="checkbox" id="seg${i}sel" onchange="selSeg(${i})" ${inst.sel ? "checked":""}>
|
<input type="checkbox" id="seg${i}sel" onchange="selSeg(${i})" ${inst.sel ? "checked":""}>
|
||||||
@@ -774,6 +779,7 @@ function populateSegments(s)
|
|||||||
${!isM?rvXck:''}
|
${!isM?rvXck:''}
|
||||||
${isM&&stoY-staY>1&&stoX-staX>1?map2D:''}
|
${isM&&stoY-staY>1&&stoX-staX>1?map2D:''}
|
||||||
${s.AudioReactive && s.AudioReactive.on ? "" : sndSim}
|
${s.AudioReactive && s.AudioReactive.on ? "" : sndSim}
|
||||||
|
${s.CustomEffects && s.CustomEffects.on ? cusEff : ""}
|
||||||
<label class="check revchkl" id="seg${i}lbtm">
|
<label class="check revchkl" id="seg${i}lbtm">
|
||||||
${isM?'Transpose':'Mirror effect'}
|
${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":"")}>
|
<input type="checkbox" id="seg${i}${isM?'tp':'mi'}" onchange="${(isM?'setTp(':'setMi(')+i})" ${isM?(inst.tp?"checked":""):(inst.mi?"checked":"")}>
|
||||||
|
|||||||
3803
wled00/html_ui.h
3803
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@@ -108,6 +108,12 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
bool on = elem["on"] | seg.on;
|
bool on = elem["on"] | seg.on;
|
||||||
if (elem["on"].is<const char*>() && elem["on"].as<const char*>()[0] == 't') on = !on;
|
if (elem["on"].is<const char*>() && elem["on"].as<const char*>()[0] == 't') on = !on;
|
||||||
seg.setOption(SEG_OPTION_ON, on); // use transition
|
seg.setOption(SEG_OPTION_ON, on); // use transition
|
||||||
|
|
||||||
|
//WLEDSR Custom Effects (but general usable)
|
||||||
|
bool reset = elem["reset"];
|
||||||
|
if (reset)
|
||||||
|
seg.markForReset();
|
||||||
|
|
||||||
bool frz = elem["frz"] | seg.freeze;
|
bool frz = elem["frz"] | seg.freeze;
|
||||||
if (elem["frz"].is<const char*>() && elem["frz"].as<const char*>()[0] == 't') frz = !seg.freeze;
|
if (elem["frz"].is<const char*>() && elem["frz"].as<const char*>()[0] == 't') frz = !seg.freeze;
|
||||||
seg.freeze = frz;
|
seg.freeze = frz;
|
||||||
|
|||||||
Reference in New Issue
Block a user