POC: Implemented segment groups (4).

Sacrificed 1 bit on sound simulation and 1D to 2D mapping each.
This commit is contained in:
Blaz Kristan 2023-04-01 23:40:43 +02:00
parent af44730418
commit 558b22c36a
6 changed files with 2055 additions and 1970 deletions

View File

@ -349,8 +349,9 @@ typedef struct Segment {
bool reverse_y : 1; // 7 : reversed Y (2D)
bool mirror_y : 1; // 8 : mirrored Y (2D)
bool transpose : 1; // 9 : transposed (2D, swapped X & Y)
uint8_t map1D2D : 3; // 10-12 : mapping for 1D effect on 2D (0-use as strip, 1-expand vertically, 2-circular/arc, 3-rectangular/corner, ...)
uint8_t soundSim : 3; // 13-15 : 0-7 sound simulation types
uint8_t map1D2D : 2; // 10-11 : mapping for 1D effect on 2D (0-use as strip, 1-expand vertically, 2-circular/arc, 3-rectangular/corner, ...)
uint8_t soundSim : 2; // 12-13 : 0-3 sound simulation types
uint8_t group : 2; // 14-15 : 0-3 UI segment groups
};
};
uint8_t grouping, spacing;

View File

@ -472,8 +472,8 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
sOpt = extractModeDefaults(fx, "o1"); check1 = (sOpt >= 0) ? (bool)sOpt : false;
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7);
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 7);
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 3);
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 3);
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt;

View File

