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    
008    package edu.wpi.first.wpilibj.buttons;
009    
010    import edu.wpi.first.wpilibj.Sendable;
011    import edu.wpi.first.wpilibj.command.Command;
012    import edu.wpi.first.wpilibj.command.Scheduler;
013    import 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
019     * link 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
023     * a 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 functionality
025     * of the Trigger class.
026     *
027     * @author Joe Grinstead
028     */
029    public 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 use is pressed.
042         * @return  whether get() return true or the internal table for SmartDashboard use is pressed
043         */
044        private boolean grab() {
045            return get() || (table != null /*&& table.isConnected()*/ && table.getBoolean("pressed", false));//FIXME make is connected work?
046        }
047    
048        /**
049         * Starts the given command whenever the trigger just becomes active.
050         * @param command the command to start
051         */
052        public void whenActive(final Command command) {
053            new ButtonScheduler() {
054    
055                boolean pressedLast = grab();
056    
057                public void execute() {
058                    if (grab()) {
059                        if (!pressedLast) {
060                            pressedLast = true;
061                            command.start();
062                        }
063                    } else {
064                        pressedLast = false;
065                    }
066                }
067            }.start();
068        }
069    
070        /**
071         * Constantly starts the given command while the button is held.
072         *
073         * {@link Command#start()} will be called repeatedly while the trigger is active,
074         * and will be canceled when the trigger becomes inactive.
075         *
076         * @param command the command to start
077         */
078        public void whileActive(final Command command) {
079            new ButtonScheduler() {
080    
081                boolean pressedLast = grab();
082    
083                public void execute() {
084                    if (grab()) {
085                        pressedLast = true;
086                        command.start();
087                    } else {
088                        if (pressedLast) {
089                            pressedLast = false;
090                            command.cancel();
091                        }
092                    }
093                }
094            }.start();
095        }
096    
097        /**
098         * Starts the command when the trigger becomes inactive
099         * @param command the command to start
100         */
101        public void whenInactive(final Command command) {
102            new ButtonScheduler() {
103    
104                boolean pressedLast = grab();
105    
106                public void execute() {
107                    if (grab()) {
108                        pressedLast = true;
109                    } else {
110                        if (pressedLast) {
111                            pressedLast = false;
112                            command.start();
113                        }
114                    }
115                }
116            }.start();
117        }
118        
119       /**
120         * Toggles a command when the trigger becomes active
121         * @param command the command to toggle
122         */
123        public void toggleWhenActive(final Command command) {
124             new ButtonScheduler() {
125    
126                boolean pressedLast = grab();
127    
128                public void execute() {
129                    if (grab()) {
130                        if (!pressedLast) {
131                            pressedLast = true;
132                            if (command.isRunning()){
133                                command.cancel();
134                            } else{
135                                command.start();
136                            }
137                        }
138                    } else {
139                        pressedLast = false;
140                    }
141                }
142            }.start();
143        }
144        
145       /**
146         * Cancels a command when the trigger becomes active
147         * @param command the command to cancel
148         */
149        public void cancelWhenActive(final Command command) {
150             new ButtonScheduler() {
151    
152                boolean pressedLast = grab();
153    
154                public void execute() {
155                    if (grab()) {
156                        if (!pressedLast) {
157                            pressedLast = true;
158                            command.cancel();
159                        }
160                    } else {
161                        pressedLast = false;
162                    }
163                }
164            }.start();
165        }
166    
167        /**
168         * An internal class of {@link Trigger}.  The user should ignore this, it is
169         * only public to interface between packages.
170         */
171        public abstract class ButtonScheduler {
172            public abstract void execute();
173    
174            protected void start() {
175                Scheduler.getInstance().addButton(this);
176            }
177        }
178        
179    /**
180     * These methods continue to return the "Button" SmartDashboard type until we decided
181     * to create a Trigger widget type for the dashboard.
182     */
183        public String getSmartDashboardType(){
184            return "Button";
185        }
186        private ITable table;
187        public void initTable(ITable table){
188            this.table = table;
189            if(table!=null){
190                table.putBoolean("pressed", get());
191            }
192        }
193        
194        /**
195         * {@inheritDoc}
196         */
197        public ITable getTable(){
198            return table;
199        }
200    }