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

@@ -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(

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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());
}
}