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