f@0
|
1 /*
|
f@0
|
2 XYPad - a haptic xy-pad that uses the jHapticGUI library
|
f@0
|
3
|
f@0
|
4 Copyright (C) 2015 Queen Mary University of London (http://depic.eecs.qmul.ac.uk/)
|
f@0
|
5
|
f@0
|
6 This program is free software: you can redistribute it and/or modify
|
f@0
|
7 it under the terms of the GNU General Public License as published by
|
f@0
|
8 the Free Software Foundation, either version 3 of the License, or
|
f@0
|
9 (at your option) any later version.
|
f@0
|
10
|
f@0
|
11 This program is distributed in the hope that it will be useful,
|
f@0
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
f@0
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
f@0
|
14 GNU General Public License for more details.
|
f@0
|
15
|
f@0
|
16 You should have received a copy of the GNU General Public License
|
f@0
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
f@0
|
18 */
|
f@0
|
19 package uk.ac.qmul.eecs.depic.jhapticgui.examples;
|
f@0
|
20
|
f@0
|
21 import java.awt.BorderLayout;
|
f@0
|
22 import java.awt.Color;
|
f@0
|
23 import java.awt.Dimension;
|
f@0
|
24 import java.awt.EventQueue;
|
f@0
|
25 import java.awt.event.ActionEvent;
|
f@0
|
26 import java.awt.event.ActionListener;
|
f@0
|
27 import java.io.InputStream;
|
f@0
|
28
|
f@0
|
29 import javax.swing.JButton;
|
f@0
|
30 import javax.swing.JFrame;
|
f@0
|
31 import javax.swing.JPanel;
|
f@0
|
32 import javax.swing.JScrollPane;
|
f@0
|
33 import javax.swing.JTextArea;
|
f@0
|
34 import javax.swing.SwingUtilities;
|
f@0
|
35 import javax.swing.UIManager;
|
f@0
|
36 import javax.swing.border.EmptyBorder;
|
f@0
|
37 import javax.swing.border.LineBorder;
|
f@0
|
38 import javax.swing.text.DefaultCaret;
|
f@0
|
39
|
f@0
|
40 import uk.ac.qmul.eecs.depic.jhapticgui.HapticDevice;
|
f@0
|
41 import uk.ac.qmul.eecs.depic.jhapticgui.HapticDeviceWinFactory;
|
f@0
|
42 import uk.ac.qmul.eecs.depic.jhapticgui.HapticListener;
|
f@0
|
43 import uk.ac.qmul.eecs.depic.jhapticgui.HapticsException;
|
f@0
|
44
|
f@0
|
45 /**
|
f@0
|
46 * A haptic XYPad.
|
f@0
|
47 *
|
f@0
|
48 * Provides two buttons for starting the haptic device and change
|
f@0
|
49 * the shape of the haptic pad, a text area to display notification messages
|
f@0
|
50 * (also from the haptic device) and an XYPanel displaying a cursor that
|
f@0
|
51 * can be manipulated using the haptic device.
|
f@0
|
52 *
|
f@0
|
53 *
|
f@0
|
54 * @author Fiore Martin
|
f@0
|
55 *
|
f@0
|
56 */
|
f@0
|
57 public class XYPad extends JFrame implements ActionListener{
|
f@0
|
58 private static final long serialVersionUID = 1L;
|
f@0
|
59 private XYPanel xyPanel;
|
f@0
|
60 private JButton startButton;
|
f@0
|
61 private JButton changeButton;
|
f@0
|
62 private HapticDevice hapticDevice;
|
f@0
|
63 private JTextArea textArea;
|
f@0
|
64
|
f@0
|
65 /**
|
f@0
|
66 * Launch the application.
|
f@0
|
67 */
|
f@0
|
68 public static void main(String[] args) {
|
f@0
|
69 try {
|
f@0
|
70 // Set System L&F
|
f@0
|
71 UIManager.setLookAndFeel(
|
f@0
|
72 UIManager.getSystemLookAndFeelClassName());
|
f@0
|
73 }catch(Exception e){}
|
f@0
|
74
|
f@0
|
75 EventQueue.invokeLater(new Runnable() {
|
f@0
|
76 public void run() {
|
f@0
|
77 try {
|
f@0
|
78 XYPad frame = new XYPad();
|
f@0
|
79 frame.setVisible(true);
|
f@0
|
80 } catch (Exception e) {
|
f@0
|
81 e.printStackTrace();
|
f@0
|
82 }
|
f@0
|
83 }
|
f@0
|
84 });
|
f@0
|
85 }
|
f@0
|
86
|
f@0
|
87 /**
|
f@0
|
88 * Creates the frame.
|
f@0
|
89 */
|
f@0
|
90 public XYPad() {
|
f@0
|
91 super("XY Pad");
|
f@0
|
92 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
f@0
|
93 setBounds(100, 100, 450, 542);
|
f@0
|
94 JPanel contentPane = new JPanel();
|
f@0
|
95 contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
f@0
|
96 contentPane.setLayout(new BorderLayout(0, 0));
|
f@0
|
97 setContentPane(contentPane);
|
f@0
|
98
|
f@0
|
99 xyPanel = new XYPanel();
|
f@0
|
100 xyPanel.setBackground(Color.LIGHT_GRAY);
|
f@0
|
101 xyPanel.setBorder(new LineBorder(Color.GRAY));
|
f@0
|
102 xyPanel.setBackground(Color.BLACK);
|
f@0
|
103 contentPane.add(xyPanel, BorderLayout.CENTER);
|
f@0
|
104
|
f@0
|
105 JPanel buttonsPanel = new JPanel();
|
f@0
|
106 contentPane.add(buttonsPanel, BorderLayout.SOUTH);
|
f@0
|
107 buttonsPanel.setLayout(new BorderLayout(0, 0));
|
f@0
|
108
|
f@0
|
109 JPanel panel_1 = new JPanel();
|
f@0
|
110 buttonsPanel.add(panel_1, BorderLayout.SOUTH);
|
f@0
|
111 buttonsPanel.setPreferredSize(new Dimension(buttonsPanel.getWidth(), 100));
|
f@0
|
112
|
f@0
|
113 startButton = new JButton("Start Haptics");
|
f@0
|
114 panel_1.add(startButton);
|
f@0
|
115
|
f@0
|
116 changeButton = new JButton("Change to Square");
|
f@0
|
117 panel_1.add(changeButton);
|
f@0
|
118 changeButton.setEnabled(false);
|
f@0
|
119
|
f@0
|
120 textArea = new JTextArea();
|
f@0
|
121 /* this makes the scroll pane to always be at the bottom */
|
f@0
|
122 ((DefaultCaret) textArea.getCaret()).setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
|
f@0
|
123 textArea.setEditable(false);
|
f@0
|
124 buttonsPanel.add(new JScrollPane(textArea), BorderLayout.CENTER);
|
f@0
|
125
|
f@0
|
126 /* install listener to buttons */
|
f@0
|
127 startButton.addActionListener(this);
|
f@0
|
128 changeButton.addActionListener(this);
|
f@0
|
129 }
|
f@0
|
130
|
f@0
|
131 /**
|
f@0
|
132 * The action performed by the two buttons of this XYPad.
|
f@0
|
133 *
|
f@0
|
134 * The first button starts the haptic device, whereas the second button
|
f@0
|
135 * sends a message to the haptic device to change the shape of the haptic
|
f@0
|
136 * xy pad shape.
|
f@0
|
137 *
|
f@0
|
138 */
|
f@0
|
139 @Override
|
f@0
|
140 public void actionPerformed(ActionEvent evt) {
|
f@0
|
141 if(evt.getSource().equals(startButton)){
|
f@0
|
142
|
f@0
|
143 textArea.append("Starting haptic device...\n");
|
f@0
|
144
|
f@0
|
145 /**
|
f@0
|
146 * creates a new haptic listener that updates the xy panel upon receiving "position"
|
f@0
|
147 * messages. Moreover it prints on the text area when the haptic proxy touches
|
f@0
|
148 * and untouches the haptic xy pad
|
f@0
|
149 *
|
f@0
|
150 *
|
f@0
|
151 */
|
f@0
|
152 class XYHapticListener extends HapticListener {
|
f@0
|
153
|
f@0
|
154 @Override
|
f@0
|
155 public void messageReceived(String command, final String args, int id) {
|
f@0
|
156
|
f@0
|
157 switch(command){
|
f@0
|
158 case "position" : {
|
f@0
|
159
|
f@0
|
160 /* The coordinates are passed as a string representing two floats (x and y). *
|
f@0
|
161 * so the string needs to be unpacked and parsed. */
|
f@0
|
162 String[] coord = args.split(" ");
|
f@0
|
163 final float x = Float.parseFloat(coord[0]);
|
f@0
|
164 final float y = Float.parseFloat(coord[1]);
|
f@0
|
165
|
f@0
|
166 /* The haptic listener runs on its own thread, therefore changes *
|
f@0
|
167 * to the GUI must be queued for the event dispatching thread. */
|
f@0
|
168 SwingUtilities.invokeLater(new Runnable(){
|
f@0
|
169 @Override
|
f@0
|
170 public void run(){
|
f@0
|
171 xyPanel.setXY(x, y);
|
f@0
|
172 }
|
f@0
|
173 });
|
f@0
|
174 } break;
|
f@0
|
175
|
f@0
|
176 case "touch" : {
|
f@0
|
177 /* The haptic listener runs on its own thread, therefore changes *
|
f@0
|
178 * to the GUI must be queued for the event dispatching thread. */
|
f@0
|
179 SwingUtilities.invokeLater(new Runnable(){
|
f@0
|
180 @Override
|
f@0
|
181 public void run(){
|
f@0
|
182
|
f@0
|
183 /* uses message argument to discriminate between touch and untouch */
|
f@0
|
184 if("yes".equals(args)){
|
f@0
|
185 textArea.append("haptic xy touched\n");
|
f@0
|
186 }else if("no".equals(args)){
|
f@0
|
187 textArea.append("haptic xy untouched\n");
|
f@0
|
188 }
|
f@0
|
189 }
|
f@0
|
190 });
|
f@0
|
191 } break;
|
f@0
|
192
|
f@0
|
193 case HapticListener.WINDOW_MSG : {
|
f@0
|
194 SwingUtilities.invokeLater(new Runnable(){
|
f@0
|
195 @Override
|
f@0
|
196 public void run(){
|
f@0
|
197 requestFocus();
|
f@0
|
198 }
|
f@0
|
199 });
|
f@0
|
200 } break;
|
f@0
|
201 }
|
f@0
|
202 }
|
f@0
|
203 };
|
f@0
|
204
|
f@0
|
205 InputStream dll = this.getClass().getResourceAsStream("XYPad.dll");
|
f@0
|
206 try {
|
f@0
|
207 hapticDevice = new HapticDeviceWinFactory().getHapticDevice(dll, new XYHapticListener(), new Dimension (getWidth(), getWidth() ));
|
f@0
|
208
|
f@0
|
209 changeButton.setEnabled(true);
|
f@0
|
210 startButton.setEnabled(false);
|
f@0
|
211
|
f@0
|
212 textArea.append("haptic device started\n");
|
f@0
|
213 } catch (HapticsException e) {
|
f@0
|
214 e.printStackTrace();
|
f@0
|
215 textArea.append(e.getMessage());
|
f@0
|
216 }
|
f@0
|
217
|
f@0
|
218 }else if(evt.getSource().equals(changeButton)){
|
f@0
|
219 /* Changes the shape of the haptics object use message args to tell *
|
f@0
|
220 * the haptics which shape to display ID is left to 0 as there is *
|
f@0
|
221 * only one haptic shape and no need to refer to a specific haptic shape. */
|
f@0
|
222 if("Change to Square".equals(changeButton.getText())){
|
f@0
|
223 changeButton.setText("Change to Circle");
|
f@0
|
224
|
f@0
|
225 hapticDevice.sendMessage("change", "square", 0);
|
f@0
|
226
|
f@0
|
227 textArea.append("shape changed to square\n");
|
f@0
|
228 }else if("Change to Circle".equals(changeButton.getText())){ // change to circle
|
f@0
|
229 changeButton.setText("Change to Square");
|
f@0
|
230
|
f@0
|
231 hapticDevice.sendMessage("change", "circle", 0);
|
f@0
|
232
|
f@0
|
233 textArea.append("shape changed to circle\n");
|
f@0
|
234 }
|
f@0
|
235
|
f@0
|
236 }
|
f@0
|
237
|
f@0
|
238 }
|
f@0
|
239
|
f@0
|
240 }
|