Support dynamic enabling and disabling of controls

See documentation in README for how this works. This commit
handles all the main controls. Pads are not yet supported.
This commit is contained in:
Ian Gray 2022-01-31 21:43:09 +00:00
parent 7dcf6a10f4
commit 896dc97c75
9 changed files with 159 additions and 9 deletions

View File

@ -37,6 +37,7 @@ The Library runs on any kind of **ESP8266** and **ESP32** (NodeMCU, AI Thinker,
- [Advanced Features](#advanced-features)
* [Dynamic Visibility](#dynamic-visibility)
* [Inline Styles](#inline-styles)
* [Disabling Controls](#disabling-controls)
* [Grouped controls](#grouped-controls)
* [Wide controls](#wide-controls)
* [Graph (Experimental)](#graph--experimental-)
@ -470,6 +471,36 @@ The [completeExample](examples/completeExample/completeExample.cpp) example incl
![More Inline Styles](docs/ui_inlinestyles2.png)
### Disabling Controls
It is possible to dynamically enable and disable controls to, for example, provide feedback to the user that a particular feature is
temporarily unavailable. To do this use the following function call:
```
ESPUI.setEnabled(controlId, enabled);
```
Setting `enabled` to false will make the control noninteractive and it will visually change to illustrate this to the user. The control
will stop firing any events. Note that whilst the widget will change appearance, the panel of the control will remain whatever colour
it was set to. If you wish to also change the colour of the panel then you should use inline styles to show the noninteractive state. For example:
```
ESPUI.setEnabled(mainButton, false);
const String disabledstyle = "background-color: #bbb; border-bottom: #999 3px solid;";
ESPUI.setPanelStyle(mainButton, disabledstyle);
```
This CSS style sets the panel background and its border to grey. To put the control back to enabled use the following:
```
ESPUI.setEnabled(mainButton, true);
ESPUI.setPanelStyle(mainButton, ";");
```
Note that we have to set the inline style to `";"` (i.e. an empty CSS rule) because if we just try to set it to `""` this will be
interpreted as "do not change the style".
Controls can also be set to disabled before the UI is started.
### Grouped controls

View File

@ -422,7 +422,7 @@ button {
background-color: #999999;
}
button:active {
button:enabled:active {
background-color: #666666;
transform: translateX(4px) translateY(4px);
}
@ -1148,3 +1148,46 @@ text {
.vert-slider span {
transform: rotate(90deg);
}
/* Styles to implement disabled controls */
button:disabled {
color: #333;
background-color: #999;
}
select:disabled {
color: #333;
background-color: #999;
}
input:disabled {
color: #333;
background-color: #999;
}
.range-slider__range:disabled {
background-color: #999;
}
.range-slider__range:disabled::-webkit-slider-thumb {
background-color: #aaa;
}
.range-slider__range:disabled::-moz-range-thumb {
background-color: #aaa;
}
.switch.disabled .in::before {
background:#bbb;
border: 1px solid #ddd;
}
.switch.disabled .in::after {
background:#bbb;
}
.switch.checked.disabled {
background: #b1d092;
}

File diff suppressed because one or more lines are too long

55
data/js/controls.js vendored
View File

@ -568,7 +568,13 @@ function start() {
break;
}
if (data.type >= UI_TITEL && data.type < UPDATE_OFFSET) {
//A UI element was just added to the DOM
processEnabled(data);
}
if (data.type >= UPDATE_OFFSET && data.type < UI_INITIAL_GUI) {
//An "update" message was just recieved and processed
var element = $("#id" + data.id);
if(data.hasOwnProperty('panelStyle')) {
@ -593,6 +599,8 @@ function start() {
);
element.addClass(colorClass(data.color));
}
processEnabled(data);
}
$(".range-slider__range").each(function(){
@ -816,4 +824,49 @@ var elementHTML = function(data) {
default:
return "";
}
}
}
var processEnabled = function(data) {
//Handle the enabling and disabling of controls
//Most controls can be disabled through the use of $("#<item>").prop("disabled", true) and CSS will style it accordingly
//The switcher also requires the addition of the "disabled" class
switch(data.type) {
case UI_SWITCHER:
case UPDATE_SWITCHER:
if(data.enabled) {
$("#sl" + data.id).removeClass('disabled');
$("#s" + data.id).prop("disabled", false);
} else {
$("#sl" + data.id).addClass('disabled');
$("#s" + data.id).prop("disabled", true);
}
break;
case UI_SLIDER:
case UPDATE_SLIDER:
$("#sl" + data.id).prop("disabled", !data.enabled);
break;
case UI_NUMBER:
case UPDATE_NUMBER:
$("#num" + data.id).prop("disabled", !data.enabled);
break;
case UI_TEXT_INPUT:
case UPDATE_TEXT_INPUT:
$("#text" + data.id).prop("disabled", !data.enabled);
break;
case UI_SELECT:
case UPDATE_SELECT:
$("#select" + data.id).prop("disabled", !data.enabled);
break;
case UI_BUTTON:
case UPDATE_BUTTON:
$("#btn" + data.id).prop("disabled", !data.enabled);
break;
}
}

View File

@ -40,11 +40,13 @@ break;case UPDATE_SELECT:$("#select"+data.id).val(data.value);if(data.hasOwnProp
break;case UPDATE_BUTTON:$("#btn"+data.id).val(data.value);$("#btn"+data.id).text(data.value);if(data.hasOwnProperty('elementStyle')){$("#btn"+data.id).attr("style",data.elementStyle);}
break;case UPDATE_PAD:case UPDATE_CPAD:break;case UPDATE_GAUGE:$("#gauge"+data.id).val(data.value);if(data.hasOwnProperty('elementStyle')){$("#gauge"+data.id).attr("style",data.elementStyle);}
break;case UPDATE_ACCEL:break;case UPDATE_TIME:var rv=new Date().toISOString();websock.send("time:"+rv+":"+data.id);break;default:console.error("Unknown type or event");break;}
if(data.type>=UI_TITEL&&data.type<UPDATE_OFFSET){processEnabled(data);}
if(data.type>=UPDATE_OFFSET&&data.type<UI_INITIAL_GUI){var element=$("#id"+data.id);if(data.hasOwnProperty('panelStyle')){$("#id"+data.id).attr("style",data.panelStyle);}
if(data.hasOwnProperty('visible')){if(data['visible'])
$("#id"+data.id).show();else
$("#id"+data.id).hide();}
if(data.type==UPDATE_SLIDER){element.removeClass("slider-turquoise slider-emerald slider-peterriver slider-wetasphalt slider-sunflower slider-carrot slider-alizarin");element.addClass("slider-"+colorClass(data.color));}else{element.removeClass("turquoise emerald peterriver wetasphalt sunflower carrot alizarin");element.addClass(colorClass(data.color));}}
if(data.type==UPDATE_SLIDER){element.removeClass("slider-turquoise slider-emerald slider-peterriver slider-wetasphalt slider-sunflower slider-carrot slider-alizarin");element.addClass("slider-"+colorClass(data.color));}else{element.removeClass("turquoise emerald peterriver wetasphalt sunflower carrot alizarin");element.addClass(colorClass(data.color));}
processEnabled(data);}
$(".range-slider__range").each(function(){$(this)[0].value=$(this).attr("value");$(this).next().html($(this).attr("value"));});};websock.onmessage=handleEvent;}
function sliderchange(number){var val=$("#sl"+number).val();websock.send("slvalue:"+val+":"+number);$(".range-slider__range").each(function(){$(this).attr("value",$(this)[0].value);});}
function numberchange(number){var val=$("#num"+number).val();websock.send("nvalue:"+val+":"+number);}
@ -94,4 +96,6 @@ data.value+"</span></div>";case UI_NUMBER:return"<input style='color:black;' "+e
"' value='"+data.value+"' onchange='textchange("+id+")' />";case UI_SELECT:return"<select style='color:black;' "+elementStyle+" id='select"+id+
"' onchange='selectchange("+id+")' />";case UI_GRAPH:return"<figure id='graph"+id+"'><figcaption>"+data.label+"</figcaption></figure>";case UI_GAUGE:return"WILL BE A GAUGE <input style='color:black;' id='gauge"+id+
"' type='number' value='"+data.value+"' onchange='numberchange("+id+")' />";case UI_ACCEL:return"ACCEL // Not implemented fully!<div class='accelerometer' id='accel"+id+
"' ><div class='ball"+id+"'></div><pre class='accelerometeroutput"+id+"'></pre>";default:return"";}}
"' ><div class='ball"+id+"'></div><pre class='accelerometeroutput"+id+"'></pre>";default:return"";}}
var processEnabled=function(data){switch(data.type){case UI_SWITCHER:case UPDATE_SWITCHER:if(data.enabled){$("#sl"+data.id).removeClass('disabled');$("#s"+data.id).prop("disabled",false);}else{$("#sl"+data.id).addClass('disabled');$("#s"+data.id).prop("disabled",true);}
break;case UI_SLIDER:case UPDATE_SLIDER:$("#sl"+data.id).prop("disabled",!data.enabled);break;case UI_NUMBER:case UPDATE_NUMBER:$("#num"+data.id).prop("disabled",!data.enabled);break;case UI_TEXT_INPUT:case UPDATE_TEXT_INPUT:$("#text"+data.id).prop("disabled",!data.enabled);break;case UI_SELECT:case UPDATE_SELECT:$("#select"+data.id).prop("disabled",!data.enabled);break;case UI_BUTTON:case UPDATE_BUTTON:$("#btn"+data.id).prop("disabled",!data.enabled);break;}}

View File

@ -783,6 +783,7 @@ void ESPUIClass::updateControl(Control* control, int clientId)
root["id"] = control->id;
root["visible"] = control->visible;
root["color"] = (int)control->color;
root["enabled"] = control->enabled;
if (control->panelStyle != 0)
root["panelStyle"] = control->panelStyle;
if (control->elementStyle != 0)
@ -855,6 +856,16 @@ void ESPUIClass::setPanelWide(uint16_t id, bool wide) {
}
}
void ESPUIClass::setEnabled(uint16_t id, bool enabled, int clientId) {
Control* control = getControl(id);
if (control)
{
control->enabled = enabled;
updateControl(control, clientId);
}
}
void ESPUIClass::setVertical(uint16_t id, bool vert) {
Control* control = getControl(id);
if (control)
@ -1108,6 +1119,7 @@ void ESPUIClass::prepareJSONChunk(AsyncWebSocketClient* client, uint16_t startin
item["value"] = String(control->value);
item["color"] = (int)control->color;
item["visible"] = (int)control->visible;
item["enabled"] = control->enabled;
if (control->panelStyle != 0)
item["panelStyle"] = String(control->panelStyle);
if (control->elementStyle != 0)

View File

@ -142,6 +142,7 @@ public:
bool visible;
bool wide;
bool vertical;
bool enabled;
uint16_t parentControl;
String panelStyle;
String elementStyle;
@ -301,6 +302,8 @@ public:
void setPanelWide(uint16_t id, bool wide);
void setVertical(uint16_t id, bool vert = true);
void setEnabled(uint16_t id, bool enabled = true, int clientId = -1);
void updateVisibility(uint16_t id, bool visibility, int clientId = -1);
// Variables

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long