001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2012. All Rights Reserved. */
003/* Open Source Software - may be modified and shared by FRC teams. The code */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project. */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj.buttons;
009
010import edu.wpi.first.wpilibj.Sendable;
011import edu.wpi.first.wpilibj.command.Command;
012import edu.wpi.first.wpilibj.command.Scheduler;
013import edu.wpi.first.wpilibj.tables.ITable;
014
015/**
016 * This class provides an easy way to link commands to inputs.
017 *
018 * It is very easy to link a button to a command. For instance, you could link
019 * the trigger button of a joystick to a "score" command.
020 *
021 * It is encouraged that teams write a subclass of Trigger if they want to have
022 * something unusual (for instance, if they want to react to the user holding a
023 * button while the robot is reading a certain sensor input). For this, they
024 * only have to write the {@link Trigger#get()} method to get the full
025 * functionality of the Trigger class.
026 *
027 * @author Joe Grinstead
028 */
029public abstract class Trigger implements Sendable {
030
031  /**
032   * Returns whether or not the trigger is active
033   *
034   * This method will be called repeatedly a command is linked to the Trigger.
035   *
036   * @return whether or not the trigger condition is active.
037   */
038  public abstract boolean get();
039
040  /**
041   * Returns whether get() return true or the internal table for SmartDashboard
042   * use is pressed.
043   *$
044   * @return whether get() return true or the internal table for SmartDashboard
045   *         use is pressed
046   */
047  private boolean grab() {
048    return get()
049        || (table != null /* && table.isConnected() */&& table.getBoolean("pressed", false));// FIXME
050                                                                                             // make
051                                                                                             // is
052                                                                                             // connected
053                                                                                             // work?
054  }
055
056  /**
057   * Starts the given command whenever the trigger just becomes active.
058   *$
059   * @param command the command to start
060   */
061  public void whenActive(final Command command) {
062    new ButtonScheduler() {
063
064      boolean pressedLast = grab();
065
066      public void execute() {
067        if (grab()) {
068          if (!pressedLast) {
069            pressedLast = true;
070            command.start();
071          }
072        } else {
073          pressedLast = false;
074        }
075      }
076    }.start();
077  }
078
079  /**
080   * Constantly starts the given command while the button is held.
081   *
082   * {@link Command#start()} will be called repeatedly while the trigger is
083   * active, and will be canceled when the trigger becomes inactive.
084   *
085   * @param command the command to start
086   */
087  public void whileActive(final Command command) {
088    new ButtonScheduler() {
089
090      boolean pressedLast = grab();
091
092      public void execute() {
093        if (grab()) {
094          pressedLast = true;
095          command.start();
096        } else {
097          if (pressedLast) {
098            pressedLast = false;
099            command.cancel();
100          }
101        }
102      }
103    }.start();
104  }
105
106  /**
107   * Starts the command when the trigger becomes inactive
108   *$
109   * @param command the command to start
110   */
111  public void whenInactive(final Command command) {
112    new ButtonScheduler() {
113
114      boolean pressedLast = grab();
115
116      public void execute() {
117        if (grab()) {
118          pressedLast = true;
119        } else {
120          if (pressedLast) {
121            pressedLast = false;
122            command.start();
123          }
124        }
125      }
126    }.start();
127  }
128
129  /**
130   * Toggles a command when the trigger becomes active
131   *$
132   * @param command the command to toggle
133   */
134  public void toggleWhenActive(final Command command) {
135    new ButtonScheduler() {
136
137      boolean pressedLast = grab();
138
139      public void execute() {
140        if (grab()) {
141          if (!pressedLast) {
142            pressedLast = true;
143            if (command.isRunning()) {
144              command.cancel();
145            } else {
146              command.start();
147            }
148          }
149        } else {
150          pressedLast = false;
151        }
152      }
153    }.start();
154  }
155
156  /**
157   * Cancels a command when the trigger becomes active
158   *$
159   * @param command the command to cancel
160   */
161  public void cancelWhenActive(final Command command) {
162    new ButtonScheduler() {
163
164      boolean pressedLast = grab();
165
166      public void execute() {
167        if (grab()) {
168          if (!pressedLast) {
169            pressedLast = true;
170            command.cancel();
171          }
172        } else {
173          pressedLast = false;
174        }
175      }
176    }.start();
177  }
178
179  /**
180   * An internal class of {@link Trigger}. The user should ignore this, it is
181   * only public to interface between packages.
182   */
183  public abstract class ButtonScheduler {
184    public abstract void execute();
185
186    protected void start() {
187      Scheduler.getInstance().addButton(this);
188    }
189  }
190
191  /**
192   * These methods continue to return the "Button" SmartDashboard type until we
193   * decided to create a Trigger widget type for the dashboard.
194   */
195  public String getSmartDashboardType() {
196    return "Button";
197  }
198
199  private ITable table;
200
201  public void initTable(ITable table) {
202    this.table = table;
203    if (table != null) {
204      table.putBoolean("pressed", get());
205    }
206  }
207
208  /**
209   * {@inheritDoc}
210   */
211  public ITable getTable() {
212    return table;
213  }
214}