mirror of
https://github.com/s00500/ESPUI.git
synced 2024-11-24 17:30:55 +00:00
introduce lambda
This commit is contained in:
parent
c7a9438149
commit
0b22328bd8
24
README.md
24
README.md
@ -153,7 +153,9 @@ This section will explain in detail how the Library is to be used from the Ardui
|
|||||||
<br><br>
|
<br><br>
|
||||||
Alternativly you may use the extended callback funtion which provides three parameters to the callback function `myCallback(Control *sender, int eventname, void * UserParameter)`. The `UserParameter` is provided as part of the `ESPUI.addControl` method set and allows the user to define contextual information that is to be presented to the callback function in an unmodified form.
|
Alternativly you may use the extended callback funtion which provides three parameters to the callback function `myCallback(Control *sender, int eventname, void * UserParameter)`. The `UserParameter` is provided as part of the `ESPUI.addControl` method set and allows the user to define contextual information that is to be presented to the callback function in an unmodified form.
|
||||||
<br><br>
|
<br><br>
|
||||||
The below example creates a button and defines a lambda function to implicitly create an `ExtendedCallback` which then invokes a more specialized button callback handler. The example uses the `UserParameter` to hold the `this` pointer to an object instance, providing a mechanism for sending the event to a specific object without the need for a switch / map / lookup translation of the Sender Id to an object reference.
|
It also possible to use a lambda function in the callback parameter. It also allows the user to define, in a more C++ way, contextual information in any form. This is shown by the [completeLambda](examples/completeLambda/completeLambda.ino) example.
|
||||||
|
<br><br>
|
||||||
|
The below example creates a button and defines a lambda function to invoke a more specialized button callback handler:
|
||||||
```
|
```
|
||||||
void YourClassName::setup()
|
void YourClassName::setup()
|
||||||
{
|
{
|
||||||
@ -163,26 +165,18 @@ void YourClassName::setup()
|
|||||||
" Button Face Text ",
|
" Button Face Text ",
|
||||||
ControlColor::None,
|
ControlColor::None,
|
||||||
ParentElementId,
|
ParentElementId,
|
||||||
[](Control *sender, int eventname, void* param)
|
[&](Control *sender, int eventname)
|
||||||
{
|
{
|
||||||
if(param)
|
myButtonCallback(sender, eventname); // class method
|
||||||
{
|
});
|
||||||
reinterpret_cast<YourClassName*>(param)->myButtonCallback(sender, eventname);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
this); // <-Third parameter for the extended callback
|
|
||||||
|
|
||||||
// or
|
// or
|
||||||
ButtonElementId = ESPUI.button(
|
ButtonElementId = ESPUI.button(
|
||||||
" Button Face Text ",
|
" Button Face Text ",
|
||||||
[](Control *sender, int eventname, void* param)
|
[&](Control *sender, int eventname)
|
||||||
{
|
{
|
||||||
if(param)
|
myButtonCallback(sender, eventname); // class method
|
||||||
{
|
});
|
||||||
reinterpret_cast<YourClassName*>(param)->myButtonCallback(sender, eventname);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
this); // <-Third parameter for the extended callback
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
```
|
```
|
||||||
|
544
examples/completeLambda/completeLambda.ino
Normal file
544
examples/completeLambda/completeLambda.ino
Normal file
@ -0,0 +1,544 @@
|
|||||||
|
/**
|
||||||
|
* @file completeExample.cpp
|
||||||
|
* @author Ian Gray @iangray1000
|
||||||
|
*
|
||||||
|
* This is an example GUI to show off all of the features of ESPUI.
|
||||||
|
* This can be built using the Arduino IDE, or PlatformIO.
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* If you just want to see examples of the ESPUI code, jump down to the setUpUI() function
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* When this program boots, it will load an SSID and password from the EEPROM.
|
||||||
|
* The SSID is a null-terminated C string stored at EEPROM addresses 0-31
|
||||||
|
* The password is a null-terminated C string stored at EEPROM addresses 32-95.
|
||||||
|
* If these credentials do not work for some reason, the ESP will create an Access
|
||||||
|
* Point wifi with the SSID HOSTNAME (defined below). You can then connect and use
|
||||||
|
* the controls on the "Wifi Credentials" tab to store credentials into the EEPROM.
|
||||||
|
*
|
||||||
|
* Version with lambdas. Comparing to version with only callbacks:
|
||||||
|
* diff -u ../completeExample/completeExample.cpp completeLambda.ino|less
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <EEPROM.h>
|
||||||
|
#include <ESPUI.h>
|
||||||
|
|
||||||
|
#if defined(ESP32)
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <ESPmDNS.h>
|
||||||
|
#else
|
||||||
|
// esp8266
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
#include <umm_malloc/umm_heap_select.h>
|
||||||
|
#ifndef CORE_MOCK
|
||||||
|
#ifndef MMU_IRAM_HEAP
|
||||||
|
#warning Try MMU option '2nd heap shared' in 'tools' IDE menu (cf. https://arduino-esp8266.readthedocs.io/en/latest/mmu.html#option-summary)
|
||||||
|
#warning use decorators: { HeapSelectIram doAllocationsInIRAM; ESPUI.addControl(...) ... } (cf. https://arduino-esp8266.readthedocs.io/en/latest/mmu.html#how-to-select-heap)
|
||||||
|
#warning then check http://<ip>/heap
|
||||||
|
#endif // MMU_IRAM_HEAP
|
||||||
|
#ifndef DEBUG_ESP_OOM
|
||||||
|
#error on ESP8266 and ESPUI, you must define OOM debug option when developping
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Settings
|
||||||
|
#define SLOW_BOOT 0
|
||||||
|
#define HOSTNAME "ESPUITest"
|
||||||
|
#define FORCE_USE_HOTSPOT 0
|
||||||
|
|
||||||
|
|
||||||
|
//Function Prototypes
|
||||||
|
void connectWifi();
|
||||||
|
void setUpUI();
|
||||||
|
void textCallback(Control *sender, int type);
|
||||||
|
void generalCallback(Control *sender, int type);
|
||||||
|
void randomString(char *buf, int len);
|
||||||
|
void paramCallback(Control* sender, int type, int param);
|
||||||
|
|
||||||
|
//UI handles
|
||||||
|
uint16_t wifi_ssid_text, wifi_pass_text;
|
||||||
|
uint16_t mainLabel, mainSwitcher, mainSlider, mainText, mainNumber, mainScrambleButton, mainTime;
|
||||||
|
uint16_t styleButton, styleLabel, styleSwitcher, styleSlider, styleButton2, styleLabel2, styleSlider2;
|
||||||
|
uint16_t graph;
|
||||||
|
volatile bool updates = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// This is the main function which builds our GUI
|
||||||
|
void setUpUI() {
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
{ HeapSelectIram doAllocationsInIRAM;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Turn off verbose debugging
|
||||||
|
ESPUI.setVerbosity(Verbosity::Quiet);
|
||||||
|
|
||||||
|
//Make sliders continually report their position as they are being dragged.
|
||||||
|
ESPUI.sliderContinuous = true;
|
||||||
|
|
||||||
|
//This GUI is going to be a tabbed GUI, so we are adding most controls using ESPUI.addControl
|
||||||
|
//which allows us to set a parent control. If we didn't need tabs we could use the simpler add
|
||||||
|
//functions like:
|
||||||
|
// ESPUI.button()
|
||||||
|
// ESPUI.label()
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tab: Basic Controls
|
||||||
|
* This tab contains all the basic ESPUI controls, and shows how to read and update them at runtime.
|
||||||
|
*-----------------------------------------------------------------------------------------------------------*/
|
||||||
|
auto maintab = ESPUI.addControl(Tab, "", "Basic controls");
|
||||||
|
|
||||||
|
ESPUI.addControl(Separator, "General controls", "", None, maintab);
|
||||||
|
ESPUI.addControl(Button, "Button", "Button 1", Alizarin, maintab, [](Control *sender, int type){ paramCallback(sender, type, 19); });
|
||||||
|
mainLabel = ESPUI.addControl(Label, "Label", "Label text", Emerald, maintab, generalCallback);
|
||||||
|
mainSwitcher = ESPUI.addControl(Switcher, "Switcher", "", Sunflower, maintab, generalCallback);
|
||||||
|
|
||||||
|
//Sliders default to being 0 to 100, but if you want different limits you can add a Min and Max control
|
||||||
|
mainSlider = ESPUI.addControl(Slider, "Slider", "200", Turquoise, maintab, generalCallback);
|
||||||
|
ESPUI.addControl(Min, "", "10", None, mainSlider);
|
||||||
|
ESPUI.addControl(Max, "", "400", None, mainSlider);
|
||||||
|
|
||||||
|
//These are the values for the selector's options. (Note that they *must* be declared static
|
||||||
|
//so that the storage is allocated in global memory and not just on the stack of this function.)
|
||||||
|
static String optionValues[] {"Value 1", "Value 2", "Value 3", "Value 4", "Value 5"};
|
||||||
|
auto mainselector = ESPUI.addControl(Select, "Selector", "Selector", Wetasphalt, maintab, generalCallback);
|
||||||
|
for(auto const& v : optionValues) {
|
||||||
|
ESPUI.addControl(Option, v.c_str(), v, None, mainselector);
|
||||||
|
}
|
||||||
|
|
||||||
|
mainText = ESPUI.addControl(Text, "Text Input", "Initial value", Alizarin, maintab, generalCallback);
|
||||||
|
|
||||||
|
//Number inputs also accept Min and Max components, but you should still validate the values.
|
||||||
|
mainNumber = ESPUI.addControl(Number, "Number Input", "42", Emerald, maintab, generalCallback);
|
||||||
|
ESPUI.addControl(Min, "", "10", None, mainNumber);
|
||||||
|
ESPUI.addControl(Max, "", "50", None, mainNumber);
|
||||||
|
|
||||||
|
ESPUI.addControl(Separator, "Updates", "", None, maintab);
|
||||||
|
|
||||||
|
//This button will update all the updatable controls on this tab to random values
|
||||||
|
mainScrambleButton = ESPUI.addControl(Button, "Scramble Values", "Scramble Values", Carrot, maintab,
|
||||||
|
//This callback updates the "values" of a bunch of controls
|
||||||
|
[](Control *sender, int type) {
|
||||||
|
static char rndString1[10];
|
||||||
|
static char rndString2[20];
|
||||||
|
static bool scText = false;
|
||||||
|
|
||||||
|
if(type == B_UP) { //Button callbacks generate events for both UP and DOWN.
|
||||||
|
//Generate some random text
|
||||||
|
randomString(rndString1, 10);
|
||||||
|
randomString(rndString2, 20);
|
||||||
|
|
||||||
|
//Set the various controls to random value to show how controls can be updated at runtime
|
||||||
|
ESPUI.updateLabel(mainLabel, String(rndString1));
|
||||||
|
ESPUI.updateSwitcher(mainSwitcher, ESPUI.getControl(mainSwitcher)->value.toInt() ? false : true);
|
||||||
|
ESPUI.updateSlider(mainSlider, random(10, 400));
|
||||||
|
ESPUI.updateText(mainText, String(rndString2));
|
||||||
|
ESPUI.updateNumber(mainNumber, random(100000));
|
||||||
|
ESPUI.updateButton(mainScrambleButton, scText ? "Scrambled!" : "Scrambled.");
|
||||||
|
scText = !scText;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ESPUI.addControl(Switcher, "Constant updates", "0", Carrot, maintab,
|
||||||
|
[](Control *sender, int type) {
|
||||||
|
updates = (sender->value.toInt() > 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
mainTime = ESPUI.addControl(Time, "", "", None, 0, generalCallback);
|
||||||
|
|
||||||
|
ESPUI.addControl(Button, "Get Time", "Get Time", Carrot, maintab,
|
||||||
|
[](Control *sender, int type) {
|
||||||
|
if(type == B_UP) {
|
||||||
|
ESPUI.updateTime(mainTime);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ESPUI.addControl(Separator, "Control Pads", "", None, maintab);
|
||||||
|
ESPUI.addControl(Pad, "Normal", "", Peterriver, maintab, generalCallback);
|
||||||
|
ESPUI.addControl(PadWithCenter, "With center", "", Peterriver, maintab, generalCallback);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tab: Colours
|
||||||
|
* This tab shows all the basic colours
|
||||||
|
*-----------------------------------------------------------------------------------------------------------*/
|
||||||
|
auto colourtab = ESPUI.addControl(Tab, "", "Colours");
|
||||||
|
ESPUI.addControl(Button, "Alizarin", "Alizarin", Alizarin, colourtab, generalCallback);
|
||||||
|
ESPUI.addControl(Button, "Turquoise", "Turquoise", Turquoise, colourtab, generalCallback);
|
||||||
|
ESPUI.addControl(Button, "Emerald", "Emerald", Emerald, colourtab, generalCallback);
|
||||||
|
ESPUI.addControl(Button, "Peterriver", "Peterriver", Peterriver, colourtab, generalCallback);
|
||||||
|
ESPUI.addControl(Button, "Wetasphalt", "Wetasphalt", Wetasphalt, colourtab, generalCallback);
|
||||||
|
ESPUI.addControl(Button, "Sunflower", "Sunflower", Sunflower, colourtab, generalCallback);
|
||||||
|
ESPUI.addControl(Button, "Carrot", "Carrot", Carrot, colourtab, generalCallback);
|
||||||
|
ESPUI.addControl(Button, "Dark", "Dark", Dark, colourtab, generalCallback);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tab: Styled controls
|
||||||
|
* This tab shows off how inline CSS styles can be applied to elements and panels in order
|
||||||
|
* to customise the look of the UI.
|
||||||
|
*-----------------------------------------------------------------------------------------------------------*/
|
||||||
|
auto styletab = ESPUI.addControl(Tab, "", "Styled controls");
|
||||||
|
styleButton = ESPUI.addControl(Button, "Styled Button", "Button", Alizarin, styletab, generalCallback);
|
||||||
|
styleLabel = ESPUI.addControl(Label, "Styled Label", "This is a label", Alizarin, styletab, generalCallback);
|
||||||
|
styleSwitcher = ESPUI.addControl(Switcher, "Styled Switcher", "1", Alizarin, styletab, generalCallback);
|
||||||
|
styleSlider = ESPUI.addControl(Slider, "Styled Slider", "0", Alizarin, styletab, generalCallback);
|
||||||
|
|
||||||
|
//This button will randomise the colours of the above controls to show updating of inline styles
|
||||||
|
ESPUI.addControl(Button, "Randomise Colours", "Randomise Colours", Sunflower, styletab,
|
||||||
|
//This callback generates and applies inline styles to a bunch of controls to change their colour.
|
||||||
|
//The styles created are of the form:
|
||||||
|
// "border-bottom: #999 3px solid; background-color: #aabbcc;"
|
||||||
|
// "background-color: #aabbcc;"
|
||||||
|
[](Control *sender, int type) {
|
||||||
|
//Declare space for style strings. These have to be static so that they are always available
|
||||||
|
//to the websocket layer. If we'd not made them static they'd be allocated on the heap and
|
||||||
|
//will be unavailable when we leave this function.
|
||||||
|
static char stylecol1[60], stylecol2[30];
|
||||||
|
if(type == B_UP) {
|
||||||
|
//Generate two random HTML hex colour codes, and print them into CSS style rules
|
||||||
|
sprintf(stylecol1, "border-bottom: #999 3px solid; background-color: #%06X;", (unsigned int) random(0x0, 0xFFFFFF));
|
||||||
|
sprintf(stylecol2, "background-color: #%06X;", (unsigned int) random(0x0, 0xFFFFFF));
|
||||||
|
|
||||||
|
//Apply those styles to various elements to show how controls react to styling
|
||||||
|
ESPUI.setPanelStyle(styleButton, stylecol1);
|
||||||
|
ESPUI.setElementStyle(styleButton, stylecol2);
|
||||||
|
ESPUI.setPanelStyle(styleLabel, stylecol1);
|
||||||
|
ESPUI.setElementStyle(styleLabel, stylecol2);
|
||||||
|
ESPUI.setPanelStyle(styleSwitcher, stylecol1);
|
||||||
|
ESPUI.setElementStyle(styleSwitcher, stylecol2);
|
||||||
|
ESPUI.setPanelStyle(styleSlider, stylecol1);
|
||||||
|
ESPUI.setElementStyle(styleSlider, stylecol2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ESPUI.addControl(Separator, "Other styling examples", "", None, styletab);
|
||||||
|
styleButton2 = ESPUI.addControl(Button, "Styled Button", "Button", Alizarin, styletab, generalCallback);
|
||||||
|
ESPUI.setPanelStyle(styleButton2, "background: linear-gradient(90deg, rgba(131,58,180,1) 0%, rgba(253,29,29,1) 50%, rgba(252,176,69,1) 100%); border-bottom: #555;");
|
||||||
|
ESPUI.setElementStyle(styleButton2, "border-radius: 2em; border: 3px solid black; width: 30%; background-color: #8df;");
|
||||||
|
|
||||||
|
styleSlider2 = ESPUI.addControl(Slider, "Styled Slider", "0", Dark, styletab, generalCallback);
|
||||||
|
ESPUI.setElementStyle(styleSlider2, "background: linear-gradient(to right, red, orange, yellow, green, blue);");
|
||||||
|
|
||||||
|
styleLabel2 = ESPUI.addControl(Label, "Styled Label", "This is a label", Dark, styletab, generalCallback);
|
||||||
|
ESPUI.setElementStyle(styleLabel2, "text-shadow: 3px 3px #74b1ff, 6px 6px #c64ad7; font-size: 60px; font-variant-caps: small-caps; background-color: unset; color: #c4f0bb; -webkit-text-stroke: 1px black;");
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tab: Grouped controls
|
||||||
|
* This tab shows how multiple control can be grouped into the same panel through the use of the
|
||||||
|
* parentControl value. This also shows how to add labels to grouped controls, and how to use vertical controls.
|
||||||
|
*-----------------------------------------------------------------------------------------------------------*/
|
||||||
|
auto grouptab = ESPUI.addControl(Tab, "", "Grouped controls");
|
||||||
|
|
||||||
|
//The parent of this button is a tab, so it will create a new panel with one control.
|
||||||
|
auto groupbutton = ESPUI.addControl(Button, "Button Group", "Button A", Dark, grouptab, generalCallback);
|
||||||
|
//However the parent of this button is another control, so therefore no new panel is
|
||||||
|
//created and the button is added to the existing panel.
|
||||||
|
ESPUI.addControl(Button, "", "Button B", Alizarin, groupbutton, generalCallback);
|
||||||
|
ESPUI.addControl(Button, "", "Button C", Alizarin, groupbutton, generalCallback);
|
||||||
|
|
||||||
|
|
||||||
|
//Sliders can be grouped as well
|
||||||
|
//To label each slider in the group, we are going add additional labels and give them custom CSS styles
|
||||||
|
//We need this CSS style rule, which will remove the label's background and ensure that it takes up the entire width of the panel
|
||||||
|
String clearLabelStyle = "background-color: unset; width: 100%;";
|
||||||
|
//First we add the main slider to create a panel
|
||||||
|
auto groupsliders = ESPUI.addControl(Slider, "Slider Group", "10", Dark, grouptab, generalCallback);
|
||||||
|
//Then we add a label and set its style to the clearLabelStyle. Here we've just given it the name "A"
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "A", None, groupsliders), clearLabelStyle);
|
||||||
|
//We can now continue to add additional sliders and labels
|
||||||
|
ESPUI.addControl(Slider, "", "20", None, groupsliders, generalCallback);
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "B", None, groupsliders), clearLabelStyle);
|
||||||
|
ESPUI.addControl(Slider, "", "30", None, groupsliders, generalCallback);
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "C", None, groupsliders), clearLabelStyle);
|
||||||
|
|
||||||
|
//We can also usefully group switchers.
|
||||||
|
auto groupswitcher = ESPUI.addControl(Switcher, "Switcher Group", "0", Dark, grouptab, generalCallback);
|
||||||
|
ESPUI.addControl(Switcher, "", "1", Sunflower, groupswitcher, generalCallback);
|
||||||
|
ESPUI.addControl(Switcher, "", "0", Sunflower, groupswitcher, generalCallback);
|
||||||
|
ESPUI.addControl(Switcher, "", "1", Sunflower, groupswitcher, generalCallback);
|
||||||
|
//To label these switchers we need to first go onto a "new line" below the line of switchers
|
||||||
|
//To do this we add an empty label set to be clear and full width (with our clearLabelStyle)
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "", None, groupswitcher), clearLabelStyle);
|
||||||
|
//We will now need another label style. This one sets its width to the same as a switcher (and turns off the background)
|
||||||
|
String switcherLabelStyle = "width: 60px; margin-left: .3rem; margin-right: .3rem; background-color: unset;";
|
||||||
|
//We can now just add the styled labels.
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "A", None, groupswitcher), switcherLabelStyle);
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "B", None, groupswitcher), switcherLabelStyle);
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "C", None, groupswitcher), switcherLabelStyle);
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "D", None, groupswitcher), switcherLabelStyle);
|
||||||
|
|
||||||
|
//You can mix and match different control types, but the results might sometimes
|
||||||
|
//need additional styling to lay out nicely.
|
||||||
|
auto grouplabel = ESPUI.addControl(Label, "Mixed Group", "Main label", Dark, grouptab);
|
||||||
|
auto grouplabel2 = ESPUI.addControl(Label, "", "Secondary label", Emerald, grouplabel);
|
||||||
|
ESPUI.addControl(Button, "", "Button D", Alizarin, grouplabel, generalCallback);
|
||||||
|
ESPUI.addControl(Switcher, "", "1", Sunflower, grouplabel, generalCallback);
|
||||||
|
ESPUI.setElementStyle(grouplabel2, "font-size: x-large; font-family: serif;");
|
||||||
|
|
||||||
|
//Some controls can even support vertical orientation, currently Switchers and Sliders
|
||||||
|
ESPUI.addControl(Separator, "Vertical controls", "", None, grouptab);
|
||||||
|
auto vertgroupswitcher = ESPUI.addControl(Switcher, "Vertical Switcher Group", "0", Dark, grouptab, generalCallback);
|
||||||
|
ESPUI.setVertical(vertgroupswitcher);
|
||||||
|
//On the following lines we wrap the value returned from addControl and send it straight to setVertical
|
||||||
|
ESPUI.setVertical(ESPUI.addControl(Switcher, "", "0", None, vertgroupswitcher, generalCallback));
|
||||||
|
ESPUI.setVertical(ESPUI.addControl(Switcher, "", "0", None, vertgroupswitcher, generalCallback));
|
||||||
|
ESPUI.setVertical(ESPUI.addControl(Switcher, "", "0", None, vertgroupswitcher, generalCallback));
|
||||||
|
//The mechanism for labelling vertical switchers is the same as we used above for horizontal ones
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "", None, vertgroupswitcher), clearLabelStyle);
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "A", None, vertgroupswitcher), switcherLabelStyle);
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "B", None, vertgroupswitcher), switcherLabelStyle);
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "C", None, vertgroupswitcher), switcherLabelStyle);
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "D", None, vertgroupswitcher), switcherLabelStyle);
|
||||||
|
|
||||||
|
auto vertgroupslider = ESPUI.addControl(Slider, "Vertical Slider Group", "15", Dark, grouptab, generalCallback);
|
||||||
|
ESPUI.setVertical(vertgroupslider);
|
||||||
|
ESPUI.setVertical(ESPUI.addControl(Slider, "", "25", None, vertgroupslider, generalCallback));
|
||||||
|
ESPUI.setVertical(ESPUI.addControl(Slider, "", "35", None, vertgroupslider, generalCallback));
|
||||||
|
ESPUI.setVertical(ESPUI.addControl(Slider, "", "45", None, vertgroupslider, generalCallback));
|
||||||
|
//The mechanism for labelling vertical sliders is the same as we used above for switchers
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "", None, vertgroupslider), clearLabelStyle);
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "A", None, vertgroupslider), switcherLabelStyle);
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "B", None, vertgroupslider), switcherLabelStyle);
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "C", None, vertgroupslider), switcherLabelStyle);
|
||||||
|
ESPUI.setElementStyle(ESPUI.addControl(Label, "", "D", None, vertgroupslider), switcherLabelStyle);
|
||||||
|
|
||||||
|
//Note that combining vertical and horizontal sliders is going to result in very messy layout!
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tab: Example UI
|
||||||
|
* An example UI for the documentation
|
||||||
|
*-----------------------------------------------------------------------------------------------------------*/
|
||||||
|
auto exampletab = ESPUI.addControl(Tab, "Example", "Example");
|
||||||
|
ESPUI.addControl(Separator, "Control and Status", "", None, exampletab);
|
||||||
|
ESPUI.addControl(Switcher, "Power", "1", Alizarin, exampletab, generalCallback);
|
||||||
|
ESPUI.addControl(Label, "Status", "System status: OK", Wetasphalt, exampletab, generalCallback);
|
||||||
|
|
||||||
|
ESPUI.addControl(Separator, "Settings", "", None, exampletab);
|
||||||
|
ESPUI.addControl(PadWithCenter, "Attitude Control", "", Dark, exampletab, generalCallback);
|
||||||
|
auto examplegroup1 = ESPUI.addControl(Button, "Activate Features", "Feature A", Carrot, exampletab, generalCallback);
|
||||||
|
ESPUI.addControl(Button, "Activate Features", "Feature B", Carrot, examplegroup1, generalCallback);
|
||||||
|
ESPUI.addControl(Button, "Activate Features", "Feature C", Carrot, examplegroup1, generalCallback);
|
||||||
|
ESPUI.addControl(Slider, "Value control", "45", Peterriver, exampletab, generalCallback);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tab: WiFi Credentials
|
||||||
|
* You use this tab to enter the SSID and password of a wifi network to autoconnect to.
|
||||||
|
*-----------------------------------------------------------------------------------------------------------*/
|
||||||
|
auto wifitab = ESPUI.addControl(Tab, "", "WiFi Credentials");
|
||||||
|
wifi_ssid_text = ESPUI.addControl(Text, "SSID", "", Alizarin, wifitab, textCallback);
|
||||||
|
//Note that adding a "Max" control to a text control sets the max length
|
||||||
|
ESPUI.addControl(Max, "", "32", None, wifi_ssid_text);
|
||||||
|
wifi_pass_text = ESPUI.addControl(Text, "Password", "", Alizarin, wifitab, textCallback);
|
||||||
|
ESPUI.addControl(Max, "", "64", None, wifi_pass_text);
|
||||||
|
ESPUI.addControl(Button, "Save", "Save", Peterriver, wifitab,
|
||||||
|
[](Control *sender, int type) {
|
||||||
|
if(type == B_UP) {
|
||||||
|
Serial.println("Saving credentials to EPROM...");
|
||||||
|
Serial.println(ESPUI.getControl(wifi_ssid_text)->value);
|
||||||
|
Serial.println(ESPUI.getControl(wifi_pass_text)->value);
|
||||||
|
unsigned int i;
|
||||||
|
EEPROM.begin(100);
|
||||||
|
for(i = 0; i < ESPUI.getControl(wifi_ssid_text)->value.length(); i++) {
|
||||||
|
EEPROM.write(i, ESPUI.getControl(wifi_ssid_text)->value.charAt(i));
|
||||||
|
if(i==30) break; //Even though we provided a max length, user input should never be trusted
|
||||||
|
}
|
||||||
|
EEPROM.write(i, '\0');
|
||||||
|
|
||||||
|
for(i = 0; i < ESPUI.getControl(wifi_pass_text)->value.length(); i++) {
|
||||||
|
EEPROM.write(i + 32, ESPUI.getControl(wifi_pass_text)->value.charAt(i));
|
||||||
|
if(i==94) break; //Even though we provided a max length, user input should never be trusted
|
||||||
|
}
|
||||||
|
EEPROM.write(i + 32, '\0');
|
||||||
|
EEPROM.end();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
//Finally, start up the UI.
|
||||||
|
//This should only be called once we are connected to WiFi.
|
||||||
|
ESPUI.begin(HOSTNAME);
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
} // HeapSelectIram
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Most elements in this test UI are assigned this generic callback which prints some
|
||||||
|
//basic information. Event types are defined in ESPUI.h
|
||||||
|
void generalCallback(Control *sender, int type) {
|
||||||
|
Serial.print("CB: id(");
|
||||||
|
Serial.print(sender->id);
|
||||||
|
Serial.print(") Type(");
|
||||||
|
Serial.print(type);
|
||||||
|
Serial.print(") '");
|
||||||
|
Serial.print(sender->label);
|
||||||
|
Serial.print("' = ");
|
||||||
|
Serial.println(sender->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Most elements in this test UI are assigned this generic callback which prints some
|
||||||
|
// basic information. Event types are defined in ESPUI.h
|
||||||
|
// The extended param can be used to pass additional information
|
||||||
|
void paramCallback(Control* sender, int type, int param)
|
||||||
|
{
|
||||||
|
Serial.print("CB: id(");
|
||||||
|
Serial.print(sender->id);
|
||||||
|
Serial.print(") Type(");
|
||||||
|
Serial.print(type);
|
||||||
|
Serial.print(") '");
|
||||||
|
Serial.print(sender->label);
|
||||||
|
Serial.print("' = ");
|
||||||
|
Serial.println(sender->value);
|
||||||
|
Serial.print("param = ");
|
||||||
|
Serial.println(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
randomSeed(0);
|
||||||
|
Serial.begin(115200);
|
||||||
|
while(!Serial);
|
||||||
|
if(SLOW_BOOT) delay(5000); //Delay booting to give time to connect a serial monitor
|
||||||
|
connectWifi();
|
||||||
|
#if defined(ESP32)
|
||||||
|
WiFi.setSleep(false); //For the ESP32: turn off sleeping to increase UI responsivness (at the cost of power use)
|
||||||
|
#endif
|
||||||
|
setUpUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
static long unsigned lastTime = 0;
|
||||||
|
|
||||||
|
//Send periodic updates if switcher is turned on
|
||||||
|
if(updates && millis() > lastTime + 500) {
|
||||||
|
static uint16_t sliderVal = 10;
|
||||||
|
|
||||||
|
//Flick this switcher on and off
|
||||||
|
ESPUI.updateSwitcher(mainSwitcher, ESPUI.getControl(mainSwitcher)->value.toInt() ? false : true);
|
||||||
|
sliderVal += 10;
|
||||||
|
if(sliderVal > 400) sliderVal = 10;
|
||||||
|
|
||||||
|
//Sliders, numbers, and labels can all be updated at will
|
||||||
|
ESPUI.updateSlider(mainSlider, sliderVal);
|
||||||
|
ESPUI.updateNumber(mainNumber, random(100000));
|
||||||
|
ESPUI.updateLabel(mainLabel, String(sliderVal));
|
||||||
|
lastTime = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Simple debug UART interface
|
||||||
|
if(Serial.available()) {
|
||||||
|
switch(Serial.read()) {
|
||||||
|
case 'w': //Print IP details
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
break;
|
||||||
|
case 'W': //Reconnect wifi
|
||||||
|
connectWifi();
|
||||||
|
break;
|
||||||
|
case 'C': //Force a crash (for testing exception decoder)
|
||||||
|
#if !defined(ESP32)
|
||||||
|
((void (*)())0xf00fdead)();
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Serial.print('#');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(ESP32)
|
||||||
|
//We don't need to call this explicitly on ESP32 but we do on 8266
|
||||||
|
MDNS.update();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Utilities
|
||||||
|
//
|
||||||
|
//If you are here just to see examples of how to use ESPUI, you can ignore the following functions
|
||||||
|
//------------------------------------------------------------------------------------------------
|
||||||
|
void readStringFromEEPROM(String& buf, int baseaddress, int size) {
|
||||||
|
buf.reserve(size);
|
||||||
|
for (int i = baseaddress; i < baseaddress+size; i++) {
|
||||||
|
char c = EEPROM.read(i);
|
||||||
|
buf += c;
|
||||||
|
if(!c) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void connectWifi() {
|
||||||
|
int connect_timeout;
|
||||||
|
|
||||||
|
#if defined(ESP32)
|
||||||
|
WiFi.setHostname(HOSTNAME);
|
||||||
|
#else
|
||||||
|
WiFi.hostname(HOSTNAME);
|
||||||
|
#endif
|
||||||
|
Serial.println("Begin wifi...");
|
||||||
|
|
||||||
|
//Load credentials from EEPROM
|
||||||
|
if(!(FORCE_USE_HOTSPOT)) {
|
||||||
|
yield();
|
||||||
|
EEPROM.begin(100);
|
||||||
|
String stored_ssid, stored_pass;
|
||||||
|
readStringFromEEPROM(stored_ssid, 0, 32);
|
||||||
|
readStringFromEEPROM(stored_pass, 32, 96);
|
||||||
|
EEPROM.end();
|
||||||
|
|
||||||
|
//Try to connect with stored credentials, fire up an access point if they don't work.
|
||||||
|
#if defined(ESP32)
|
||||||
|
WiFi.begin(stored_ssid.c_str(), stored_pass.c_str());
|
||||||
|
#else
|
||||||
|
WiFi.begin(stored_ssid, stored_pass);
|
||||||
|
#endif
|
||||||
|
connect_timeout = 28; //7 seconds
|
||||||
|
while (WiFi.status() != WL_CONNECTED && connect_timeout > 0) {
|
||||||
|
delay(250);
|
||||||
|
Serial.print(".");
|
||||||
|
connect_timeout--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
Serial.println("Wifi started");
|
||||||
|
|
||||||
|
if (!MDNS.begin(HOSTNAME)) {
|
||||||
|
Serial.println("Error setting up MDNS responder!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Serial.println("\nCreating access point...");
|
||||||
|
WiFi.mode(WIFI_AP);
|
||||||
|
WiFi.softAPConfig(IPAddress(192, 168, 1, 1), IPAddress(192, 168, 1, 1), IPAddress(255, 255, 255, 0));
|
||||||
|
WiFi.softAP(HOSTNAME);
|
||||||
|
|
||||||
|
connect_timeout = 20;
|
||||||
|
do {
|
||||||
|
delay(250);
|
||||||
|
Serial.print(",");
|
||||||
|
connect_timeout--;
|
||||||
|
} while(connect_timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void textCallback(Control *sender, int type) {
|
||||||
|
//This callback is needed to handle the changed values, even though it doesn't do anything itself.
|
||||||
|
}
|
||||||
|
|
||||||
|
void randomString(char *buf, int len) {
|
||||||
|
for(auto i = 0; i < len-1; i++)
|
||||||
|
buf[i] = random(0, 26) + 'A';
|
||||||
|
buf[len-1] = '\0';
|
||||||
|
}
|
@ -627,27 +627,25 @@ uint16_t ESPUIClass::addControl(ControlType type, const char* label, const Strin
|
|||||||
uint16_t ESPUIClass::addControl(
|
uint16_t ESPUIClass::addControl(
|
||||||
ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl)
|
ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl)
|
||||||
{
|
{
|
||||||
return addControl(type, label, value, color, parentControl, nullptr);
|
return addControl(type, label, value, color, parentControl, new Control(type, label, nullptr, value, color, true, parentControl));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ESPUIClass::addControl(ControlType type, const char* label, const String& value, ControlColor color,
|
uint16_t ESPUIClass::addControl(ControlType type, const char* label, const String& value, ControlColor color,
|
||||||
uint16_t parentControl, void (*callback)(Control*, int))
|
uint16_t parentControl, std::function<void(Control*, int)> callback)
|
||||||
{
|
{
|
||||||
uint16_t id = addControl(type, label, value, color, parentControl, nullptr, nullptr);
|
uint16_t id = addControl(type, label, value, color, parentControl);
|
||||||
// set the original style callback
|
// set the original style callback
|
||||||
getControl(id)->callback = callback;
|
getControl(id)->callback = callback;
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ESPUIClass::addControl(ControlType type, const char* label, const String& value, ControlColor color,
|
uint16_t ESPUIClass::addControl(
|
||||||
uint16_t parentControl, void (*callback)(Control*, int, void*), void* UserData)
|
ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl, Control* control)
|
||||||
{
|
{
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
xSemaphoreTake(ControlsSemaphore, portMAX_DELAY);
|
xSemaphoreTake(ControlsSemaphore, portMAX_DELAY);
|
||||||
#endif // def ESP32
|
#endif // def ESP32
|
||||||
|
|
||||||
Control* control = new Control(type, label, callback, UserData, value, color, true, parentControl);
|
|
||||||
|
|
||||||
if (controls == nullptr)
|
if (controls == nullptr)
|
||||||
{
|
{
|
||||||
controls = control;
|
controls = control;
|
||||||
@ -753,70 +751,37 @@ uint16_t ESPUIClass::graph(const char* label, ControlColor color)
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ESPUIClass::slider(
|
uint16_t ESPUIClass::slider(
|
||||||
const char* label, void (*callback)(Control*, int), ControlColor color, int value, int min, int max)
|
const char* label, std::function<void(Control*, int)> callback, ControlColor color, int value, int min, int max)
|
||||||
{
|
|
||||||
uint16_t id = slider(label, nullptr, color, value, min, max, nullptr);
|
|
||||||
getControl(id)->callback = callback;
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t ESPUIClass::slider(const char* label, void (*callback)(Control*, int, void*), ControlColor color, int value,
|
|
||||||
int min, int max, void* userData)
|
|
||||||
{
|
{
|
||||||
uint16_t sliderId
|
uint16_t sliderId
|
||||||
= addControl(ControlType::Slider, label, String(value), color, Control::noParent, callback, userData);
|
= addControl(ControlType::Slider, label, String(value), color, Control::noParent, callback);
|
||||||
addControl(ControlType::Min, label, String(min), ControlColor::None, sliderId);
|
addControl(ControlType::Min, label, String(min), ControlColor::None, sliderId);
|
||||||
addControl(ControlType::Max, label, String(max), ControlColor::None, sliderId);
|
addControl(ControlType::Max, label, String(max), ControlColor::None, sliderId);
|
||||||
|
|
||||||
return sliderId;
|
return sliderId;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ESPUIClass::button(const char* label, void (*callback)(Control*, int), ControlColor color, const String& value)
|
uint16_t ESPUIClass::button(const char* label, std::function<void(Control*, int)> callback, ControlColor color, const String& value)
|
||||||
{
|
{
|
||||||
return addControl(ControlType::Button, label, value, color, Control::noParent, callback);
|
return addControl(ControlType::Button, label, value, color, Control::noParent, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ESPUIClass::button(
|
uint16_t ESPUIClass::switcher(const char* label, std::function<void(Control*, int)> callback, ControlColor color, bool startState)
|
||||||
const char* label, void (*callback)(Control*, int, void*), ControlColor color, const String& value, void* UserData)
|
|
||||||
{
|
|
||||||
return addControl(ControlType::Button, label, value, color, Control::noParent, callback, UserData);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t ESPUIClass::switcher(const char* label, void (*callback)(Control*, int), ControlColor color, bool startState)
|
|
||||||
{
|
{
|
||||||
return addControl(ControlType::Switcher, label, startState ? "1" : "0", color, Control::noParent, callback);
|
return addControl(ControlType::Switcher, label, startState ? "1" : "0", color, Control::noParent, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ESPUIClass::switcher(
|
uint16_t ESPUIClass::pad(const char* label, std::function<void(Control*, int)> callback, ControlColor color)
|
||||||
const char* label, void (*callback)(Control*, int, void*), ControlColor color, bool startState, void* UserData)
|
|
||||||
{
|
|
||||||
return addControl(
|
|
||||||
ControlType::Switcher, label, startState ? "1" : "0", color, Control::noParent, callback, UserData);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t ESPUIClass::pad(const char* label, void (*callback)(Control*, int), ControlColor color)
|
|
||||||
{
|
{
|
||||||
return addControl(ControlType::Pad, label, "", color, Control::noParent, callback);
|
return addControl(ControlType::Pad, label, "", color, Control::noParent, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ESPUIClass::pad(const char* label, void (*callback)(Control*, int, void*), ControlColor color, void* UserData)
|
uint16_t ESPUIClass::padWithCenter(const char* label, std::function<void(Control*, int)> callback, ControlColor color)
|
||||||
{
|
|
||||||
return addControl(ControlType::Pad, label, "", color, Control::noParent, callback, UserData);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t ESPUIClass::padWithCenter(const char* label, void (*callback)(Control*, int), ControlColor color)
|
|
||||||
{
|
{
|
||||||
return addControl(ControlType::PadWithCenter, label, "", color, Control::noParent, callback);
|
return addControl(ControlType::PadWithCenter, label, "", color, Control::noParent, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ESPUIClass::padWithCenter(
|
|
||||||
const char* label, void (*callback)(Control*, int, void*), ControlColor color, void* UserData)
|
|
||||||
{
|
|
||||||
return addControl(ControlType::PadWithCenter, label, "", color, Control::noParent, callback, UserData);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t ESPUIClass::number(
|
uint16_t ESPUIClass::number(
|
||||||
const char* label, void (*callback)(Control*, int), ControlColor color, int number, int min, int max)
|
const char* label, std::function<void(Control*, int)> callback, ControlColor color, int number, int min, int max)
|
||||||
{
|
{
|
||||||
uint16_t numberId = addControl(ControlType::Number, label, String(number), color, Control::noParent, callback);
|
uint16_t numberId = addControl(ControlType::Number, label, String(number), color, Control::noParent, callback);
|
||||||
addControl(ControlType::Min, label, String(min), ControlColor::None, numberId);
|
addControl(ControlType::Min, label, String(min), ControlColor::None, numberId);
|
||||||
@ -824,16 +789,6 @@ uint16_t ESPUIClass::number(
|
|||||||
return numberId;
|
return numberId;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ESPUIClass::number(const char* label, void (*callback)(Control*, int, void*), ControlColor color, int number,
|
|
||||||
int min, int max, void* UserData)
|
|
||||||
{
|
|
||||||
uint16_t numberId
|
|
||||||
= addControl(ControlType::Number, label, String(number), color, Control::noParent, callback, UserData);
|
|
||||||
addControl(ControlType::Min, label, String(min), ControlColor::None, numberId);
|
|
||||||
addControl(ControlType::Max, label, String(max), ControlColor::None, numberId);
|
|
||||||
return numberId;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t ESPUIClass::gauge(const char* label, ControlColor color, int number, int min, int max)
|
uint16_t ESPUIClass::gauge(const char* label, ControlColor color, int number, int min, int max)
|
||||||
{
|
{
|
||||||
uint16_t numberId = addControl(ControlType::Gauge, label, String(number), color, Control::noParent);
|
uint16_t numberId = addControl(ControlType::Gauge, label, String(number), color, Control::noParent);
|
||||||
@ -847,28 +802,16 @@ uint16_t ESPUIClass::separator(const char* label)
|
|||||||
return addControl(ControlType::Separator, label, "", ControlColor::Alizarin, Control::noParent, nullptr);
|
return addControl(ControlType::Separator, label, "", ControlColor::Alizarin, Control::noParent, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ESPUIClass::accelerometer(const char* label, void (*callback)(Control*, int), ControlColor color)
|
uint16_t ESPUIClass::accelerometer(const char* label, std::function<void(Control*, int)> callback, ControlColor color)
|
||||||
{
|
{
|
||||||
return addControl(ControlType::Accel, label, "", color, Control::noParent, callback);
|
return addControl(ControlType::Accel, label, "", color, Control::noParent, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ESPUIClass::accelerometer(
|
uint16_t ESPUIClass::text(const char* label, std::function<void(Control*, int)> callback, ControlColor color, const String& value)
|
||||||
const char* label, void (*callback)(Control*, int, void*), ControlColor color, void* UserData)
|
|
||||||
{
|
|
||||||
return addControl(ControlType::Accel, label, "", color, Control::noParent, callback, UserData);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t ESPUIClass::text(const char* label, void (*callback)(Control*, int), ControlColor color, const String& value)
|
|
||||||
{
|
{
|
||||||
return addControl(ControlType::Text, label, value, color, Control::noParent, callback);
|
return addControl(ControlType::Text, label, value, color, Control::noParent, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t ESPUIClass::text(
|
|
||||||
const char* label, void (*callback)(Control*, int, void*), ControlColor color, const String& value, void* UserData)
|
|
||||||
{
|
|
||||||
return addControl(ControlType::Text, label, value, color, Control::noParent, callback, UserData);
|
|
||||||
}
|
|
||||||
|
|
||||||
Control* ESPUIClass::getControl(uint16_t id)
|
Control* ESPUIClass::getControl(uint16_t id)
|
||||||
{
|
{
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
|
73
src/ESPUI.h
73
src/ESPUI.h
@ -125,33 +125,19 @@ public:
|
|||||||
uint16_t addControl(ControlType type, const char* label, const String& value);
|
uint16_t addControl(ControlType type, const char* label, const String& value);
|
||||||
uint16_t addControl(ControlType type, const char* label, const String& value, ControlColor color);
|
uint16_t addControl(ControlType type, const char* label, const String& value, ControlColor color);
|
||||||
uint16_t addControl(ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl);
|
uint16_t addControl(ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl);
|
||||||
uint16_t addControl(ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl, void (*callback)(Control*, int));
|
uint16_t addControl(ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl, std::function<void(Control*, int)> callback);
|
||||||
uint16_t addControl(ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl, void (*callback)(Control*, int, void *), void* UserData);
|
|
||||||
|
|
||||||
bool removeControl(uint16_t id, bool force_rebuild_ui = false);
|
bool removeControl(uint16_t id, bool force_rebuild_ui = false);
|
||||||
|
|
||||||
// create Elements
|
// create Elements
|
||||||
// Create Event Button
|
// Create Event Button
|
||||||
uint16_t button(const char* label, void (*callback)(Control*, int), ControlColor color, const String& value = "");
|
uint16_t button(const char* label, std::function<void(Control*, int)> callback, ControlColor color, const String& value = "");
|
||||||
uint16_t button(const char* label, void (*callback)(Control*, int, void*), ControlColor color, const String& value, void* UserData);
|
uint16_t switcher(const char* label, std::function<void(Control*, int)> callback, ControlColor color, bool startState = false); // Create Toggle Button
|
||||||
|
uint16_t pad(const char* label, std::function<void(Control*, int)> callback, ControlColor color); // Create Pad Control
|
||||||
uint16_t switcher(const char* label, void (*callback)(Control*, int), ControlColor color, bool startState = false); // Create Toggle Button
|
uint16_t padWithCenter(const char* label, std::function<void(Control*, int)> callback, ControlColor color); // Create Pad Control with Centerbutton
|
||||||
uint16_t switcher(const char* label, void (*callback)(Control*, int, void*), ControlColor color, bool startState, void* UserData); // Create Toggle Button
|
uint16_t slider(const char* label, std::function<void(Control*, int)> callback, ControlColor color, int value, int min = 0, int max = 100); // Create Slider Control
|
||||||
|
uint16_t number(const char* label, std::function<void(Control*, int)> callback, ControlColor color, int value, int min = 0, int max = 100); // Create a Number Input Control
|
||||||
uint16_t pad(const char* label, void (*callback)(Control*, int), ControlColor color); // Create Pad Control
|
uint16_t text(const char* label, std::function<void(Control*, int)> callback, ControlColor color, const String& value = ""); // Create a Text Input Control
|
||||||
uint16_t pad(const char* label, void (*callback)(Control*, int, void*), ControlColor color, void* UserData); // Create Pad Control
|
|
||||||
|
|
||||||
uint16_t padWithCenter(const char* label, void (*callback)(Control*, int), ControlColor color); // Create Pad Control with Centerbutton
|
|
||||||
uint16_t padWithCenter(const char* label, void (*callback)(Control*, int, void*), ControlColor color, void* UserData); // Create Pad Control with Centerbutton
|
|
||||||
|
|
||||||
uint16_t slider(const char* label, void (*callback)(Control*, int), ControlColor color, int value, int min = 0, int max = 100); // Create Slider Control
|
|
||||||
uint16_t slider(const char* label, void (*callback)(Control*, int, void*), ControlColor color, int value, int min, int max, void* UserData); // Create Slider Control
|
|
||||||
|
|
||||||
uint16_t number(const char* label, void (*callback)(Control*, int), ControlColor color, int value, int min = 0, int max = 100); // Create a Number Input Control
|
|
||||||
uint16_t number(const char* label, void (*callback)(Control*, int, void*), ControlColor color, int value, int min, int max, void* UserData); // Create a Number Input Control
|
|
||||||
|
|
||||||
uint16_t text(const char* label, void (*callback)(Control*, int), ControlColor color, const String& value = ""); // Create a Text Input Control
|
|
||||||
uint16_t text(const char* label, void (*callback)(Control*, int, void*), ControlColor color, const String& value, void* UserData); // Create a Text Input Control
|
|
||||||
|
|
||||||
// Output only
|
// Output only
|
||||||
uint16_t label(const char* label, ControlColor color,
|
uint16_t label(const char* label, ControlColor color,
|
||||||
@ -162,8 +148,7 @@ public:
|
|||||||
uint16_t separator(const char* label); //Create separator
|
uint16_t separator(const char* label); //Create separator
|
||||||
|
|
||||||
// Input only
|
// Input only
|
||||||
uint16_t accelerometer(const char* label, void (*callback)(Control*, int), ControlColor color);
|
uint16_t accelerometer(const char* label, std::function<void(Control*, int)> callback, ControlColor color);
|
||||||
uint16_t accelerometer(const char* label, void (*callback)(Control*, int, void*), ControlColor color, void* UserData);
|
|
||||||
|
|
||||||
// Update Elements
|
// Update Elements
|
||||||
|
|
||||||
@ -213,6 +198,44 @@ public:
|
|||||||
Verbosity verbosity = Verbosity::Quiet;
|
Verbosity verbosity = Verbosity::Quiet;
|
||||||
AsyncWebServer* server;
|
AsyncWebServer* server;
|
||||||
|
|
||||||
|
// emulate former extended callback API by using an intermediate lambda (no deprecation)
|
||||||
|
uint16_t addControl(ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl, std::function<void(Control*, int, void*)> callback, void* userData)
|
||||||
|
{
|
||||||
|
return addControl(type, label, value, color, parentControl, [callback, userData](Control* sender, int type){ callback(sender, type, userData); });
|
||||||
|
}
|
||||||
|
uint16_t button(const char* label, std::function<void(Control*, int, void*)> callback, ControlColor color, const String& value, void* userData)
|
||||||
|
{
|
||||||
|
return button(label, [callback, userData](Control* sender, int type){ callback(sender, type, userData); }, color, value);
|
||||||
|
}
|
||||||
|
uint16_t switcher(const char* label, std::function<void(Control*, int, void*)> callback, ControlColor color, bool startState, void* userData)
|
||||||
|
{
|
||||||
|
return switcher(label, [callback, userData](Control* sender, int type){ callback(sender, type, userData); }, color, startState);
|
||||||
|
}
|
||||||
|
uint16_t pad(const char* label, std::function<void(Control*, int, void*)> callback, ControlColor color, void* userData)
|
||||||
|
{
|
||||||
|
return pad(label, [callback, userData](Control* sender, int type){ callback(sender, type, userData); }, color);
|
||||||
|
}
|
||||||
|
uint16_t padWithCenter(const char* label, std::function<void(Control*, int, void*)> callback, ControlColor color, void* userData)
|
||||||
|
{
|
||||||
|
return padWithCenter(label, [callback, userData](Control* sender, int type){ callback(sender, type, userData); }, color);
|
||||||
|
}
|
||||||
|
uint16_t slider(const char* label, std::function<void(Control*, int, void*)> callback, ControlColor color, int value, int min, int max, void* userData)
|
||||||
|
{
|
||||||
|
return slider(label, [callback, userData](Control* sender, int type){ callback(sender, type, userData); }, color, value, min, max);
|
||||||
|
}
|
||||||
|
uint16_t number(const char* label, std::function<void(Control*, int, void*)> callback, ControlColor color, int value, int min, int max, void* userData)
|
||||||
|
{
|
||||||
|
return number(label, [callback, userData](Control* sender, int type){ callback(sender, type, userData); }, color, value, min, max);
|
||||||
|
}
|
||||||
|
uint16_t text(const char* label, std::function<void(Control*, int, void*)> callback, ControlColor color, const String& value, void* userData)
|
||||||
|
{
|
||||||
|
return text(label, [callback, userData](Control* sender, int type){ callback(sender, type, userData); } , color, value);
|
||||||
|
}
|
||||||
|
uint16_t accelerometer(const char* label, std::function<void(Control*, int, void*)> callback, ControlColor color, void* userData)
|
||||||
|
{
|
||||||
|
return accelerometer(label, [callback, userData](Control* sender, int type){ callback(sender, type, userData); }, color);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class ESPUIclient;
|
friend class ESPUIclient;
|
||||||
friend class ESPUIcontrol;
|
friend class ESPUIcontrol;
|
||||||
@ -226,6 +249,8 @@ protected:
|
|||||||
bool basicAuth = true;
|
bool basicAuth = true;
|
||||||
uint16_t controlCount = 0;
|
uint16_t controlCount = 0;
|
||||||
|
|
||||||
|
uint16_t addControl(ControlType type, const char* label, const String& value, ControlColor color, uint16_t parentControl, Control* control);
|
||||||
|
|
||||||
#define ClientUpdateType_t ESPUIclient::ClientUpdateType_t
|
#define ClientUpdateType_t ESPUIclient::ClientUpdateType_t
|
||||||
void NotifyClients(ClientUpdateType_t newState);
|
void NotifyClients(ClientUpdateType_t newState);
|
||||||
void NotifyClient(uint32_t WsClientId, ClientUpdateType_t newState);
|
void NotifyClient(uint32_t WsClientId, ClientUpdateType_t newState);
|
||||||
|
@ -3,13 +3,11 @@
|
|||||||
static uint16_t idCounter = 0;
|
static uint16_t idCounter = 0;
|
||||||
static const String ControlError = "*** ESPUI ERROR: Could not transfer control ***";
|
static const String ControlError = "*** ESPUI ERROR: Could not transfer control ***";
|
||||||
|
|
||||||
Control::Control(ControlType type, const char* label, void (*callback)(Control*, int, void*), void* UserData,
|
Control::Control(ControlType type, const char* label, std::function<void(Control*, int)> callback,
|
||||||
const String& value, ControlColor color, bool visible, uint16_t parentControl)
|
const String& value, ControlColor color, bool visible, uint16_t parentControl)
|
||||||
: type(type),
|
: type(type),
|
||||||
label(label),
|
label(label),
|
||||||
callback(nullptr),
|
callback(callback),
|
||||||
extendedCallback(callback),
|
|
||||||
user(UserData),
|
|
||||||
value(value),
|
value(value),
|
||||||
color(color),
|
color(color),
|
||||||
visible(visible),
|
visible(visible),
|
||||||
@ -27,8 +25,6 @@ Control::Control(const Control& Control)
|
|||||||
id(Control.id),
|
id(Control.id),
|
||||||
label(Control.label),
|
label(Control.label),
|
||||||
callback(Control.callback),
|
callback(Control.callback),
|
||||||
extendedCallback(Control.extendedCallback),
|
|
||||||
user(Control.user),
|
|
||||||
value(Control.value),
|
value(Control.value),
|
||||||
color(Control.color),
|
color(Control.color),
|
||||||
visible(Control.visible),
|
visible(Control.visible),
|
||||||
@ -42,17 +38,11 @@ void Control::SendCallback(int type)
|
|||||||
{
|
{
|
||||||
callback(this, type);
|
callback(this, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extendedCallback)
|
|
||||||
{
|
|
||||||
extendedCallback(this, type, user);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Control::DeleteControl()
|
void Control::DeleteControl()
|
||||||
{
|
{
|
||||||
ControlSyncState = ControlSyncState_t::deleted;
|
ControlSyncState = ControlSyncState_t::deleted;
|
||||||
extendedCallback = nullptr;
|
|
||||||
callback = nullptr;
|
callback = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
enum ControlType : uint8_t
|
enum ControlType : uint8_t
|
||||||
{
|
{
|
||||||
@ -53,9 +54,7 @@ public:
|
|||||||
ControlType type;
|
ControlType type;
|
||||||
uint16_t id; // just mirroring the id here for practical reasons
|
uint16_t id; // just mirroring the id here for practical reasons
|
||||||
const char* label;
|
const char* label;
|
||||||
void (*callback)(Control*, int);
|
std::function<void(Control*, int)> callback;
|
||||||
void (*extendedCallback)(Control*, int, void*);
|
|
||||||
void* user;
|
|
||||||
String value;
|
String value;
|
||||||
ControlColor color;
|
ControlColor color;
|
||||||
bool visible;
|
bool visible;
|
||||||
@ -72,8 +71,7 @@ public:
|
|||||||
|
|
||||||
Control(ControlType type,
|
Control(ControlType type,
|
||||||
const char* label,
|
const char* label,
|
||||||
void (*callback)(Control*, int, void*),
|
std::function<void(Control*, int)> callback,
|
||||||
void* UserData,
|
|
||||||
const String& value,
|
const String& value,
|
||||||
ControlColor color,
|
ControlColor color,
|
||||||
bool visible,
|
bool visible,
|
||||||
@ -82,7 +80,7 @@ public:
|
|||||||
Control(const Control& Control);
|
Control(const Control& Control);
|
||||||
|
|
||||||
void SendCallback(int type);
|
void SendCallback(int type);
|
||||||
bool HasCallback() { return ((nullptr != callback) || (nullptr != extendedCallback)); }
|
bool HasCallback() { return (nullptr != callback); }
|
||||||
void MarshalControl(ArduinoJson::JsonObject& item, bool refresh);
|
void MarshalControl(ArduinoJson::JsonObject& item, bool refresh);
|
||||||
void MarshalErrorMessage(ArduinoJson::JsonObject& item);
|
void MarshalErrorMessage(ArduinoJson::JsonObject& item);
|
||||||
bool ToBeDeleted() { return (ControlSyncState_t::deleted == ControlSyncState); }
|
bool ToBeDeleted() { return (ControlSyncState_t::deleted == ControlSyncState); }
|
||||||
|
Loading…
Reference in New Issue
Block a user