f@0: /* f@0: XYPad - a haptic xy-pad that uses the jHapticGUI library f@0: f@0: Copyright (C) 2015 Queen Mary University of London (http://depic.eecs.qmul.ac.uk/) f@0: f@0: This program is free software: you can redistribute it and/or modify f@0: it under the terms of the GNU General Public License as published by f@0: the Free Software Foundation, either version 3 of the License, or f@0: (at your option) any later version. f@0: f@0: This program is distributed in the hope that it will be useful, f@0: but WITHOUT ANY WARRANTY; without even the implied warranty of f@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the f@0: GNU General Public License for more details. f@0: f@0: You should have received a copy of the GNU General Public License f@0: along with this program. If not, see . f@0: */ f@0: package uk.ac.qmul.eecs.depic.jhapticgui.examples; f@0: f@0: import java.awt.BorderLayout; f@0: import java.awt.Color; f@0: import java.awt.Dimension; f@0: import java.awt.EventQueue; f@0: import java.awt.event.ActionEvent; f@0: import java.awt.event.ActionListener; f@0: import java.io.InputStream; f@0: f@0: import javax.swing.JButton; f@0: import javax.swing.JFrame; f@0: import javax.swing.JPanel; f@0: import javax.swing.JScrollPane; f@0: import javax.swing.JTextArea; f@0: import javax.swing.SwingUtilities; f@0: import javax.swing.UIManager; f@0: import javax.swing.border.EmptyBorder; f@0: import javax.swing.border.LineBorder; f@0: import javax.swing.text.DefaultCaret; f@0: f@0: import uk.ac.qmul.eecs.depic.jhapticgui.HapticDevice; f@0: import uk.ac.qmul.eecs.depic.jhapticgui.HapticDeviceWinFactory; f@0: import uk.ac.qmul.eecs.depic.jhapticgui.HapticListener; f@0: import uk.ac.qmul.eecs.depic.jhapticgui.HapticsException; f@0: f@0: /** f@0: * A haptic XYPad. f@0: * f@0: * Provides two buttons for starting the haptic device and change f@0: * the shape of the haptic pad, a text area to display notification messages f@0: * (also from the haptic device) and an XYPanel displaying a cursor that f@0: * can be manipulated using the haptic device. f@0: * f@0: * f@0: * @author Fiore Martin f@0: * f@0: */ f@0: public class XYPad extends JFrame implements ActionListener{ f@0: private static final long serialVersionUID = 1L; f@0: private XYPanel xyPanel; f@0: private JButton startButton; f@0: private JButton changeButton; f@0: private HapticDevice hapticDevice; f@0: private JTextArea textArea; f@0: f@0: /** f@0: * Launch the application. f@0: */ f@0: public static void main(String[] args) { f@0: try { f@0: // Set System L&F f@0: UIManager.setLookAndFeel( f@0: UIManager.getSystemLookAndFeelClassName()); f@0: }catch(Exception e){} f@0: f@0: EventQueue.invokeLater(new Runnable() { f@0: public void run() { f@0: try { f@0: XYPad frame = new XYPad(); f@0: frame.setVisible(true); f@0: } catch (Exception e) { f@0: e.printStackTrace(); f@0: } f@0: } f@0: }); f@0: } f@0: f@0: /** f@0: * Creates the frame. f@0: */ f@0: public XYPad() { f@0: super("XY Pad"); f@0: setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f@0: setBounds(100, 100, 450, 542); f@0: JPanel contentPane = new JPanel(); f@0: contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); f@0: contentPane.setLayout(new BorderLayout(0, 0)); f@0: setContentPane(contentPane); f@0: f@0: xyPanel = new XYPanel(); f@0: xyPanel.setBackground(Color.LIGHT_GRAY); f@0: xyPanel.setBorder(new LineBorder(Color.GRAY)); f@0: xyPanel.setBackground(Color.BLACK); f@0: contentPane.add(xyPanel, BorderLayout.CENTER); f@0: f@0: JPanel buttonsPanel = new JPanel(); f@0: contentPane.add(buttonsPanel, BorderLayout.SOUTH); f@0: buttonsPanel.setLayout(new BorderLayout(0, 0)); f@0: f@0: JPanel panel_1 = new JPanel(); f@0: buttonsPanel.add(panel_1, BorderLayout.SOUTH); f@0: buttonsPanel.setPreferredSize(new Dimension(buttonsPanel.getWidth(), 100)); f@0: f@0: startButton = new JButton("Start Haptics"); f@0: panel_1.add(startButton); f@0: f@0: changeButton = new JButton("Change to Square"); f@0: panel_1.add(changeButton); f@0: changeButton.setEnabled(false); f@0: f@0: textArea = new JTextArea(); f@0: /* this makes the scroll pane to always be at the bottom */ f@0: ((DefaultCaret) textArea.getCaret()).setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); f@0: textArea.setEditable(false); f@0: buttonsPanel.add(new JScrollPane(textArea), BorderLayout.CENTER); f@0: f@0: /* install listener to buttons */ f@0: startButton.addActionListener(this); f@0: changeButton.addActionListener(this); f@0: } f@0: f@0: /** f@0: * The action performed by the two buttons of this XYPad. f@0: * f@0: * The first button starts the haptic device, whereas the second button f@0: * sends a message to the haptic device to change the shape of the haptic f@0: * xy pad shape. f@0: * f@0: */ f@0: @Override f@0: public void actionPerformed(ActionEvent evt) { f@0: if(evt.getSource().equals(startButton)){ f@0: f@0: textArea.append("Starting haptic device...\n"); f@0: f@0: /** f@0: * creates a new haptic listener that updates the xy panel upon receiving "position" f@0: * messages. Moreover it prints on the text area when the haptic proxy touches f@0: * and untouches the haptic xy pad f@0: * f@0: * f@0: */ f@0: class XYHapticListener extends HapticListener { f@0: f@0: @Override f@0: public void messageReceived(String command, final String args, int id) { f@0: f@0: switch(command){ f@0: case "position" : { f@0: f@0: /* The coordinates are passed as a string representing two floats (x and y). * f@0: * so the string needs to be unpacked and parsed. */ f@0: String[] coord = args.split(" "); f@0: final float x = Float.parseFloat(coord[0]); f@0: final float y = Float.parseFloat(coord[1]); f@0: f@0: /* The haptic listener runs on its own thread, therefore changes * f@0: * to the GUI must be queued for the event dispatching thread. */ f@0: SwingUtilities.invokeLater(new Runnable(){ f@0: @Override f@0: public void run(){ f@0: xyPanel.setXY(x, y); f@0: } f@0: }); f@0: } break; f@0: f@0: case "touch" : { f@0: /* The haptic listener runs on its own thread, therefore changes * f@0: * to the GUI must be queued for the event dispatching thread. */ f@0: SwingUtilities.invokeLater(new Runnable(){ f@0: @Override f@0: public void run(){ f@0: f@0: /* uses message argument to discriminate between touch and untouch */ f@0: if("yes".equals(args)){ f@0: textArea.append("haptic xy touched\n"); f@0: }else if("no".equals(args)){ f@0: textArea.append("haptic xy untouched\n"); f@0: } f@0: } f@0: }); f@0: } break; f@0: f@0: case HapticListener.WINDOW_MSG : { f@0: SwingUtilities.invokeLater(new Runnable(){ f@0: @Override f@0: public void run(){ f@0: requestFocus(); f@0: } f@0: }); f@0: } break; f@0: } f@0: } f@0: }; f@0: f@0: InputStream dll = this.getClass().getResourceAsStream("XYPad.dll"); f@0: try { f@0: hapticDevice = new HapticDeviceWinFactory().getHapticDevice(dll, new XYHapticListener(), new Dimension (getWidth(), getWidth() )); f@0: f@0: changeButton.setEnabled(true); f@0: startButton.setEnabled(false); f@0: f@0: textArea.append("haptic device started\n"); f@0: } catch (HapticsException e) { f@0: e.printStackTrace(); f@0: textArea.append(e.getMessage()); f@0: } f@0: f@0: }else if(evt.getSource().equals(changeButton)){ f@0: /* Changes the shape of the haptics object use message args to tell * f@0: * the haptics which shape to display ID is left to 0 as there is * f@0: * only one haptic shape and no need to refer to a specific haptic shape. */ f@0: if("Change to Square".equals(changeButton.getText())){ f@0: changeButton.setText("Change to Circle"); f@0: f@0: hapticDevice.sendMessage("change", "square", 0); f@0: f@0: textArea.append("shape changed to square\n"); f@0: }else if("Change to Circle".equals(changeButton.getText())){ // change to circle f@0: changeButton.setText("Change to Square"); f@0: f@0: hapticDevice.sendMessage("change", "circle", 0); f@0: f@0: textArea.append("shape changed to circle\n"); f@0: } f@0: f@0: } f@0: f@0: } f@0: f@0: }