diff --git a/wled00/const.h b/wled00/const.h
index 70373316fd..6edf333218 100644
--- a/wled00/const.h
+++ b/wled00/const.h
@@ -448,6 +448,8 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit");
//Playlist option byte
#define PL_OPTION_SHUFFLE 0x01
#define PL_OPTION_RESTORE 0x02
+#define PL_OPTION_DETERMINISTIC_SHUFFLE 0x04
+#define PL_OPTION_CLOCK_SYNC 0x08
// Segment capability byte
#define SEG_CAPABILITY_RGB 0x01
diff --git a/wled00/data/index.js b/wled00/data/index.js
index ee5126973c..4b4f3b4c2c 100644
--- a/wled00/data/index.js
+++ b/wled00/data/index.js
@@ -2004,10 +2004,46 @@ function pleTr(p,i,field)
plJson[p].transition[i] = Math.floor(field.value*10);
}
-function plR(p)
+function plUpdateOptions(p, changed)
{
var pl = plJson[p];
- pl.r = gId(`pl${p}rtgl`).checked;
+
+ const shuffle = gId(`pl${p}rtgl`).checked;
+ const deterministic = gId(`pl${p}deterministic`);
+ const clockSync = gId(`pl${p}clockSync`);
+ const manual = gId(`pl${p}manual`);
+ let manualChanged = changed == "manual";
+
+ // Ensure clock sync and manual advance can't be checked at the same time
+ if (clockSync.checked && manual.checked) {
+ if (changed == "clockSync") {
+ manual.checked = false;
+ manualChanged = true;
+ } else {
+ clockSync.checked = false;
+ }
+ }
+
+ // Reset & hide deterministic flag when not shuffling
+ if (!shuffle) deterministic.checked = false;
+ gId(`pl${p}deterministicRow`).style.display = shuffle ? "block" : "none";
+
+ pl.r = shuffle;
+ pl.deterministic = deterministic.checked;
+ pl.clockSync = clockSync.checked;
+
+ // Normalize durations when manual advance changes
+ if (manualChanged) {
+ plJson[p].dur.forEach((_,i)=>{
+ const e = manual.checked ? 0 : 100;
+ const d = gId(`pl${p}du${i}`);
+ plJson[p].dur[i] = e;
+ d.value = e/10; // 10s default
+ d.readOnly = manual.checked;
+ });
+ }
+
+ // Update repeat/end-preset controls
if (gId(`pl${p}rptgl`).checked) { // infinite
pl.repeat = 0;
delete pl.end;
@@ -2019,17 +2055,6 @@ function plR(p)
}
}
-function plM(p)
-{
- const man = gId(`pl${p}manual`).checked;
- plJson[p].dur.forEach((e,i)=>{
- const d = gId(`pl${p}du${i}`);
- plJson[p].dur[i] = e = man ? 0 : 100;
- d.value = e/10; // 10s default
- d.readOnly = man;
- });
-}
-
function makeP(i,pl)
{
var content = "";
@@ -2041,27 +2066,39 @@ function makeP(i,pl)
transition: [tr],
repeat: 0,
r: false,
+ deterministic: false,
+ clockSync: false,
end: 0
};
+ const clockSync = !!plJson[i].clockSync;
+ if (!plJson[i].r) plJson[i].deterministic = false;
const rep = plJson[i].repeat ? plJson[i].repeat : 0;
- const man = plJson[i].dur == 0;
+ const man = !clockSync && plJson[i].dur.every(d => d == 0);
content =
`
+
+
-
Repeat 0?rep:1}> times
+
Repeat 0?rep:1}> times
End preset:
-