Package com.limelight.gui

Source Code of com.limelight.gui.GamepadConfigFrame$GamepadCheckBox

package com.limelight.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.HashMap;
import java.util.Map.Entry;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;

import com.limelight.LimeLog;
import com.limelight.input.Device;
import com.limelight.input.DeviceListener;
import com.limelight.input.gamepad.GamepadComponent;
import com.limelight.input.gamepad.GamepadListener;
import com.limelight.input.gamepad.GamepadMapping;
import com.limelight.input.gamepad.GamepadMapping.Mapping;
import com.limelight.input.gamepad.SourceComponent.Direction;
import com.limelight.input.gamepad.SourceComponent;
import com.limelight.settings.GamepadSettingsManager;

/**
* A frame used to configure the gamepad mappings.
* @author Diego Waxemberg
*/
public class GamepadConfigFrame extends JFrame {
  private static final long serialVersionUID = 1L;

  private boolean configChanged = false;

  private MappingThread mappingThread;
  private GamepadMapping config;
  private HashMap<Box, Mapping> componentMap;

  /**
   * Constructs a new config frame. The frame is initially invisible and will <br>
   * be made visible after all components are built by calling <code>build()</code>
   */
  public GamepadConfigFrame() {
    super("Gamepad Settings");
    LimeLog.info("Creating Settings Frame");
    this.setSize(850, 550);
    this.setResizable(false);
    this.setAlwaysOnTop(true);
    config = GamepadSettingsManager.getSettings();
  }

  /**
   * Builds all components of the config frame and sets the frame visible.
   */
  public void build() {
    componentMap = new HashMap<Box, Mapping>();

    GridLayout layout = new GridLayout(GamepadComponent.values().length/2 + 1, 2);
    layout.setHgap(60);
    layout.setVgap(3);
    JPanel mainPanel = new JPanel(layout);

    GamepadComponent[] components = GamepadComponent.values();

    for (int i = 0; i < components.length; i++) {

      Mapping mapping = config.get(components[i]);
      if (mapping == null) {
        mapping = config.new Mapping(components[i], false, false);
      }
      Box componentBox = createComponentBox(mapping);

      mainPanel.add(componentBox);

    }

    Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();

    this.setLocation(dim.width/2-this.getSize().width/2, dim.height/2-this.getSize().height/2);
    this.setLayout(new BorderLayout());

    this.getContentPane().add(mainPanel, "Center");
    this.getContentPane().add(Box.createVerticalStrut(20), "North");
    this.getContentPane().add(Box.createVerticalStrut(20), "South");
    this.getContentPane().add(Box.createHorizontalStrut(20), "East");
    this.getContentPane().add(Box.createHorizontalStrut(20), "West");

    this.addWindowListener(createWindowListener());
    this.setVisible(true);
  }

  /*
   * Creates the box that holds the button and checkboxes
   */
  private Box createComponentBox(Mapping mapping) {
    Box componentBox = Box.createHorizontalBox();

    JButton mapButton = new JButton();
    JCheckBox invertBox = new GamepadCheckBox("Invert", GamepadCheckBox.Type.INVERT);
    JCheckBox triggerBox = new GamepadCheckBox("Trigger", GamepadCheckBox.Type.TRIGGER);

    Dimension buttonSize = new Dimension(110, 24);
    mapButton.setMaximumSize(buttonSize);
    mapButton.setMinimumSize(buttonSize);
    mapButton.setPreferredSize(buttonSize);
    mapButton.addActionListener(createMapListener());

    setButtonText(mapButton, config.getMapping(mapping.padComp));

    invertBox.setSelected(mapping.invert);
    invertBox.addActionListener(createCheckboxListener());
    invertBox.setName(mapping.padComp.name());

    triggerBox.setSelected(mapping.trigger);
    triggerBox.addActionListener(createCheckboxListener());
    triggerBox.setName(mapping.padComp.name());
    triggerBox.setToolTipText("If this component should act as a trigger. (one-way axis)");

    componentBox.add(Box.createHorizontalStrut(5));
    componentBox.add(mapping.padComp.getLabel());
    componentBox.add(Box.createHorizontalGlue());
    componentBox.add(mapButton);
    componentBox.add(invertBox);
    componentBox.add(triggerBox);
    componentBox.add(Box.createHorizontalStrut(5));

    componentBox.setBorder(new LineBorder(Color.GRAY, 1, true));

    componentMap.put(componentBox, mapping);

    return componentBox;
  }

