blob: e30a7faf138fb4f8b708363a1e8e6da363654e1e [file] [log] [blame] [raw]
/**
* Copyright (c) 2010-2011, Vincent Vollers and Christopher J. Kucera
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Minecraft X-Ray team nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL VINCENT VOLLERS OR CJ KUCERA BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.apocalyptech.minecraft.xray.dialog;
import com.apocalyptech.minecraft.xray.XRay;
import static com.apocalyptech.minecraft.xray.MinecraftConstants.*;
import com.centerkey.utils.BareBonesBrowserLaunch;
import java.awt.Font;
import java.awt.Cursor;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.util.List;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Map;
import java.util.HashMap;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.KeyStroke;
import javax.swing.JSeparator;
import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.AbstractAction;
import org.lwjgl.input.Keyboard;
/**
*/
public class KeyMapDialog extends JFrame {
private static final int FRAMEWIDTH = 500;
private static final int FRAMEHEIGHT = 620;
private static String window_title = "X-Ray Keyboard Binding Editor";
private JButton saveButton;
private JButton cancelButton;
private GridBagLayout gridBagLayoutManager;
private JPanel basicPanel;
private static boolean dialog_showing = false;
private static KeyMapDialog keymap_dialog;
public static Image iconImage;
public static HashMap<KEY_ACTIONS, Integer> key_mapping;
private HashMap<KEY_ACTIONS, Integer> newMap;
/***
* Centers this dialog on the screen
*/
private void centerDialogOnScreen() {
Toolkit t = Toolkit.getDefaultToolkit();
Dimension screenSize = t.getScreenSize();
int x = (screenSize.width / 2) - (this.getWidth()/ 2);
int y = (screenSize.height/ 2) - (this.getHeight()/ 2);
gridBagLayoutManager = new GridBagLayout();
this.setLocation(x,y);
}
/***
* Layouts all the controls and labels on the dialog using a gridbaglayout
*/
private void layoutControlsOnDialog() {
this.getContentPane().setLayout(gridBagLayoutManager);
GridBagConstraints c = new GridBagConstraints();
float flabel = 0.1f;
float flist = 1.9f;
JLabel titleLabel = new JLabel(window_title);
titleLabel.setFont(new Font("Arial", Font.BOLD, 16));
Font sectionFont = new Font("Arial", Font.BOLD, 14);
Font descFont = new Font("Arial", Font.PLAIN, 12);
Font keyFont = new Font("Arial", Font.BOLD, 12);
Font noteFont = new Font("Arial", Font.ITALIC, 10);
JLabel sectionLabel;
JLabel descLabel;
JLabel keyLabel;
Insets standardInsets = new Insets(5, 5, 5, 5);
Insets categoryInsets = new Insets(20, 5, 5, 5);
Insets noBottomInsets = new Insets(5, 5, 0, 5);
Insets noTopInsets = new Insets(0, 5, 5, 5);
c.insets = standardInsets;
c.weighty = .1f;
// Scrollpane to put stuff into
JPanel keyPanel = new JPanel();
GridBagLayout keyLayout = new GridBagLayout();
keyPanel.setLayout(keyLayout);
JScrollPane keyScroll = new JScrollPane(keyPanel);
keyScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
keyScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
keyScroll.setBorder(null);
int current_grid_y = 0;
int bound_key;
ACTION_CAT curCat = null;
for (KEY_ACTIONS key : KEY_ACTIONS.values())
{
bound_key = key_mapping.get(key);
current_grid_y++;
c.gridy = current_grid_y;
if (curCat != key.category)
{
curCat = key.category;
c.gridx = 0;
c.gridwidth = 2;
c.anchor = GridBagConstraints.WEST;
c.insets = categoryInsets;
sectionLabel = new JLabel(curCat.title);
sectionLabel.setFont(sectionFont);
addComponent(keyPanel, sectionLabel, c, keyLayout);
current_grid_y++;
c.gridy = current_grid_y;
c.gridwidth = 1;
c.insets = standardInsets;
}
if (key == KEY_ACTIONS.TOGGLE_SLIME_CHUNKS)
{
c.insets = noBottomInsets;
}
c.gridx = 0;
c.anchor = GridBagConstraints.EAST;
descLabel = new JLabel(key.desc + ":");
descLabel.setFont(descFont);
addComponent(keyPanel, descLabel, c, keyLayout);
c.gridx = 1;
c.anchor = GridBagConstraints.WEST;
switch (key)
{
case SPEED_INCREASE:
keyLabel = new JLabel(Keyboard.getKeyName(bound_key) + " / Left Mouse Button (hold)");
break;
case SPEED_DECREASE:
keyLabel = new JLabel(Keyboard.getKeyName(bound_key) + " / Right Mouse Button (hold)");
break;
case QUIT:
keyLabel = new JLabel("CTRL-" + Keyboard.getKeyName(bound_key));
break;
default:
if (Keyboard.getKeyName(bound_key).startsWith("NUMPAD"))
{
keyLabel = new JLabel(Keyboard.getKeyName(bound_key) + " (numlock must be on)");
}
else if (Keyboard.getKeyName(bound_key).equals("GRAVE"))
{
keyLabel = new JLabel("` (grave accent)");
}
else
{
keyLabel = new JLabel(Keyboard.getKeyName(bound_key));
}
break;
}
keyLabel.setFont(keyFont);
addComponent(keyPanel, keyLabel, c, keyLayout);
// One extra note for slime chunks
if (key == KEY_ACTIONS.TOGGLE_SLIME_CHUNKS)
{
current_grid_y++;
c.gridy = current_grid_y;
c.insets = noTopInsets;
c.gridx = 0;
c.anchor = GridBagConstraints.EAST;
descLabel = new JLabel("");
addComponent(keyPanel, descLabel, c, keyLayout);
c.gridx = 1;
c.anchor = GridBagConstraints.WEST;
keyLabel = new JLabel("May not be accurate for all Minecraft Versions");
keyLabel.setFont(noteFont);
addComponent(keyPanel, keyLabel, c, keyLayout);
c.insets = standardInsets;
}
}
current_grid_y = 0;
// A title
current_grid_y++;
c.weightx = 1f;
c.weighty = 0f;
c.gridx = 0; c.gridy = current_grid_y;
c.anchor = GridBagConstraints.CENTER;
addComponent(this.getContentPane(), titleLabel, c);
// Add our scrollpane to the window
current_grid_y++;
c.weightx = 1f;
c.weighty = 1f;
c.gridx = 0; c.gridy = current_grid_y;
c.fill = GridBagConstraints.BOTH;
addComponent(this.getContentPane(), keyScroll, c);
// Now add the buttons
c.insets = new Insets(5,15,5,15);
current_grid_y++;
c.weightx = flist;
c.weighty = 0f;
c.gridx = 0; c.gridy = current_grid_y;
c.anchor = GridBagConstraints.EAST;
c.fill = GridBagConstraints.HORIZONTAL;
addComponent(this.getContentPane(), saveButton,c);
current_grid_y++;
c.weightx = flist;
c.weighty = 0f;
c.gridx = 0; c.gridy = current_grid_y;
c.anchor = GridBagConstraints.EAST;
c.fill = GridBagConstraints.HORIZONTAL;
addComponent(this.getContentPane(), cancelButton,c);
}
/***
* Adds a component to the container and updates the constraints for that component
* @param root The contiainer to add the component to
* @param comp The component to add to the container
* @param constraints The constraints which affect the component
*/
private void addComponent(Container root, Component comp, GridBagConstraints constraints) {
gridBagLayoutManager.setConstraints(comp,constraints);
root.add(comp);
}
/***
* Adds a component to the container and updates the constraints for that component
* @param root The contiainer to add the component to
* @param comp The component to add to the container
* @param constraints The constraints which affect the component
* @param manager The GridBagLayout to operate on
*/
private void addComponent(Container root, Component comp, GridBagConstraints constraints, GridBagLayout manager) {
manager.setConstraints(comp,constraints);
root.add(comp);
}
/***
* Builds the Go and Exit Buttons and attaches the actions to them
*/
private void buildButtons() {
JRootPane rootPane = this.getRootPane();
// The "Save" button
saveButton = new JButton("Save");
saveButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialogSave();
}
});
// Key mapping for the Save button. Enter is Save
KeyStroke enterStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false);
rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(enterStroke, "ENTER");
rootPane.getActionMap().put("ENTER", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
dialogSave();
}
});
// The "Cancel" button
cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialogExit();
}
});
// Key mapping for the Save button. Enter is Save
KeyStroke escapeStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escapeStroke, "ESCAPE");
rootPane.getActionMap().put("ESCAPE", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
dialogExit();
}
});
}
/**
* Actions to perform if the "Jump" button is hit, or otherwise triggered.
*/
private void dialogSave()
{
newMap = buildHashMap();
setVisible(false);
dispose();
KeyMapDialog.dialog_showing = false;
synchronized(KeyMapDialog.this) {
KeyMapDialog.this.notify();
}
}
private void dialogExit()
{
newMap = null;
setVisible(false);
dispose();
KeyMapDialog.dialog_showing = false;
synchronized(KeyMapDialog.this) {
KeyMapDialog.this.notify();
}
}
/***
* Creates a new KeyMapDialog
* @param windowName the title of the dialog
*/
protected KeyMapDialog()
{
super(window_title);
if(KeyMapDialog.iconImage != null)
this.setIconImage(KeyMapDialog.iconImage);
this.setSize(FRAMEWIDTH,FRAMEHEIGHT);
this.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
this.addWindowListener(new WindowListener() {
public void windowActivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowClosing(WindowEvent e)
{
dialogExit();
}
public void windowDeactivated(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}
});
this.setMinimumSize(new Dimension(FRAMEWIDTH, FRAMEHEIGHT));
centerDialogOnScreen();
buildButtons();
layoutControlsOnDialog();
validate();
this.setVisible(true);
}
/***
* Pops up the dialog window
* @param windowName the title of the dialog
*/
public static HashMap<KEY_ACTIONS, Integer> presentDialog(HashMap<KEY_ACTIONS, Integer> key_mapping)
{
if (dialog_showing)
{
KeyMapDialog.keymap_dialog.toFront();
KeyMapDialog.keymap_dialog.requestFocus();
}
else
{
KeyMapDialog.key_mapping = key_mapping;
KeyMapDialog.dialog_showing = true;
KeyMapDialog.keymap_dialog = new KeyMapDialog();
}
try {
synchronized(keymap_dialog) {
keymap_dialog.wait();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return keymap_dialog.newMap;
}
public static void closeDialog()
{
if (KeyMapDialog.dialog_showing && KeyMapDialog.keymap_dialog != null)
{
KeyMapDialog.keymap_dialog.dialogExit();
}
}
}