/* * Copyright 2014 MovingBlocks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.terasology.rendering.nui.widgets; import com.google.common.collect.Lists; import org.terasology.utilities.Assets; import org.terasology.audio.StaticSound; import org.terasology.input.MouseInput; import org.terasology.math.geom.Vector2i; import org.terasology.rendering.assets.font.Font; import org.terasology.rendering.assets.texture.TextureRegion; import org.terasology.rendering.nui.BaseInteractionListener; import org.terasology.rendering.nui.Canvas; import org.terasology.rendering.nui.CoreWidget; import org.terasology.rendering.nui.InteractionListener; import org.terasology.rendering.nui.LayoutConfig; import org.terasology.rendering.nui.TextLineBuilder; import org.terasology.rendering.nui.databinding.Binding; import org.terasology.rendering.nui.databinding.DefaultBinding; import org.terasology.rendering.nui.events.NUIMouseClickEvent; import org.terasology.rendering.nui.events.NUIMouseReleaseEvent; import java.util.List; /** * A widget displaying a clickable button, containing text and an optional image */ public class UIButton extends CoreWidget { public static final String DOWN_MODE = "down"; /** * The {@link Binding} containing the {@link TextureRegion} corresponding to the image shown on this button */ @LayoutConfig private Binding<TextureRegion> image = new DefaultBinding<>(); /** * The {@code Binding} containing the text to be shown on this button */ @LayoutConfig private Binding<String> text = new DefaultBinding<>(""); /** * The {@code Binding} containing the {@link StaticSound} to be played when this button is clicked */ @LayoutConfig private Binding<StaticSound> clickSound = new DefaultBinding<>(Assets.getSound("engine:click").get()); /** * The {@code Binding} containing the float representing the volume of the click sound, 1.0 by default */ @LayoutConfig private Binding<Float> clickVolume = new DefaultBinding<>(1.0f); /** * Whether the button is currently being pressed */ private boolean down; /** * A {@link List} of listeners subscribed to this button */ private List<ActivateEventListener> listeners = Lists.newArrayList(); /** * An {@link InteractionListener} that listens for mouse interaction with this button */ private InteractionListener interactionListener = new BaseInteractionListener() { @Override public boolean onMouseClick(NUIMouseClickEvent event) { if (event.getMouseButton() == MouseInput.MOUSE_LEFT) { down = true; return true; } return false; } @Override public void onMouseRelease(NUIMouseReleaseEvent event) { if (event.getMouseButton() == MouseInput.MOUSE_LEFT) { if (isMouseOver()) { if (getClickSound() != null) { getClickSound().play(getClickVolume()); } activate(); } down = false; } } }; /** * Creates an empty {@code UIButton}. */ public UIButton() { } /** * Creates an empty {@code UIButton} with the given id. * * @param id The id assigned to this {@code UIButton} */ public UIButton(String id) { super(id); } /** * Creates a {@code UIButton} with the given id, containing the given text. * * @param id The id assigned to this {@code UIButton} * @param text The text shown on this {@code UIButton} */ public UIButton(String id, String text) { super(id); this.text.set(text); } /** * Creates a {@code UIButton} with the given id, containing the text in the given {@code Binding}. * * @param id The id assigned to this {@code UIButton} * @param text The {@code Binding} containing the text shown on this {@code UIButton} */ public UIButton(String id, Binding<String> text) { super(id); this.text = text; } /** * Handles how the {@code UIButton} is drawn. * This is called every frame. * * @param canvas The {@link Canvas} on which this {@code UIButton} is drawn */ @Override public void onDraw(Canvas canvas) { if (image.get() != null) { canvas.drawTexture(image.get()); } canvas.drawText(text.get()); if (isEnabled()) { canvas.addInteractionRegion(interactionListener); } } /** * Retrieves the preferred content size of the {@code UIButton}. * This is the minimum size this layout will take, given no space restrictions. * * @param canvas The {@code Canvas} on which the {@code UIButton} is drawn * @param areaHint A {@link Vector2i} representing the available space for this {@code UIButton} * @return A {@link Vector2i} representing the preferred content size of the {@code UIButton} */ @Override public Vector2i getPreferredContentSize(Canvas canvas, Vector2i areaHint) { Font font = canvas.getCurrentStyle().getFont(); List<String> lines = TextLineBuilder.getLines(font, text.get(), areaHint.getX()); return font.getSize(lines); } /** * Retrieves the current mode of this {@code UIButton}. * <p><ul> * <li> DISABLED_MODE - The {@code UIButton} is disabled * <li> DOWN_MODE - The {@code UIButton} is being pressed * <li> HOVER_MODE - The mouse is hovering over the {@code UIButton} * <li> DEFAULT_MODE - The default mode if no other modes are applicable * </ul></p> * * @return A {@code String} representing the current mode of this {@code UIButton} */ @Override public String getMode() { if (!isEnabled()) { return DISABLED_MODE; } else if (down) { return DOWN_MODE; } else if (interactionListener.isMouseOver()) { return HOVER_MODE; } return DEFAULT_MODE; } /** * Called when this {@code UIButton} is pressed to activate all subscribed listeners. */ private void activate() { for (ActivateEventListener listener : listeners) { listener.onActivated(this); } } /** * Binds the text to be shown on this {@code UIButton}. * * @param binding The {@code Binding} containing the text */ public void bindText(Binding<String> binding) { this.text = binding; } /** * Retrieves the text shown on this {@code UIButton}. * * @return The text shown on this {@code UIButton} */ public String getText() { return text.get(); } /** * Sets the text shown on this {@code UIButton}. * * @param text The text to be shown on this {@code UIButton} */ public void setText(String text) { this.text.set(text); } /** * Binds the image shown on this {@code UIButton}. * * @param binding The {@code Binding} containing the {@code TextureRegion} corresponding to the image */ public void bindImage(Binding<TextureRegion> binding) { this.image = binding; } /** * Sets the image shown on this {@code UIButton}. * * @param image The {@code TextureRegion} corresponding to the image */ public void setImage(TextureRegion image) { this.image.set(image); } /** * Retrieves the the image shown on this {@code UIButton}. * * @return A {@code TextureRegion} corresponding to the image */ public TextureRegion getImage() { return image.get(); } /** * Binds the click sound played when this {@code UIButton} is clicked. * * @param binding The {@code Binding} containing the {@code StaticSound} corresponding to the click sound */ public void bindClickSound(Binding<StaticSound> binding) { clickSound = binding; } /** * Retrieves the click sound played when this {@code UIButton} is clicked. * * @return A {@code StaticSound} corresponding to the click sound */ public StaticSound getClickSound() { return clickSound.get(); } /** * Sets the click sound played when this {@code UIButton} is clicked. * * @param val A {@code StaticSound} corresponding to the click sound */ public void setClickSound(StaticSound val) { clickSound.set(val); } /** * Binds the volume of the click sound. * * @param binding The {@code Binding} containing the float representing the volume the click sound */ public void bindClickVolume(Binding<Float> binding) { clickVolume = binding; } /** * Retrieves the volume of the click sound. * * @return A float representing the volume of the click sound */ public float getClickVolume() { return clickVolume.get(); } /** * Sets the volume of the click sound. * * @param val The float representing the volume of the click sound */ public void setClickVolume(float val) { clickVolume.set(val); } /** * Subscribes a listener that is called whenever this {@code UIButton} is activated. * * @param listener The {@link ActivateEventListener} to be subscribed */ public void subscribe(ActivateEventListener listener) { listeners.add(listener); } /** * Unsubscribes a listener from this {@code UIButton}. * * @param listener The {@code ActivateEventListener}to be unsubscribed */ public void unsubscribe(ActivateEventListener listener) { listeners.remove(listener); } }