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 org
.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
;
45 import javax
.swing
.Box
;
46 import org
.sourceforge
.desert
.ImageFilter
;
47 import org
.sourceforge
.desert
.ImageFilterClearImplementation
;
48 import org
.sourceforge
.desert
.ImageFilterFadeImplementation
;
49 import org
.sourceforge
.desert
.Particle
;
50 import org
.sourceforge
.desert
.ParticleEngine
;
51 import org
.sourceforge
.desert
.ParticleEngineCustomImplementation
;
52 import org
.sourceforge
.desert
.ParticleEngineDMapImplementation
;
53 import org
.sourceforge
.desert
.ParticleEngineDMapImplementation
;
54 import org
.sourceforge
.desert
.ParticleEngineJBulletImplementation
;
55 import org
.sourceforge
.desert
.ParticleEngineOde4JImplementation
;
56 import org
.sourceforge
.desert
.ParticleEnginePhys2DImplementation
;
57 import org
.sourceforge
.desert
.Utilities
;
61 * @author codistmonk (creation 2010-04-15)
63 @SuppressWarnings("serial")
64 public class DesertPanel
extends Panel
{
66 private final Timer timer
;
68 private final DrawingBoard drawingBoard
;
70 private final GCThread gcThread
;
72 public DesertPanel() {
73 super(new BorderLayout());
74 this.timer
= new Timer(FRAMERATE
);
75 this.drawingBoard
= new DrawingBoard();
77 final CursorPositionLabel xyMouse
= new CursorPositionLabel();
78 final FramerateLabel framerateLabel
= new FramerateLabel();
79 final ParticleCountLabel particleCountLabel
= this.new ParticleCountLabel();
80 final Checkbox pauseButton
= new Checkbox("Pause");
81 final Button resetButton
= new Button("Reset");
83 this.add(this.getDrawingBoard(), BorderLayout
.CENTER
);
85 horizontalBox(framerateLabel
, particleCountLabel
, xyMouse
),
86 horizontalBox(resetButton
, pauseButton
),
87 horizontalBox(new Label("Particle engine: "), this.new ParticleEngineChoice()),
88 horizontalBox(new Label("Particle type: "), this.new ParticleTypeChoice()),
89 horizontalBox(new Label("Image filter: "), this.new ImageFilterChoice()),
90 horizontalBox(new Label("Particle brush: "), this.new BrushChoice())
91 ), BorderLayout
.SOUTH
);
93 pauseButton
.addItemListener(this.new Pause());
94 resetButton
.addActionListener(this.new Reset());
96 this.getTimer().addActionListener(this.getDrawingBoard());
97 this.getDrawingBoard().addMouseMotionListener(xyMouse
);
98 this.getTimer().addActionListener(framerateLabel
);
99 this.getTimer().addActionListener(particleCountLabel
);
100 this.gcThread
= new GCThread();
101 this.gcThread
.start();
107 * <br>A non-null value
110 public final Timer
getTimer() {
117 * <br>A non-null value
120 public final DrawingBoard
getDrawingBoard() {
121 return this.drawingBoard
;
126 * @author codistmonk (creation 2010-04-20)
128 private final class Reset
implements ActionListener
{
131 public final void actionPerformed(final ActionEvent event
) {
132 DesertPanel
.this.getDrawingBoard().getParticleEngine().removeAllParticles();
139 * @author codistmonk (creation 2010-04-20)
141 private final class Pause
implements ItemListener
{
144 public final void itemStateChanged(final ItemEvent event
) {
145 DesertPanel
.this.getDrawingBoard().setPaused(event
.getStateChange() == ItemEvent
.SELECTED
);
152 * @author codistmonk (creation 2010-04-17)
154 @SuppressWarnings("serial")
155 private final class ParticleEngineChoice
extends Choice
{
157 public ParticleEngineChoice() {
164 this.addItemListener(this.new ItemHandler());
169 * @author codistmonk (creation 2010-04-17)
171 private final class ItemHandler
implements ItemListener
{
174 public final void itemStateChanged(final ItemEvent event
) {
175 if (event
.getStateChange() == ItemEvent
.SELECTED
) {
177 DesertPanel
.this.getDrawingBoard().setParticleEngine(this.createParticleEngine());
178 } catch (final InstantiationException exception
) {
179 Logger
.getLogger(DesertPanel
.class.getName()).log(Level
.SEVERE
, null, exception
);
180 } catch (final IllegalAccessException exception
) {
181 Logger
.getLogger(DesertPanel
.class.getName()).log(Level
.SEVERE
, null, exception
);
189 * <br>A non-null value
190 * @throws InstantiationException
191 * @throws IllegalAccessException
193 private final ParticleEngine
createParticleEngine() throws InstantiationException
, IllegalAccessException
{
194 return (ParticleEngine
) new Class
<?
>[] {
195 ParticleEngineCustomImplementation
.class,
196 ParticleEngineDMapImplementation
.class,
197 ParticleEngineJBulletImplementation
.class,
198 ParticleEnginePhys2DImplementation
.class,
199 ParticleEngineOde4JImplementation
.class
200 }[ParticleEngineChoice
.this.getSelectedIndex()].newInstance();
209 * @author codistmonk (creation 2010-04-21)
211 @SuppressWarnings("serial")
212 private final class ImageFilterChoice
extends Choice
{
214 public ImageFilterChoice() {
218 this.addItemListener(this.new ItemHandler());
223 * @author codistmonk (creation 2010-04-17)
225 private final class ItemHandler
implements ItemListener
{
228 public final void itemStateChanged(final ItemEvent event
) {
229 if (event
.getStateChange() == ItemEvent
.SELECTED
) {
231 DesertPanel
.this.getDrawingBoard().setImageFilter(this.createImageFilter());
232 } catch (final InstantiationException exception
) {
233 Logger
.getLogger(DesertPanel
.class.getName()).log(Level
.SEVERE
, null, exception
);
234 } catch (final IllegalAccessException exception
) {
235 Logger
.getLogger(DesertPanel
.class.getName()).log(Level
.SEVERE
, null, exception
);
243 * <br>A non-null value
244 * @throws InstantiationException
245 * @throws IllegalAccessException
247 private final ImageFilter
createImageFilter() throws InstantiationException
, IllegalAccessException
{
248 return (ImageFilter
) new Class
<?
>[] {
249 ImageFilterClearImplementation
.class,
250 ImageFilterFadeImplementation
.class
251 }[ImageFilterChoice
.this.getSelectedIndex()].newInstance();
260 * @author andrew (creation 2010-04-17)
262 @SuppressWarnings("serial")
263 private final class ParticleTypeChoice
extends Choice
{
265 public ParticleTypeChoice() {
266 final ResourceBundle resourceBundle
= ResourceBundle
.getBundle(Utilities
.RESOURCE_BASE
+ "messages");
268 for (final Particle
.Type type
: Particle
.Type
.values()) {
269 this.add(resourceBundle
.getString(type
.toString()));
272 this.updateDrawingBoardParticleType();
274 this.addItemListener(this.new ItemHandler());
277 final void updateDrawingBoardParticleType() {
278 DesertPanel
.this.getDrawingBoard().setParticleType(
279 Particle
.Type
.values()[ParticleTypeChoice
.this.getSelectedIndex()]);
284 * @author andrew (creation 2010-04-17)
286 private final class ItemHandler
implements ItemListener
{
289 public final void itemStateChanged(final ItemEvent event
) {
290 if (event
.getStateChange() == ItemEvent
.SELECTED
) {
291 ParticleTypeChoice
.this.updateDrawingBoardParticleType();
301 * @author codistmonk (creation 2010-04-25)
303 @SuppressWarnings("serial")
304 private final class BrushChoice
extends Choice
{
306 private final List
<String
> brushPaths
;
308 public BrushChoice() {
309 this.brushPaths
= Utilities
.listBrushPaths();
311 for (final String brushPath
: this.brushPaths
) {
312 this.addItem(getUserReadableBrushName(brushPath
));
315 this.updateDrawingBoardBrush();
317 this.addItemListener(this.new ItemHandler());
320 final void updateDrawingBoardBrush() {
321 DesertPanel
.this.getDrawingBoard().setBrush(
322 Utilities
.getBrush(this.brushPaths
.get(BrushChoice
.this.getSelectedIndex())));
327 * @author condistmonk (creation 2010-04-25)
329 private final class ItemHandler
implements ItemListener
{
332 public final void itemStateChanged(final ItemEvent event
) {
333 if (event
.getStateChange() == ItemEvent
.SELECTED
) {
334 BrushChoice
.this.updateDrawingBoardBrush();
344 * @author codistmonk (creation 2010-04-15)
346 @SuppressWarnings("serial")
347 private final class ParticleCountLabel
extends Label
implements ActionListener
{
350 public final void actionPerformed(final ActionEvent event
) {
351 this.setText("Particle count: " + DesertPanel
.this.getDrawingBoard().getParticleCount());
358 * @author andrew (creation 2010-04-19)
360 @SuppressWarnings("serial")
361 private final class CursorPositionLabel
extends Label
implements MouseMotionListener
{
364 public final void mouseMoved(final MouseEvent event
) {
365 this.updateText(event
);
369 public final void mouseDragged(final MouseEvent event
) {
370 this.updateText(event
);
376 * <br>Should not be null
378 private final void updateText(final MouseEvent event
) {
379 this.setText("(" + event
.getX() + ", " +
380 (DesertPanel
.this.getDrawingBoard().getHeight() - event
.getY() - 1) + ")");
385 public static final int FRAMERATE
= 25;
390 * <br> Should not be null
393 * <br>A non-null value
395 private static final Box
horizontalBox(final Component
... components
) {
396 // TODO do not use Swing
397 final Box result
= Box
.createHorizontalBox();
399 for (final Component component
: components
) {
400 result
.add(component
);
409 * <br> Should not be null
412 * <br>A non-null value
414 private static final Box
verticalBox(final Component
... components
) {
415 // TODO do not use Swing
416 final Box result
= Box
.createVerticalBox();
418 for (final Component component
: components
) {
419 result
.add(component
);
426 * Transforms the brush resource path into a user-readable form.
427 * <br>Eg: "org/sourceforge/desert/resources/images/dot_1x1.png" becomes "Dot 1x1"
429 * <br>Should not be null
431 * <br>A non-null value
434 static final String
getUserReadableBrushName(final String brushPath
) {
435 final String result
= Utilities
.getResourceName(brushPath
).split("brush_")[1].split("\\.")[0].replaceAll("_", " ");
437 return Character
.toUpperCase(result
.charAt(0)) + result
.substring(1);
442 * @author codistmonk (creation 2010-04-15)
444 @SuppressWarnings("serial")
445 private static final class FramerateLabel
extends Label
implements ActionListener
{
448 public final void actionPerformed(final ActionEvent event
) {
449 this.setText("Framerate: " + String
.format("%.1f", 1.0 / ((Timer
.Event
) event
).getDeltaTime()));
458 private static final class GCThread
extends Thread
{
467 } catch (Exception e
) {