001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.wpilibj.shuffleboard;
006
007import edu.wpi.first.cscore.VideoSource;
008import edu.wpi.first.networktables.NetworkTableType;
009import edu.wpi.first.util.function.FloatSupplier;
010import edu.wpi.first.util.sendable.Sendable;
011import java.util.List;
012import java.util.NoSuchElementException;
013import java.util.function.BooleanSupplier;
014import java.util.function.DoubleSupplier;
015import java.util.function.LongSupplier;
016import java.util.function.Supplier;
017
018/** Common interface for objects that can contain shuffleboard components. */
019public interface ShuffleboardContainer extends ShuffleboardValue {
020  /**
021   * Gets the components that are direct children of this container.
022   *
023   * @return The components that are direct children of this container.
024   */
025  List<ShuffleboardComponent<?>> getComponents();
026
027  /**
028   * Gets the layout with the given type and title, creating it if it does not already exist at the
029   * time this method is called. Note: this method should only be used to use a layout type that is
030   * not already built into Shuffleboard. To use a layout built into Shuffleboard, use {@link
031   * #getLayout(String, LayoutType)} and the layouts in {@link BuiltInLayouts}.
032   *
033   * @param title the title of the layout
034   * @param type the type of the layout, eg "List Layout" or "Grid Layout"
035   * @return the layout
036   * @see #getLayout(String, LayoutType)
037   */
038  ShuffleboardLayout getLayout(String title, String type);
039
040  /**
041   * Gets the layout with the given type and title, creating it if it does not already exist at the
042   * time this method is called.
043   *
044   * @param title the title of the layout
045   * @param layoutType the type of the layout, eg "List" or "Grid"
046   * @return the layout
047   */
048  default ShuffleboardLayout getLayout(String title, LayoutType layoutType) {
049    return getLayout(title, layoutType.getLayoutName());
050  }
051
052  /**
053   * Gets the already-defined layout in this container with the given title.
054   *
055   * <pre>{@code
056   * Shuffleboard.getTab("Example Tab")
057   *   .getLayout("My Layout", BuiltInLayouts.kList);
058   *
059   * // Later...
060   * Shuffleboard.getTab("Example Tab")
061   *   .getLayout("My Layout");
062   * }</pre>
063   *
064   * @param title the title of the layout to get
065   * @return the layout with the given title
066   * @throws NoSuchElementException if no layout has yet been defined with the given title
067   */
068  ShuffleboardLayout getLayout(String title);
069
070  /**
071   * Adds a widget to this container to display the given sendable.
072   *
073   * @param title the title of the widget
074   * @param sendable the sendable to display
075   * @return a widget to display the sendable data
076   * @throws IllegalArgumentException if a widget already exists in this container with the given
077   *     title
078   */
079  ComplexWidget add(String title, Sendable sendable);
080
081  /**
082   * Adds a widget to this container to display the given video stream.
083   *
084   * @param title the title of the widget
085   * @param video the video stream to display
086   * @return a widget to display the sendable data
087   * @throws IllegalArgumentException if a widget already exists in this container with the given
088   *     title
089   */
090  default ComplexWidget add(String title, VideoSource video) {
091    return add(title, SendableCameraWrapper.wrap(video));
092  }
093
094  /**
095   * Adds a widget to this container to display the given sendable.
096   *
097   * @param sendable the sendable to display
098   * @return a widget to display the sendable data
099   * @throws IllegalArgumentException if a widget already exists in this container with the given
100   *     title, or if the sendable's name has not been specified
101   */
102  ComplexWidget add(Sendable sendable);
103
104  /**
105   * Adds a widget to this container to display the given video stream.
106   *
107   * @param video the video to display
108   * @return a widget to display the sendable data
109   * @throws IllegalArgumentException if a widget already exists in this container with the same
110   *     title as the video source
111   */
112  default ComplexWidget add(VideoSource video) {
113    return add(SendableCameraWrapper.wrap(video));
114  }
115
116  /**
117   * Adds a widget to this container to display the given data.
118   *
119   * @param title the title of the widget
120   * @param defaultValue the default value of the widget
121   * @return a widget to display the sendable data
122   * @throws IllegalArgumentException if a widget already exists in this container with the given
123   *     title
124   * @see #addPersistent(String, Object) add(String title, Object defaultValue)
125   */
126  SimpleWidget add(String title, Object defaultValue);
127
128  /**
129   * Adds a widget to this container to display the given data.
130   *
131   * @param title the title of the widget
132   * @param typeString the NT type string
133   * @param defaultValue the default value of the widget
134   * @return a widget to display the sendable data
135   * @throws IllegalArgumentException if a widget already exists in this container with the given
136   *     title
137   * @see #addPersistent(String, Object) add(String title, Object defaultValue)
138   */
139  SimpleWidget add(String title, String typeString, Object defaultValue);
140
141  /**
142   * Adds a widget to this container to display a video stream.
143   *
144   * @param title the title of the widget
145   * @param cameraName the name of the streamed camera
146   * @param cameraUrls the URLs with which the dashboard can access the camera stream
147   * @return a widget to display the camera stream
148   * @throws IllegalArgumentException if a widget already exists in this container with the given
149   *     title
150   */
151  default ComplexWidget addCamera(String title, String cameraName, String... cameraUrls) {
152    return add(title, SendableCameraWrapper.wrap(cameraName, cameraUrls));
153  }
154
155  /**
156   * Adds a widget to this container. The widget will display the data provided by the value
157   * supplier. Changes made on the dashboard will not propagate to the widget object, and will be
158   * overridden by values from the value supplier.
159   *
160   * @param title the title of the widget
161   * @param valueSupplier the supplier for values
162   * @return a widget to display data
163   * @throws IllegalArgumentException if a widget already exists in this container with the given
164   *     title
165   */
166  SuppliedValueWidget<String> addString(String title, Supplier<String> valueSupplier);
167
168  /**
169   * Adds a widget to this container. The widget will display the data provided by the value
170   * supplier. Changes made on the dashboard will not propagate to the widget object, and will be
171   * overridden by values from the value supplier.
172   *
173   * @param title the title of the widget
174   * @param valueSupplier the supplier for values
175   * @return a widget to display data
176   * @throws IllegalArgumentException if a widget already exists in this container with the given
177   *     title
178   */
179  SuppliedValueWidget<Double> addNumber(String title, DoubleSupplier valueSupplier);
180
181  /**
182   * Adds a widget to this container. The widget will display the data provided by the value
183   * supplier. Changes made on the dashboard will not propagate to the widget object, and will be
184   * overridden by values from the value supplier.
185   *
186   * @param title the title of the widget
187   * @param valueSupplier the supplier for values
188   * @return a widget to display data
189   * @throws IllegalArgumentException if a widget already exists in this container with the given
190   *     title
191   */
192  SuppliedValueWidget<Double> addDouble(String title, DoubleSupplier valueSupplier);
193
194  /**
195   * Adds a widget to this container. The widget will display the data provided by the value
196   * supplier. Changes made on the dashboard will not propagate to the widget object, and will be
197   * overridden by values from the value supplier.
198   *
199   * @param title the title of the widget
200   * @param valueSupplier the supplier for values
201   * @return a widget to display data
202   * @throws IllegalArgumentException if a widget already exists in this container with the given
203   *     title
204   */
205  SuppliedValueWidget<Float> addFloat(String title, FloatSupplier valueSupplier);
206
207  /**
208   * Adds a widget to this container. The widget will display the data provided by the value
209   * supplier. Changes made on the dashboard will not propagate to the widget object, and will be
210   * overridden by values from the value supplier.
211   *
212   * @param title the title of the widget
213   * @param valueSupplier the supplier for values
214   * @return a widget to display data
215   * @throws IllegalArgumentException if a widget already exists in this container with the given
216   *     title
217   */
218  SuppliedValueWidget<Long> addInteger(String title, LongSupplier valueSupplier);
219
220  /**
221   * Adds a widget to this container. The widget will display the data provided by the value
222   * supplier. Changes made on the dashboard will not propagate to the widget object, and will be
223   * overridden by values from the value supplier.
224   *
225   * @param title the title of the widget
226   * @param valueSupplier the supplier for values
227   * @return a widget to display data
228   * @throws IllegalArgumentException if a widget already exists in this container with the given
229   *     title
230   */
231  SuppliedValueWidget<Boolean> addBoolean(String title, BooleanSupplier valueSupplier);
232
233  /**
234   * Adds a widget to this container. The widget will display the data provided by the value
235   * supplier. Changes made on the dashboard will not propagate to the widget object, and will be
236   * overridden by values from the value supplier.
237   *
238   * @param title the title of the widget
239   * @param valueSupplier the supplier for values
240   * @return a widget to display data
241   * @throws IllegalArgumentException if a widget already exists in this container with the given
242   *     title
243   */
244  SuppliedValueWidget<String[]> addStringArray(String title, Supplier<String[]> valueSupplier);
245
246  /**
247   * Adds a widget to this container. The widget will display the data provided by the value
248   * supplier. Changes made on the dashboard will not propagate to the widget object, and will be
249   * overridden by values from the value supplier.
250   *
251   * @param title the title of the widget
252   * @param valueSupplier the supplier for values
253   * @return a widget to display data
254   * @throws IllegalArgumentException if a widget already exists in this container with the given
255   *     title
256   */
257  SuppliedValueWidget<double[]> addDoubleArray(String title, Supplier<double[]> valueSupplier);
258
259  /**
260   * Adds a widget to this container. The widget will display the data provided by the value
261   * supplier. Changes made on the dashboard will not propagate to the widget object, and will be
262   * overridden by values from the value supplier.
263   *
264   * @param title the title of the widget
265   * @param valueSupplier the supplier for values
266   * @return a widget to display data
267   * @throws IllegalArgumentException if a widget already exists in this container with the given
268   *     title
269   */
270  SuppliedValueWidget<float[]> addFloatArray(String title, Supplier<float[]> valueSupplier);
271
272  /**
273   * Adds a widget to this container. The widget will display the data provided by the value
274   * supplier. Changes made on the dashboard will not propagate to the widget object, and will be
275   * overridden by values from the value supplier.
276   *
277   * @param title the title of the widget
278   * @param valueSupplier the supplier for values
279   * @return a widget to display data
280   * @throws IllegalArgumentException if a widget already exists in this container with the given
281   *     title
282   */
283  SuppliedValueWidget<long[]> addIntegerArray(String title, Supplier<long[]> valueSupplier);
284
285  /**
286   * Adds a widget to this container. The widget will display the data provided by the value
287   * supplier. Changes made on the dashboard will not propagate to the widget object, and will be
288   * overridden by values from the value supplier.
289   *
290   * @param title the title of the widget
291   * @param valueSupplier the supplier for values
292   * @return a widget to display data
293   * @throws IllegalArgumentException if a widget already exists in this container with the given
294   *     title
295   */
296  SuppliedValueWidget<boolean[]> addBooleanArray(String title, Supplier<boolean[]> valueSupplier);
297
298  /**
299   * Adds a widget to this container. The widget will display the data provided by the value
300   * supplier. Changes made on the dashboard will not propagate to the widget object, and will be
301   * overridden by values from the value supplier.
302   *
303   * @param title the title of the widget
304   * @param valueSupplier the supplier for values
305   * @return a widget to display data
306   * @throws IllegalArgumentException if a widget already exists in this container with the given
307   *     title
308   */
309  default SuppliedValueWidget<byte[]> addRaw(String title, Supplier<byte[]> valueSupplier) {
310    return addRaw(title, "raw", valueSupplier);
311  }
312
313  /**
314   * Adds a widget to this container. The widget will display the data provided by the value
315   * supplier. Changes made on the dashboard will not propagate to the widget object, and will be
316   * overridden by values from the value supplier.
317   *
318   * @param title the title of the widget
319   * @param typeString the NT type string for the value
320   * @param valueSupplier the supplier for values
321   * @return a widget to display data
322   * @throws IllegalArgumentException if a widget already exists in this container with the given
323   *     title
324   */
325  SuppliedValueWidget<byte[]> addRaw(
326      String title, String typeString, Supplier<byte[]> valueSupplier);
327
328  /**
329   * Adds a widget to this container to display a simple piece of data. Unlike {@link #add(String,
330   * Object)}, the value in the widget will be saved on the robot and will be used when the robot
331   * program next starts rather than {@code defaultValue}.
332   *
333   * @param title the title of the widget
334   * @param defaultValue the default value of the widget
335   * @return a widget to display the sendable data
336   * @throws IllegalArgumentException if a widget already exists in this container with the given
337   *     title
338   * @see #add(String, Object) add(String title, Object defaultValue)
339   */
340  default SimpleWidget addPersistent(String title, Object defaultValue) {
341    return addPersistent(title, NetworkTableType.getStringFromObject(defaultValue), defaultValue);
342  }
343
344  /**
345   * Adds a widget to this container to display a simple piece of data. Unlike {@link #add(String,
346   * Object)}, the value in the widget will be saved on the robot and will be used when the robot
347   * program next starts rather than {@code defaultValue}.
348   *
349   * @param title the title of the widget
350   * @param typeString the NT type string
351   * @param defaultValue the default value of the widget
352   * @return a widget to display the sendable data
353   * @throws IllegalArgumentException if a widget already exists in this container with the given
354   *     title
355   * @see #add(String, Object) add(String title, Object defaultValue)
356   */
357  default SimpleWidget addPersistent(String title, String typeString, Object defaultValue) {
358    SimpleWidget widget = add(title, defaultValue);
359    widget.getEntry(typeString).getTopic().setPersistent(true);
360    return widget;
361  }
362}