/** | |
* 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.plusminus.craft; | |
/* | |
* Copyright (c) 2005-2006, The ParticleReality Project | |
* 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 ParticleReality Project 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 THE COPYRIGHT OWNER OR | |
* CONTRIBUTORS 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. | |
*/ | |
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.ItemEvent; | |
import java.awt.event.ItemListener; | |
import java.util.ArrayList; | |
import java.util.Map; | |
import java.util.TreeMap; | |
import java.util.TreeSet; | |
import java.util.HashMap; | |
import java.util.Properties; | |
import javax.swing.Box; | |
import javax.swing.ComboBoxModel; | |
import javax.swing.DefaultComboBoxModel; | |
import javax.swing.JButton; | |
import javax.swing.JCheckBox; | |
import javax.swing.JComboBox; | |
import javax.swing.JFrame; | |
import javax.swing.JLabel; | |
import javax.swing.JList; | |
import javax.swing.JPanel; | |
import javax.swing.JSeparator; | |
import javax.swing.ButtonGroup; | |
import javax.swing.JRadioButton; | |
import javax.swing.SwingConstants; | |
import javax.swing.plaf.basic.BasicComboBoxRenderer; | |
import org.lwjgl.LWJGLException; | |
import org.lwjgl.opengl.Display; | |
import org.lwjgl.opengl.DisplayMode; | |
/*** | |
* Static popup screen which enables the user to set values such as | |
* resolution, refreshrate, antialas modes and fullscreen</br> | |
* </br> | |
* Will query the system for available resolutions, bit depths and appropriate | |
* refresh rates.</br> | |
* </br> | |
* Allows the programmer to pass a set of preferred values for each property, | |
* the ResolutionDialog will attempt to find the nearest match</br> | |
* </br> | |
* Allows the programmer to attach a second panel where optional | |
* advanced properties can be set</br> | |
* </br> | |
* The static method "presentDialog" will popup the screen and will not | |
* return untill the user has either selected "go" or "exit". The return | |
* value of the method determines which button the user has clicked</br> | |
* </br> | |
* </br> | |
* </br> | |
* <i>(example:)</i><br/> | |
* <code> | |
* if(ResolutionDialog.presentDialog("Choose Video Options") == ResolutionDialog.DIALOG_BUTTON_EXIT) { | |
* System.exit(0); | |
* } | |
* </code> | |
* <br/> | |
* The selected properties can be read this way<br/> | |
* <code> | |
* ResolutionDialog.selectedDisplayMode | |
* ResolutionDialog.selectedFullScreenValue | |
* ResolutionDialog.selectedWorld | |
* </code> | |
* @author Vincent Vollers | |
* @version 1.0 | |
*/ | |
public class ResolutionDialog extends JFrame { | |
private static final long serialVersionUID = -1496486770452508286L; | |
private static final int FRAMEWIDTH = 400; | |
private static final int FRAMEHEIGHT = 400; | |
private static final int[][] defaultPreferredResolutions = | |
new int[][] {{1920,1080},{1600,900},{1280,720},{1024, 768}, {800, 600}, {666, 666}, {1280,1024}}; | |
// fallbackResolutions defines resolutions that we'll offer in the dropdown regardless of whether or not | |
// they show up in the list of detected resolutions | |
private static final int[][] fallbackResolutions = | |
new int[][] {{1280,1024},{1024,768},{800,600}}; | |
private static final int[] defaultPreferredBitDepths = | |
new int[] {32, 16, 8}; | |
private static final int[] defaultPreferredRefreshRates = | |
new int[] {85, 80, 75, 70, 65, 60}; | |
private static final boolean defaultPreferredFullScreenValue = false; | |
public static final int DIALOG_BUTTON_EXIT = 0; | |
public static final int DIALOG_BUTTON_GO = 1; | |
private JComboBox resolutionsList; | |
private JComboBox bitDepthList; | |
private JComboBox refreshRateList; | |
private JButton runButton; | |
private JButton exitButton; | |
private GridBagLayout gridBagLayoutManager; | |
private JPanel basicPanel; | |
private JCheckBox fullScreenCheckBox; | |
private ButtonGroup worldButtonGroup; | |
JRadioButton[] worldButtons; | |
private DefaultComboBoxModel resolutionsModel; | |
private DefaultComboBoxModel bitDepthModel; | |
private DefaultComboBoxModel refreshRateModel; | |
private Map<IntegerPair, List<DisplayMode>> resolutionsMap; | |
private ArrayList<WorldInfo> availableWorlds; | |
private int[][] preferredResolutions; | |
private int[] preferredRefreshRates; | |
private int[] preferredBitDepths; | |
private boolean preferredFullScreenValue; | |
private String preferredWorld; | |
private int exitCode = -1; | |
private Properties xray_properties; | |
public static DisplayMode selectedDisplayMode; | |
public static int selectedRefreshRate; | |
public static int selectedBitDepth; | |
public static boolean selectedFullScreenValue; | |
public static int selectedWorld; | |
public static Image iconImage; | |
/*** | |
* Class holding a pair of two integers where the order is determined | |
* first by the first integer and when these are equal, by the second | |
* integer. This is used for holding resolution information | |
* @author Vincent Vollers | |
*/ | |
@SuppressWarnings("rawtypes") | |
private class IntegerPair implements Comparable { | |
private int valueOne; | |
private int valueTwo; | |
public IntegerPair(int valueOne, int valueTwo) { | |
this.valueOne = valueOne; | |
this.valueTwo = valueTwo; | |
} | |
public int getValueOne() { | |
return this.valueOne; | |
} | |
public int getValueTwo() { | |
return this.valueTwo; | |
} | |
public int compareTo(Object o) { | |
if(!(o instanceof IntegerPair)) { | |
return -1; | |
} | |
IntegerPair i = (IntegerPair) o; | |
if(i.getValueOne()>valueOne) | |
return 1; | |
if(i.getValueOne()<valueOne) | |
return -1; | |
if(i.getValueTwo()>valueTwo) | |
return 1; | |
if(i.getValueTwo()<valueTwo) | |
return -1; | |
return 0; | |
} | |
} | |
/*** | |
* Renders IntegerPairs ("[a] x [b]", so "1024 x 768" for example) | |
* @author Vincent Vollers | |
*/ | |
private class DisplayModesRenderer extends BasicComboBoxRenderer { | |
private static final long serialVersionUID = 8272355980006119103L; | |
public DisplayModesRenderer() { | |
super(); | |
} | |
public Component getListCellRendererComponent( | |
JList list, | |
Object value, | |
int index, | |
boolean isSelected, | |
boolean cellHasFocus) | |
{ | |
IntegerPair pair = (IntegerPair) value; | |
String newValue = "" + pair.getValueOne() + " x " + pair.getValueTwo(); | |
return super.getListCellRendererComponent(list, newValue, index, isSelected, cellHasFocus); | |
} | |
} | |
/*** | |
* 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(ArrayList<WorldInfo> availableWorlds) { | |
basicPanel = new JPanel(); | |
this.getContentPane().setLayout(gridBagLayoutManager); | |
basicPanel.setLayout(gridBagLayoutManager); | |
GridBagConstraints c = new GridBagConstraints(); | |
JLabel resolutionsLabel = new JLabel("Resolution: "); | |
JLabel bitDepthLabel = new JLabel("Bit Depth: "); | |
JLabel refreshRateLabel = new JLabel("Refresh Rate: "); | |
JLabel fullScreenLabel = new JLabel("Full Screen: "); | |
float flabel = 0.1f; | |
float flist = 1.9f; | |
c.insets = new Insets(5,5,5,5); | |
c.weighty = .1f; | |
// Add the resolution label | |
c.weightx = flabel; | |
c.gridx = 0; c.gridy = 0; | |
c.anchor = GridBagConstraints.EAST; | |
c.fill = GridBagConstraints.NONE; | |
addComponent(basicPanel, resolutionsLabel,c); | |
// Add the resolution list | |
c.weightx = flist; | |
c.fill = GridBagConstraints.HORIZONTAL; | |
c.gridx = 1; c.gridy = 0; | |
addComponent(basicPanel, resolutionsList,c); | |
// Add the bit depth label | |
c.weightx = flabel; | |
c.gridx = 0; c.gridy = 1; | |
c.fill = GridBagConstraints.NONE; | |
c.anchor = GridBagConstraints.EAST; | |
addComponent(basicPanel, bitDepthLabel,c); | |
// Add the bit depth list | |
c.weightx = flist; | |
c.fill = GridBagConstraints.HORIZONTAL; | |
c.gridx = 1; c.gridy = 1; | |
addComponent(basicPanel, bitDepthList,c); | |
// Add the refresh rate label | |
c.weightx = flabel; | |
c.gridx = 0; c.gridy = 2; | |
c.fill = GridBagConstraints.NONE; | |
c.anchor = GridBagConstraints.EAST; | |
addComponent(basicPanel, refreshRateLabel,c); | |
// Add the refresh rate list | |
c.weightx = flist; | |
c.fill = GridBagConstraints.HORIZONTAL; | |
c.gridx = 1; c.gridy = 2; | |
addComponent(basicPanel, refreshRateList,c); | |
// Add the fullscreen label | |
c.weightx = flabel; | |
c.gridx = 0; c.gridy = 3; | |
c.fill = GridBagConstraints.NONE; | |
c.anchor = GridBagConstraints.EAST; | |
addComponent(basicPanel, fullScreenLabel,c); | |
// Set up the fullscreen checkbox | |
fullScreenCheckBox = new JCheckBox(); | |
c.insets = new Insets(5,0,5,0); | |
fullScreenCheckBox.setSelected(this.preferredFullScreenValue); | |
// Add the fullscreen checkbox | |
c.weightx = flist; | |
c.gridx = 1; c.gridy = 3; | |
c.fill = GridBagConstraints.HORIZONTAL; | |
addComponent(basicPanel, fullScreenCheckBox,c); | |
// Separator | |
c.insets = new Insets(5,5,5,5); | |
c.weightx = 1.0f; | |
c.gridx = 0; c.gridy = 4; | |
c.gridwidth = 2; | |
c.fill = GridBagConstraints.HORIZONTAL; | |
addComponent(basicPanel, Box.createVerticalStrut(5), c); | |
addComponent(basicPanel, new JSeparator(SwingConstants.HORIZONTAL), c); | |
addComponent(basicPanel, Box.createVerticalStrut(5), c); | |
// World Label | |
c.gridx = 0; c.gridy = 6; | |
c.gridwidth = 2; | |
addComponent(basicPanel, new JLabel("Choose a World to Open:"), c); | |
// Create a buttongroup and radio buttons | |
worldButtonGroup = new ButtonGroup(); | |
worldButtons = new JRadioButton[availableWorlds.size()]; | |
int curidx = 0; | |
int selectedWorld = 0; | |
boolean matched_world = false; | |
for (WorldInfo world : availableWorlds) | |
{ | |
JRadioButton button; | |
if (world.isCustom()) | |
{ | |
button = new JRadioButton("Other..."); | |
} | |
else if (world.isNether()) | |
{ | |
button = new JRadioButton("World " + world.getWorldnum() + " Nether"); | |
} | |
else | |
{ | |
button = new JRadioButton("World " + world.getWorldnum()); | |
} | |
worldButtonGroup.add(button); | |
worldButtons[curidx] = button; | |
if (!matched_world && this.preferredWorld != null) | |
{ | |
if (world.isCustom()) | |
{ | |
selectedWorld = curidx; | |
matched_world = true; | |
} | |
else if (world.getBasePath().equalsIgnoreCase(this.preferredWorld)) | |
{ | |
selectedWorld = curidx; | |
matched_world = true; | |
} | |
} | |
curidx += 1; | |
} | |
worldButtons[selectedWorld].setSelected(true); | |
// Now insert the world radio buttons | |
c.insets = new Insets(5, 15, 5, 5); | |
c.gridx = 0; c.gridy = 7; | |
c.gridwidth = 2; | |
for (JRadioButton button : worldButtons) | |
{ | |
addComponent(basicPanel, button, c); | |
c.gridy += 1; | |
} | |
// Add our JPanel to the window | |
c.weightx = 1.0f; | |
c.weighty = .1f; | |
c.gridwidth = 2; | |
c.gridx = 0; c.gridy = 0; | |
c.fill = GridBagConstraints.BOTH; | |
addComponent(this.getContentPane(), basicPanel,c); | |
// Now add the buttons | |
c.insets = new Insets(5,15,5,15); | |
c.gridwidth = 1; | |
c.weightx = flabel; | |
c.weighty = 1.0f; | |
c.gridx = 0; c.gridy = 1; | |
c.anchor = GridBagConstraints.WEST; | |
c.fill = GridBagConstraints.HORIZONTAL; | |
addComponent(this.getContentPane(), exitButton,c); | |
c.weightx = flist; | |
c.weighty = 1.0f; | |
c.gridx = 1; c.gridy = 1; | |
c.anchor = GridBagConstraints.EAST; | |
c.fill = GridBagConstraints.HORIZONTAL; | |
addComponent(this.getContentPane(), runButton,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); | |
} | |
/*** | |
* Builds the Go and Exit Buttons and attaches the actions to them | |
*/ | |
private void buildButtons() { | |
runButton = new JButton("Go!"); | |
runButton.addActionListener(new ActionListener() { | |
public void actionPerformed(ActionEvent e) { | |
exitCode = ResolutionDialog.DIALOG_BUTTON_GO; | |
setSelectedValues(); | |
setVisible(false); | |
dispose(); | |
synchronized(ResolutionDialog.this) { | |
ResolutionDialog.this.notify(); | |
} | |
} | |
}); | |
exitButton = new JButton("Exit"); | |
exitButton.addActionListener(new ActionListener() { | |
public void actionPerformed(ActionEvent e) { | |
exitCode = ResolutionDialog.DIALOG_BUTTON_EXIT; | |
setVisible(false); | |
dispose(); | |
synchronized(ResolutionDialog.this) { | |
ResolutionDialog.this.notify(); | |
} | |
} | |
}); | |
} | |
/*** | |
* Builds the different lists and fills them with their respective information | |
* (Available Resolutions, Available Bit Depths, Available Refresh Rates etc) | |
*/ | |
private void buildLists() { | |
resolutionsModel = new DefaultComboBoxModel(); | |
bitDepthModel = new DefaultComboBoxModel(); | |
refreshRateModel = new DefaultComboBoxModel(); | |
resolutionsMap = new TreeMap<IntegerPair, List<DisplayMode>>(); | |
bitDepthList = new JComboBox(); | |
bitDepthList.setModel(bitDepthModel); | |
refreshRateList = new JComboBox(); | |
refreshRateList.setModel(refreshRateModel); | |
// Create a map of our fallback resolutions | |
HashMap<Integer, Boolean> fallbackMap = new HashMap<Integer, Boolean>(); | |
for (int[] res : fallbackResolutions) | |
{ | |
fallbackMap.put(res[0]*10000 + res[1], false); | |
} | |
try { | |
DisplayMode[] modes = Display.getAvailableDisplayModes(); | |
for(DisplayMode mode : modes) { | |
IntegerPair modePair = new IntegerPair(mode.getWidth(), mode.getHeight()); | |
// Mark that we've seen our fallback resolution if it exists | |
int hash = mode.getWidth()*10000 + mode.getHeight(); | |
if (fallbackMap.containsKey(hash)) | |
fallbackMap.put(hash, true); | |
// Now add the mode into the full list | |
if(!resolutionsMap.containsKey(modePair)) | |
resolutionsMap.put(modePair, new ArrayList<DisplayMode>()); | |
resolutionsMap.get(modePair).add(mode); | |
} | |
// Add in our resolutions that we want to display regardless of what was auto-detected | |
DisplayMode curMode = Display.getDisplayMode(); | |
for(int[] res: fallbackResolutions) | |
{ | |
int hash = res[0]*10000+res[1]; | |
if (fallbackMap.containsKey(hash)) | |
{ | |
//System.out.println(res[0] + "x" + res[1] + ": " + preferredMap.get(hash)); | |
if (!fallbackMap.get(hash)) | |
{ | |
if (res[0] <= curMode.getWidth() && res[1] <= curMode.getHeight()) | |
{ | |
DisplayMode mode = new DisplayMode(res[0], res[1]); | |
ArrayList<DisplayMode> modelist = new ArrayList<DisplayMode>(); | |
modelist.add(mode); | |
resolutionsMap.put(new IntegerPair(res[0], res[1]), modelist); | |
} | |
} | |
} | |
} | |
IntegerPair firstMode = null; | |
for(IntegerPair mode : resolutionsMap.keySet()) { | |
resolutionsModel.addElement(mode); | |
if(firstMode == null) | |
firstMode = mode; | |
} | |
fillBppAndRefreshForMode(firstMode); | |
} catch (LWJGLException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
resolutionsList = new JComboBox(); | |
resolutionsList.setModel(resolutionsModel); | |
resolutionsList.setRenderer(new DisplayModesRenderer()); | |
resolutionsList.addItemListener(new ItemListener() { | |
public void itemStateChanged(ItemEvent e) { | |
IntegerPair pair = (IntegerPair) resolutionsList.getSelectedItem(); | |
if(pair != null) | |
fillBppAndRefreshForMode(pair); | |
} | |
}); | |
findSelectionIntegerPair(resolutionsList, preferredResolutions); | |
} | |
/*** | |
* Reconstructs the Bpp (bits per pixel, or color depth) and refresh rates lists | |
* for a given resolution. Will then attempt to select the most compatible color depth | |
* and refresh rate given the preferred values for each | |
* @param mode The mode for which to look up the color depth and refresh rates | |
*/ | |
private void fillBppAndRefreshForMode(IntegerPair mode) { | |
List<DisplayMode> modes = resolutionsMap.get(mode); | |
bitDepthList.setSelectedIndex(-1); | |
refreshRateList.setSelectedItem(-1); | |
bitDepthModel.removeAllElements(); | |
refreshRateModel.removeAllElements(); | |
TreeSet<Integer> bppSet = new TreeSet<Integer>(); | |
TreeSet<Integer> refreshRateSet = new TreeSet<Integer>(); | |
for(DisplayMode m : modes) { | |
bppSet.add(m.getBitsPerPixel()); | |
refreshRateSet.add(m.getFrequency()); | |
} | |
for(Integer bpp : bppSet) { | |
bitDepthModel.addElement(bpp); | |
} | |
for(Integer refreshRate : refreshRateSet) { | |
refreshRateModel.addElement(refreshRate); | |
} | |
findSelectionInteger(bitDepthList, preferredBitDepths); | |
findSelectionInteger(refreshRateList, preferredRefreshRates); | |
bitDepthList.validate(); | |
refreshRateList.validate(); | |
} | |
/*** | |
* Will attempt to locate and select a preferred integer-pair value in a given combobox | |
* @param box the combobox to look in | |
* @param preferred the list of integer pairs, in order of preference, to look for | |
*/ | |
private void findSelectionIntegerPair(JComboBox box, int[][] preferred) { | |
ComboBoxModel model = box.getModel(); | |
int arrayOff = Integer.MAX_VALUE; | |
int modelOff = -1; | |
for(int i=0; i<model.getSize(); i++) { | |
IntegerPair pair = (IntegerPair) model.getElementAt(i); | |
int foundOff = -1; | |
for(int j=0; j<preferred.length; j++) { | |
if( pair.getValueOne() == preferred[j][0] && | |
pair.getValueTwo() == preferred[j][1]) { | |
foundOff = j; | |
break; | |
} | |
} | |
if(foundOff != -1 && foundOff < arrayOff) { | |
arrayOff = foundOff; | |
modelOff = i; | |
} | |
} | |
if(modelOff != -1) { | |
box.setSelectedIndex(modelOff); | |
} | |
box.validate(); | |
} | |
/*** | |
* Will attempt to locate and select a preferred integer value in a given combobox | |
* @param box the combobox to look in | |
* @param preferred the list of integers, in order of preference, to look for | |
*/ | |
private void findSelectionInteger(JComboBox box, int[] preferred) { | |
ComboBoxModel model = box.getModel(); | |
int arrayOff = Integer.MAX_VALUE; | |
int modelOff = -1; | |
for(int i=0; i<model.getSize(); i++) { | |
Integer intVal = (Integer) model.getElementAt(i); | |
int foundOff = -1; | |
for(int j=0; j<preferred.length; j++) { | |
if( intVal == preferred[j]) { | |
foundOff = j; | |
break; | |
} | |
} | |
if(foundOff != -1 && foundOff < arrayOff) { | |
arrayOff = foundOff; | |
modelOff = i; | |
} | |
} | |
if(modelOff != -1) { | |
box.setSelectedIndex(modelOff); | |
} | |
box.validate(); | |
} | |
/*** | |
* Sets the selected values to the static properties of this resolution dialog | |
*/ | |
private void setSelectedValues() { | |
IntegerPair resolution; | |
if(resolutionsList.getSelectedIndex() == -1) { | |
resolution = (IntegerPair) resolutionsModel.getElementAt(0); | |
} else { | |
resolution = (IntegerPair) resolutionsModel.getElementAt(resolutionsList.getSelectedIndex()); | |
} | |
Integer bitDepth; | |
if(bitDepthList.getSelectedIndex() == -1) { | |
bitDepth = (Integer) bitDepthModel.getElementAt(0); | |
} else { | |
bitDepth = (Integer) bitDepthModel.getElementAt(bitDepthList.getSelectedIndex()); | |
} | |
Integer refreshRate; | |
if(refreshRateList.getSelectedIndex() == -1) { | |
refreshRate = (Integer) refreshRateModel.getElementAt(0); | |
} else { | |
refreshRate = (Integer) refreshRateModel.getElementAt(refreshRateList.getSelectedIndex()); | |
} | |
for(DisplayMode mode : resolutionsMap.get(resolution)) { | |
if(mode.getBitsPerPixel() == bitDepth && | |
mode.getFrequency() == refreshRate) { | |
ResolutionDialog.selectedDisplayMode = mode; | |
break; | |
} | |
} | |
ResolutionDialog.selectedRefreshRate = refreshRate; | |
ResolutionDialog.selectedBitDepth = bitDepth; | |
ResolutionDialog.selectedFullScreenValue = this.fullScreenCheckBox.isSelected(); | |
for (int i=0; i<worldButtons.length; i++) | |
{ | |
if (worldButtons[i].isSelected()) | |
{ | |
ResolutionDialog.selectedWorld = i; | |
break; | |
} | |
} | |
// Also set the info in our properties object | |
this.xray_properties.setProperty("LAST_RESOLUTION_X", Integer.toString(ResolutionDialog.selectedDisplayMode.getWidth())); | |
this.xray_properties.setProperty("LAST_RESOLUTION_Y", Integer.toString(ResolutionDialog.selectedDisplayMode.getHeight())); | |
this.xray_properties.setProperty("LAST_BPP", Integer.toString(ResolutionDialog.selectedBitDepth)); | |
this.xray_properties.setProperty("LAST_REFRESH_RATE", Integer.toString(ResolutionDialog.selectedRefreshRate)); | |
if (ResolutionDialog.selectedFullScreenValue) | |
{ | |
this.xray_properties.setProperty("LAST_FULLSCREEN", "1"); | |
} | |
else | |
{ | |
this.xray_properties.setProperty("LAST_FULLSCREEN", "0"); | |
} | |
// World directory preference is set out in XRay.java, because we might have loaded a world from an arbitrary dir | |
} | |
/** | |
* Given an array of ints, prepend it with a value from our properties file, if it | |
* exists. | |
* | |
* @param prop_name | |
* @param dest_var | |
* @param existing_var | |
*/ | |
private int[] prepend_int_array(String prop_name, int[] dest_var, int[] existing_var) | |
{ | |
String val = this.xray_properties.getProperty(prop_name); | |
if (val != null) | |
{ | |
dest_var = new int[existing_var.length+1]; | |
dest_var[0] = Integer.valueOf(val); | |
for (int i=0; i<existing_var.length; i++) | |
{ | |
dest_var[i+1] = existing_var[i]; | |
} | |
} | |
return dest_var; | |
} | |
/*** | |
* Creates a new Resolutions Dialog | |
* @param windowName the title of the dialog | |
* @param advancedPanel an optional advanced panel | |
* @param preferredResolutions a list of resolutions, in order of preference, which will be looked for | |
* @param preferredBitDepths a list of color depths, in order of preference, which will be looked for | |
* @param preferredRefreshRates a list of refresh rates, in order of preference, which will be looked for | |
* @param preferredFullScreenValue the initial value of the full-screen checkbox | |
*/ | |
protected ResolutionDialog(String windowName, Container advancedPanel, | |
int[][] preferredResolutions, int[] preferredBitDepths, int[] preferredRefreshRates, | |
boolean preferredFullScreenValue, | |
ArrayList<WorldInfo> availableWorlds, Properties xray_properties) { | |
super(windowName); | |
this.xray_properties = xray_properties; | |
this.preferredResolutions = preferredResolutions; | |
this.preferredBitDepths = preferredBitDepths; | |
this.preferredRefreshRates = preferredRefreshRates; | |
this.preferredFullScreenValue = preferredFullScreenValue; | |
this.availableWorlds = availableWorlds; | |
// Load last-used resolution/display information from our properties file | |
String val_1 = this.xray_properties.getProperty("LAST_RESOLUTION_X"); | |
String val_2 = this.xray_properties.getProperty("LAST_RESOLUTION_Y"); | |
if (val_1 != null && val_2 != null) | |
{ | |
this.preferredResolutions = new int[preferredResolutions.length+1][]; | |
this.preferredResolutions[0] = new int[2]; | |
this.preferredResolutions[0][0] = Integer.valueOf(val_1); | |
this.preferredResolutions[0][1] = Integer.valueOf(val_2); | |
for (int i=0; i<preferredResolutions.length; i++) | |
{ | |
this.preferredResolutions[i+1] = preferredResolutions[i]; | |
} | |
} | |
this.preferredBitDepths = this.prepend_int_array("LAST_BPP", this.preferredBitDepths, preferredBitDepths); | |
this.preferredRefreshRates = this.prepend_int_array("LAST_REFRESH_RATE", this.preferredRefreshRates, preferredRefreshRates); | |
this.preferredWorld = this.xray_properties.getProperty("LAST_WORLD"); | |
// ... aaand fullscreen, too | |
val_1 = this.xray_properties.getProperty("LAST_FULLSCREEN"); | |
if (val_1 != null) | |
{ | |
val_1 = val_1.substring(0, 1); | |
if (val_1.equalsIgnoreCase("y") || | |
val_1.equalsIgnoreCase("t") || | |
val_1.equalsIgnoreCase("1")) | |
{ | |
this.preferredFullScreenValue = true; | |
} | |
else | |
{ | |
this.preferredFullScreenValue = false; | |
} | |
} | |
if(ResolutionDialog.iconImage != null) | |
this.setIconImage(ResolutionDialog.iconImage); | |
this.setSize(FRAMEWIDTH,FRAMEHEIGHT); | |
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
this.setMinimumSize(new Dimension(FRAMEWIDTH, FRAMEHEIGHT)); | |
centerDialogOnScreen(); | |
buildLists(); | |
buildButtons(); | |
layoutControlsOnDialog(availableWorlds); | |
validate(); | |
this.setVisible(true); | |
// Adjust to the appropriate height, in case our list of worlds is too long. | |
// This should correctly deal with differences in WM decoration size. | |
Dimension preferred = this.getContentPane().getPreferredSize(); | |
int framediff = FRAMEHEIGHT - this.getContentPane().getHeight(); | |
if (preferred.height > FRAMEHEIGHT-framediff) | |
{ | |
this.setSize(FRAMEWIDTH, preferred.height+framediff); | |
} | |
} | |
/*** | |
* Pops up the dialog window | |
* @param windowName the title of the dialog | |
* @param advancedPanel an optional advanced panel | |
* @param preferredResolutions a list of resolutions, in order of preference, which will be looked for | |
* @param preferredBitDepths a list of color depths, in order of preference, which will be looked for | |
* @param preferredRefreshRates a list of refresh rates, in order of preference, which will be looked for | |
* @param preferredFullScreenValue the initial value of the full-screen checkbox | |
* @return an integer value which represents which button was clicked (DIALOG_BUTTON_EXIT or DIALOG_BUTTON_GO) | |
*/ | |
public static int presentDialog(String windowName, Container advancedPanel, | |
int[][] preferredResolutions, int[] preferredBitDepths, int[] preferredRefreshRates, | |
boolean preferredFullScreenValue, | |
ArrayList<WorldInfo> availableWorlds, Properties xray_properties) { | |
ResolutionDialog dialog = new ResolutionDialog( | |
windowName, | |
advancedPanel, | |
preferredResolutions, | |
preferredBitDepths, | |
preferredRefreshRates, | |
preferredFullScreenValue, | |
availableWorlds, | |
xray_properties | |
); | |
try { | |
synchronized(dialog) { | |
dialog.wait(); | |
} | |
} catch (InterruptedException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
return dialog.exitCode; | |
} | |
/*** | |
* Pops up the dialog window using the default preffered values | |
* @return an integer value which represents which button was clicked (DIALOG_BUTTON_EXIT or DIALOG_BUTTON_GO) | |
*/ | |
public static int presentDialog(String windowName, ArrayList<WorldInfo> availableWorlds, Properties xray_properties) { | |
return presentDialog(windowName, null, availableWorlds, xray_properties); | |
} | |
/*** | |
* Pops up the dialog window using the default preffered values and an | |
* advanced panel | |
* @return an integer value which represents which button was clicked (DIALOG_BUTTON_EXIT or DIALOG_BUTTON_GO) | |
*/ | |
public static int presentDialog(String windowName, Container advancedPanel, | |
ArrayList<WorldInfo> availableWorlds, Properties xray_properties) { | |
return presentDialog(windowName,advancedPanel, | |
defaultPreferredResolutions, | |
defaultPreferredBitDepths, | |
defaultPreferredRefreshRates, | |
defaultPreferredFullScreenValue, | |
availableWorlds, | |
xray_properties | |
); | |
} | |
/*** | |
* Pops up the dialog window | |
* @param windowName the title of the dialog | |
* @param preferredResolutions a list of resolutions, in order of preference, which will be looked for | |
* @param preferredBitDepths a list of color depths, in order of preference, which will be looked for | |
* @param preferredRefreshRates a list of refresh rates, in order of preference, which will be looked for | |
* @param preferredFullScreenValue the initial value of the full-screen checkbox | |
* @return an integer value which represents which button was clicked (DIALOG_BUTTON_EXIT or DIALOG_BUTTON_GO) | |
*/ | |
public static int presentDialog(String windowName, | |
int[][] preferredResolutions, int[] preferredBitDepths, int[] preferredRefreshRates, | |
boolean preferredFullScreenValue, | |
ArrayList<WorldInfo> availableWorlds, Properties xray_properties) { | |
return presentDialog(windowName, null, | |
preferredResolutions, preferredBitDepths, preferredRefreshRates, | |
preferredFullScreenValue, | |
availableWorlds, xray_properties); | |
} | |
} |