mirror of
https://github.com/jneug/zeichenmaschine.git
synced 2026-10-12 09:56:33 +02:00
Projektstruktur an Gradle angepasst
This commit is contained in:
268
src/main/java/schule/ngb/zm/Zeichenleinwand.java
Normal file
268
src/main/java/schule/ngb/zm/Zeichenleinwand.java
Normal file
@@ -0,0 +1,268 @@
|
||||
package schule.ngb.zm;
|
||||
|
||||
import schule.ngb.zm.shapes.ShapesLayer;
|
||||
|
||||
import java.awt.Canvas;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.image.BufferStrategy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* Eine Leinwand ist die Hauptkomponente einer Zeichenmaschine. Sie besteht aus
|
||||
* mehreren Ebenen, auf denen auf verschiedene Arten gezeichnet werden kann. Die
|
||||
* Ebenen lassen sich beliebig übereinander legen, ausblenden oder wieder
|
||||
* löschen.
|
||||
* <p>
|
||||
* Jede Ebene besitzt eine Zeichenfläche, auf der ihre Zeichnung liegt. Diese
|
||||
* Zeichenflächen werden pro Frame einmal von "unten" nach "oben" auf diese
|
||||
* Leinwand gezeichnet.
|
||||
*/
|
||||
public class Zeichenleinwand extends Canvas {
|
||||
|
||||
/**
|
||||
* Liste der hinzugefügten Ebenen.
|
||||
*/
|
||||
private LinkedList<Layer> layers;
|
||||
|
||||
/**
|
||||
* Erstellt eine neue Zeichenleinwand mit einer festen Größe.
|
||||
*
|
||||
* @param width Breite der Zeichenleinwand.
|
||||
* @param height Höhe der Zeichenleinwand.
|
||||
*/
|
||||
public Zeichenleinwand( int width, int height ) {
|
||||
super.setSize(width, height);
|
||||
this.setPreferredSize(this.getSize());
|
||||
this.setMinimumSize(this.getSize());
|
||||
this.setBackground(Constants.STD_BACKGROUND.getJavaColor());
|
||||
|
||||
// Liste der Ebenen initialisieren und die Standardebenen einfügen
|
||||
layers = new LinkedList<>();
|
||||
synchronized( layers ) {
|
||||
layers.add(new ColorLayer(width, height, Constants.STD_BACKGROUND));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ändert die Größe der Zeichenleinwand auf die angegebene Größe in Pixeln.
|
||||
* <p>
|
||||
* Bei einer Größenänderung wird auch die Größe aller bisher hinzugefügter
|
||||
* {@link Layer Ebenen} angepasst, sodass sie die gesamte Leinwand füllen.
|
||||
*
|
||||
* @param width Neue Width der Leinwand in Pixeln.
|
||||
* @param height Neue Höhe der Leinwand in Pixeln.
|
||||
*/
|
||||
@Override
|
||||
public void setSize( int width, int height ) {
|
||||
super.setSize(width, height);
|
||||
this.setPreferredSize(this.getSize());
|
||||
this.setMinimumSize(this.getSize());
|
||||
|
||||
synchronized( layers ) {
|
||||
for( Layer layer : layers ) {
|
||||
layer.setSize(width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt der Zeichenleinwand eine Ebene hinzu, die oberhalb aller bisherigen
|
||||
* Ebenen eingefügt wird.
|
||||
*
|
||||
* @param layer Die neue Ebene.
|
||||
*/
|
||||
public void addLayer( Layer layer ) {
|
||||
if( layer != null ) {
|
||||
synchronized( layers ) {
|
||||
layer.setSize(getWidth(), getHeight());
|
||||
layers.add(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt der Zeichenleinwand eine Ebene an einem bestimmten Index hinzu. Wenn
|
||||
* der Index noch nicht existiert (also größer als die
|
||||
* {@link #getLayerCount() Anzahl der Ebenen} ist, dann wird die neue Ebene
|
||||
* als letzte eingefügt. Die aufrufende Methode kann also nicht sicher sein,
|
||||
* dass die neue Ebene am Ende wirklich am Index {@code i} steht.
|
||||
*
|
||||
* @param i Index der Ebene, beginnend mit <code>0</code>.
|
||||
* @param layer Die neue Ebene.
|
||||
*/
|
||||
public void addLayer( int i, Layer layer ) {
|
||||
if( layer != null ) {
|
||||
synchronized( layers ) {
|
||||
layer.setSize(getWidth(), getHeight());
|
||||
if( i > layers.size() ) {
|
||||
layers.add(layer);
|
||||
} else {
|
||||
layers.add(i, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Anzahl der {@link Layer Ebenen} in dieser Leinwand zurück.
|
||||
*
|
||||
* @return Die Anzahl der Ebenen.
|
||||
*/
|
||||
public int getLayerCount() {
|
||||
return layers.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Liste der bisher hinzugefügten Ebenen zurück.
|
||||
*
|
||||
* @return Liste der Ebenen.
|
||||
*/
|
||||
public java.util.List<Layer> getLayers() {
|
||||
return layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holt die Ebene am Index <var>i</var> (beginnend bei <code>0</code>).
|
||||
*
|
||||
* @param i Index der Ebene (beginnend bei <code>0</code>).
|
||||
* @return Die Ebene am Index <var>i</var> oder <code>null</code>.
|
||||
* @throws IndexOutOfBoundsException Falls der Index nicht existiert.
|
||||
*/
|
||||
public Layer getLayer( int i ) {
|
||||
if( layers.size() > i ) {
|
||||
return layers.get(i);
|
||||
} else {
|
||||
throw new IndexOutOfBoundsException("No layer at index " + i + " (max: " + (layers.size() - 1) + ").");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht die erste Ebene des angegebenen Typs aus der Liste der Ebenen.
|
||||
* Existiert keine solche Ebene, wird <code>null</code> zurückgegeben.
|
||||
*
|
||||
* @param clazz Typ der Ebene.
|
||||
* @param <L>
|
||||
* @return Erste Ebene vom angegeben Typ.
|
||||
*/
|
||||
public <L extends Layer> L getLayer( Class<L> clazz ) {
|
||||
for( Layer layer : layers ) {
|
||||
if( layer.getClass().equals(clazz) ) {
|
||||
return clazz.cast(layer);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht alle Ebenen von einem bestimmten Typ aus der Liste der Ebenen und
|
||||
* gibt diese als Liste zurück. Die Reihenfolge in der Liste entspricht der
|
||||
* Reihenfolge der Ebenen in der Leinwand (von unten nach oben).
|
||||
*
|
||||
* @param pClazz
|
||||
* @param <L>
|
||||
* @return
|
||||
*/
|
||||
public <L extends Layer> java.util.List<L> getLayers( Class<L> pClazz ) {
|
||||
ArrayList<L> result = new ArrayList<>(layers.size());
|
||||
for( Layer layer : layers ) {
|
||||
if( layer.getClass().equals(pClazz) ) {
|
||||
result.add(pClazz.cast(layer));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean removeLayer( Layer pLayer ) {
|
||||
return layers.remove(pLayer);
|
||||
}
|
||||
|
||||
public void removeLayers( Layer... pLayers ) {
|
||||
for( Layer layer : pLayers ) {
|
||||
layers.remove(layer);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearLayers() {
|
||||
layers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt eine passende {@link BufferStrategy} für diese Ebene.
|
||||
*/
|
||||
public void allocateBuffer() {
|
||||
this.createBufferStrategy(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Löscht alle Ebenen der Zeichenebene und gibt deren Ressourcen frei.
|
||||
*/
|
||||
public void dispose() {
|
||||
synchronized( layers ) {
|
||||
for( Layer layer : layers ) {
|
||||
layer.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g ) {
|
||||
render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeichnet den Inhalt aller {@link Layer Ebenen} in den Grafik-Kontext.
|
||||
*
|
||||
* @param graphics
|
||||
*/
|
||||
public void draw( Graphics graphics ) {
|
||||
Graphics2D g2d = (Graphics2D) graphics.create();
|
||||
synchronized( layers ) {
|
||||
for( Layer layer : layers ) {
|
||||
layer.draw(g2d);
|
||||
}
|
||||
}
|
||||
g2d.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt den aktuellen Inhalt der Zeichenleinwand an.
|
||||
*/
|
||||
public void render() {
|
||||
if( getBufferStrategy() == null ) {
|
||||
allocateBuffer();
|
||||
}
|
||||
|
||||
if( isDisplayable() ) {
|
||||
BufferStrategy strategy = this.getBufferStrategy();
|
||||
if( strategy != null ) {
|
||||
do {
|
||||
do {
|
||||
Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();
|
||||
g2d.clearRect(0, 0, getWidth(), getHeight());
|
||||
|
||||
synchronized( layers ) {
|
||||
for( Layer layer : layers ) {
|
||||
layer.draw(g2d);
|
||||
}
|
||||
}
|
||||
|
||||
g2d.dispose();
|
||||
} while( strategy.contentsRestored() );
|
||||
|
||||
// Display the buffer
|
||||
if( !strategy.contentsLost() ) {
|
||||
strategy.show();
|
||||
|
||||
Toolkit.getDefaultToolkit().sync();
|
||||
}
|
||||
|
||||
// Repeat the rendering if the drawing buffer was lost
|
||||
} while( strategy.contentsLost() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user