Allow widgets to be added by passing value suppliers (#1690)

This commit is contained in:
Sam Carlberg
2019-05-30 12:45:23 -04:00
committed by Peter Johnson
parent 4a00cd77bb
commit b52e40b80c
10 changed files with 788 additions and 6 deletions

View File

@@ -141,6 +141,108 @@ SimpleWidget& ShuffleboardContainer::Add(
return Add(title, nt::Value::MakeStringArray(defaultValue));
}
SuppliedValueWidget<std::string>& ShuffleboardContainer::AddString(
const wpi::Twine& title, std::function<std::string()> supplier) {
static auto setter = [](nt::NetworkTableEntry entry, std::string value) {
entry.SetString(value);
};
CheckTitle(title);
auto widget = std::make_unique<SuppliedValueWidget<std::string>>(
*this, title, supplier, setter);
auto ptr = widget.get();
m_components.emplace_back(std::move(widget));
return *ptr;
}
SuppliedValueWidget<double>& ShuffleboardContainer::AddNumber(
const wpi::Twine& title, std::function<double()> supplier) {
static auto setter = [](nt::NetworkTableEntry entry, double value) {
entry.SetDouble(value);
};
CheckTitle(title);
auto widget = std::make_unique<SuppliedValueWidget<double>>(*this, title,
supplier, setter);
auto ptr = widget.get();
m_components.emplace_back(std::move(widget));
return *ptr;
}
SuppliedValueWidget<bool>& ShuffleboardContainer::AddBoolean(
const wpi::Twine& title, std::function<bool()> supplier) {
static auto setter = [](nt::NetworkTableEntry entry, bool value) {
entry.SetBoolean(value);
};
CheckTitle(title);
auto widget = std::make_unique<SuppliedValueWidget<bool>>(*this, title,
supplier, setter);
auto ptr = widget.get();
m_components.emplace_back(std::move(widget));
return *ptr;
}
SuppliedValueWidget<std::vector<std::string>>&
ShuffleboardContainer::AddStringArray(
const wpi::Twine& title,
std::function<std::vector<std::string>()> supplier) {
static auto setter = [](nt::NetworkTableEntry entry,
std::vector<std::string> value) {
entry.SetStringArray(value);
};
CheckTitle(title);
auto widget = std::make_unique<SuppliedValueWidget<std::vector<std::string>>>(
*this, title, supplier, setter);
auto ptr = widget.get();
m_components.emplace_back(std::move(widget));
return *ptr;
}
SuppliedValueWidget<std::vector<double>>& ShuffleboardContainer::AddNumberArray(
const wpi::Twine& title, std::function<std::vector<double>()> supplier) {
static auto setter = [](nt::NetworkTableEntry entry,
std::vector<double> value) {
entry.SetDoubleArray(value);
};
CheckTitle(title);
auto widget = std::make_unique<SuppliedValueWidget<std::vector<double>>>(
*this, title, supplier, setter);
auto ptr = widget.get();
m_components.emplace_back(std::move(widget));
return *ptr;
}
SuppliedValueWidget<std::vector<int>>& ShuffleboardContainer::AddBooleanArray(
const wpi::Twine& title, std::function<std::vector<int>()> supplier) {
static auto setter = [](nt::NetworkTableEntry entry, std::vector<int> value) {
entry.SetBooleanArray(value);
};
CheckTitle(title);
auto widget = std::make_unique<SuppliedValueWidget<std::vector<int>>>(
*this, title, supplier, setter);
auto ptr = widget.get();
m_components.emplace_back(std::move(widget));
return *ptr;
}
SuppliedValueWidget<wpi::StringRef>& ShuffleboardContainer::AddRaw(
const wpi::Twine& title, std::function<wpi::StringRef()> supplier) {
static auto setter = [](nt::NetworkTableEntry entry, wpi::StringRef value) {
entry.SetRaw(value);
};
CheckTitle(title);
auto widget = std::make_unique<SuppliedValueWidget<wpi::StringRef>>(
*this, title, supplier, setter);
auto ptr = widget.get();
m_components.emplace_back(std::move(widget));
return *ptr;
}
SimpleWidget& ShuffleboardContainer::AddPersistent(
const wpi::Twine& title, std::shared_ptr<nt::Value> defaultValue) {
auto& widget = Add(title, defaultValue);

View File

@@ -7,6 +7,7 @@
#pragma once
#include <functional>
#include <memory>
#include <string>
#include <vector>
@@ -24,6 +25,7 @@
#include "frc/shuffleboard/LayoutType.h"
#include "frc/shuffleboard/ShuffleboardComponentBase.h"
#include "frc/shuffleboard/ShuffleboardValue.h"
#include "frc/shuffleboard/SuppliedValueWidget.h"
namespace cs {
class VideoSource;
@@ -262,6 +264,98 @@ class ShuffleboardContainer : public virtual ShuffleboardValue,
SimpleWidget& Add(const wpi::Twine& title,
wpi::ArrayRef<std::string> defaultValue);
/**
* Adds a widget to this container. The widget will display the data provided
* by the value supplier. Changes made on the dashboard will not propagate to
* the widget object, and will be overridden by values from the value
* supplier.
*
* @param title the title of the widget
* @param valueSupplier the supplier for values
* @return a widget to display data
*/
SuppliedValueWidget<std::string>& AddString(
const wpi::Twine& title, std::function<std::string()> supplier);
/**
* Adds a widget to this container. The widget will display the data provided
* by the value supplier. Changes made on the dashboard will not propagate to
* the widget object, and will be overridden by values from the value
* supplier.
*
* @param title the title of the widget
* @param valueSupplier the supplier for values
* @return a widget to display data
*/
SuppliedValueWidget<double>& AddNumber(const wpi::Twine& title,
std::function<double()> supplier);
/**
* Adds a widget to this container. The widget will display the data provided
* by the value supplier. Changes made on the dashboard will not propagate to
* the widget object, and will be overridden by values from the value
* supplier.
*
* @param title the title of the widget
* @param valueSupplier the supplier for values
* @return a widget to display data
*/
SuppliedValueWidget<bool>& AddBoolean(const wpi::Twine& title,
std::function<bool()> supplier);
/**
* Adds a widget to this container. The widget will display the data provided
* by the value supplier. Changes made on the dashboard will not propagate to
* the widget object, and will be overridden by values from the value
* supplier.
*
* @param title the title of the widget
* @param valueSupplier the supplier for values
* @return a widget to display data
*/
SuppliedValueWidget<std::vector<std::string>>& AddStringArray(
const wpi::Twine& title,
std::function<std::vector<std::string>()> supplier);
/**
* Adds a widget to this container. The widget will display the data provided
* by the value supplier. Changes made on the dashboard will not propagate to
* the widget object, and will be overridden by values from the value
* supplier.
*
* @param title the title of the widget
* @param valueSupplier the supplier for values
* @return a widget to display data
*/
SuppliedValueWidget<std::vector<double>>& AddNumberArray(
const wpi::Twine& title, std::function<std::vector<double>()> supplier);
/**
* Adds a widget to this container. The widget will display the data provided
* by the value supplier. Changes made on the dashboard will not propagate to
* the widget object, and will be overridden by values from the value
* supplier.
*
* @param title the title of the widget
* @param valueSupplier the supplier for values
* @return a widget to display data
*/
SuppliedValueWidget<std::vector<int>>& AddBooleanArray(
const wpi::Twine& title, std::function<std::vector<int>()> supplier);
/**
* Adds a widget to this container. The widget will display the data provided
* by the value supplier. Changes made on the dashboard will not propagate to
* the widget object, and will be overridden by values from the value
* supplier.
*
* @param title the title of the widget
* @param valueSupplier the supplier for values
* @return a widget to display data
*/
SuppliedValueWidget<wpi::StringRef>& AddRaw(
const wpi::Twine& title, std::function<wpi::StringRef()> supplier);
/**
* Adds a widget to this container to display a simple piece of data.
*

View File

@@ -0,0 +1,48 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <functional>
#include <memory>
#include <networktables/NetworkTable.h>
#include <networktables/NetworkTableEntry.h>
#include <wpi/Twine.h>
#include "frc/shuffleboard/ShuffleboardComponent.h"
#include "frc/shuffleboard/ShuffleboardComponent.inc"
#include "frc/shuffleboard/ShuffleboardComponentBase.h"
#include "frc/shuffleboard/ShuffleboardContainer.h"
#include "frc/shuffleboard/ShuffleboardWidget.h"
namespace frc {
template <typename T>
class SuppliedValueWidget : public ShuffleboardWidget<SuppliedValueWidget<T> > {
public:
SuppliedValueWidget(ShuffleboardContainer& parent, const wpi::Twine& title,
std::function<T()> supplier,
std::function<void(nt::NetworkTableEntry, T)> setter)
: ShuffleboardValue(title),
ShuffleboardWidget<SuppliedValueWidget<T> >(parent, title),
m_supplier(supplier),
m_setter(setter) {}
void BuildInto(std::shared_ptr<nt::NetworkTable> parentTable,
std::shared_ptr<nt::NetworkTable> metaTable) override {
this->BuildMetadata(metaTable);
metaTable->GetEntry("Controllable").SetBoolean(false);
auto entry = parentTable->GetEntry(this->GetTitle());
m_setter(entry, m_supplier());
}
private:
std::function<T()> m_supplier;
std::function<void(nt::NetworkTableEntry, T)> m_setter;
};
} // namespace frc

View File

@@ -0,0 +1,107 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include <networktables/NetworkTableEntry.h>
#include <networktables/NetworkTableInstance.h>
#include "frc/shuffleboard/ShuffleboardInstance.h"
#include "frc/shuffleboard/ShuffleboardTab.h"
#include "gtest/gtest.h"
using namespace frc;
class SuppliedValueWidgetTest : public testing::Test {
void SetUp() override {
m_ntInstance = nt::NetworkTableInstance::Create();
m_instance = std::make_unique<detail::ShuffleboardInstance>(m_ntInstance);
m_tab = &(m_instance->GetTab("Tab"));
}
protected:
nt::NetworkTableInstance m_ntInstance;
ShuffleboardTab* m_tab;
std::unique_ptr<detail::ShuffleboardInstance> m_instance;
};
TEST_F(SuppliedValueWidgetTest, AddString) {
std::string str = "foo";
m_tab->AddString("String", [&str]() { return str; });
auto entry = m_ntInstance.GetEntry("/Shuffleboard/Tab/String");
m_instance->Update();
EXPECT_EQ("foo", entry.GetValue()->GetString());
}
TEST_F(SuppliedValueWidgetTest, AddNumber) {
int num = 0;
m_tab->AddNumber("Num", [&num]() { return ++num; });
auto entry = m_ntInstance.GetEntry("/Shuffleboard/Tab/Num");
m_instance->Update();
EXPECT_FLOAT_EQ(1.0, entry.GetValue()->GetDouble());
}
TEST_F(SuppliedValueWidgetTest, AddBoolean) {
bool value = true;
m_tab->AddBoolean("Bool", [&value]() { return value; });
auto entry = m_ntInstance.GetEntry("/Shuffleboard/Tab/Bool");
m_instance->Update();
EXPECT_EQ(true, entry.GetValue()->GetBoolean());
}
TEST_F(SuppliedValueWidgetTest, AddStringArray) {
std::vector<std::string> strings = {"foo", "bar"};
m_tab->AddStringArray("Strings", [&strings]() { return strings; });
auto entry = m_ntInstance.GetEntry("/Shuffleboard/Tab/Strings");
m_instance->Update();
auto actual = entry.GetValue()->GetStringArray();
EXPECT_EQ(strings.size(), actual.size());
for (size_t i = 0; i < strings.size(); i++) {
EXPECT_EQ(strings[i], actual[i]);
}
}
TEST_F(SuppliedValueWidgetTest, AddNumberArray) {
std::vector<double> nums = {0, 1, 2, 3};
m_tab->AddNumberArray("Numbers", [&nums]() { return nums; });
auto entry = m_ntInstance.GetEntry("/Shuffleboard/Tab/Numbers");
m_instance->Update();
auto actual = entry.GetValue()->GetDoubleArray();
EXPECT_EQ(nums.size(), actual.size());
for (size_t i = 0; i < nums.size(); i++) {
EXPECT_FLOAT_EQ(nums[i], actual[i]);
}
}
TEST_F(SuppliedValueWidgetTest, AddBooleanArray) {
std::vector<int> bools = {true, false};
m_tab->AddBooleanArray("Booleans", [&bools]() { return bools; });
auto entry = m_ntInstance.GetEntry("/Shuffleboard/Tab/Booleans");
m_instance->Update();
auto actual = entry.GetValue()->GetBooleanArray();
EXPECT_EQ(bools.size(), actual.size());
for (size_t i = 0; i < bools.size(); i++) {
EXPECT_FLOAT_EQ(bools[i], actual[i]);
}
}
TEST_F(SuppliedValueWidgetTest, AddRaw) {
wpi::StringRef bytes = "\1\2\3";
m_tab->AddRaw("Raw", [&bytes]() { return bytes; });
auto entry = m_ntInstance.GetEntry("/Shuffleboard/Tab/Raw");
m_instance->Update();
auto actual = entry.GetValue()->GetRaw();
EXPECT_EQ(bytes, actual);
}