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
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
;
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
);
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
);
99 * <br>A non-null value
102 public final Timer
getTimer() {
109 * <br>A non-null value
112 public final DrawingBoard
getDrawingBoard() {
113 return this.drawingBoard
;
118 * @author codistmonk (creation 2010-04-20)
120 private final class Reset
implements ActionListener
{
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
{
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() {
153 this.addItemListener(this.new ItemHandler());
158 * @author codistmonk (creation 2010-04-17)
160 private final class ItemHandler
implements ItemListener
{
163 public final void itemStateChanged(final ItemEvent event
) {
164 if (event
.getStateChange() == ItemEvent
.SELECTED
) {
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
);
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
{
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() {
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
{
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
{
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
{
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
{
337 public final void mouseMoved(final MouseEvent event
) {
338 this.updateText(event
);
342 public final void mouseDragged(final MouseEvent event
) {
343 this.updateText(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;
363 * <br> Should not be null
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
);
382 * <br> Should not be null
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
);
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"
402 * <br>Should not be null
404 * <br>A non-null 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
;
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
));