mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-25 01:41:43 +00:00
Allow widgets to be added by passing value suppliers (#1690)
This commit is contained in:
committed by
Peter Johnson
parent
4a00cd77bb
commit
b52e40b80c
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* 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. */
|
||||
@@ -15,6 +15,10 @@ import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.DoubleSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import edu.wpi.first.networktables.NetworkTableEntry;
|
||||
import edu.wpi.first.wpilibj.Sendable;
|
||||
@@ -22,6 +26,7 @@ import edu.wpi.first.wpilibj.Sendable;
|
||||
/**
|
||||
* A helper class for Shuffleboard containers to handle common child operations.
|
||||
*/
|
||||
@SuppressWarnings("PMD.TooManyMethods")
|
||||
final class ContainerHelper {
|
||||
private final ShuffleboardContainer m_container;
|
||||
private final Set<String> m_usedTitles = new HashSet<>();
|
||||
@@ -79,6 +84,55 @@ final class ContainerHelper {
|
||||
return widget;
|
||||
}
|
||||
|
||||
SuppliedValueWidget<String> addString(String title, Supplier<String> valueSupplier) {
|
||||
precheck(title, valueSupplier);
|
||||
return addSupplied(title, valueSupplier, NetworkTableEntry::setString);
|
||||
}
|
||||
|
||||
SuppliedValueWidget<Double> addNumber(String title, DoubleSupplier valueSupplier) {
|
||||
precheck(title, valueSupplier);
|
||||
return addSupplied(title, valueSupplier::getAsDouble, NetworkTableEntry::setDouble);
|
||||
}
|
||||
|
||||
SuppliedValueWidget<Boolean> addBoolean(String title, BooleanSupplier valueSupplier) {
|
||||
precheck(title, valueSupplier);
|
||||
return addSupplied(title, valueSupplier::getAsBoolean, NetworkTableEntry::setBoolean);
|
||||
}
|
||||
|
||||
SuppliedValueWidget<String[]> addStringArray(String title, Supplier<String[]> valueSupplier) {
|
||||
precheck(title, valueSupplier);
|
||||
return addSupplied(title, valueSupplier, NetworkTableEntry::setStringArray);
|
||||
}
|
||||
|
||||
SuppliedValueWidget<double[]> addDoubleArray(String title, Supplier<double[]> valueSupplier) {
|
||||
precheck(title, valueSupplier);
|
||||
return addSupplied(title, valueSupplier, NetworkTableEntry::setDoubleArray);
|
||||
}
|
||||
|
||||
SuppliedValueWidget<boolean[]> addBooleanArray(String title, Supplier<boolean[]> valueSupplier) {
|
||||
precheck(title, valueSupplier);
|
||||
return addSupplied(title, valueSupplier, NetworkTableEntry::setBooleanArray);
|
||||
}
|
||||
|
||||
SuppliedValueWidget<byte[]> addRaw(String title, Supplier<byte[]> valueSupplier) {
|
||||
precheck(title, valueSupplier);
|
||||
return addSupplied(title, valueSupplier, NetworkTableEntry::setRaw);
|
||||
}
|
||||
|
||||
private void precheck(String title, Object valueSupplier) {
|
||||
Objects.requireNonNull(title, "Title cannot be null");
|
||||
Objects.requireNonNull(valueSupplier, "Value supplier cannot be null");
|
||||
checkTitle(title);
|
||||
}
|
||||
|
||||
private <T> SuppliedValueWidget<T> addSupplied(String title,
|
||||
Supplier<T> supplier,
|
||||
BiConsumer<NetworkTableEntry, T> setter) {
|
||||
SuppliedValueWidget<T> widget = new SuppliedValueWidget<>(m_container, title, supplier, setter);
|
||||
m_components.add(widget);
|
||||
return widget;
|
||||
}
|
||||
|
||||
private static void checkNtType(Object data) {
|
||||
if (!NetworkTableEntry.isValidDataType(data)) {
|
||||
throw new IllegalArgumentException(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* 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. */
|
||||
@@ -9,6 +9,9 @@ package edu.wpi.first.wpilibj.shuffleboard;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.DoubleSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import edu.wpi.cscore.VideoSource;
|
||||
import edu.wpi.first.wpilibj.Sendable;
|
||||
@@ -16,6 +19,7 @@ import edu.wpi.first.wpilibj.Sendable;
|
||||
/**
|
||||
* Common interface for objects that can contain shuffleboard components.
|
||||
*/
|
||||
@SuppressWarnings("PMD.TooManyMethods")
|
||||
public interface ShuffleboardContainer extends ShuffleboardValue {
|
||||
|
||||
/**
|
||||
@@ -80,8 +84,8 @@ public interface ShuffleboardContainer extends ShuffleboardValue {
|
||||
/**
|
||||
* Adds a widget to this container to display the given video stream.
|
||||
*
|
||||
* @param title the title of the widget
|
||||
* @param video the video stream to display
|
||||
* @param title the title of the widget
|
||||
* @param video the video stream to display
|
||||
* @return a widget to display the sendable data
|
||||
* @throws IllegalArgumentException if a widget already exists in this container with the given
|
||||
* title
|
||||
@@ -124,6 +128,104 @@ public interface ShuffleboardContainer extends ShuffleboardValue {
|
||||
*/
|
||||
SimpleWidget add(String title, Object defaultValue) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws IllegalArgumentException if a widget already exists in this container with the given
|
||||
* title
|
||||
*/
|
||||
SuppliedValueWidget<String> addString(String title, Supplier<String> valueSupplier)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws IllegalArgumentException if a widget already exists in this container with the given
|
||||
* title
|
||||
*/
|
||||
SuppliedValueWidget<Double> addNumber(String title, DoubleSupplier valueSupplier)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws IllegalArgumentException if a widget already exists in this container with the given
|
||||
* title
|
||||
*/
|
||||
SuppliedValueWidget<Boolean> addBoolean(String title, BooleanSupplier valueSupplier)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws IllegalArgumentException if a widget already exists in this container with the given
|
||||
* title
|
||||
*/
|
||||
SuppliedValueWidget<String[]> addStringArray(String title, Supplier<String[]> valueSupplier)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws IllegalArgumentException if a widget already exists in this container with the given
|
||||
* title
|
||||
*/
|
||||
SuppliedValueWidget<double[]> addDoubleArray(String title, Supplier<double[]> valueSupplier)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws IllegalArgumentException if a widget already exists in this container with the given
|
||||
* title
|
||||
*/
|
||||
SuppliedValueWidget<boolean[]> addBooleanArray(String title, Supplier<boolean[]> valueSupplier)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws IllegalArgumentException if a widget already exists in this container with the given
|
||||
* title
|
||||
*/
|
||||
SuppliedValueWidget<byte[]> addRaw(String title, Supplier<byte[]> valueSupplier)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Adds a widget to this container to display a simple piece of data. Unlike
|
||||
* {@link #add(String, Object)}, the value in the widget will be saved on the robot and will be
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* 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. */
|
||||
@@ -10,6 +10,9 @@ package edu.wpi.first.wpilibj.shuffleboard;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.DoubleSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import edu.wpi.first.networktables.NetworkTable;
|
||||
import edu.wpi.first.wpilibj.Sendable;
|
||||
@@ -17,6 +20,7 @@ import edu.wpi.first.wpilibj.Sendable;
|
||||
/**
|
||||
* A layout in a Shuffleboard tab. Layouts can contain widgets and other layouts.
|
||||
*/
|
||||
@SuppressWarnings("PMD.TooManyMethods")
|
||||
public class ShuffleboardLayout extends ShuffleboardComponent<ShuffleboardLayout>
|
||||
implements ShuffleboardContainer {
|
||||
private final ContainerHelper m_helper = new ContainerHelper(this);
|
||||
@@ -55,6 +59,55 @@ public class ShuffleboardLayout extends ShuffleboardComponent<ShuffleboardLayout
|
||||
return m_helper.add(title, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<String> addString(String title,
|
||||
Supplier<String> valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addString(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<Double> addNumber(String title,
|
||||
DoubleSupplier valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addNumber(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<Boolean> addBoolean(String title,
|
||||
BooleanSupplier valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addBoolean(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<String[]> addStringArray(String title,
|
||||
Supplier<String[]> valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addStringArray(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<double[]> addDoubleArray(String title,
|
||||
Supplier<double[]> valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addDoubleArray(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<boolean[]> addBooleanArray(String title,
|
||||
Supplier<boolean[]> valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addBooleanArray(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<byte[]> addRaw(String title,
|
||||
Supplier<byte[]> valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addRaw(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildInto(NetworkTable parentTable, NetworkTable metaTable) {
|
||||
buildMetadata(metaTable);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* 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. */
|
||||
@@ -9,6 +9,9 @@ package edu.wpi.first.wpilibj.shuffleboard;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.DoubleSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import edu.wpi.first.networktables.NetworkTable;
|
||||
import edu.wpi.first.wpilibj.Sendable;
|
||||
@@ -19,6 +22,7 @@ import edu.wpi.first.wpilibj.Sendable;
|
||||
* can also be added to layouts with {@link #getLayout(String, String)}; layouts can be nested
|
||||
* arbitrarily deep (note that too many levels may make deeper components unusable).
|
||||
*/
|
||||
@SuppressWarnings("PMD.TooManyMethods")
|
||||
public final class ShuffleboardTab implements ShuffleboardContainer {
|
||||
private final ContainerHelper m_helper = new ContainerHelper(this);
|
||||
private final ShuffleboardRoot m_root;
|
||||
@@ -68,6 +72,55 @@ public final class ShuffleboardTab implements ShuffleboardContainer {
|
||||
return m_helper.add(title, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<String> addString(String title,
|
||||
Supplier<String> valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addString(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<Double> addNumber(String title,
|
||||
DoubleSupplier valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addNumber(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<Boolean> addBoolean(String title,
|
||||
BooleanSupplier valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addBoolean(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<String[]> addStringArray(String title,
|
||||
Supplier<String[]> valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addStringArray(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<double[]> addDoubleArray(String title,
|
||||
Supplier<double[]> valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addDoubleArray(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<boolean[]> addBooleanArray(String title,
|
||||
Supplier<boolean[]> valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addBooleanArray(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuppliedValueWidget<byte[]> addRaw(String title,
|
||||
Supplier<byte[]> valueSupplier)
|
||||
throws IllegalArgumentException {
|
||||
return m_helper.addRaw(title, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildInto(NetworkTable parentTable, NetworkTable metaTable) {
|
||||
NetworkTable tabTable = parentTable.getSubTable(m_title);
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.wpilibj.shuffleboard;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import edu.wpi.first.networktables.NetworkTable;
|
||||
import edu.wpi.first.networktables.NetworkTableEntry;
|
||||
|
||||
/**
|
||||
* A Shuffleboard widget whose value is provided by user code.
|
||||
*
|
||||
* @param <T> the type of values in the widget
|
||||
*/
|
||||
public final class SuppliedValueWidget<T> extends ShuffleboardWidget<SuppliedValueWidget<T>> {
|
||||
private final Supplier<T> m_supplier;
|
||||
private final BiConsumer<NetworkTableEntry, T> m_setter;
|
||||
|
||||
/**
|
||||
* Package-private constructor for use by the Shuffleboard API.
|
||||
*
|
||||
* @param parent the parent container for the widget
|
||||
* @param title the title of the widget
|
||||
* @param supplier the supplier for values to place in the NetworkTable entry
|
||||
* @param setter the function for placing values in the NetworkTable entry
|
||||
*/
|
||||
SuppliedValueWidget(ShuffleboardContainer parent,
|
||||
String title,
|
||||
Supplier<T> supplier,
|
||||
BiConsumer<NetworkTableEntry, T> setter) {
|
||||
super(parent, title);
|
||||
this.m_supplier = supplier;
|
||||
this.m_setter = setter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildInto(NetworkTable parentTable, NetworkTable metaTable) {
|
||||
buildMetadata(metaTable);
|
||||
metaTable.getEntry("Controllable").setBoolean(false);
|
||||
|
||||
NetworkTableEntry entry = parentTable.getEntry(getTitle());
|
||||
m_setter.accept(entry, m_supplier.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.wpilibj.shuffleboard;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import edu.wpi.first.networktables.NetworkTableEntry;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class SuppliedValueWidgetTest {
|
||||
private NetworkTableInstance m_ntInstance;
|
||||
private ShuffleboardInstance m_instance;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
m_ntInstance = NetworkTableInstance.create();
|
||||
m_instance = new ShuffleboardInstance(m_ntInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddString() {
|
||||
AtomicInteger count = new AtomicInteger(0);
|
||||
m_instance.getTab("Tab")
|
||||
.addString("Title", () -> Integer.toString(count.incrementAndGet()));
|
||||
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
|
||||
|
||||
m_instance.update();
|
||||
assertEquals("1", entry.getString(null));
|
||||
|
||||
m_instance.update();
|
||||
assertEquals("2", entry.getString(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddDouble() {
|
||||
AtomicInteger num = new AtomicInteger(0);
|
||||
m_instance.getTab("Tab")
|
||||
.addNumber("Title", num::incrementAndGet);
|
||||
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
|
||||
|
||||
m_instance.update();
|
||||
assertEquals(1, entry.getDouble(0));
|
||||
|
||||
m_instance.update();
|
||||
assertEquals(2, entry.getDouble(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddBoolean() {
|
||||
boolean[] bool = {false};
|
||||
m_instance.getTab("Tab")
|
||||
.addBoolean("Title", () -> bool[0] = !bool[0]);
|
||||
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
|
||||
|
||||
m_instance.update();
|
||||
assertTrue(entry.getBoolean(false));
|
||||
|
||||
m_instance.update();
|
||||
assertFalse(entry.getBoolean(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddStringArray() {
|
||||
String[] arr = {"foo", "bar"};
|
||||
m_instance.getTab("Tab")
|
||||
.addStringArray("Title", () -> arr);
|
||||
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
|
||||
|
||||
m_instance.update();
|
||||
assertArrayEquals(arr, entry.getStringArray(new String[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddDoubleArray() {
|
||||
double[] arr = {0, 1};
|
||||
m_instance.getTab("Tab")
|
||||
.addDoubleArray("Title", () -> arr);
|
||||
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
|
||||
|
||||
m_instance.update();
|
||||
assertArrayEquals(arr, entry.getDoubleArray(new double[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddBooleanArray() {
|
||||
boolean[] arr = {true, false};
|
||||
m_instance.getTab("Tab")
|
||||
.addBooleanArray("Title", () -> arr);
|
||||
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
|
||||
|
||||
m_instance.update();
|
||||
assertArrayEquals(arr, entry.getBooleanArray(new boolean[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddRawBytes() {
|
||||
byte[] arr = {0, 1, 2, 3};
|
||||
m_instance.getTab("Tab")
|
||||
.addRaw("Title", () -> arr);
|
||||
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
|
||||
|
||||
m_instance.update();
|
||||
assertArrayEquals(arr, entry.getRaw(new byte[0]));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user