C++ Shuffleboard fixes (#1595)

* Fix C++ ShuffleboardComponent template type

* Fix `WithWidget(WidgetType&)`not being properly capitalized

* Fix data members across dll boundaries by using enum for built in types
This commit is contained in:
Sam Carlberg
2019-02-14 23:44:30 -05:00
committed by Peter Johnson
parent 182758c05b
commit e8b24717c7
12 changed files with 184 additions and 89 deletions

View File

@@ -18,7 +18,7 @@ constexpr std::chrono::milliseconds Watchdog::kMinPrintPeriod;
class Watchdog::Thread : public wpi::SafeThread {
public:
template <typename T>
struct DerefGreater : public std::binary_function<T, T, bool> {
struct DerefGreater {
constexpr bool operator()(const T& lhs, const T& rhs) const {
return *lhs > *rhs;
}

View File

@@ -1,13 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 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 "frc/shuffleboard/BuiltInLayouts.h"
using namespace frc;
const LayoutType BuiltInLayouts::kList{"List Layout"};
const LayoutType BuiltInLayouts::kGrid{"Grid Layout"};

View File

@@ -1,35 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 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 "frc/shuffleboard/BuiltInWidgets.h"
using namespace frc;
const WidgetType BuiltInWidgets::kTextView{"Text View"};
const WidgetType BuiltInWidgets::kNumberSlider{"Number Slider"};
const WidgetType BuiltInWidgets::kNumberBar{"Number Bar"};
const WidgetType BuiltInWidgets::kDial{"Simple Dial"};
const WidgetType BuiltInWidgets::kGraph{"Graph"};
const WidgetType BuiltInWidgets::kBooleanBox{"Boolean Box"};
const WidgetType BuiltInWidgets::kToggleButton{"Toggle Button"};
const WidgetType BuiltInWidgets::kToggleSwitch{"Toggle Switch"};
const WidgetType BuiltInWidgets::kVoltageView{"Voltage View"};
const WidgetType BuiltInWidgets::kPowerDistributionPanel{"PDP"};
const WidgetType BuiltInWidgets::kComboBoxChooser{"ComboBox Chooser"};
const WidgetType BuiltInWidgets::kSplitButtonChooser{"Split Button Chooser"};
const WidgetType BuiltInWidgets::kEncoder{"Encoder"};
const WidgetType BuiltInWidgets::kSpeedController{"Speed Controller"};
const WidgetType BuiltInWidgets::kCommand{"Command"};
const WidgetType BuiltInWidgets::kPIDCommand{"PID Command"};
const WidgetType BuiltInWidgets::kPIDController{"PID Controller"};
const WidgetType BuiltInWidgets::kAccelerometer{"Accelerometer"};
const WidgetType BuiltInWidgets::k3AxisAccelerometer{"3-Axis Accelerometer"};
const WidgetType BuiltInWidgets::kGyro{"Gyro"};
const WidgetType BuiltInWidgets::kRelay{"Relay"};
const WidgetType BuiltInWidgets::kDifferentialDrive{"Differential Drivebase"};
const WidgetType BuiltInWidgets::kMecanumDrive{"Mecanum Drivebase"};
const WidgetType BuiltInWidgets::kCameraStream{"Camera Stream"};

View File

@@ -18,6 +18,12 @@
using namespace frc;
static constexpr const char* layoutStrings[] = {"List Layout", "Grid Layout"};
static constexpr const char* GetStringFromBuiltInLayout(BuiltInLayouts layout) {
return layoutStrings[static_cast<int>(layout)];
}
ShuffleboardContainer::ShuffleboardContainer(const wpi::Twine& title)
: ShuffleboardValue(title) {}
@@ -26,6 +32,11 @@ ShuffleboardContainer::GetComponents() const {
return m_components;
}
ShuffleboardLayout& ShuffleboardContainer::GetLayout(const wpi::Twine& title,
BuiltInLayouts type) {
return GetLayout(title, GetStringFromBuiltInLayout(type));
}
ShuffleboardLayout& ShuffleboardContainer::GetLayout(const wpi::Twine& title,
const LayoutType& type) {
return GetLayout(title, type.GetLayoutName());

View File

@@ -0,0 +1,41 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 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 "frc/shuffleboard/ShuffleboardWidget.h"
using namespace frc;
static constexpr const char* widgetStrings[] = {
"Text View",
"Number Slider",
"Number Bar",
"Simple Dial",
"Graph",
"Boolean Box",
"Toggle Button",
"Toggle Switch",
"Voltage View",
"PDP",
"ComboBox Chooser",
"Split Button Chooser",
"Encoder",
"Speed Controller",
"Command",
"PID Command",
"PID Controller",
"Accelerometer",
"3-Axis Accelerometer",
"Gyro",
"Relay",
"Differential Drivebase",
"Mecanum Drivebase",
"Camera Stream",
};
const char* detail::GetStringForWidgetType(BuiltInWidgets type) {
return widgetStrings[static_cast<int>(type)];
}

View File

@@ -19,8 +19,7 @@ namespace frc {
* .GetLayout(BuiltinLayouts::kList, "My List");
* }</pre>
*/
class BuiltInLayouts {
public:
enum class BuiltInLayouts {
/**
* Groups components in a vertical list. New widgets added to the layout will
* be placed at the bottom of the list. <br>Custom properties: <table>
@@ -30,7 +29,7 @@ class BuiltInLayouts {
* {@code ["TOP", "LEFT", "BOTTOM", "RIGHT", "HIDDEN"}</td></tr>
* </table>
*/
static const LayoutType kList;
kList,
/**
* Groups components in an <i>n</i> x <i>m</i> grid. Grid layouts default to
@@ -47,7 +46,7 @@ class BuiltInLayouts {
* </tr>
* </table>
*/
static const LayoutType kGrid;
kGrid
};
} // namespace frc

View File

@@ -25,8 +25,7 @@ namespace frc {
* <p>Each value in this enum goes into detail on what data types that widget
* can support, as well as the custom properties that widget uses.
*/
class BuiltInWidgets {
public:
enum class BuiltInWidgets {
/**
* Displays a value with a simple text field.
* <br>Supported types:
@@ -37,7 +36,7 @@ class BuiltInWidgets {
* </ul>
* <br>This widget has no custom properties.
*/
static const WidgetType kTextView;
kTextView,
/**
* Displays a number with a controllable slider.
* <br>Supported types:
@@ -54,7 +53,7 @@ class BuiltInWidgets {
* slider by with the arrow keys</td></tr>
* </table>
*/
static const WidgetType kNumberSlider;
kNumberSlider,
/**
* Displays a number with a view-only bar.
* <br>Supported types:
@@ -71,7 +70,7 @@ class BuiltInWidgets {
* of the bar</td></tr>
* </table>
*/
static const WidgetType kNumberBar;
kNumberBar,
/**
* Displays a number with a view-only dial. Displayed values are rounded to
* the nearest integer. <br>Supported types: <ul> <li>Number</li>
@@ -86,7 +85,7 @@ class BuiltInWidgets {
* value as text</td></tr>
* </table>
*/
static const WidgetType kDial;
kDial,
/**
* Displays a number with a graph. <strong>NOTE:</strong> graphs can be taxing
* on the computer running the dashboard. Keep the number of visible data
@@ -103,7 +102,7 @@ class BuiltInWidgets {
* <td>How long, in seconds, should past data be visible for</td></tr>
* </table>
*/
static const WidgetType kGraph;
kGraph,
/**
* Displays a boolean value as a large colored box.
* <br>Supported types:
@@ -121,7 +120,7 @@ class BuiltInWidgets {
* <td>Can be specified as a string or a number</td></tr>
* </table>
*/
static const WidgetType kBooleanBox;
kBooleanBox,
/**
* Displays a boolean with a large interactive toggle button.
* <br>Supported types:
@@ -130,7 +129,7 @@ class BuiltInWidgets {
* </ul>
* <br>This widget has no custom properties.
*/
static const WidgetType kToggleButton;
kToggleButton,
/**
* Displays a boolean with a fixed-size toggle switch.
* <br>Supported types:
@@ -139,7 +138,7 @@ class BuiltInWidgets {
* </ul>
* <br>This widget has no custom properties.
*/
static const WidgetType kToggleSwitch;
kToggleSwitch,
/**
* Displays an analog input or a raw number with a number bar.
* <br>Supported types:
@@ -162,7 +161,7 @@ class BuiltInWidgets {
* bar</td></tr>
* </table>
*/
static const WidgetType kVoltageView;
kVoltageView,
/**
* Displays a {@link edu.wpi.first.wpilibj.PowerDistributionPanel
* PowerDistributionPanel}. <br>Supported types: <ul> <li>{@link
@@ -175,7 +174,7 @@ class BuiltInWidgets {
* <td>Whether or not to display the voltage and current draw</td></tr>
* </table>
*/
static const WidgetType kPowerDistributionPanel;
kPowerDistributionPanel,
/**
* Displays a {@link edu.wpi.first.wpilibj.smartdashboard.SendableChooser
* SendableChooser} with a dropdown combo box with a list of options.
@@ -185,7 +184,7 @@ class BuiltInWidgets {
* </ul>
* <br>This widget has no custom properties.
*/
static const WidgetType kComboBoxChooser;
kComboBoxChooser,
/**
* Displays a {@link edu.wpi.first.wpilibj.smartdashboard.SendableChooser
* SendableChooser} with a toggle button for each available option.
@@ -195,7 +194,7 @@ class BuiltInWidgets {
* </ul>
* <br>This widget has no custom properties.
*/
static const WidgetType kSplitButtonChooser;
kSplitButtonChooser,
/**
* Displays an {@link edu.wpi.first.wpilibj.Encoder} displaying its speed,
* total travelled distance, and its distance per tick. <br>Supported types:
@@ -204,7 +203,7 @@ class BuiltInWidgets {
* </ul>
* <br>This widget has no custom properties.
*/
static const WidgetType kEncoder;
kEncoder,
/**
* Displays a {@link edu.wpi.first.wpilibj.SpeedController SpeedController}.
* The speed controller will be controllable from the dashboard when test mode
@@ -228,7 +227,7 @@ class BuiltInWidgets {
* <td>One of {@code ["HORIZONTAL", "VERTICAL"]}</td></tr>
* </table>
*/
static const WidgetType kSpeedController;
kSpeedController,
/**
* Displays a command with a toggle button. Pressing the button will start the
* command, and the button will automatically release when the command
@@ -239,7 +238,7 @@ class BuiltInWidgets {
* </ul>
* <br>This widget has no custom properties.
*/
static const WidgetType kCommand;
kCommand,
/**
* Displays a PID command with a checkbox and an editor for the PIDF
* constants. Selecting the checkbox will start the command, and the checkbox
@@ -249,7 +248,7 @@ class BuiltInWidgets {
* </ul>
* <br>This widget has no custom properties.
*/
static const WidgetType kPIDCommand;
kPIDCommand,
/**
* Displays a PID controller with an editor for the PIDF constants and a
* toggle switch for enabling and disabling the controller. <br>Supported
@@ -257,7 +256,7 @@ class BuiltInWidgets {
* </ul>
* <br>This widget has no custom properties.
*/
static const WidgetType kPIDController;
kPIDController,
/**
* Displays an accelerometer with a number bar displaying the magnitude of the
* acceleration and text displaying the exact value. <br>Supported types: <ul>
@@ -278,7 +277,7 @@ class BuiltInWidgets {
* <td>Show or hide the tick marks on the number bars</td></tr>
* </table>
*/
static const WidgetType kAccelerometer;
kAccelerometer,
/**
* Displays a 3-axis accelerometer with a number bar for each axis'
* accleration. <br>Supported types: <ul> <li>{@link
@@ -298,7 +297,7 @@ class BuiltInWidgets {
* <td>Show or hide the tick marks on the number bars</td></tr>
* </table>
*/
static const WidgetType k3AxisAccelerometer;
k3AxisAccelerometer,
/**
* Displays a gyro with a dial from 0 to 360 degrees.
* <br>Supported types:
@@ -317,7 +316,7 @@ class BuiltInWidgets {
* <tr><td>Show tick mark ring</td><td>Boolean</td><td>true</td></tr>
* </table>
*/
static const WidgetType kGyro;
kGyro,
/**
* Displays a relay with toggle buttons for each supported mode (off, on,
* forward, reverse). <br>Supported types: <ul> <li>{@link
@@ -325,7 +324,7 @@ class BuiltInWidgets {
* </ul>
* <br>This widget has no custom properties.
*/
static const WidgetType kRelay;
kRelay,
/**
* Displays a differential drive with a widget that displays the speed of each
* side of the drivebase and a vector for the direction and rotation of the
@@ -344,7 +343,7 @@ class BuiltInWidgets {
* <tr><td>Show velocity vectors</td><td>Boolean</td><td>true</td></tr>
* </table>
*/
static const WidgetType kDifferentialDrive;
kDifferentialDrive,
/**
* Displays a mecanum drive with a widget that displays the speed of each
* wheel, and vectors for the direction and rotation of the drivebase. The
@@ -357,7 +356,7 @@ class BuiltInWidgets {
* <tr><td>Show velocity vectors</td><td>Boolean</td><td>true</td></tr>
* </table>
*/
static const WidgetType kMecanumDrive;
kMecanumDrive,
/**
* Displays a camera stream.
* <br>Supported types:
@@ -381,7 +380,7 @@ class BuiltInWidgets {
* </td></tr>
* </table>
*/
static const WidgetType kCameraStream;
kCameraStream
};
} // namespace frc

View File

@@ -7,7 +7,7 @@
#pragma once
#include <wpi/Twine.h>
#include <wpi/StringRef.h>
namespace frc {
@@ -20,7 +20,8 @@ namespace frc {
*/
class LayoutType {
public:
explicit LayoutType(const char* layoutName) : m_layoutName(layoutName) {}
explicit constexpr LayoutType(const char* layoutName)
: m_layoutName(layoutName) {}
~LayoutType() = default;
/**
@@ -30,7 +31,7 @@ class LayoutType {
wpi::StringRef GetLayoutName() const;
private:
wpi::StringRef m_layoutName;
const char* m_layoutName;
};
} // namespace frc

View File

@@ -20,6 +20,7 @@
#include "frc/ErrorBase.h"
#include "frc/WPIErrors.h"
#include "frc/shuffleboard/BuiltInLayouts.h"
#include "frc/shuffleboard/LayoutType.h"
#include "frc/shuffleboard/ShuffleboardComponentBase.h"
#include "frc/shuffleboard/ShuffleboardValue.h"
@@ -53,6 +54,16 @@ class ShuffleboardContainer : public virtual ShuffleboardValue,
const std::vector<std::unique_ptr<ShuffleboardComponentBase>>& GetComponents()
const;
/**
* Gets the layout with the given type and title, creating it if it does not
* already exist at the time this method is called.
*
* @param title the title of the layout
* @param layoutType the type of the layout, eg "List" or "Grid"
* @return the layout
*/
ShuffleboardLayout& GetLayout(const wpi::Twine& title, BuiltInLayouts type);
/**
* Gets the layout with the given type and title, creating it if it does not
* already exist at the time this method is called.

View File

@@ -9,6 +9,7 @@
#include <wpi/Twine.h>
#include "frc/shuffleboard/BuiltInWidgets.h"
#include "frc/shuffleboard/ShuffleboardComponent.h"
#include "frc/shuffleboard/WidgetType.h"
@@ -16,6 +17,10 @@ namespace frc {
class ShuffleboardContainer;
namespace detail {
const char* GetStringForWidgetType(BuiltInWidgets type);
} // namespace detail
/**
* Abstract superclass for widgets.
*
@@ -24,12 +29,11 @@ class ShuffleboardContainer;
* @tparam Derived the self type
*/
template <typename Derived>
class ShuffleboardWidget
: public ShuffleboardComponent<ShuffleboardWidget<Derived>> {
class ShuffleboardWidget : public ShuffleboardComponent<Derived> {
public:
ShuffleboardWidget(ShuffleboardContainer& parent, const wpi::Twine& title)
: ShuffleboardValue(title),
ShuffleboardComponent<ShuffleboardWidget<Derived>>(parent, title) {}
ShuffleboardComponent<Derived>(parent, title) {}
/**
* Sets the type of widget used to display the data. If not set, the default
@@ -39,7 +43,18 @@ class ShuffleboardWidget
* @return this widget object
* @see BuiltInWidgets
*/
Derived& withWidget(const WidgetType& widgetType) {
Derived& WithWidget(BuiltInWidgets widgetType) {
return WithWidget(detail::GetStringForWidgetType(widgetType));
}
/**
* Sets the type of widget used to display the data. If not set, the default
* widget type will be used.
*
* @param widgetType the type of the widget used to display the data
* @return this widget object
*/
Derived& WithWidget(const WidgetType& widgetType) {
return WithWidget(widgetType.GetWidgetName());
}

View File

@@ -7,7 +7,7 @@
#pragma once
#include <wpi/Twine.h>
#include <wpi/StringRef.h>
namespace frc {
@@ -20,7 +20,8 @@ namespace frc {
*/
class WidgetType {
public:
explicit WidgetType(const char* widgetName) : m_widgetName(widgetName) {}
explicit constexpr WidgetType(const char* widgetName)
: m_widgetName(widgetName) {}
~WidgetType() = default;
/**
@@ -30,7 +31,7 @@ class WidgetType {
wpi::StringRef GetWidgetName() const;
private:
wpi::StringRef m_widgetName;
const char* m_widgetName;
};
} // namespace frc

View File

@@ -0,0 +1,65 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 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 <array>
#include <memory>
#include <string>
#include <networktables/NetworkTableEntry.h>
#include <networktables/NetworkTableInstance.h>
#include "frc/commands/InstantCommand.h"
#include "frc/shuffleboard/BuiltInWidgets.h"
#include "frc/shuffleboard/ShuffleboardInstance.h"
#include "frc/shuffleboard/ShuffleboardTab.h"
#include "frc/shuffleboard/ShuffleboardWidget.h"
#include "frc/smartdashboard/Sendable.h"
#include "gtest/gtest.h"
using namespace frc;
class ShuffleboardWidgetTest : 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(ShuffleboardWidgetTest, UseBuiltInWidget) {
auto entry =
m_tab->Add("Name", "").WithWidget(BuiltInWidgets::kTextView).GetEntry();
EXPECT_EQ("/Shuffleboard/Tab/Name", entry.GetName())
<< "The widget entry has the wrong name";
}
TEST_F(ShuffleboardWidgetTest, WithProperties) {
wpi::StringMap<std::shared_ptr<nt::Value>> properties{
std::make_pair("min", nt::Value::MakeDouble(0)),
std::make_pair("max", nt::Value::MakeDouble(1))};
auto entry =
m_tab->Add("WithProperties", "").WithProperties(properties).GetEntry();
// Update the instance to generate
// the metadata entries for the widget properties
m_instance->Update();
auto propertiesTable = m_ntInstance.GetTable(
"/Shuffleboard/.metadata/Tab/WithProperties/Properties");
EXPECT_EQ("/Shuffleboard/Tab/WithProperties", entry.GetName())
<< "The widget entry has the wrong name";
EXPECT_FLOAT_EQ(0, propertiesTable->GetEntry("min").GetDouble(-1))
<< "The 'min' property should be 0";
EXPECT_FLOAT_EQ(1, propertiesTable->GetEntry("max").GetDouble(-1))
<< "The 'max' property should be 1";
}