package com.knutejohnson.pi.jpigpio.gui;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;
import java.util.*;

import com.knutejohnson.pi.jpigpio.*;
import static com.knutejohnson.pi.jpigpio.JPigpioConstants.*;
import com.knutejohnson.pi.jpigpio.gui.*;

/**
 * JPButtonExample is a simple program to demonstrate the use of
 * JPMomentaryButton and JPLatchingButton.
 *
 * @author  Knute Johnson
 * @version 2021-11-29
 */
public class JPButtonExample extends JFrame {
    /** Serial version UID */
    private static final long serialVersionUID = 1L;

    /** Momentary button */
    private JPMomentaryButton momButton;

    /** Latching button */
    private JPLatchingButton latButton;

    /**
     * Create a new JPButtonExample GUI.
     */
    public JPButtonExample() {
        super("JPButtonExample");

        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(30,30,30,30));

        GridBagConstraints c = new GridBagConstraints();
        c.insets = new Insets(2,2,2,2);
        c.gridy = 0;

        try {
            JPigpio j = new JPigpio();

            addWindowListener(new WindowAdapter() {
                public void windowClosing(WindowEvent we) {
                    try {
                        j.close();
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }
                    dispose();
                }
            });

            c.gridwidth = 4;
            JLabel label =
             new JLabel("Control a GPIO output with a JP?Button",JLabel.CENTER);
            panel.add(label,c);

            momButton = new JPMomentaryButton("Momentary");
            latButton = new JPLatchingButton("Latching");

            java.util.List<Integer> validGPIO = new ArrayList<>();
            validGPIO.add(0);
            for (int i=2; i<=27; i++)
                validGPIO.add(i);

            ++c.gridy;  c.gridwidth = 1;
            JComboBox<Integer> momBox =
             new JComboBox<>(validGPIO.toArray(new Integer[0]));
            momBox.addActionListener(ev -> {
                int gpio =
                 ((Integer)((JComboBox)ev.getSource()).getSelectedItem());
                momButton.setEnabled(gpio != 0);
            }); 
            panel.add(momBox,c);

            momButton.setEnabled(false);
            momButton.addJPButtonListener(be -> {
                try {
                    int gpio = (Integer)momBox.getSelectedItem();
                    if (gpio != 0) {
                        if (j.modeGet(gpio) != PI_OUTPUT)
                            j.modeSet(gpio,PI_OUTPUT);
                        momBox.setEnabled(be.getId() == JPButtonEvent.OFF);
                        j.write(gpio,
                         be.getId() == JPButtonEvent.ON ? PI_ON : PI_OFF);
                        System.out.printf("%d %s\n",gpio,
                         be.getId() == JPButtonEvent.ON ? "ON" : "OFF");
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            });
            panel.add(momButton,c);
    
            JComboBox<Integer> latBox =
             new JComboBox<>(validGPIO.toArray(new Integer[0]));
            latBox.addActionListener(ev -> {
                int gpio =
                 ((Integer)((JComboBox)ev.getSource()).getSelectedItem());
                latButton.setEnabled(gpio != 0);
            }); 
            panel.add(latBox,c);

            latButton.setEnabled(false);
            latButton.addJPButtonListener(be -> {
                try {
                    int gpio = (Integer)latBox.getSelectedItem();
                    if (gpio != 0) {
                        if (j.modeGet(gpio) != PI_OUTPUT)
                            j.modeSet(gpio,PI_OUTPUT);
                        latBox.setEnabled(be.getId() == JPButtonEvent.OFF);
                        j.write(gpio,
                         be.getId() == JPButtonEvent.ON ? PI_ON : PI_OFF);
                        System.out.printf("%d %s\n",gpio,
                         be.getId() == JPButtonEvent.ON ? "ON" : "OFF");
                    }
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            });
            panel.add(latButton,c);
    
            add(panel,BorderLayout.CENTER);
            pack();
            setLocationRelativeTo(null);
            setVisible(true);
        } catch (IOException ioe) {
            JOptionPane.showMessageDialog(null,
             ioe.toString().concat(ioe instanceof ConnectException ?
             "\nProbably caused by pigpiod not running" : ""),
             "Fatal Error",JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * Program entry point.
     *
     * @param   args    command line arguments (not used)
     */
    public static void main(String... args) {
        EventQueue.invokeLater(() -> new JPButtonExample());
    }
}
package com.knutejohnson.pi.jpigpio.gui;

import java.util.*;

/**
 * Button event for use with JPMomentaryButton and JPLatchingButton.
 *
 * @author  Knute Johnson
 * @version 2020-12-28
 */
public class JPButtonEvent extends EventObject {
    /** Serial version UID */
    private static final long serialVersionUID = 1L;

    /** Off button state */
    public static final int OFF = 0;

    /** On button state */
    public static final int ON = 1;

    /** Event id */
    private int id = OFF;

    /**
     * Create a new JPButton event.
     *
     * @param   source  object creating the event
     * @param   id      event id, OFF or ON
     */
    public JPButtonEvent(Object source, int id) {
        super(source);
        this.id = id;
    }

    /**
     * Gets the event id.
     *
     * @return  event id, OFF or ON
     */
    public int getId() {
        return id;
    }
}

package com.knutejohnson.pi.jpigpio.gui;

import java.util.*;

/**
 * JPButtonEvent listener interface.
 *
 */
public interface JPButtonListener extends EventListener {
    /**
     * Invoked when event occurs.
     *
     * @param   be  event passed to be processed
     */
    public void buttonState(JPButtonEvent be);
}

package com.knutejohnson.pi.jpigpio.gui;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

/**
 * JPLatchingButton creates an ON JPButtonEvent when the mouse or space key
 * is pressed and an OFF JPButtonEvent when the mouse or space key is pressed
 * again.
 *
 * @author  Knute Johnson
 * @version 2020-12-28
 */
public class JPLatchingButton extends JToggleButton {
    /** Serial version UID */
    private static final long serialVersionUID = 1L;

    /** List of JPButtonListeners attached to this button */
    private final java.util.List<JPButtonListener> jpbutListeners =
      new ArrayList<>();

    /**
     * Create a new JPLatchingButton object.
     *
     * @param   text    button text
     */
    public JPLatchingButton(String text) {
        super(text);

        addChangeListener(ce -> {
            ButtonModel model = ((AbstractButton)ce.getSource()).getModel();
            if (!model.isArmed() && !model.isPressed() && model.isSelected())
                fireJPButtonEvent(JPButtonEvent.ON);
            if (!model.isArmed() && !model.isPressed() && !model.isSelected())
                fireJPButtonEvent(JPButtonEvent.OFF);
        });

    }

    /**
     * Adds a JPButtonListener to this button.
     *
     * @param   listener    the JPButtonListener to be added
     */
    public void addJPButtonListener(JPButtonListener listener) {
        jpbutListeners.add(listener);
    }

    /**
     * Removes a JPbuttonListener from the button.
     *
     * @param   listener    the listener to be removed
     */
    public void removeJPButtonListener(JPButtonListener listener) {
        jpbutListeners.remove(listener);
    }

    /**
     * Notifies all listeners that have registered for notification of this
     * type of event.
     *
     * @param   id  the event id, ON or OFF
     */
    public void fireJPButtonEvent(int id) {
        JPButtonEvent ev = new JPButtonEvent(this,id);

        for (JPButtonListener listener : jpbutListeners)
            listener.buttonState(ev);
    }
}

package com.knutejohnson.pi.jpigpio.gui;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;

/**
 * JPMomentary button creates an ON JPButtonEvent when the mouse or space key
 * is pressed and a OFF JPButtonEvent when released.
 *
 * @author  Knute Johnson
 * @version 2020-12-28
 */
public class JPMomentaryButton extends JToggleButton {
    /** Serial version UID */
    private static final long serialVersionUID = 1L;

    /** List of JPButtonListeners */
    private final java.util.List<JPButtonListener> jpbutListeners =
      new ArrayList<>();

    /**
     * Create a new JPMomentaryButton
     *
     * @param   text    button text
     */
    public JPMomentaryButton(String text) {
        super(text);

        // remove all the change listeners so they won't interfere with the
        // mouse or space key
        for (ChangeListener l : getChangeListeners())
            removeChangeListener(l);

        addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent me) {
                ((AbstractButton)me.getSource()).getModel().setSelected(true);
                fireJPButtonEvent(JPButtonEvent.ON);
            }
            public void mouseReleased(MouseEvent me) {
                ((AbstractButton)me.getSource()).getModel().setSelected(false);
                fireJPButtonEvent(JPButtonEvent.OFF);
            }
        });

        addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent ke) {
                if (ke.getKeyCode() == KeyEvent.VK_SPACE) {
                    ((AbstractButton)ke.getSource()).getModel().
                     setSelected(true);
                    fireJPButtonEvent(JPButtonEvent.ON);
                }
            }
            public void keyReleased(KeyEvent ke) {
                if (ke.getKeyCode() == KeyEvent.VK_SPACE) {
                    ((AbstractButton)ke.getSource()).getModel().
                     setPressed(false);
                    ((AbstractButton)ke.getSource()).getModel().
                     setSelected(false);
                    fireJPButtonEvent(JPButtonEvent.OFF);
                }
            }
        });
    }

    /**
     * Adds a JPButtonListener to this button.
     *
     * @param   listener    the JPButtonListener to register for events
     */
    public void addJPButtonListener(JPButtonListener listener) {
        jpbutListeners.add(listener);
    }

    /**
     * Removes a JPButtonListener from this button.
     *
     * @param   listener    the JPButtonListener to remove from the registry
     */
    public void removeJPButtonListener(JPButtonListener listener) {
        jpbutListeners.remove(listener);
    }

    /**
     * Send a JPButtonEvent to all the registered listeners.
     *
     * @param   id  event id of this event
     */
    public void fireJPButtonEvent(int id) {
        JPButtonEvent ev = new JPButtonEvent(this,id);

        for (JPButtonListener listener : jpbutListeners)
            listener.buttonState(ev);
    }
}