-
Notifications
You must be signed in to change notification settings - Fork 0
/
SandDisplay.java
189 lines (163 loc) · 5.76 KB
/
SandDisplay.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import javax.swing.*;
/*
* Display for sand project from http://nifty.stanford.edu/2017/feinberg-falling-sand/
*/
public class SandDisplay {
private final Image image;
private final int cellSize;
private int tool;
private final int numRows;
private final int numCols;
private int[] mouseLoc;
private final JRadioButton[] buttons;
private int speed;
private final JPanel display;
/**
* Create SandDisplay window of given size and tools
*
* @param title The window title
* @param toolNames Names of the tools for user to choose from.
* @param numRows Number of rows
* @param numCols Number of columns
*/
public SandDisplay(String title, String[] toolNames, int numRows, int numCols) {
this.numRows = numRows;
this.numCols = numCols;
tool = 1;
mouseLoc = null;
speed = computeSpeed(50);
//determine cell size
cellSize = Math.max(1, 600 / Math.max(numRows, numCols));
image = new BufferedImage(numCols * cellSize, numRows * cellSize, BufferedImage.TYPE_INT_RGB);
JFrame frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.PAGE_AXIS));
JPanel topPanel = new JPanel();
topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.LINE_AXIS));
frame.getContentPane().add(topPanel);
display = new JPanel() {
public void paintComponent(Graphics g) {
g.drawImage(image, 0, 0, null);
}
};
display.setPreferredSize(new Dimension(numCols * cellSize, numRows * cellSize));
MouseAdapter mouseHandler = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
mouseLoc = toLocation(e);
}
@Override
public void mouseReleased(MouseEvent e) {
mouseLoc = null;
}
@Override
public void mouseDragged(MouseEvent e) {
mouseLoc = toLocation(e);
}
};
display.addMouseListener(mouseHandler);
display.addMouseMotionListener(mouseHandler);
topPanel.add(display);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.PAGE_AXIS));
topPanel.add(buttonPanel);
buttons = new JRadioButton[toolNames.length];
ButtonGroup buttonGroup = new ButtonGroup();
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JRadioButton(toolNames[i]);
buttonGroup.add(buttons[i]);
final int finalI = i;
buttons[i].addActionListener(e -> {
tool = finalI;
});
buttonPanel.add(buttons[i]);
}
buttons[tool].setSelected(true);
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 100, 50);
slider.addChangeListener(e -> speed = computeSpeed(slider.getValue()));
slider.setMajorTickSpacing(1);
slider.setPaintTicks(true);
Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
labelTable.put(0, new JLabel("Slow"));
labelTable.put(100, new JLabel("Fast"));
slider.setLabelTable(labelTable);
slider.setPaintLabels(true);
frame.getContentPane().add(slider);
frame.pack();
frame.setVisible(true);
}
/**
* Repaint the display and pause to allow for mouse input.
* @param milliseconds How many milliseconds to pause?
*/
public void repaintAndPause(int milliseconds) {
display.repaint();
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
/**
* Get last mouse click location
* @return Array containing row and column of mouse click.
*/
public int[] getMouseLocation() {
return mouseLoc;
}
/**
* Get name of currently selected tool
* @return Tool String
*/
public String getToolString() {
return buttons[tool].getText();
}
/**
* Set color for given cell location.
* @param row The cell row
* @param col The cell column
* @param color The new color for the cell
*/
public void setColor(int row, int col, Color color) {
Graphics g = image.getGraphics();
g.setColor(color);
g.fillRect(col * cellSize, row * cellSize, cellSize, cellSize);
}
/**
* Find cell location of a mouse event.
* @param e The mouse event
* @return Array of (row, col)
*/
private int[] toLocation(MouseEvent e) {
int row = e.getY() / cellSize;
int col = e.getX() / cellSize;
if (row < 0 || row >= numRows || col < 0 || col >= numCols) {
return null;
}
int[] loc = new int[2];
loc[0] = row;
loc[1] = col;
return loc;
}
/**
* Get simulation speed.
* @return number of times to step between repainting and processing mouse input
*/
public int getSpeed() {
return speed;
}
/**
* Returns speed based on sliderValue
* speed of 0 returns 10^3
* speed of 100 returns 10^6
* @param sliderValue Value from slider
* @return Speed value
*/
private static int computeSpeed(int sliderValue) {
return (int) Math.pow(10, 0.03 * sliderValue + 3);
}
}