Initial temp support. (Thanks, Jack)
[desert.git] / src / net / sourceforge / desert / ui / DesertPanel.java
blob85a8a9252f50c033572c1cbf776766d935f9bf92
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 net.sourceforge.desert.ui;
28 import java.awt.BorderLayout;
29 import java.awt.Button;
30 import java.awt.Checkbox;
31 import java.awt.Choice;
32 import java.awt.Component;
33 import java.awt.Label;
34 import java.awt.Panel;
35 import java.awt.event.ActionEvent;
36 import java.awt.event.ActionListener;
37 import java.awt.event.ItemEvent;
38 import java.awt.event.ItemListener;
39 import java.awt.event.MouseMotionListener;
40 import java.awt.event.MouseEvent;
41 import java.util.List;
42 import java.util.ResourceBundle;
43 import java.util.logging.Level;
44 import java.util.logging.Logger;
46 import javax.swing.Box;
48 import net.sourceforge.desert.ImageFilter;
49 import net.sourceforge.desert.ImageFilterClearImplementation;
50 import net.sourceforge.desert.ImageFilterFadeImplementation;
51 import net.sourceforge.desert.Particle;
52 import net.sourceforge.desert.ParticleEngine;
53 import net.sourceforge.desert.Utilities;
55 /**
57 * @author codistmonk (creation 2010-04-15)
59 @SuppressWarnings("serial")
60 public class DesertPanel extends Panel {
62 private final Timer timer;
64 private final DrawingBoard drawingBoard;
66 public DesertPanel() {
67 super(new BorderLayout());
68 this.timer = new Timer(FRAMERATE);
69 this.drawingBoard = new DrawingBoard();
71 final CursorPositionLabel xyMouse = new CursorPositionLabel();
72 final FramerateLabel framerateLabel = new FramerateLabel();
73 final ParticleCountLabel particleCountLabel = this.new ParticleCountLabel();
74 final Checkbox pauseButton = new Checkbox("Pause");
75 final Button resetButton = new Button("Reset");
77 this.add(this.getDrawingBoard(), BorderLayout.CENTER);
78 this.add(verticalBox(
79 horizontalBox(framerateLabel, particleCountLabel, xyMouse),
80 horizontalBox(resetButton, pauseButton),
81 horizontalBox(new Label("Particle type: "), this.new ParticleTypeChoice()),
82 horizontalBox(new Label("Image filter: "), this.new ImageFilterChoice()),
83 horizontalBox(new Label("Brush mode: "), this.new BrushModeChoice(), new Label("Brush shape: "), this.new BrushChoice())
84 ), BorderLayout.SOUTH);
86 pauseButton.addItemListener(this.new Pause());
87 resetButton.addActionListener(this.new Reset());
89 this.getTimer().addActionListener(this.getDrawingBoard());
90 this.getDrawingBoard().addMouseMotionListener(xyMouse);
91 this.getDrawingBoard().setParticleEngine(new ParticleEngine());
92 this.getTimer().addActionListener(framerateLabel);
93 this.getTimer().addActionListener(particleCountLabel);
96 /**
98 * @return
99 * <br>A non-null value
100 * <br>A reference
102 public final Timer getTimer() {
103 return this.timer;
108 * @return
109 * <br>A non-null value
110 * <br>A reference
112 public final DrawingBoard getDrawingBoard() {
113 return this.drawingBoard;
118 * @author codistmonk (creation 2010-04-20)
120 private final class Reset implements ActionListener {
122 @Override
123 public final void actionPerformed(final ActionEvent event) {
124 DesertPanel.this.getDrawingBoard().getParticleEngine().removeAllParticles();
131 * @author codistmonk (creation 2010-04-20)
133 private final class Pause implements ItemListener {
135 @Override
136 public final void itemStateChanged(final ItemEvent event) {
137 DesertPanel.this.getDrawingBoard().setPaused(event.getStateChange() == ItemEvent.SELECTED);
144 * @author codistmonk (creation 2010-04-21)
146 @SuppressWarnings("serial")
147 private final class ImageFilterChoice extends Choice {
149 public ImageFilterChoice() {
150 this.add("Clear");
151 this.add("Fade");
153 this.addItemListener(this.new ItemHandler());
158 * @author codistmonk (creation 2010-04-17)
160 private final class ItemHandler implements ItemListener {
162 @Override
163 public final void itemStateChanged(final ItemEvent event) {
164 if (event.getStateChange() == ItemEvent.SELECTED) {
165 try {
166 DesertPanel.this.getDrawingBoard().setImageFilter(this.createImageFilter());
167 } catch (final InstantiationException exception) {
168 Logger.getLogger(DesertPanel.class.getName()).log(Level.SEVERE, null, exception);
169 } catch (final IllegalAccessException exception) {
170 Logger.getLogger(DesertPanel.class.getName()).log(Level.SEVERE, null, exception);
176 * @return
177 * <br>A new value
178 * <br>A non-null value
179 * @throws InstantiationException
180 * @throws IllegalAccessException
182 private final ImageFilter createImageFilter() throws InstantiationException, IllegalAccessException {
183 return (ImageFilter) new Class<?>[] {
184 ImageFilterClearImplementation.class,
185 ImageFilterFadeImplementation.class
186 }[ImageFilterChoice.this.getSelectedIndex()].newInstance();
195 * @author andrew (creation 2010-04-17)
197 @SuppressWarnings("serial")
198 private final class ParticleTypeChoice extends Choice {
200 public ParticleTypeChoice() {
201 final ResourceBundle resourceBundle = ResourceBundle.getBundle(Utilities.RESOURCE_BASE + "messages");
203 for (final Particle.Type type : Particle.Type.values()) {
204 this.addItem(resourceBundle.getString(type.toString()));
207 this.updateDrawingBoardParticleType();
209 this.addItemListener(this.new ItemHandler());
212 final void updateDrawingBoardParticleType() {
213 DesertPanel.this.getDrawingBoard().setParticleType(
214 Particle.Type.values()[ParticleTypeChoice.this.getSelectedIndex()]);
219 * @author andrew (creation 2010-04-17)
221 private final class ItemHandler implements ItemListener {
223 @Override
224 public final void itemStateChanged(final ItemEvent event) {
225 if (event.getStateChange() == ItemEvent.SELECTED) {
226 ParticleTypeChoice.this.updateDrawingBoardParticleType();
236 * @author codistmonk (creation 2010-04-28)
238 @SuppressWarnings("serial")
239 private final class BrushModeChoice extends Choice {
241 public BrushModeChoice() {
242 this.addItem("Add");
243 this.addItem("Erase");
245 this.updateDrawingBoardBrushMode();
247 this.addItemListener(this.new ItemHandler());
250 final void updateDrawingBoardBrushMode() {
251 DesertPanel.this.getDrawingBoard().setBrushMode(
252 DrawingBoard.BrushMode.values()[BrushModeChoice.this.getSelectedIndex()]);
257 * @author andrew (creation 2010-04-17)
259 private final class ItemHandler implements ItemListener {
261 @Override
262 public final void itemStateChanged(final ItemEvent event) {
263 if (event.getStateChange() == ItemEvent.SELECTED) {
264 BrushModeChoice.this.updateDrawingBoardBrushMode();
274 * @author codistmonk (creation 2010-04-25)
276 @SuppressWarnings("serial")
277 private final class BrushChoice extends Choice {
279 private final List<String> brushPaths;
281 public BrushChoice() {
282 this.brushPaths = Utilities.listBrushPaths();
284 for (final String brushPath : this.brushPaths) {
285 this.addItem(getUserReadableBrushName(brushPath));
288 this.updateDrawingBoardBrush();
290 this.addItemListener(this.new ItemHandler());
293 final void updateDrawingBoardBrush() {
294 DesertPanel.this.getDrawingBoard().setBrush(
295 Utilities.getBrush(this.brushPaths.get(BrushChoice.this.getSelectedIndex())));
300 * @author condistmonk (creation 2010-04-25)
302 private final class ItemHandler implements ItemListener {
304 @Override
305 public final void itemStateChanged(final ItemEvent event) {
306 if (event.getStateChange() == ItemEvent.SELECTED) {
307 BrushChoice.this.updateDrawingBoardBrush();
317 * @author codistmonk (creation 2010-04-15)
319 @SuppressWarnings("serial")
320 private final class ParticleCountLabel extends Label implements ActionListener {
322 @Override
323 public final void actionPerformed(final ActionEvent event) {
324 this.setText("Particle count: " + DesertPanel.this.getDrawingBoard().getParticleCount());
331 * @author andrew (creation 2010-04-19)
333 @SuppressWarnings("serial")
334 private final class CursorPositionLabel extends Label implements MouseMotionListener {
336 @Override
337 public final void mouseMoved(final MouseEvent event) {
338 this.updateText(event);
341 @Override
342 public final void mouseDragged(final MouseEvent event) {
343 this.updateText(event);
348 * @param event
349 * <br>Should not be null
351 private final void updateText(final MouseEvent event) {
352 this.setText("(" + event.getX() + ", " +
353 (DesertPanel.this.getDrawingBoard().getHeight() - event.getY() - 1) + ")");
358 public static final int FRAMERATE = 25;
362 * @param components
363 * <br> Should not be null
364 * @return
365 * <br>A new value
366 * <br>A non-null value
368 private static final Box horizontalBox(final Component... components) {
369 // TODO do not use Swing
370 final Box result = Box.createHorizontalBox();
372 for (final Component component : components) {
373 result.add(component);
376 return result;
381 * @param components
382 * <br> Should not be null
383 * @return
384 * <br>A new value
385 * <br>A non-null value
387 private static final Box verticalBox(final Component... components) {
388 // TODO do not use Swing
389 final Box result = Box.createVerticalBox();
391 for (final Component component : components) {
392 result.add(component);
395 return result;
399 * Transforms the brush resource path into a user-readable form.
400 * <br>Eg: "org/sourceforge/desert/resources/images/dot_1x1.png" becomes "Dot 1x1"
401 * @param brushPath
402 * <br>Should not be null
403 * @return
404 * <br>A non-null value
405 * <br>A new value
407 static final String getUserReadableBrushName(final String brushPath) {
408 final String result = Utilities.getResourceName(brushPath).split("brush_")[1].split("\\.")[0].replaceAll("_", " ");
410 return Character.toUpperCase(result.charAt(0)) + result.substring(1);
415 * @author codistmonk (creation 2010-04-15)
417 @SuppressWarnings("serial")
418 private static final class FramerateLabel extends Label implements ActionListener {
420 private double meanFramerate;
422 @Override
423 public final void actionPerformed(final ActionEvent event) {
424 this.meanFramerate = 0.9F * this.meanFramerate + 0.1F * 1.0 / ((Timer.Event) event).getDeltaTime();
425 this.setText("Framerate: " + String.format("%.1f", this.meanFramerate));