  /*
   * Creates the listener for the checkbox
   */
  private ActionListener createCheckboxListener() {
    return new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        JCheckBox clicked = (JCheckBox)e.getSource();
        GamepadComponent padComp = GamepadComponent.valueOf(clicked.getName());
        Mapping currentMapping = config.get(padComp);
        if (currentMapping == null) {
          //this makes more semantic sense to me than using !=
          clicked.setSelected(!(clicked.isSelected()));
        } else {
          ((GamepadCheckBox)clicked).setValue(currentMapping, clicked.isSelected());
          configChanged = true;
        }
      }
    };
  }

  /*
   * Creates the listener for the window.
   * It will save configs on exit and restart controller threads
   */
  private WindowListener createWindowListener() {
    return new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent e) {
        if (mappingThread != null && mappingThread.isAlive()) {
          mappingThread.interrupt();
        }
        if (configChanged) {
          updateConfigs();
        }
        dispose();
      }
    };
  }

  /*
   * Creates the listener for the map button
   */
  private ActionListener createMapListener() {
    return new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        Box toMap = (Box)((JButton)e.getSource()).getParent();

        if (GamepadListener.getInstance().deviceCount() == 0) {
          JOptionPane.showMessageDialog(GamepadConfigFrame.this, "No Gamepad Detected");
          return;
        }

        map(toMap);
      }
    };
  }

  /*
   * Maps a gamepad component to the clicked component
   */
  private void map(final Box toMap) {
    if (mappingThread == null || !mappingThread.isAlive()) {

      //a little janky, could probably be fixed up a bit
      final JButton buttonPressed = getButton(toMap);
      final Mapping mappingToMap = componentMap.get(toMap);

      buttonPressed.setSelected(true);

      buttonPressed.setText("Select Input");

      mappingThread = new MappingThread(buttonPressed, mappingToMap);
      mappingThread.start();

      GamepadListener.getInstance().addDeviceListener(mappingThread);
    }

  }

  /*
   * Helper method to get the box component that contains the given a mapping
   */
  private Box getBox(Mapping mapping) {
    for (Entry<Box, Mapping> entry : componentMap.entrySet()) {
      if (entry.getValue() == mapping) {
        return entry.getKey();
      }
    }
    return null;
  }

  /*
   * Helper method to get the button out of the box component
   */
  private JButton getButton(Box componentBox) {
    for (java.awt.Component comp : componentBox.getComponents()) {
      if (comp instanceof JButton)
        return (JButton)comp;
    }
    return null;
  }

  /*
   * Writes the current cofig to the configs on disk.
   */
  private void updateConfigs() {
    GamepadSettingsManager.writeSettings(config);
  }

  private void setButtonText(JButton button, SourceComponent comp) {
    if (comp == null) {
      button.setText("");
    } else {
      String dir = "";
      if (comp.getDirection() == Direction.POSITIVE) {
        dir = "+";
      } else if (comp.getDirection() == Direction.NEGATIVE) {
        dir = "-";
      }
      button.setText(comp.getType().name() + " " + comp.getId() + " " + dir);
    }
  }

  private class MappingThread extends Thread implements DeviceListener {
    private SourceComponent newMapping = null;
    private JButton buttonPressed;
    private Mapping mappingToMap;

    public MappingThread(JButton buttonPressed, Mapping mappingToMap) {
      super("Gamepad Mapping Thread");
      this.buttonPressed = buttonPressed;
      this.mappingToMap = mappingToMap;
    }

    @Override
    public void run() {

      while (newMapping == null) {
        try {
          Thread.sleep(100);
        } catch (InterruptedException e) {
          setButtonText(buttonPressed, config.getMapping(mappingToMap.padComp));
          GamepadListener.getInstance().removeListener(this);
          buttonPressed.setSelected(false);
          return;
        }
      }

      Mapping oldConfig = config.get(newMapping);
      if (oldConfig != null) {
        getButton(getBox(oldConfig)).setText("");
      }

      SourceComponent oldSource = config.getMapping(mappingToMap.padComp);
      if (oldSource != null) {
        config.remove(oldSource);
      }

      config.insertMapping(mappingToMap, newMapping);

      setButtonText(buttonPressed, newMapping);
      buttonPressed.setSelected(false);
      configChanged = true;

      GamepadListener.getInstance().removeListener(this);

    }

    public void handleButton(Device device, int buttonId, boolean pressed) {
      if (pressed) {
        newMapping = new SourceComponent(SourceComponent.Type.BUTTON, buttonId, null);
      }
    }

    public void handleAxis(Device device, int axisId, float newValue,
        float lastValue) {
      if (newValue > 0.75) {
        newMapping = new SourceComponent(SourceComponent.Type.AXIS, axisId, Direction.POSITIVE);
      } else if (newValue < -0.75) {
        newMapping = new SourceComponent(SourceComponent.Type.AXIS, axisId, Direction.NEGATIVE);
      }
    }

  }

  private static class GamepadCheckBox extends JCheckBox {
    private static final long serialVersionUID = 1L;
    private enum Type { TRIGGER, INVERT }
    private Type type;

    public GamepadCheckBox(String text, Type type) {
      super(text);
      this.type = type;
    }

    public void setValue(Mapping mapping, boolean value) {
      switch (type) {
      case TRIGGER:
        mapping.trigger = value;
        break;
      case INVERT:
        mapping.invert = value;
        break;
      default:
        LimeLog.severe("You did something terrible and should feel terrible.");
        LimeLog.severe("Fix it or the checkbox gods will smite you!");
        break;
      }
    }
  }
}
TOP

Related Classes of com.limelight.gui.GamepadConfigFrame$GamepadCheckBox

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.