diff --git a/plugins/ch/psi/pshell/swing/MotorPanel.java b/plugins/ch/psi/pshell/swing/MotorPanel.java new file mode 100644 index 0000000..9a757df --- /dev/null +++ b/plugins/ch/psi/pshell/swing/MotorPanel.java @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2014 Paul Scherrer Institute. All rights reserved. + */ +package ch.psi.pshell.swing; + +import ch.psi.pshell.device.Device; +import ch.psi.pshell.device.Motor; +import ch.psi.utils.State; +import ch.psi.utils.swing.SwingUtils; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.io.IOException; +import javax.swing.JButton; +import javax.swing.SpinnerNumberModel; + +/** + * + */ +public class MotorPanel extends DevicePanel { + + public MotorPanel() { + initComponents(); + FocusListener jogFocusListener = new FocusAdapter() { + @Override + public void focusLost(FocusEvent e) { + if ((e.isTemporary()) && (e.getSource() instanceof JButton)) { + if (jogging) { + stop(); + } + } + } + }; + buttonJogPos.addFocusListener(jogFocusListener); + buttonJogNeg.addFocusListener(jogFocusListener); + + textState.setBackground(TEXT_READONLY_BACKGROUND_COLOR); + } + + @Override + public Motor getDevice() { + return (Motor) super.getDevice(); + } + + @Override + public void setDevice(Device device) { + super.setDevice(device); + readout.setDevice(device); + if (device != null) { + onDeviceStateChanged(device.getState(), null); + onDeviceStatusChanged(((Motor) device).takeStatus()); + double min = getDevice().getMinSpeed(); + double max = getDevice().getMaxSpeed(); + double def = getDevice().getDefaultSpeed(); + def = Math.max(min, def); + def = Math.min(max, def); + spinnerSpeed.setModel(new SpinnerNumberModel(def, min, max, 1.0)); + //In a different thread because can be blocking + new Thread(() -> { + try { + spinnerSpeed.setValue(getDevice().getSpeed()); + } catch (Exception ex) { + } + }).start(); + + } else { + textState.setText(""); + } + } + + protected void setSpeed(double speed) throws IOException { + Double current = getDevice().getVelocity().take(); + if ((current == null) || (current != speed)) { + getDevice().getVelocity().writeAsync(speed); + } + } + + protected void moveRel(double offset) throws IOException { + Double destination = getDevice().take(); + if (destination != null) { + destination += offset; + getDevice().writeAsync(destination).handle((ok, ex) -> { + if ((ex != null) && (ex instanceof IOException)) { + SwingUtils.showException(this, (Exception) ex); + } + return ok; + }); + + } + } + + boolean jogging; + + protected void jog(boolean positive) throws IOException, InterruptedException { + getDevice().startJog(positive); + jogging = true; + } + + protected void reference() { + new Thread(() -> { + try { + getDevice().reference(); + } catch (Exception ex) { + } + }).start(); + } + + protected void stop() { + jogging = false; + new Thread(() -> { + try { + getDevice().stop(); + } catch (Exception ex) { + } + }).start(); + } + + @Override + protected void onDeviceSpeedChanged(Double value) { + spinnerSpeed.setValue(value); + } + + @Override + protected void onDeviceStateChanged(State state, State former) { + if ((state != State.Ready) || (state != State.Busy)) { + textState.setText(state.toString()); + } + } + + @Override + protected void onDeviceStatusChanged(Object value) { + textState.setText((value == null) ? "" : value.toString()); + } + + public void setDecimals(int decimals) { + readout.setDecimals(decimals); + } + + public int getDecimals() { + return readout.getDecimals(); + } + + @Override + public void setEnabled(boolean value) { + buttonJogNeg.setEnabled(value); + buttonJogPos.setEnabled(value); + buttonBack.setEnabled(value); + buttonFor.setEnabled(value); + buttonReset.setEnabled(value); + buttonStop.setEnabled(value); + spinnerStep.setEnabled(value); + spinnerSpeed.setEnabled(value); + readout.setEnabled(value); + if (!value) { + textState.setText(""); + } + } + + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT + * modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + buttonStop = new javax.swing.JButton(); + buttonReset = new javax.swing.JButton(); + buttonFor = new javax.swing.JButton(); + buttonBack = new javax.swing.JButton(); + readout = new ch.psi.pshell.swing.MotorReadoutPanel(); + buttonJogNeg = new javax.swing.JButton(); + buttonJogPos = new javax.swing.JButton(); + jLabel1 = new javax.swing.JLabel(); + spinnerStep = new javax.swing.JSpinner(); + spinnerSpeed = new javax.swing.JSpinner(); + jLabel2 = new javax.swing.JLabel(); + textState = new javax.swing.JTextField(); + + setBorder(javax.swing.BorderFactory.createTitledBorder("")); + + buttonStop.setText("Stop"); + buttonStop.setToolTipText("Stop Movement"); + buttonStop.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonStopActionPerformed(evt); + } + }); + + buttonReset.setText("Home"); + buttonReset.setToolTipText("Start Homing"); + buttonReset.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonResetActionPerformed(evt); + } + }); + + buttonFor.setText(">|"); + buttonFor.setToolTipText("Step Forward"); + buttonFor.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonForActionPerformed(evt); + } + }); + + buttonBack.setText("|<"); + buttonBack.setToolTipText("Step Backwad"); + buttonBack.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonBackActionPerformed(evt); + } + }); + + buttonJogNeg.setText("<<"); + buttonJogNeg.setToolTipText("Jog Backward"); + buttonJogNeg.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + buttonJogNegMousePressed(evt); + } + public void mouseReleased(java.awt.event.MouseEvent evt) { + buttonJogNegMouseReleased(evt); + } + }); + + buttonJogPos.setText(">>"); + buttonJogPos.setToolTipText("Jog Forward"); + buttonJogPos.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + buttonJogPosMousePressed(evt); + } + public void mouseReleased(java.awt.event.MouseEvent evt) { + buttonJogPosMouseReleased(evt); + } + }); + + jLabel1.setText("Step size:"); + + spinnerStep.setModel(new javax.swing.SpinnerNumberModel(1.0d, 0.001d, 10000.0d, 1.0d)); + + spinnerSpeed.setModel(new javax.swing.SpinnerNumberModel(1.0d, 0.001d, 10000.0d, 1.0d)); + spinnerSpeed.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spinnerSpeedStateChanged(evt); + } + }); + + jLabel2.setText("Speed:"); + + textState.setEditable(false); + textState.setHorizontalAlignment(javax.swing.JTextField.CENTER); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(buttonJogNeg) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonBack) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(readout, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonFor) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonJogPos) + .addGap(8, 8, 8)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createSequentialGroup() + .addComponent(buttonReset) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonStop)) + .addComponent(textState)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spinnerSpeed, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spinnerStep, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()))) + ); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonReset, buttonStop}); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonBack, buttonFor, buttonJogNeg, buttonJogPos}); + + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {spinnerSpeed, spinnerStep}); + + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonBack) + .addComponent(buttonJogNeg)) + .addComponent(readout, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonFor) + .addComponent(buttonJogPos))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(buttonReset) + .addComponent(buttonStop) + .addComponent(spinnerStep, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel1)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(textState, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel2) + .addComponent(spinnerSpeed, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + + layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {buttonBack, buttonFor, buttonJogNeg, buttonJogPos, readout}); + + }// //GEN-END:initComponents + + private void buttonBackActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonBackActionPerformed + try { + double step = (Double) spinnerStep.getValue(); + moveRel(-step); + } catch (Exception ex) { + showException(ex); + } + }//GEN-LAST:event_buttonBackActionPerformed + + private void buttonForActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonForActionPerformed + try { + double step = (Double) spinnerStep.getValue(); + moveRel(step); + } catch (Exception ex) { + showException(ex); + } + + }//GEN-LAST:event_buttonForActionPerformed + + private void buttonResetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonResetActionPerformed + try { + reference(); + } catch (Exception ex) { + showException(ex); + } + + }//GEN-LAST:event_buttonResetActionPerformed + + private void buttonStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonStopActionPerformed + try { + stop(); + } catch (Exception ex) { + showException(ex); + } + + }//GEN-LAST:event_buttonStopActionPerformed + + private void buttonJogPosMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_buttonJogPosMousePressed + try { + jog(true); + } catch (Exception ex) { + showException(ex); + } + }//GEN-LAST:event_buttonJogPosMousePressed + + private void buttonJogPosMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_buttonJogPosMouseReleased + stop(); + }//GEN-LAST:event_buttonJogPosMouseReleased + + private void buttonJogNegMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_buttonJogNegMousePressed + try { + jog(false); + } catch (Exception ex) { + showException(ex); + } + }//GEN-LAST:event_buttonJogNegMousePressed + + private void buttonJogNegMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_buttonJogNegMouseReleased + stop(); + }//GEN-LAST:event_buttonJogNegMouseReleased + + private void spinnerSpeedStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spinnerSpeedStateChanged + try { + setSpeed((Double) spinnerSpeed.getValue()); + } catch (Exception ex) { + showException(ex); + } + }//GEN-LAST:event_spinnerSpeedStateChanged + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonBack; + private javax.swing.JButton buttonFor; + private javax.swing.JButton buttonJogNeg; + private javax.swing.JButton buttonJogPos; + private javax.swing.JButton buttonReset; + private javax.swing.JButton buttonStop; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private ch.psi.pshell.swing.MotorReadoutPanel readout; + private javax.swing.JSpinner spinnerSpeed; + private javax.swing.JSpinner spinnerStep; + private javax.swing.JTextField textState; + // End of variables declaration//GEN-END:variables +}