From 5a05587de49464cdccb4e3f923f42fdb0e21d389 Mon Sep 17 00:00:00 2001 From: BenCheung0422 <74168521+BenCheung0422@users.noreply.github.com> Date: Thu, 3 Aug 2023 01:36:53 +0800 Subject: [PATCH] Add reset and redo color codes --- src/client/java/minicraft/gfx/Color.java | 5 ++ src/client/java/minicraft/gfx/Font.java | 75 +++++++++++++------ .../minicraft/screen/entry/KeyInputEntry.java | 7 +- .../minicraft/screen/entry/ListEntry.java | 6 +- 4 files changed, 65 insertions(+), 28 deletions(-) diff --git a/src/client/java/minicraft/gfx/Color.java b/src/client/java/minicraft/gfx/Color.java index cdc1e757d..c0389501c 100644 --- a/src/client/java/minicraft/gfx/Color.java +++ b/src/client/java/minicraft/gfx/Color.java @@ -51,6 +51,11 @@ public class Color { public static final String MAGENTA_CODE = Color.toStringCode(Color.MAGENTA); public static final String CYAN_CODE = Color.toStringCode(Color.CYAN); + // Reset color to the original setting of the string. + public static final String RESET_CODE = COLOR_CHAR + "\u0002\u0000\u0000\u0000"; + // Set the color before the last color code; if the last code is: RESET or unset: no operation; REDO: RESET. + public static final String REDO_CODE = COLOR_CHAR + "\u0003\u0000\u0000\u0000"; + /** This returns a minicraftrgb. * a should be between 0-1, r,g,and b should be 0-255 */ public static int get(int a, int r, int g, int b) { diff --git a/src/client/java/minicraft/gfx/Font.java b/src/client/java/minicraft/gfx/Font.java index ff141eea8..85b79c094 100644 --- a/src/client/java/minicraft/gfx/Font.java +++ b/src/client/java/minicraft/gfx/Font.java @@ -1,5 +1,6 @@ package minicraft.gfx; +import minicraft.core.Action; import minicraft.core.Renderer; import minicraft.core.io.Localization; import minicraft.gfx.SpriteLinker.SpriteType; @@ -7,6 +8,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Stack; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; public class Font { // These are all the characters that will be translated to the screen. (The spaces are important) @@ -34,32 +38,61 @@ public class Font { } } - public static void drawColor(String message, Screen screen, int x, int y) { - // Set default color message if it doesn't have initially - if (message.charAt(0) != Color.COLOR_CHAR) { - message = Color.WHITE_CODE + message; - } + public static void drawColor(String message, Screen screen, int x, int y) { drawColor(message, screen, x, y, -1); } + public static void drawColor(String message, Screen screen, int x, int y, int whiteTint) { + AtomicInteger leading = new AtomicInteger(); + AtomicReference toRender = new AtomicReference<>(new StringBuilder()); + SizedStack colors = new SizedStack<>(2); + Action textRenderer = () -> { + if (toRender.get().length() > 0) { + String text = toRender.toString(); + Font.draw(text, screen, x + leading.get(), y, colors.isEmpty() ? whiteTint : colors.peek()); + leading.addAndGet(Font.textWidth(text)); + toRender.set(new StringBuilder()); // Clears the appended text. + } + }; + for (int i = 0; i < message.length(); i++) { + char c = message.charAt(i); + if (c == Color.COLOR_CHAR) { + if (message.length() - 1 - i >= 4) { // There should be 4 chars for color values. + textRenderer.act(); // Renders with the last color instantly. + String colorCode = message.substring(i, i + 5); // Gets the 5 characters including color char. + if (colorCode.equals(Color.RESET_CODE)) { + colors.clear(); + } else if (colorCode.equals(Color.REDO_CODE)) { + if (colors.size() > 0) colors.pop(); + } else { + colors.add(Color.get(colorCode)); + } + + i += 4; // Shifts for 4 characters (color values). + continue; + } + } - int leading = 0; - for (String data : message.split(String.valueOf(Color.COLOR_CHAR))) { - if (data.isEmpty()) { - continue; + toRender.get().append(c); + if (i == message.length() - 1) { // If this is the last character + textRenderer.act(); // Renders the text remaining. } + } + } - String text; - String color; + // Reference: https://stackoverflow.com/a/16206356 + private static class SizedStack extends Stack { + private final int maxSize; - try { - text = data.substring(4); - color = data.substring(0, 4); // ARGB value - } catch (IndexOutOfBoundsException ignored) { - // Bad formatted colored string - text = data; - color = Color.WHITE_CODE; - } + public SizedStack(int size) { + super(); + this.maxSize = size; + } - Font.draw(text, screen, x + leading, y, Color.get(color)); - leading += Font.textWidth(text); + @Override + public T push(T object) { + //If the stack is too big, remove elements until it's the right size. + while (this.size() >= maxSize) { + this.remove(0); + } + return super.push(object); } } diff --git a/src/client/java/minicraft/screen/entry/KeyInputEntry.java b/src/client/java/minicraft/screen/entry/KeyInputEntry.java index c75fec687..ac1efbec6 100644 --- a/src/client/java/minicraft/screen/entry/KeyInputEntry.java +++ b/src/client/java/minicraft/screen/entry/KeyInputEntry.java @@ -26,11 +26,10 @@ private void setMapping(String mapping, Set duplicated) { for (int spaces = 0; spaces < Screen.w/Font.textWidth(" ") - action.length() - mapping.length(); spaces++) buffer.append(" "); - String newMapping = ""; + StringBuilder newMapping = new StringBuilder(); for (String k : mapping.split("\\|")) { - if (duplicated.contains(k)) k = Color.RED_CODE + k; - k = Color.GRAY_CODE + k + Color.WHITE_CODE; - newMapping += k + "|"; + if (duplicated.contains(k)) k = Color.RED_CODE + k + Color.RESET_CODE; + newMapping.append(k).append("|"); } this.mapping = newMapping.substring(0, newMapping.length() - 1); diff --git a/src/client/java/minicraft/screen/entry/ListEntry.java b/src/client/java/minicraft/screen/entry/ListEntry.java index 9b60eda8d..346731c16 100644 --- a/src/client/java/minicraft/screen/entry/ListEntry.java +++ b/src/client/java/minicraft/screen/entry/ListEntry.java @@ -33,7 +33,7 @@ public void render(Screen screen, int x, int y, boolean isSelected, String conta String string = toString().toLowerCase(Locale.ENGLISH); contain = contain.toLowerCase(Locale.ENGLISH); - Font.drawColor(string.replace(contain, Color.toStringCode(containColor) + contain + Color.WHITE_CODE), screen, x, y); + Font.drawColor(string.replace(contain, Color.toStringCode(containColor) + contain + Color.REDO_CODE), screen, x, y); } /** @@ -46,9 +46,9 @@ public void render(Screen screen, int x, int y, boolean isSelected, String conta */ public void render(Screen screen, int x, int y, boolean isSelected) { if (visible) { - String text = toString().replace(Color.WHITE_CODE + Color.GRAY_CODE, Color.toStringCode(getColor(isSelected))); + String text = toString(); if (text.contains(String.valueOf(Color.COLOR_CHAR))) - Font.drawColor(Color.toStringCode(getColor(isSelected)) + text, screen, x, y); + Font.drawColor(text, screen, x, y, getColor(isSelected)); else Font.draw(text, screen, x, y, getColor(isSelected)); }