Skip to content

Commit

Permalink
Add events for GuiComponent rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
steffen-wilke committed Dec 12, 2021
1 parent 884d1a9 commit bfc8d2f
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package de.gurkenlabs.litiengine.gui;

import java.awt.Graphics2D;
import java.util.EventObject;

public class ComponentRenderEvent extends EventObject {

private final transient Graphics2D graphics;
private final transient GuiComponent component;

/**
* Constructs a prototypical Event.
*
* @param source the object on which the Event initially occurred
* @throws IllegalArgumentException if source is null
*/
public ComponentRenderEvent(final Graphics2D graphics, final GuiComponent source) {
super(source);

this.graphics = graphics;
this.component = source;
}

/**
* Get the component involved with the rendering process.
*
* @return The component involved with the rendering process.
*/
public GuiComponent getComponent() {
return this.component;
}

/**
* Gets the graphics object on which the entity is rendered.
*
* @return The graphics object on which the entity is rendered.
*/
public Graphics2D getGraphics() {
return this.graphics;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package de.gurkenlabs.litiengine.gui;

import de.gurkenlabs.litiengine.entities.EntityRenderEvent;
import java.awt.Graphics2D;

/**
* This listener interface is used for receiving events during a component's rendering process.
*
* @see GuiComponent#render(Graphics2D)
*/
public interface ComponentRenderListener extends ComponentRenderedListener {

/**
* This method gets called after all rendering checks have successfully passed and right before
* the component is about to be rendered.
*
* @param event The event that contains the render data.
*/
default void rendering(ComponentRenderEvent event) {
}

/**
* This method gets called before an {@code GuiComponent} is about to be rendered. Returning false
* prevents the rendering of the specified component.
*
* @param component The component to be rendered.
* @return True if the component should be rendered; otherwise false.
*/
default boolean canRender(GuiComponent component) {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package de.gurkenlabs.litiengine.gui;

import java.awt.Graphics2D;
import java.util.EventListener;

/**
* This listener interface is used for receiving events after an component was rendered.
*
* @see GuiComponent#render(Graphics2D)
*/
@FunctionalInterface
public interface ComponentRenderedListener extends EventListener {

/**
* This method gets called after an {@link GuiComponent} was rendered.
*
* @param event The event that contains the render data.
*/
void rendered(ComponentRenderEvent event);
}
86 changes: 65 additions & 21 deletions core/src/main/java/de/gurkenlabs/litiengine/gui/GuiComponent.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
import java.awt.geom.Rectangle2D;
import java.awt.geom.RectangularShape;
import java.awt.geom.RoundRectangle2D;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;

Expand Down Expand Up @@ -59,6 +61,9 @@ public abstract class GuiComponent
private final List<Consumer<ComponentMouseEvent>> hoverConsumer;
private final List<Consumer<String>> textChangedConsumer;

private final Collection<ComponentRenderListener> renderListeners = ConcurrentHashMap.newKeySet();
private final Collection<ComponentRenderedListener> renderedListeners = ConcurrentHashMap.newKeySet();

private final int componentId;
private final Appearance appearance;
private final Appearance hoveredAppearance;
Expand Down Expand Up @@ -110,9 +115,9 @@ protected GuiComponent(final double x, final double y) {
/**
* Instantiates a new gui component at the point (x,y) with the dimension (width,height).
*
* @param x the x
* @param y the y
* @param width the width
* @param x the x
* @param y the y
* @param width the width
* @param height the height
*/
protected GuiComponent(final double x, final double y, final double width, final double height) {
Expand Down Expand Up @@ -705,6 +710,22 @@ public void onTextChanged(final Consumer<String> cons) {
this.textChangedConsumer.add(cons);
}

public void addRenderListener(final ComponentRenderListener listener) {
this.renderListeners.add(listener);
}

public void removeListener(final ComponentRenderListener listener) {
this.renderListeners.remove(listener);
}

public void addRenderedListener(final ComponentRenderedListener listener) {
this.renderedListeners.add(listener);
}

public void removeListener(final ComponentRenderedListener listener) {
this.renderedListeners.remove(listener);
}

/**
* Prepare the GuiComponent and all its child Components (Makes the GuiComponent visible and adds
* mouse listeners.). This is, for example, done right before switching to a new screen.
Expand All @@ -730,6 +751,17 @@ public void render(final Graphics2D g) {
return;
}

for (ComponentRenderListener listener : this.renderListeners) {
if (!listener.canRender(this)) {
return;
}
}

final ComponentRenderEvent event = new ComponentRenderEvent(g, this);
for (ComponentRenderListener listener : this.renderListeners) {
listener.rendering(event);
}

Shape clip = g.getClip();
g.clip(this.getShape());

Expand Down Expand Up @@ -760,6 +792,14 @@ && getCurrentAppearance().getBorderStyle() != null) {
component.render(g);
}

for (ComponentRenderListener listener : this.renderListeners) {
listener.rendered(event);
}

for (ComponentRenderedListener listener : this.renderedListeners) {
listener.rendered(event);
}

if (Game.config().debug().renderGuiComponentBoundingBoxes()) {
g.setColor(Color.RED);
ShapeRenderer.renderOutline(g, this.getBoundingBox());
Expand All @@ -770,33 +810,33 @@ && getCurrentAppearance().getBorderStyle() != null) {
public float[] getTweenValues(TweenType tweenType) {
switch (tweenType) {
case POSITION_X:
return new float[] {(float) this.getX()};
return new float[]{(float) this.getX()};
case POSITION_Y:
return new float[] {(float) this.getY()};
return new float[]{(float) this.getY()};
case POSITION_XY:
return new float[] {(float) this.getX(), (float) this.getY()};
return new float[]{(float) this.getX(), (float) this.getY()};
case SIZE_WIDTH:
return new float[] {(float) this.getWidth()};
return new float[]{(float) this.getWidth()};
case SIZE_HEIGHT:
return new float[] {(float) this.getHeight()};
return new float[]{(float) this.getHeight()};
case SIZE_BOTH:
return new float[] {(float) this.getWidth(), (float) this.getHeight()};
return new float[]{(float) this.getWidth(), (float) this.getHeight()};
case ANGLE:
return new float[] {(float) this.getTextAngle()};
return new float[]{(float) this.getTextAngle()};
case FONTSIZE:
return new float[] {this.getFont().getSize2D()};
return new float[]{this.getFont().getSize2D()};
case OPACITY:
Color bg1 = this.getCurrentAppearance().getBackgroundColor1();
Color bg2 = this.getCurrentAppearance().getBackgroundColor2();
Color fore = this.getCurrentAppearance().getForeColor();
Color shadow = this.getTextShadowColor();
Color border = this.getCurrentAppearance().getBorderColor();
return new float[] {
(float) (bg1 == null ? 0 : bg1.getAlpha()),
(float) (bg2 == null ? 0 : bg2.getAlpha()),
(float) (fore == null ? 0 : fore.getAlpha()),
(float) (shadow == null ? 0 : shadow.getAlpha()),
(float) (border == null ? 0 : border.getAlpha())
return new float[]{
(float) (bg1 == null ? 0 : bg1.getAlpha()),
(float) (bg2 == null ? 0 : bg2.getAlpha()),
(float) (fore == null ? 0 : fore.getAlpha()),
(float) (shadow == null ? 0 : shadow.getAlpha()),
(float) (border == null ? 0 : border.getAlpha())
};
default:
return Tweenable.super.getTweenValues(tweenType);
Expand Down Expand Up @@ -879,7 +919,7 @@ public RectangularShape getShape() {
/**
* Sets the width and height of this GuiComponent.
*
* @param width the width
* @param width the width
* @param height the height
*/
public void setDimension(final double width, final double height) {
Expand Down Expand Up @@ -1019,7 +1059,7 @@ public void setText(final String text) {
* Sets the {@link RenderingHints#KEY_TEXT_ANTIALIASING} settings for the rendered text.
*
* @param antialiasing Either {@link RenderingHints#VALUE_TEXT_ANTIALIAS_ON} or {@link
* RenderingHints#VALUE_TEXT_ANTIALIAS_OFF}
* RenderingHints#VALUE_TEXT_ANTIALIAS_OFF}
*/
public void setTextAntialiasing(boolean antialiasing) {
this.textAntialiasing = antialiasing;
Expand Down Expand Up @@ -1149,7 +1189,9 @@ public void suspend() {
}
}

/** Toggle this GuiComponent's selection. */
/**
* Toggle this GuiComponent's selection.
*/
public void toggleSelection() {
this.setSelected(!this.isSelected);
}
Expand Down Expand Up @@ -1254,7 +1296,9 @@ protected List<Consumer<ComponentMouseWheelEvent>> getMouseWheelConsumer() {
return this.mouseWheelConsumer;
}

/** Initialize child components. */
/**
* Initialize child components.
*/
protected void initializeComponents() {
// nothing to do in the base class
}
Expand Down

0 comments on commit bfc8d2f

Please sign in to comment.