diff --git a/library.json b/library.json index 54621d8..0642c6a 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "maintainer": true } ], - "version": "5.3.3", + "version": "5.4.0", "frameworks": ["espidf", "arduino"], "platforms": "espressif32", "dependencies": [ diff --git a/src/gridui_version.h b/src/gridui_version.h index d72ca83..35badd9 100644 --- a/src/gridui_version.h +++ b/src/gridui_version.h @@ -1,3 +1,3 @@ #pragma once -#define RB_GRIDUI_VERSION 0x050303 +#define RB_GRIDUI_VERSION 0x050400 diff --git a/src/widgets/arm.h b/src/widgets/arm.h index 3c517b8..6a25807 100644 --- a/src/widgets/arm.h +++ b/src/widgets/arm.h @@ -14,11 +14,11 @@ class Arm : public Widget { public: double x() const { - return data().getDouble("armX"); + return m_state->getDouble("armX"); } double y() const { - return data().getDouble("armY"); + return m_state->getDouble("armY"); } }; diff --git a/src/widgets/bar.h b/src/widgets/bar.h index 2a2bc7e..cb73e10 100644 --- a/src/widgets/bar.h +++ b/src/widgets/bar.h @@ -18,7 +18,7 @@ class Bar : public Widget { } std::string color() const { - return data().getString("color"); + return m_state->getString("color"); } void setFontSize(float fontSize) { @@ -26,7 +26,7 @@ class Bar : public Widget { } float fontSize() const { - return data().getDouble("fontSize"); + return m_state->getDouble("fontSize"); } void setMin(float min) { @@ -34,7 +34,7 @@ class Bar : public Widget { } float min() const { - return data().getDouble("min"); + return m_state->getDouble("min"); } void setMax(float max) { @@ -42,7 +42,7 @@ class Bar : public Widget { } float max() const { - return data().getDouble("max"); + return m_state->getDouble("max"); } void setValue(float value) { @@ -50,7 +50,7 @@ class Bar : public Widget { } float value() const { - return data().getDouble("value"); + return m_state->getDouble("value"); } void setShowValue(bool showValue) { @@ -58,7 +58,7 @@ class Bar : public Widget { } bool showValue() const { - return data().getBool("showValue"); + return m_state->getBool("showValue"); } }; diff --git a/src/widgets/button.h b/src/widgets/button.h index 8b4a82a..5227ab4 100644 --- a/src/widgets/button.h +++ b/src/widgets/button.h @@ -18,7 +18,7 @@ class Button : public Widget { } std::string text() const { - return data().getString("text"); + return m_state->getString("text"); } void setFontSize(float fontSize) { @@ -26,7 +26,7 @@ class Button : public Widget { } float fontSize() const { - return data().getDouble("fontSize"); + return m_state->getDouble("fontSize"); } void setColor(const std::string& color) { @@ -34,7 +34,7 @@ class Button : public Widget { } std::string color() const { - return data().getString("color"); + return m_state->getString("color"); } void setBackground(const std::string& background) { @@ -42,7 +42,7 @@ class Button : public Widget { } std::string background() const { - return data().getString("background"); + return m_state->getString("background"); } void setAlign(const std::string& align) { @@ -50,7 +50,7 @@ class Button : public Widget { } std::string align() const { - return data().getString("align"); + return m_state->getString("align"); } void setValign(const std::string& valign) { @@ -58,7 +58,7 @@ class Button : public Widget { } std::string valign() const { - return data().getString("valign"); + return m_state->getString("valign"); } void setNumber(float number) { @@ -67,7 +67,7 @@ class Button : public Widget { } bool pressed() const { - return data().getBool("pressed"); + return m_state->getBool("pressed"); } void setDisabled(bool disabled) { @@ -75,7 +75,7 @@ class Button : public Widget { } bool disabled() const { - return data().getBool("disabled"); + return m_state->getBool("disabled"); } }; diff --git a/src/widgets/camera.h b/src/widgets/camera.h index 611a1ef..eb01027 100644 --- a/src/widgets/camera.h +++ b/src/widgets/camera.h @@ -23,7 +23,7 @@ class Camera : public Widget { } float rotation() const { - return data().getDouble("rotation"); + return m_state->getDouble("rotation"); } void setClip(bool clip) { @@ -31,21 +31,23 @@ class Camera : public Widget { } bool clip() const { - return data().getBool("clip"); + return m_state->getBool("clip"); } void addTag(const Tag& t) { - auto* tagsArray = data().getArray("tags"); + auto lock = m_state->uniqueStateLock(); + + auto* tagsArray = m_state->dataLocked().getArray("tags"); const bool existedBefore = tagsArray != NULL; if (!existedBefore) { tagsArray = new rbjson::Array; } tagsArray->push_back(buildTagObject(t)); + lock.unlock(); + if (!existedBefore) { m_state->set("tags", tagsArray); - } - { m_state->markChanged("tags"); } } diff --git a/src/widgets/checkbox.h b/src/widgets/checkbox.h index 051a15b..a0eebaf 100644 --- a/src/widgets/checkbox.h +++ b/src/widgets/checkbox.h @@ -18,7 +18,7 @@ class Checkbox : public Widget { } float fontSize() const { - return data().getDouble("fontSize"); + return m_state->getDouble("fontSize"); } void setChecked(bool checked) { @@ -26,7 +26,7 @@ class Checkbox : public Widget { } bool checked() const { - return data().getBool("checked"); + return m_state->getBool("checked"); } void setColor(const std::string& color) { @@ -34,7 +34,7 @@ class Checkbox : public Widget { } std::string color() const { - return data().getString("color"); + return m_state->getString("color"); } void setText(const std::string& text) { @@ -42,7 +42,7 @@ class Checkbox : public Widget { } std::string text() const { - return data().getString("text"); + return m_state->getString("text"); } }; diff --git a/src/widgets/circle.h b/src/widgets/circle.h index 10ee85c..1af00d0 100644 --- a/src/widgets/circle.h +++ b/src/widgets/circle.h @@ -18,7 +18,7 @@ class Circle : public Widget { } std::string color() const { - return data().getString("color"); + return m_state->getString("color"); } void setFontSize(float fontSize) { @@ -26,7 +26,7 @@ class Circle : public Widget { } float fontSize() const { - return data().getDouble("fontSize"); + return m_state->getDouble("fontSize"); } void setMin(float min) { @@ -34,7 +34,7 @@ class Circle : public Widget { } float min() const { - return data().getDouble("min"); + return m_state->getDouble("min"); } void setMax(float max) { @@ -42,7 +42,7 @@ class Circle : public Widget { } float max() const { - return data().getDouble("max"); + return m_state->getDouble("max"); } void setLineWidth(float lineWidth) { @@ -50,7 +50,7 @@ class Circle : public Widget { } float lineWidth() const { - return data().getDouble("lineWidth"); + return m_state->getDouble("lineWidth"); } void setValueStart(float valueStart) { @@ -58,7 +58,7 @@ class Circle : public Widget { } float valueStart() const { - return data().getDouble("valueStart"); + return m_state->getDouble("valueStart"); } void setValue(float value) { @@ -66,7 +66,7 @@ class Circle : public Widget { } float value() const { - return data().getDouble("value"); + return m_state->getDouble("value"); } void setShowValue(bool showValue) { @@ -74,7 +74,7 @@ class Circle : public Widget { } bool showValue() const { - return data().getBool("showValue"); + return m_state->getBool("showValue"); } }; diff --git a/src/widgets/input.h b/src/widgets/input.h index 733a9bd..ea1c932 100644 --- a/src/widgets/input.h +++ b/src/widgets/input.h @@ -18,7 +18,7 @@ class Input : public Widget { } std::string text() const { - return data().getString("text"); + return m_state->getString("text"); } void setColor(const std::string& color) { @@ -26,7 +26,7 @@ class Input : public Widget { } std::string color() const { - return data().getString("color"); + return m_state->getString("color"); } void setType(const std::string& type) { @@ -34,7 +34,7 @@ class Input : public Widget { } std::string type() const { - return data().getString("type"); + return m_state->getString("type"); } void setDisabled(bool disabled) { @@ -42,7 +42,7 @@ class Input : public Widget { } bool disabled() const { - return data().getBool("disabled"); + return m_state->getBool("disabled"); } }; diff --git a/src/widgets/joystick.h b/src/widgets/joystick.h index f0455ad..4dfa40f 100644 --- a/src/widgets/joystick.h +++ b/src/widgets/joystick.h @@ -18,7 +18,7 @@ class Joystick : public Widget { } std::string color() const { - return data().getString("color"); + return m_state->getString("color"); } void setKeys(const std::string& keys) { @@ -26,7 +26,7 @@ class Joystick : public Widget { } std::string keys() const { - return data().getString("keys"); + return m_state->getString("keys"); } void setText(const std::string& text) { @@ -34,15 +34,15 @@ class Joystick : public Widget { } std::string text() const { - return data().getString("text"); + return m_state->getString("text"); } int32_t x() const { - return data().getInt("jx"); + return m_state->getInt("jx"); } int32_t y() const { - return data().getInt("jy"); + return m_state->getInt("jy"); } }; diff --git a/src/widgets/led.h b/src/widgets/led.h index 8402d3f..46c89bd 100644 --- a/src/widgets/led.h +++ b/src/widgets/led.h @@ -18,7 +18,7 @@ class Led : public Widget { } std::string color() const { - return data().getString("color"); + return m_state->getString("color"); } void setOn(bool on) { @@ -26,7 +26,7 @@ class Led : public Widget { } bool on() const { - return data().getBool("on"); + return m_state->getBool("on"); } }; diff --git a/src/widgets/orientation.h b/src/widgets/orientation.h index a801ff4..8bdabb5 100644 --- a/src/widgets/orientation.h +++ b/src/widgets/orientation.h @@ -20,19 +20,19 @@ class Orientation : public Widget { } std::string color() const { - return data().getString("color"); + return m_state->getString("color"); } float yaw() const { - return data().getDouble("oy"); + return m_state->getDouble("oy"); } float pitch() const { - return data().getDouble("op"); + return m_state->getDouble("op"); } float roll() const { - return data().getDouble("or"); + return m_state->getDouble("or"); } int32_t joystickX() { diff --git a/src/widgets/select.h b/src/widgets/select.h index e9aa564..161d32b 100644 --- a/src/widgets/select.h +++ b/src/widgets/select.h @@ -23,7 +23,7 @@ class Select : public Widget { } std::string color() const { - return data().getString("color"); + return m_state->getString("color"); } void setBackground(const std::string& background) { @@ -31,7 +31,7 @@ class Select : public Widget { } std::string background() const { - return data().getString("background"); + return m_state->getString("background"); } void setOptions(const std::vector& options) { @@ -48,7 +48,7 @@ class Select : public Widget { std::vector options() const { std::vector out; - std::string str = data().getString("options"); + std::string str = m_state->getString("options"); std::string::size_type lastDelim = 0; std::string::size_type delim = 0; @@ -66,7 +66,7 @@ class Select : public Widget { } int selectedIndex() const { - return data().getInt("selectedIndex"); + return m_state->getInt("selectedIndex"); } void setDisabled(bool disabled) { @@ -74,7 +74,7 @@ class Select : public Widget { } bool disabled() const { - return data().getBool("disabled"); + return m_state->getBool("disabled"); } }; diff --git a/src/widgets/slider.h b/src/widgets/slider.h index d28463c..0c9f730 100644 --- a/src/widgets/slider.h +++ b/src/widgets/slider.h @@ -18,7 +18,7 @@ class Slider : public Widget { } std::string color() const { - return data().getString("color"); + return m_state->getString("color"); } void setFontSize(float fontSize) { @@ -26,7 +26,7 @@ class Slider : public Widget { } float fontSize() const { - return data().getDouble("fontSize"); + return m_state->getDouble("fontSize"); } void setMin(float min) { @@ -34,7 +34,7 @@ class Slider : public Widget { } float min() const { - return data().getDouble("min"); + return m_state->getDouble("min"); } void setMax(float max) { @@ -42,7 +42,7 @@ class Slider : public Widget { } float max() const { - return data().getDouble("max"); + return m_state->getDouble("max"); } void setValue(float value) { @@ -50,7 +50,7 @@ class Slider : public Widget { } float value() const { - return data().getDouble("value"); + return m_state->getDouble("value"); } void setPrecision(float precision) { @@ -58,7 +58,7 @@ class Slider : public Widget { } float precision() const { - return data().getDouble("precision"); + return m_state->getDouble("precision"); } void setShowValue(bool showValue) { @@ -66,7 +66,7 @@ class Slider : public Widget { } bool showValue() const { - return data().getBool("showValue"); + return m_state->getBool("showValue"); } }; diff --git a/src/widgets/spinedit.h b/src/widgets/spinedit.h index a67c01e..e772762 100644 --- a/src/widgets/spinedit.h +++ b/src/widgets/spinedit.h @@ -18,7 +18,7 @@ class SpinEdit : public Widget { } float fontSize() const { - return data().getDouble("fontSize"); + return m_state->getDouble("fontSize"); } void setColor(const std::string& color) { @@ -26,7 +26,7 @@ class SpinEdit : public Widget { } std::string color() const { - return data().getString("color"); + return m_state->getString("color"); } void setValue(float value) { @@ -34,7 +34,7 @@ class SpinEdit : public Widget { } float value() const { - return data().getDouble("value"); + return m_state->getDouble("value"); } void setStep(float step) { @@ -42,7 +42,7 @@ class SpinEdit : public Widget { } float step() const { - return data().getDouble("step"); + return m_state->getDouble("step"); } void setPrecision(float precision) { @@ -50,7 +50,7 @@ class SpinEdit : public Widget { } float precision() const { - return data().getDouble("precision"); + return m_state->getDouble("precision"); } }; diff --git a/src/widgets/switcher.h b/src/widgets/switcher.h index 7e36590..8bcea49 100644 --- a/src/widgets/switcher.h +++ b/src/widgets/switcher.h @@ -18,7 +18,7 @@ class Switcher : public Widget { } float fontSize() const { - return data().getDouble("fontSize"); + return m_state->getDouble("fontSize"); } void setColor(const std::string& color) { @@ -26,11 +26,11 @@ class Switcher : public Widget { } std::string color() const { - return data().getString("color"); + return m_state->getString("color"); } int value() const { - return data().getInt("value"); + return m_state->getInt("value"); } void setMin(int min) { @@ -38,7 +38,7 @@ class Switcher : public Widget { } int min() const { - return data().getInt("min"); + return m_state->getInt("min"); } void setMax(int max) { @@ -46,7 +46,7 @@ class Switcher : public Widget { } int max() const { - return data().getInt("max"); + return m_state->getInt("max"); } }; diff --git a/src/widgets/text.h b/src/widgets/text.h index be43a5a..fbaf674 100644 --- a/src/widgets/text.h +++ b/src/widgets/text.h @@ -18,7 +18,7 @@ class Text : public Widget { } std::string text() const { - return data().getString("text"); + return m_state->getString("text"); } void setFontSize(float fontSize) { @@ -26,7 +26,7 @@ class Text : public Widget { } float fontSize() const { - return data().getDouble("fontSize"); + return m_state->getDouble("fontSize"); } void setColor(const std::string& color) { @@ -34,7 +34,7 @@ class Text : public Widget { } std::string color() const { - return data().getString("color"); + return m_state->getString("color"); } void setBackground(const std::string& background) { @@ -42,7 +42,7 @@ class Text : public Widget { } std::string background() const { - return data().getString("background"); + return m_state->getString("background"); } void setAlign(const std::string& align) { @@ -50,7 +50,7 @@ class Text : public Widget { } std::string align() const { - return data().getString("align"); + return m_state->getString("align"); } void setValign(const std::string& valign) { @@ -58,7 +58,7 @@ class Text : public Widget { } std::string valign() const { - return data().getString("valign"); + return m_state->getString("valign"); } void setPrefix(const std::string& prefix) { @@ -66,7 +66,7 @@ class Text : public Widget { } std::string prefix() const { - return data().getString("prefix"); + return m_state->getString("prefix"); } void setSuffix(const std::string& suffix) { @@ -74,7 +74,7 @@ class Text : public Widget { } std::string suffix() const { - return data().getString("suffix"); + return m_state->getString("suffix"); } void setNumber(float number) { diff --git a/src/widgets/widget.cpp b/src/widgets/widget.cpp index 6fef900..cb733d5 100644 --- a/src/widgets/widget.cpp +++ b/src/widgets/widget.cpp @@ -24,11 +24,31 @@ WidgetState::WidgetState(uint16_t uuid, float x, float y, float w, float h, uint } } +std::string WidgetState::getString(const std::string& key, std::string def) const { + std::unique_lock lock(m_mutex); + return m_data.getString(key, def); +} + +int64_t WidgetState::getInt(const std::string& key, int64_t def) const { + std::unique_lock lock(m_mutex); + return m_data.getInt(key, def); +} + +double WidgetState::getDouble(const std::string& key, double def) const { + std::unique_lock lock(m_mutex); + return m_data.getDouble(key, def); +} + +bool WidgetState::getBool(const std::string& key, bool def) const { + std::unique_lock lock(m_mutex); + return m_data.getBool(key, def); +} + bool WidgetState::set(const std::string& key, rbjson::Value* value) { if (m_uuid == 0) return false; - std::lock_guard lock(m_mutex); + std::unique_lock lock(m_mutex); const auto* old = m_data.get(key); if (old != nullptr && old->equals(*value)) { @@ -45,7 +65,7 @@ bool WidgetState::setInnerObjectProp(const std::string& objectName, const std::s if (m_uuid == 0) return false; - std::lock_guard lock(m_mutex); + std::unique_lock lock(m_mutex); auto* obj = m_data.getObject(objectName); if (obj == nullptr) { @@ -65,7 +85,7 @@ bool WidgetState::setInnerObjectProp(const std::string& objectName, const std::s } bool WidgetState::popChanges(rbjson::Object& state) { - std::lock_guard lock(m_mutex); + std::unique_lock lock(m_mutex); if (m_bloom_tick == 0) return false; @@ -123,7 +143,7 @@ void WidgetState::markChanged(const std::string& key) { if (m_uuid == 0) return; - std::lock_guard lock(m_mutex); + std::unique_lock lock(m_mutex); markChangedLocked(key); } @@ -154,7 +174,7 @@ bool WidgetState::wasChangedInTickLocked(const char *key, size_t key_len) const } bool WidgetState::remarkAllChanges() { - std::lock_guard lock(m_mutex); + std::unique_lock lock(m_mutex); if (m_bloom_global == 0) return false; m_bloom_tick = m_bloom_global; diff --git a/src/widgets/widget.h b/src/widgets/widget.h index 9e20f60..70374cb 100644 --- a/src/widgets/widget.h +++ b/src/widgets/widget.h @@ -107,7 +107,11 @@ class WidgetState { WidgetState(uint16_t uuid, float x, float y, float w, float h, uint16_t tab); uint16_t uuid() const { return m_uuid; } - const rbjson::Object& data() const { return m_data; } + + std::string getString(const std::string& key, std::string def = "") const; + int64_t getInt(const std::string& key, int64_t def = 0) const; + double getDouble(const std::string& key, double def = 0.0) const; + bool getBool(const std::string& key, bool def = false) const; bool set(const std::string& key, rbjson::Value* value); bool setInnerObjectProp(const std::string& objectName, const std::string& propertyName, @@ -120,12 +124,19 @@ class WidgetState { } WidgetPos pos() const { - return WidgetPos(m_data.getInt("p")); + return WidgetPos(getInt("p")); } void setPos(const WidgetPos& p) { - m_data.set("p", p.encoded()); + set("p", new rbjson::Number(p.encoded())); + } + + // Use dataLocked only with sharedStateLock or uniqueStateLock locked. + // shared is for reads, unique for writes. + std::unique_lock uniqueStateLock() { + return std::unique_lock(m_mutex); } + const rbjson::Object& dataLocked() const { return m_data; } private: // Each mutex is ~100 bytes of heap allocation. Let's keep just one for this. @@ -239,7 +250,7 @@ class Widget { } uint16_t widgetTab() const { - return data().getInt("tab"); + return m_state->getInt("tab"); } void setCss(const std::string& propertyName, const std::string& value) { @@ -247,7 +258,8 @@ class Widget { } std::string css(const std::string& propertyName) const { - auto* css = data().getObject("css"); + auto lock = m_state->uniqueStateLock(); + auto* css = m_state->dataLocked().getObject("css"); if (css == nullptr) return ""; return css->getString(propertyName); @@ -260,8 +272,6 @@ class Widget { Widget& operator=(const Widget&) = delete; - const rbjson::Object& data() const { return static_cast(m_state)->data(); } - WidgetState* m_state; private: