package ethanjones.cubes.graphics.hud; import ethanjones.cubes.core.util.Toggle; import ethanjones.cubes.graphics.menu.Fonts; import ethanjones.cubes.graphics.menu.Menu; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.scenes.scene2d.Touchable; import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; import java.util.ArrayDeque; public class ChatActor extends ScrollPane { private static final int MAX_OLD_MESSAGES = 500; private static final int MESSAGES_DISPLAY = 7; private static final int HIDE_MSG_MS = 11000; private static final int FADE_MSG_MS = 10000; private ArrayDeque<ChatMessage> history = new ArrayDeque<ChatMessage>(); private ArrayDeque<ChatMessage> current = new ArrayDeque<ChatMessage>(); private SimpleListActor<ChatMessage> listActor = new SimpleListActor<ChatMessage>(Fonts.hud) { @Override public void draw(Batch batch, float parentAlpha) { validate(); Color color = getColor(); batch.setColor(color.r, color.g, color.b, color.a * parentAlpha); float currentY = getItemHeight(); for (ChatMessage item : items) { if (open.isDisabled()) { long ms = System.currentTimeMillis() - item.timeReceived; font.getColor().a = ms < FADE_MSG_MS ? 1 : 1f - (((float) (ms - FADE_MSG_MS)) / (HIDE_MSG_MS - FADE_MSG_MS)); } font.draw(batch, item.toString(), getX(), getY() + currentY); currentY += itemHeight; } font.getColor().a = 1; } }; public Toggle open = new Toggle(false) { @Override protected void doEnable() { listActor.setCollection(history); getStage().setScrollFocus(ChatActor.this); setScrollingDisabled(true, false); layout(); setScrollY(getMaxY()); updateVisualScroll(); } @Override protected void doDisable() { listActor.setCollection(current); getStage().setScrollFocus(null); setScrollingDisabled(true, true); layout(); setScrollY(getMaxY()); updateVisualScroll(); } }; private boolean newMessages = false; public ChatActor() { super(null, Menu.skin); setActor(listActor); listActor.setGap(4f); } @Override public Touchable getTouchable() { return open.isEnabled() ? Touchable.enabled : Touchable.disabled; } @Override public void act(float delta) { if (open.isEnabled()) { if (newMessages) { listActor.invalidate(); newMessages = false; } } else { long oldestToDisplay = System.currentTimeMillis() - HIDE_MSG_MS; boolean updated = newMessages; while (current.peekLast() != null && current.peekLast().timeReceived < oldestToDisplay) { current.removeLast(); updated = true; } if (updated) { listActor.invalidate(); newMessages = false; } } super.act(delta); } public void newMessage(String str) { ChatMessage chatMessage = new ChatMessage(str); history.addFirst(chatMessage); trim(history, MAX_OLD_MESSAGES); current.addFirst(chatMessage); trim(current, MESSAGES_DISPLAY); newMessages = true; } @Override public float getPrefHeight() { return listActor.getItemHeight() * MESSAGES_DISPLAY; } private void trim(ArrayDeque<ChatMessage> messages, int maxLength) { while (messages.size() > maxLength) { messages.removeLast(); } } private static class ChatMessage { final String msg; final long timeReceived; ChatMessage(String msg) { this.msg = msg; this.timeReceived = System.currentTimeMillis(); } @Override public String toString() { return msg; } } }