package de.lessvoid.nifty.effects.impl;
import java.util.List;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import de.lessvoid.nifty.EndNotify;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.NiftyIdCreator;
import de.lessvoid.nifty.builder.ControlBuilder;
import de.lessvoid.nifty.builder.ElementBuilder;
import de.lessvoid.nifty.builder.LayerBuilder;
import de.lessvoid.nifty.effects.EffectEventId;
import de.lessvoid.nifty.effects.EffectImpl;
import de.lessvoid.nifty.effects.EffectProperties;
import de.lessvoid.nifty.effects.Falloff;
import de.lessvoid.nifty.elements.Element;
import de.lessvoid.nifty.render.NiftyRenderEngine;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.tools.SizeValue;
/**
* Hint - show a hint, a nifty hint!
* <p/>
* This is the new, even more nifty version of the hint. It maintains only a single layer and does not delete this
* layer once its created. All hints are stored on this single layer. Thanks to the render order system of Nifty the
* hints are still always shown at the very top of the layer stack.
*
* @author void
* @author Martin Karing <nitram@illarion.org>
*/
public class Hint implements EffectImpl {
@Nonnull
private static final Logger log = Logger.getLogger(Hint.class.getName());
@Nonnull
private static final String HINT_LAYER_ID = "niftyHintLayer";
@Nullable
private Nifty nifty;
@Nullable
private Screen screen;
@Nullable
private Element hintLayer;
@Nullable
private Element hintPanel;
private int hintDelay;
@Nullable
private String offsetX;
@Nullable
private String offsetY;
@Override
public void activate(
@Nonnull final Nifty nifty,
@Nonnull final Element element,
@Nonnull final EffectProperties parameter) {
this.nifty = nifty;
screen = nifty.getCurrentScreen();
if (screen == null) {
log.severe("Can't activate hint effect without a screen that is currently active.");
return;
}
final String hintControl = parameter.getProperty("hintControl", "nifty-default-hint");
final String hintStyle = parameter.getProperty("hintStyle", null);
final String hintText = parameter.getProperty("hintText", "hint: add a 'hintText' attribute to the hint effect :)");
hintDelay = Integer.valueOf(parameter.getProperty("hintDelay", "0"));
offsetX = parameter.getProperty("offsetX", "0");
offsetY = parameter.getProperty("offsetY", "0");
Element hintLayer = getHintLayer();
hintLayer.setVisible(false);
ControlBuilder builder = new ControlBuilder(NiftyIdCreator.generate(), hintControl);
builder.parameter("hintText", hintText);
if (hintStyle != null) {
builder.style(hintStyle);
}
hintPanel = builder.build(nifty, screen, hintLayer);
}
@Nonnull
private Element getHintLayer() {
if (hintLayer != null) {
return hintLayer;
}
if (screen == null || nifty == null) {
throw new IllegalStateException("Can't create or retrieve hint layer while there is no active screen.");
}
hintLayer = screen.findElementById(HINT_LAYER_ID);
if (hintLayer != null) {
return hintLayer;
}
LayerBuilder builder = new LayerBuilder(HINT_LAYER_ID);
builder.childLayout(ElementBuilder.ChildLayoutType.Absolute);
builder.visible(false);
hintLayer = builder.build(nifty, screen, screen.getRootElement());
hintLayer.setRenderOrder(Integer.MAX_VALUE);
return hintLayer;
}
@Override
public void execute(
@Nonnull final Element element,
final float normalizedTime,
@Nullable final Falloff falloff,
@Nonnull final NiftyRenderEngine r) {
if (nifty == null || screen == null || hintLayer == null || hintPanel == null) {
log.severe("Can't execute effect. Activation not done or failed.");
return;
}
if (normalizedTime > 0.0) {
if (!hintLayer.isVisible()) {
// decide if we can already show the hint
if (nifty.getNiftyMouse().getNoMouseMovementTime() > hintDelay) {
hintPanel.setConstraintX(SizeValue.px(getPosX(element, hintPanel, r.getWidth())));
hintPanel.setConstraintY(SizeValue.px(getPosY(element, hintPanel, r.getHeight())));
// hard remove all old hints, else they only mess with the new ones
List<Element> hints = hintLayer.getChildren();
for (int i = 0; i < hints.size() - 1; i++) {
nifty.removeElement(screen, hints.get(i));
}
hintLayer.layoutElements();
hintLayer.show();
}
}
}
}
@Override
public void deactivate() {
if (hintPanel != null) {
if (hintPanel.isVisible()) {
hintPanel.startEffect(EffectEventId.onCustom, new EndNotify() {
@Override
public void perform() {
removePanel();
}
});
} else {
removePanel();
}
}
}
private void removePanel() {
if (hintPanel != null && hintLayer != null) {
hintPanel.markForRemoval(new EndNotify() {
@Override
public void perform() {
if (hintLayer.getChildrenCount() <= 1) {
hintLayer.hide();
}
}
});
}
}
private int getPosX(@Nonnull final Element element, @Nonnull final Element hintPanel, final int screenWidth) {
int pos;
if ("center".equals(offsetX)) {
pos = element.getX() + element.getWidth() / 2 - hintPanel.getWidth() / 2;
} else if ("left".equals(offsetX)) {
pos = element.getX();
} else if ("right".equals(offsetX)) {
pos = element.getX() + element.getWidth() - hintPanel.getWidth();
} else {
pos = Integer.valueOf(offsetX);
}
if (pos < 0) {
pos = 0;
}
if (pos + hintPanel.getWidth() > screenWidth) {
pos = screenWidth - hintPanel.getWidth();
}
return pos;
}
private int getPosY(@Nonnull final Element element, @Nonnull final Element hintPanel, final int screenHeight) {
int pos;
if ("center".equals(offsetY)) {
pos = element.getY() + element.getHeight() / 2 - hintPanel.getHeight() / 2;
} else if ("top".equals(offsetY)) {
pos = element.getY();
} else if ("bottom".equals(offsetY)) {
pos = element.getY() + element.getHeight() - hintPanel.getHeight();
} else {
pos = Integer.valueOf(offsetY);
}
if (pos < 0) {
pos = 0;
}
if (pos + hintPanel.getHeight() > screenHeight) {
pos = screenHeight - hintPanel.getHeight();
}
return pos;
}
}