Added an immobile particle type; updated UI, engines and tests; ticket #7 is done.
[desert.git] / src / org / sourceforge / desert / DesertPanel.java
blobc3f58701c36013de208f1581fa92fe597c0a302e
1 /*
2 * Copyright (c) 2010 The Desert team
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use,
8 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following
11 * conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
26 package org.sourceforge.desert;
28 import java.awt.BorderLayout;
29 import java.awt.Choice;
30 import java.awt.Component;
31 import java.awt.Label;
32 import java.awt.Panel;
33 import java.awt.event.ActionEvent;
34 import java.awt.event.ActionListener;
35 import java.awt.event.ItemEvent;
36 import java.awt.event.ItemListener;
37 import java.awt.event.MouseMotionListener;
38 import java.awt.event.MouseEvent;
39 import java.util.ResourceBundle;
40 import java.util.logging.Level;
41 import java.util.logging.Logger;
42 import javax.swing.Box;
44 /**
46 * @author codistmonk (creation 2010-04-15)
48 @SuppressWarnings("serial")
49 public class DesertPanel extends Panel {
51 private final Timer timer;
53 private final DrawingBoard drawingBoard;
55 private final GCThread gcThread;
57 public DesertPanel() {
58 super(new BorderLayout());
59 this.timer = new Timer(FRAMERATE);
60 this.drawingBoard = new DrawingBoard();
62 final CursorPositionLabel xyMouse = new CursorPositionLabel();
63 final FramerateLabel framerateLabel = new FramerateLabel();
64 final ParticleCountLabel particleCountLabel = this.new ParticleCountLabel();
66 this.add(this.getDrawingBoard(), BorderLayout.CENTER);
67 this.add(verticalBox(
68 horizontalBox(framerateLabel, particleCountLabel, xyMouse),
69 horizontalBox(new Label("Particle engine: "), this.new ParticleEngineChoice()),
70 horizontalBox(new Label("Particle type: "), this.new ParticleTypeChoice())
71 ), BorderLayout.SOUTH);
73 this.getTimer().addActionListener(this.getDrawingBoard());
74 this.getDrawingBoard().addMouseMotionListener(xyMouse);
75 this.getTimer().addActionListener(framerateLabel);
76 this.getTimer().addActionListener(particleCountLabel);
77 this.gcThread = new GCThread();
78 this.gcThread.start();
81 /**
83 * @return
84 * <br>A non-null value
85 * <br>A reference
87 public final Timer getTimer() {
88 return this.timer;
91 /**
93 * @return
94 * <br>A non-null value
95 * <br>A reference
97 public final DrawingBoard getDrawingBoard() {
98 return this.drawingBoard;
103 * @author codistmonk (creation 2010-04-17)
105 @SuppressWarnings("serial")
106 private final class ParticleEngineChoice extends Choice {
108 public ParticleEngineChoice() {
109 this.add("Custom");
110 this.add("JBullet");
111 this.add("Phys2D");
112 this.add("Ode4J");
114 this.addItemListener(this.new ItemHandler());
119 * @author codistmonk (creation 2010-04-17)
121 private final class ItemHandler implements ItemListener {
123 @Override
124 public final void itemStateChanged(final ItemEvent event) {
125 if (event.getStateChange() == ItemEvent.SELECTED) {
126 try {
127 DesertPanel.this.getDrawingBoard().setParticleEngine(this.createParticleEngine());
128 } catch (final InstantiationException exception) {
129 Logger.getLogger(DesertPanel.class.getName()).log(Level.SEVERE, null, exception);
130 } catch (final IllegalAccessException exception) {
131 Logger.getLogger(DesertPanel.class.getName()).log(Level.SEVERE, null, exception);
137 * @return
138 * <br>A new value
139 * <br>A non-null value
140 * @throws InstantiationException
141 * @throws IllegalAccessException
143 private final ParticleEngine createParticleEngine() throws InstantiationException, IllegalAccessException {
144 return (ParticleEngine) new Class<?>[] {
145 ParticleEngineCustomImplementation.class,
146 ParticleEngineJBulletImplementation.class,
147 ParticleEnginePhys2DImplementation.class,
148 ParticleEngineOde4JImplementation.class
149 }[ParticleEngineChoice.this.getSelectedIndex()].newInstance();
158 * @author andrew (creation 2010-04-17)
160 @SuppressWarnings("serial")
161 private final class ParticleTypeChoice extends Choice {
163 public ParticleTypeChoice() {
164 final ResourceBundle resourceBundle = ResourceBundle.getBundle("org.sourceforge.desert.resources.messages");
166 for (final Particle.Type type : Particle.Type.values()) {
167 this.add(resourceBundle.getString(type.toString()));
170 this.updateDrawingBoardParticleType();
172 this.addItemListener(this.new ItemHandler());
175 final void updateDrawingBoardParticleType() {
176 DesertPanel.this.getDrawingBoard().setParticleType(
177 Particle.Type.values()[ParticleTypeChoice.this.getSelectedIndex()]);
182 * @author andrew (creation 2010-04-17)
184 private final class ItemHandler implements ItemListener {
186 @Override
187 public final void itemStateChanged(final ItemEvent event) {
188 if (event.getStateChange() == ItemEvent.SELECTED) {
189 ParticleTypeChoice.this.updateDrawingBoardParticleType();
199 * @author codistmonk (creation 2010-04-15)
201 @SuppressWarnings("serial")
202 private final class ParticleCountLabel extends Label implements ActionListener {
204 @Override
205 public final void actionPerformed(final ActionEvent event) {
206 this.setText("Particle count: " + DesertPanel.this.getDrawingBoard().getParticleCount());
213 * @author andrew (creation 2010-04-19)
215 @SuppressWarnings("serial")
216 private final class CursorPositionLabel extends Label implements MouseMotionListener {
218 @Override
219 public final void mouseMoved(final MouseEvent event) {
220 this.updateText(event);
223 @Override
224 public final void mouseDragged(final MouseEvent event) {
225 this.updateText(event);
230 * @param event
231 * <br>Should not be null
233 private final void updateText(final MouseEvent event) {
234 this.setText("(" + event.getX() + ", " +
235 (DesertPanel.this.getDrawingBoard().getHeight() - event.getY() - 1) + ")");
240 public static final int FRAMERATE = 25;
244 * @param components
245 * <br> Should not be null
246 * @return
247 * <br>A new value
248 * <br>A non-null value
250 private static final Box horizontalBox(final Component... components) {
251 final Box result = Box.createHorizontalBox();
253 for (final Component component : components) {
254 result.add(component);
257 return result;
262 * @param components
263 * <br> Should not be null
264 * @return
265 * <br>A new value
266 * <br>A non-null value
268 private static final Box verticalBox(final Component... components) {
269 final Box result = Box.createVerticalBox();
271 for (final Component component : components) {
272 result.add(component);
275 return result;
280 * @author codistmonk (creation 2010-04-15)
282 @SuppressWarnings("serial")
283 private static final class FramerateLabel extends Label implements ActionListener {
285 @Override
286 public final void actionPerformed(final ActionEvent event) {
287 this.setText("Framerate: " + String.format("%.1f", 1.0 / ((Timer.Event) event).getDeltaTime()));
294 * @author andrew
296 private static final class GCThread extends Thread {
297 int rune;
299 @Override
300 public void run() {
301 rune = 0;
302 while (rune == 0) {
303 try {
304 Thread.sleep(2000);
305 } catch (Exception e) {
306 // nothing
308 System.gc();