mirror of
https://github.com/s00500/ESPUI.git
synced 2024-11-21 17:40:54 +00:00
Merge pull request #154 from iangray001/enabledisable
Support for Enabling and Disabling controls
This commit is contained in:
commit
e3e5c34953
31
README.md
31
README.md
@ -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
|
||||
|
||||
|
@ -422,7 +422,7 @@ button {
|
||||
background-color: #999999;
|
||||
}
|
||||
|
||||
button:active {
|
||||
button:enabled:active {
|
||||
background-color: #666666;
|
||||
transform: translateX(4px) translateY(4px);
|
||||
}
|
||||
@ -587,6 +587,13 @@ hr {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.control:not(.disabled) a.confirm:active {
|
||||
background-color:#777
|
||||
}
|
||||
.control:not(.disabled) li:active {
|
||||
background-color:#777
|
||||
}
|
||||
|
||||
/* Switch
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
|
||||
@ -1148,3 +1155,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;
|
||||
}
|
||||
|
2
data/css/style.min.css
vendored
2
data/css/style.min.css
vendored
File diff suppressed because one or more lines are too long
137
data/js/controls.js
vendored
137
data/js/controls.js
vendored
@ -433,24 +433,27 @@ function start() {
|
||||
|
||||
case UI_MIN:
|
||||
if (data.parentControl) {
|
||||
var parent = $("#id" + data.parentControl + " input");
|
||||
if (parent.size()) {
|
||||
parent.attr("min", data.value);
|
||||
//Is it applied to a slider?
|
||||
if($('#sl' + data.parentControl).length) {
|
||||
$('#sl' + data.parentControl).attr("min", data.value);
|
||||
} else if($('#num' + data.parentControl).length) {
|
||||
//Or a number
|
||||
$('#num' + data.parentControl).attr("min", data.value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case UI_MAX:
|
||||
if (data.parentControl) {
|
||||
var parent = $("#id" + data.parentControl + " input");
|
||||
if (parent.size()) {
|
||||
if(!parent.attr("type")) {
|
||||
//type is not set so therefore it is a text input
|
||||
parent.attr("maxlength", data.value);
|
||||
} else {
|
||||
//type might be range (slider) or number
|
||||
parent.attr("max", data.value);
|
||||
}
|
||||
//Is it applied to a slider?
|
||||
if($('#sl' + data.parentControl).length) {
|
||||
$('#sl' + data.parentControl).attr("max", data.value);
|
||||
} else if($('#text' + data.parentControl).length) {
|
||||
//Is it a text element
|
||||
$('#text' + data.parentControl).attr("maxlength", data.value);
|
||||
} else if($('#num' + data.parentControl).length) {
|
||||
//Or a number
|
||||
$('#num' + data.parentControl).attr("max", data.value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -568,7 +571,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 +602,8 @@ function start() {
|
||||
);
|
||||
element.addClass(colorClass(data.color));
|
||||
}
|
||||
|
||||
processEnabled(data);
|
||||
}
|
||||
|
||||
$(".range-slider__range").each(function(){
|
||||
@ -639,27 +650,29 @@ function buttonclick(number, isdown) {
|
||||
}
|
||||
|
||||
function padclick(type, number, isdown) {
|
||||
switch (type) {
|
||||
case CENTER:
|
||||
if (isdown) websock.send("pcdown:" + number);
|
||||
else websock.send("pcup:" + number);
|
||||
break;
|
||||
case UP:
|
||||
if (isdown) websock.send("pfdown:" + number);
|
||||
else websock.send("pfup:" + number);
|
||||
break;
|
||||
case DOWN:
|
||||
if (isdown) websock.send("pbdown:" + number);
|
||||
else websock.send("pbup:" + number);
|
||||
break;
|
||||
case LEFT:
|
||||
if (isdown) websock.send("pldown:" + number);
|
||||
else websock.send("plup:" + number);
|
||||
break;
|
||||
case RIGHT:
|
||||
if (isdown) websock.send("prdown:" + number);
|
||||
else websock.send("prup:" + number);
|
||||
break;
|
||||
if(!$("#id" + number + " nav").hasClass("disabled")) {
|
||||
switch (type) {
|
||||
case CENTER:
|
||||
if (isdown) websock.send("pcdown:" + number);
|
||||
else websock.send("pcup:" + number);
|
||||
break;
|
||||
case UP:
|
||||
if (isdown) websock.send("pfdown:" + number);
|
||||
else websock.send("pfup:" + number);
|
||||
break;
|
||||
case DOWN:
|
||||
if (isdown) websock.send("pbdown:" + number);
|
||||
else websock.send("pbup:" + number);
|
||||
break;
|
||||
case LEFT:
|
||||
if (isdown) websock.send("pldown:" + number);
|
||||
else websock.send("plup:" + number);
|
||||
break;
|
||||
case RIGHT:
|
||||
if (isdown) websock.send("prdown:" + number);
|
||||
else websock.send("prup:" + number);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -816,4 +829,60 @@ 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 and pads also require 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;
|
||||
|
||||
case UI_PAD:
|
||||
case UI_CPAD:
|
||||
case UPDATE_PAD:
|
||||
case UPDATE_CPAD:
|
||||
if(data.enabled) {
|
||||
$("#id" + data.id + " nav").removeClass('disabled');
|
||||
} else {
|
||||
$("#id" + data.id + " nav").addClass('disabled');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
15
data/js/controls.min.js
vendored
15
data/js/controls.min.js
vendored
@ -25,8 +25,8 @@ data.selected+
|
||||
">"+
|
||||
data.label+
|
||||
"</option>");}
|
||||
break;case UI_MIN:if(data.parentControl){var parent=$("#id"+data.parentControl+" input");if(parent.size()){parent.attr("min",data.value);}}
|
||||
break;case UI_MAX:if(data.parentControl){var parent=$("#id"+data.parentControl+" input");if(parent.size()){if(!parent.attr("type")){parent.attr("maxlength",data.value);}else{parent.attr("max",data.value);}}}
|
||||
break;case UI_MIN:if(data.parentControl){if($('#sl'+data.parentControl).length){$('#sl'+data.parentControl).attr("min",data.value);}else if($('#num'+data.parentControl).length){$('#num'+data.parentControl).attr("min",data.value);}}
|
||||
break;case UI_MAX:if(data.parentControl){if($('#sl'+data.parentControl).length){$('#sl'+data.parentControl).attr("max",data.value);}else if($('#text'+data.parentControl).length){$('#text'+data.parentControl).attr("maxlength",data.value);}else if($('#num'+data.parentControl).length){$('#num'+data.parentControl).attr("max",data.value);}}
|
||||
break;case UI_STEP:if(data.parentControl){var parent=$("#id"+data.parentControl+" input");if(parent.size()){parent.attr("step",data.value);}}
|
||||
break;case UI_GRAPH:if(data.visible){addToHTML(data);graphData[data.id]=restoreGraphData(data.id);renderGraphSvg(graphData[data.id],"graph"+data.id);}
|
||||
break;case ADD_GRAPH_POINT:var ts=Math.round(new Date().getTime()/1000);graphData[data.id].push({x:ts,y:data.value});saveGraphData();renderGraphSvg(graphData[data.id],"graph"+data.id);break;case CLEAR_GRAPH:graphData[data.id]=[];saveGraphData();renderGraphSvg(graphData[data.id],"graph"+data.id);break;case UI_ACCEL:if(hasAccel)break;hasAccel=true;if(data.visible){addToHTML(data);requestOrientationPermission();}
|
||||
@ -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);}
|
||||
@ -52,7 +54,7 @@ function textchange(number){var val=$("#text"+number).val();websock.send("tvalue
|
||||
function tabclick(number){var val=$("#tab"+number).val();websock.send("tabvalue:"+val+":"+number);}
|
||||
function selectchange(number){var val=$("#select"+number).val();websock.send("svalue:"+val+":"+number);}
|
||||
function buttonclick(number,isdown){if(isdown)websock.send("bdown:"+number);else websock.send("bup:"+number);}
|
||||
function padclick(type,number,isdown){switch(type){case CENTER:if(isdown)websock.send("pcdown:"+number);else websock.send("pcup:"+number);break;case UP:if(isdown)websock.send("pfdown:"+number);else websock.send("pfup:"+number);break;case DOWN:if(isdown)websock.send("pbdown:"+number);else websock.send("pbup:"+number);break;case LEFT:if(isdown)websock.send("pldown:"+number);else websock.send("plup:"+number);break;case RIGHT:if(isdown)websock.send("prdown:"+number);else websock.send("prup:"+number);break;}}
|
||||
function padclick(type,number,isdown){if(!$("#id"+number+" nav").hasClass("disabled")){switch(type){case CENTER:if(isdown)websock.send("pcdown:"+number);else websock.send("pcup:"+number);break;case UP:if(isdown)websock.send("pfdown:"+number);else websock.send("pfup:"+number);break;case DOWN:if(isdown)websock.send("pbdown:"+number);else websock.send("pbup:"+number);break;case LEFT:if(isdown)websock.send("pldown:"+number);else websock.send("plup:"+number);break;case RIGHT:if(isdown)websock.send("prdown:"+number);else websock.send("prup:"+number);break;}}}
|
||||
function switcher(number,state){if(state==null){if(!$("#sl"+number).hasClass("checked")){websock.send("sactive:"+number);$("#sl"+number).addClass("checked");}else{websock.send("sinactive:"+number);$("#sl"+number).removeClass("checked");}}else if(state==1){$("#sl"+number).addClass("checked");$("#sl"+number).prop("checked",true);}else if(state==0){$("#sl"+number).removeClass("checked");$("#sl"+number).prop("checked",false);}}
|
||||
var rangeSlider=function(isDiscrete){var range=$(".range-slider__range");var slidercb=function(){sliderchange($(this).attr("id").replace(/^\D+/g,""));};range.on({input:function(){$(this).next().html(this.value)}});range.each(function(){$(this).next().html(this.value);if($(this).attr("callbackSet")!="true"){if(!isDiscrete){$(this).on({input:slidercb});}else{$(this).on({change:slidercb});}
|
||||
$(this).attr("callbackSet","true");}});};var addToHTML=function(data){panelStyle=data.hasOwnProperty('panelStyle')?" style='"+data.panelStyle+"' ":"";panelwide=data.hasOwnProperty('wide')?"wide":"";if(!data.hasOwnProperty('parentControl')||$("#tab"+data.parentControl).length>0){var parent=data.hasOwnProperty('parentControl')?$("#tab"+data.parentControl):$("#row");var html="";switch(data.type){case UI_LABEL:case UI_BUTTON:case UI_SWITCHER:case UI_CPAD:case UI_PAD:case UI_SLIDER:case UI_NUMBER:case UI_TEXT_INPUT:case UI_SELECT:case UI_GRAPH:case UI_GAUGE:case UI_ACCEL:html="<div id='id"+data.id+"' "+panelStyle+" class='two columns "+panelwide+" card tcenter "+
|
||||
@ -94,4 +96,7 @@ 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;case UI_PAD:case UI_CPAD:case UPDATE_PAD:case UPDATE_CPAD:if(data.enabled){$("#id"+data.id+" nav").removeClass('disabled');}else{$("#id"+data.id+" nav").addClass('disabled');}
|
||||
break;}}
|
@ -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.length())
|
||||
root["panelStyle"] = control->panelStyle;
|
||||
if (control->elementStyle.length())
|
||||
@ -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.length())
|
||||
item["panelStyle"] = String(control->panelStyle);
|
||||
if (control->elementStyle.length())
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user