@ -178,18 +178,49 @@ button {
}
.e-icon {
transform: translateY(3px);
/*transform: translateY(3px);*/
}
.sel-icon {
transform: translateX(3px);
}
.e-icon, .sel-icon, .slider-icon {
.e-icon, .g-icon, .sel-icon, .slider-icon {
cursor: pointer;
color: var(--c-d);
}
.g-icon {
font-style: normal;
position: absolute;
top: 8px;
right: 8px;
}
/* pop-up container */
.pop {
position: absolute;
display: inline-block;
top: 0;
right: 0;
}
/* pop-up content */
.pop-c {
position: absolute;
background-color: var(--c-5);
border: 1px solid var(--c-e);
border-radius: 16px;
z-index: 1;
top: 3px;
left: -164px;
padding: 4px 8px 2px;
font-size: 24px;
}
.pop-c span {
padding: 2px 6px;
}
.search-icon {
position: absolute;
top: 8px;
@ -201,7 +232,6 @@ button {
.clear-icon {
position: absolute;
display: none;
top: 8px;
right: 9px;
cursor: pointer;
@ -229,14 +259,12 @@ button {
#liveview {
height: 4px;
display: none;
width: 100%;
border: 0px;
}
#liveview2D {
height: 90%;
display: none;
width: 90%;
border: 0px;
position: absolute;
@ -467,13 +495,6 @@ button {
opacity: 1;
}
#pql, .edit-icon {
display: none;
}
.hide {
display: none !important;
}
.fade {
visibility: hidden; /* hide it */
opacity: 0; /* make it transparent */
@ -551,7 +572,6 @@ button {
position: fixed;
top: calc(var(--th) + 5px);
left: 1px;
display: none;
cursor: pointer;
}
@ -651,7 +671,9 @@ img {
#wbal .sliderdisplay { background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #cbdbff); }
/* wrapper divs hidden by default */
#rgbwrap, #swrap, #hwrap, #kwrap, #wwrap, #wbal, #qcs-w, #hexw {
#liveview, #liveview2D, #roverstar, #pql
#rgbwrap, #swrap, #hwrap, #kwrap, #wwrap, #wbal, #qcs-w, #hexw,
.clear-icon, .edit-icon, .ptxt {
display: none;
}
@ -984,8 +1006,7 @@ textarea {
}
.ptxt {
margin: -1px 4px 8px !important;
display: none;
margin: -1px 4px 8px !important;
}
.stxt {
@ -1088,18 +1109,14 @@ textarea {
}
.frz {
left: 32px;
left: 10px;
position: absolute;
top: -3px;
top: 8px;
cursor: pointer;
padding: 8px;
/*padding: 8px;*/
z-index: 1;
}
.expanded .frz {
display: none;
}
/* radiobuttons and checkmarks */
.check, .radio {
display: block;
@ -1412,13 +1429,13 @@ TD .checkmark, TD .radiomark {
.check input:checked ~ .checkmark:after,
.radio input:checked ~ .radiomark:after,
.show,
.show, .g-icon,
.expanded .edit-icon,
.expanded .segin, .expanded .presin, .expanded .sbs,
.expanded {
display: inline-block !important;
}
.expanded .segin.hide, .expanded .presin.hide, .expanded .sbs.hide {
.hide, .expanded .segin.hide, .expanded .presin.hide, .expanded .sbs.hide, .expanded .frz, .expanded .g-icon {
display: none !important;
}

View File

@ -697,6 +697,13 @@ function populateSegments(s)
let sg = gId(`seg${i}`);
let exp = sg ? (sg.classList.contains('expanded') || (i===0 && cfg.comp.segexp)) : false;
let cG = "var(--c-b)";
switch (inst.group) {
case 1: cG = "var(--c-r)"; break;
case 2: cG = "var(--c-g)"; break;
case 3: cG = "var(--c-b)"; break;
}
let segp = `<div id="segp${i}" class="sbs">
<i class="icons e-icon pwr ${inst.on ? "act":""}" id="seg${i}pwr" onclick="setSegPwr(${i})">&#xe08f;</i>
<div class="sliderwrap il">
@ -731,15 +738,19 @@ function populateSegments(s)
<option value="3" ${inst.si==3?' selected':''}>U14_3</option>
</select></div>
</div>`;
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}" data-group="${inst.group?inst.group:0}">
<label class="check schkl">
<input type="checkbox" id="seg${i}sel" onchange="selSeg(${i})" ${inst.sel ? "checked":""}>
<span class="checkmark"></span>
</label>
<i class="icons e-icon frz" id="seg${i}frz" onclick="event.preventDefault();tglFreeze(${i});">&#x${inst.frz ? (li.live && li.liveseg==i?'e410':'e0e8') : 'e325'};</i>
<div class="segname" onclick="selSegEx(${i})">
<i class="icons e-icon frz" id="seg${i}frz" onclick="event.preventDefault();tglFreeze(${i});">&#x${inst.frz ? (li.live && li.liveseg==i?'e410':'e0e8') : 'e325'};</i>
${inst.n ? inst.n : "Segment "+i}
<i class="icons edit-icon flr" id="seg${i}nedit" onclick="tglSegn(${i})">&#xe2c6;</i>
<div class="pop" onclick="event.preventDefault();event.stopPropagation();">
<i class="icons g-icon" style="color:${cG};" onclick="this.nextElementSibling.classList.toggle('hide');">&#x278${String.fromCharCode(inst.group+"A".charCodeAt(0))};</i>
<div class="pop-c hide"><span style="color:var(--c-b);" onclick="setGrp(${i},0);">&#x278A;</span><span style="color:var(--c-r);" onclick="setGrp(${i},1);">&#x278B;</span><span style="color:var(--c-g);" onclick="setGrp(${i},2);">&#x278C;</span><span style="color:var(--c-l);" onclick="setGrp(${i},3);">&#x278D;</span></div>
</div>
</div>
<i class="icons e-icon flr" id="sege${i}" onclick="expand(${i})">&#xe395;</i>
${cfg.comp.segpwr?segp:''}
@ -947,7 +958,7 @@ function genPalPrevCss(id)
function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', effectPar = '')
{
return `<div class="lstI${id==0?' sticky':''}" data-id="${id}" ${effectPar===''?'':'data-opt="'+effectPar+'"'}onClick="${clickAction}(${id})">
return `<div class="lstI${id==0?' sticky':''}" data-id="${id}" ${effectPar===''?'':'data-opt="'+effectPar+'" '}onClick="${clickAction}(${id})">
<label class="radio schkl" onclick="event.preventDefault()">
<input type="radio" value="${id}" name="${listName}">
<span class="radiomark"></span>
@ -1750,7 +1761,11 @@ function resetUtil(off=false)
{
gId('segutil').innerHTML = `<div class="seg btn btn-s ${off?'off':''}" style="border-radius:24px;padding:0;">`
+ '<label class="check schkl"><input type="checkbox" id="selall" onchange="selSegAll(this)"><span class="checkmark"></span></label>'
+ `<div class="segname" ${off?'':'onclick="makeSeg()"'}><i class="icons btn-icon">&#xe18a;</i>Add segment</div></div>`;
+ `<div class="segname" ${off?'':'onclick="makeSeg()"'}><i class="icons btn-icon">&#xe18a;</i>Add segment</div>`
+ '<div class="pop" onclick="event.stopPropagation();">'
+ `<i class="icons g-icon" style="color:var(--c-0);" onclick="this.nextElementSibling.classList.toggle('hide');">&#x238B;</i>`
+ '<div class="pop-c hide"><span style="color:var(--c-b);" onclick="selGrp(0);">&#x278A;</span><span style="color:var(--c-r);" onclick="selGrp(1);">&#x278B;</span><span style="color:var(--c-g);" onclick="selGrp(2);">&#x278C;</span><span style="color:var(--c-l);" onclick="selGrp(3);">&#x278D;</span></div>'
+ '</div></div>';
}
function makePlSel(el, incPl=false)
@ -2036,6 +2051,20 @@ function selSeg(s)
requestJson(obj);
}
function selGrp(g)
{
event.preventDefault();
event.stopPropagation();
var sel = gId(`segcont`).querySelectorAll(`div[data-group="${g}"]`);
var obj = {"seg":[]};
for (let i=0; i<=lSeg; i++) obj.seg.push({"id":i,"sel":false});
if (sel) for (let s of sel||[]) {
let i = parseInt(s.id.substring(3));
obj.seg[i] = {"id":i,"sel":true};
}
if (obj.seg.length) requestJson(obj);
}
function rptSeg(s)
{
//TODO: 2D support
@ -2156,6 +2185,14 @@ function setTp(s)
requestJson(obj);
}
function setGrp(s, g)
{
event.preventDefault();
event.stopPropagation();
var obj = {"seg": {"id": s, "group": g}};
requestJson(obj);
}
function setSegPwr(s)
{
var pwr = gId(`seg${s}pwr`).classList.contains('act');

File diff suppressed because it is too large Load Diff

View File

@ -92,8 +92,11 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
if ((spc>0 && spc!=seg.spacing) || seg.map1D2D!=map1D2D) seg.fill(BLACK); // clear spacing gaps
seg.map1D2D = constrain(map1D2D, 0, 7);
seg.soundSim = constrain(soundSim, 0, 7);
seg.map1D2D = constrain(map1D2D, 0, 3);
seg.soundSim = constrain(soundSim, 0, 3);
uint8_t group = elem[F("group")] | seg.group;
seg.group = constrain(group, 0, 3);
uint16_t len = 1;
if (stop > start) len = stop - start;
@ -459,6 +462,7 @@ void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, b
byte segbri = seg.opacity;
root["bri"] = (segbri) ? segbri : 255;
root["cct"] = seg.cct;
root[F("group")] = seg.group;
if (segmentBounds && seg.name != nullptr) root["n"] = reinterpret_cast<const char *>(seg.name); //not good practice, but decreases required JSON buffer