Skip to content

Commit

Permalink
Merge branch 'patch-34' into notification
Browse files Browse the repository at this point in the history
  • Loading branch information
BenCheung0422 committed Nov 15, 2023
2 parents bd2b40e + 1bec04e commit 9df4a4f
Show file tree
Hide file tree
Showing 14 changed files with 456 additions and 75 deletions.
15 changes: 10 additions & 5 deletions src/client/java/minicraft/gfx/Font.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import minicraft.core.Renderer;
import minicraft.gfx.SpriteLinker.SpriteType;
import minicraft.screen.entry.ListEntry;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -24,18 +26,21 @@ public class Font {
public static void draw(String msg, Screen screen, int x, int y) { draw(msg, screen, x, y, -1); }

/** Draws the message to the x & y coordinates on the screen. */
public static void
draw(String msg, Screen screen, int x, int y, int whiteTint) {
public static void draw(String msg, Screen screen, int x, int y, int whiteTint) { draw(msg, screen, x, y, whiteTint, null); }
public static void draw(String msg, Screen screen, int x, int y, int whiteTint, @Nullable ListEntry.IntRange bounds) {
for (int i = 0; i < msg.length(); i++) { // Loops through all the characters that you typed
int ix = chars.indexOf(msg.charAt(i)); // The current letter in the message loop
if (ix >= 0) {
// If that character's position is larger than or equal to 0, then render the character on the screen.
screen.render(x + i * textWidth(msg.substring(i, i+1)), y, ix % 32, ix / 32, 0, Renderer.spriteLinker.getSheet(SpriteType.Gui, "font"), whiteTint);
int xx = x + i * textWidth(msg.substring(i, i+1));
if (bounds == null || xx >= bounds.lower && xx + MinicraftImage.boxWidth <= bounds.upper)
screen.render(xx, y, ix % 32, ix / 32, 0, Renderer.spriteLinker.getSheet(SpriteType.Gui, "font"), whiteTint);
}
}
}

public static void drawColor(String message, Screen screen, int x, int y) {
public static void drawColor(String message, Screen screen, int x, int y) { drawColor(message, screen, x, y, null); }
public static void drawColor(String message, Screen screen, int x, int y, @Nullable ListEntry.IntRange bounds) {
// Set default color message if it doesn't have initially
if (message.charAt(0) != Color.COLOR_CHAR) {
message = Color.WHITE_CODE + message;
Expand All @@ -59,7 +64,7 @@ public static void drawColor(String message, Screen screen, int x, int y) {
color = Color.WHITE_CODE;
}

Font.draw(text, screen, x + leading, y, Color.get(color));
Font.draw(text, screen, x + leading, y, Color.get(color), bounds);
leading += Font.textWidth(text);
}
}
Expand Down
25 changes: 17 additions & 8 deletions src/client/java/minicraft/screen/ControlsDisplay.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import minicraft.core.io.Localization;
import minicraft.gfx.Color;
import minicraft.gfx.Font;
import minicraft.gfx.MinicraftImage;
import minicraft.gfx.Point;
import minicraft.gfx.Screen;
import minicraft.screen.entry.ListEntry;
import minicraft.screen.entry.SelectableStringEntry;
import minicraft.screen.entry.StringEntry;

import java.util.ArrayList;
Expand All @@ -20,10 +22,11 @@ public class ControlsDisplay extends Display {
private int displaying; // 0 for keyboard; 1 for controller.

public ControlsDisplay() {
super(true, true, new Menu.Builder(false, 0, RelPos.CENTER)
super(true, true, new Menu.Builder(false, 0, RelPos.LEFT)
.setSelectable(true)
.setPositioning(new Point(Screen.w/2, 20), RelPos.BOTTOM)
.setPositioning(new Point(0, 20), RelPos.BOTTOM_RIGHT)
.setDisplayLength(17)
.setSize(Screen.w, 17 * 8)
.createMenu()
);

Expand All @@ -36,17 +39,23 @@ public ControlsDisplay() {

private void initKeyControls() {
ArrayList<ListEntry> entries = new ArrayList<>(23);
for (int i = 0; i < 23; i++)
entries.addAll(Arrays.asList(StringEntry.useLines(String.format("minicraft.displays.controls.display.keyboard.%02d", i))));
entries.forEach(e -> e.setSelectable(true));
for (int i = 0; i < 23; i++) {
SelectableStringEntry entry = new SelectableStringEntry(String.format("minicraft.displays.controls.display.keyboard.%02d", i));
entry.setScrollingTextRenderTicker(
new ListEntry.IntRange(MinicraftImage.boxWidth * 2, Screen.w - MinicraftImage.boxWidth * 2), MinicraftImage.boxWidth * 2);
entries.add(entry);
}
keyControls = entries.toArray(new ListEntry[0]);
}

private void initControllerControls() {
ArrayList<ListEntry> entries = new ArrayList<>(16);
for (int i = 0; i < 16; i++)
entries.addAll(Arrays.asList(StringEntry.useLines(String.format("minicraft.displays.controls.display.controller.%02d", i))));
entries.forEach(e -> e.setSelectable(true));
for (int i = 0; i < 16; i++) {
SelectableStringEntry entry = new SelectableStringEntry(String.format("minicraft.displays.controls.display.controller.%02d", i));
entry.setScrollingTextRenderTicker(
new ListEntry.IntRange(MinicraftImage.boxWidth * 2, Screen.w - MinicraftImage.boxWidth * 2), MinicraftImage.boxWidth * 2);
entries.add(entry);
}
controllerControls = entries.toArray(new ListEntry[0]);
}

Expand Down
121 changes: 106 additions & 15 deletions src/client/java/minicraft/screen/Menu.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class Menu {
private int spacing = 0;
private Rectangle bounds = null;
private Rectangle entryBounds = null;
private Rectangle renderingBounds = null;
private RelPos entryPos = RelPos.CENTER; // the x part of this is re-applied per entry, while the y part is calculated once using the cumulative height of all entries and spacing.

private String title = "";
Expand Down Expand Up @@ -76,6 +77,7 @@ protected Menu(Menu m) {
spacing = m.spacing;
bounds = m.bounds == null ? null : new Rectangle(m.bounds);
entryBounds = m.entryBounds == null ? null : new Rectangle(m.entryBounds);
renderingBounds = m.renderingBounds;
entryPos = m.entryPos;
title = m.title;
titleColor = m.titleColor;
Expand Down Expand Up @@ -170,11 +172,16 @@ public void tick(InputHandler input) {
if(!selectable || entries.size() == 0) return;

int prevSel = selection;
if (input.inputPressed("cursor-up")) selection--;
if (input.inputPressed("cursor-down")) selection++;
if (input.getKey("shift-cursor-up").clicked && selectionSearcher == 0) selectionSearcher -= 2;
if (input.getKey("shift-cursor-down").clicked && selectionSearcher == 0) selectionSearcher += 2;
if (prevSel != selection && selectionSearcher != 0) selection = prevSel;
if (input.getKey("ALT").down) {
if (input.inputPressed("cursor-left")) entries.get(selection).displaceRight(entryBounds.getWidth());
if (input.inputPressed("cursor-right")) entries.get(selection).displaceLeft(entryBounds.getWidth());
} else {
if (input.inputPressed("cursor-up")) selection--;
if (input.inputPressed("cursor-down")) selection++;
if (input.getKey("shift-cursor-up").clicked && selectionSearcher == 0) selectionSearcher -= 2;
if (input.getKey("shift-cursor-down").clicked && selectionSearcher == 0) selectionSearcher += 2;
if (prevSel != selection && selectionSearcher != 0) selection = prevSel;
}

if (useSearcherBar) {
if (input.getKey("searcher-bar").clicked) {
Expand Down Expand Up @@ -336,24 +343,29 @@ public void render(Screen screen) {
int extra = diff*(ListEntry.getHeight() + spacing) / 2;
y += extra;
}
ListEntry.IntRange renderingXBounds = new ListEntry.IntRange(renderingBounds.getLeft(), renderingBounds.getRight());
for(int i = offset; i < (wrap ? offset + displayLength : Math.min(offset + displayLength, entries.size())); i++) {
if(special && i-offset >= entries.size()) break;

int idx = i % entries.size();
ListEntry entry = entries.get(idx);

if(!(entry instanceof BlankEntry)) {
Point pos = entryPos.positionRect(new Dimension(entry.getWidth(), ListEntry.getHeight()), new Rectangle(entryBounds.getLeft(), y, entryBounds.getWidth(), ListEntry.getHeight(), Rectangle.CORNER_DIMS));
int entryWidth = entry.getWidth();
Point pos = entryPos.positionRect(new Dimension(entryWidth, ListEntry.getHeight()), new Rectangle(entryBounds.getLeft(), y, entryBounds.getWidth(), ListEntry.getHeight(), Rectangle.CORNER_DIMS));
boolean selected = idx == selection;
int xDisplacement = selected ? entry.getXDisplacement() : 0;
boolean hideOverflow = entry.hideWhenOverflow() && entry.isSelectable();
if (searcherBarActive && useSearcherBar) {
entry.render(screen, pos.x, pos.y, selected, typingSearcher, Color.YELLOW);
entry.render(screen, pos.x + xDisplacement, pos.y, selected, hideOverflow ? renderingXBounds : null, typingSearcher, Color.YELLOW);
} else {
entry.render(screen, pos.x, pos.y, selected);
entry.render(screen, pos.x + xDisplacement, pos.y, selected, hideOverflow ? renderingXBounds : null);
}
if (selected && entry.isSelectable()) {
// draw the arrows
Font.draw("> ", screen, pos.x - Font.textWidth("> "), y, ListEntry.COL_SLCT);
Font.draw(" <", screen, pos.x + entry.getWidth(), y, ListEntry.COL_SLCT);
boolean hiddenOverflow = hideOverflow && entryWidth > entryBounds.getWidth();
Font.draw("> ", screen, hiddenOverflow ? entryBounds.getLeft() - Font.textWidth("> ") : pos.x + xDisplacement - Font.textWidth("> "), y, ListEntry.COL_SLCT);
Font.draw(" <", screen, hiddenOverflow ? entryBounds.getRight() : pos.x + xDisplacement + entryWidth, y, ListEntry.COL_SLCT);
}
}

Expand Down Expand Up @@ -426,6 +438,9 @@ public static class Builder {
@NotNull private Point anchor = center;
@NotNull private RelPos menuPos = RelPos.CENTER;
private Dimension menuSize = null;
private Rectangle limitingBounds = null;
private Rectangle renderingBounds = null;
private boolean removeEntryPeaks = false;

private boolean searcherBar;

Expand Down Expand Up @@ -462,6 +477,31 @@ public Builder setBounds(Rectangle rect) {

public Builder setDisplayLength(int numEntries) { menu.displayLength = numEntries; return this; }

/** This restricts the maximum bounds this menu could be. */
public Builder setMaxBounds(Rectangle rect) {
limitingBounds = rect;
return this;
}

public Builder setMaxBoundsAsMaxMenuBounds() {
limitingBounds = new Rectangle(0, 0, Screen.w, Screen.h, Rectangle.CORNERS);
return this;
}

public Builder setRemoveEntryPeaks(boolean removeEntryPeaks) {
this.removeEntryPeaks = removeEntryPeaks;
return this;
}

public Builder setRenderingBounds(Rectangle rect) {
renderingBounds = rect;
return this;
}

public Builder setMaxBoundsAsRenderingBounds() {
renderingBounds = new Rectangle(0, 0, Screen.w, Screen.h, Rectangle.CORNERS);
return this;
}

public Builder setTitlePos(RelPos rp) { titlePos = (rp == null ? RelPos.TOP : rp); return this; }

Expand Down Expand Up @@ -587,11 +627,46 @@ else if (c.xIndex == 2) // must be center right

if(menuSize == null) {
int width = titleDim.width;
for(ListEntry entry: menu.entries) {
int entryWidth = entry.getWidth();
if(menu.isSelectable() && !entry.isSelectable())
entryWidth = Math.max(0, entryWidth - MinicraftImage.boxWidth * 4);
width = Math.max(width, entryWidth);
// There should be valid peaks to be handled when the number of entries is greater than 1.
if (removeEntryPeaks && menu.entries.size() > 1) {
// First write into an array to more easily find peaks.
int[] entryWidths = new int[menu.entries.size()];
for (int i = 0; i < menu.entries.size(); ++i) {
entryWidths[i] = menu.entries.get(i).getWidth();
}

// Reference: https://www.geeksforgeeks.org/print-all-the-peaks-and-troughs-in-an-array-of-integers/
boolean handled = false; // For security check.
ArrayList<Integer> peaks = new ArrayList<>();
for (int i = 0; i < entryWidths.length; ++i) {
// Checks if the element is greater than the neighbours
if ((i == 0 || entryWidths[i] > entryWidths[i - 1]) && (i == entryWidths.length - 1 || entryWidths[i] > entryWidths[i + 1])) {
peaks.add(entryWidths[i]);
} else {
int entryWidth = entryWidths[i];
if (menu.isSelectable() && !menu.entries.get(i).isSelectable())
entryWidth = Math.max(0, entryWidth - MinicraftImage.boxWidth * 4);
width = Math.max(width, entryWidth);
handled = true;
}
}

if (!handled) width = Math.max(width, Arrays.stream(entryWidths).max().getAsInt());
else {
if (peaks.size() > 0) { // Count in the peaks into the resultant width with small ratio.
double peaksAvg = (double) peaks.stream().mapToInt(a -> a).sum() / peaks.size();
double ratio = .07 / Math.max(peaksAvg / width - 1, .07); // max is used to prevent extreme case.
width = (int) (width * ratio + (1 - ratio) * peaksAvg);
width -= width % MinicraftImage.boxWidth; // strip extra pixels
}
}
} else {
for(ListEntry entry: menu.entries) {
int entryWidth = entry.getWidth();
if(menu.isSelectable() && !entry.isSelectable())
entryWidth = Math.max(0, entryWidth - MinicraftImage.boxWidth * 4);
width = Math.max(width, entryWidth);
}
}

if(menu.displayLength > 0) { // has been set; use to determine entry bounds
Expand Down Expand Up @@ -632,10 +707,23 @@ else if(menuPos.yIndex == 2)
// based on the menu centering, and the anchor, determine the upper-left point from which to draw the menu.
menu.bounds = menuPos.positionRect(menuSize, anchor, new Rectangle()); // reset to a value that is actually useful to the menu

if (limitingBounds != null) {
// Exceeded areas are cut off from the bounds.
if (!limitingBounds.intersects(menu.bounds))
throw new IndexOutOfBoundsException("limitingBounds does not intersect bounds");
int x = Math.max(limitingBounds.getLeft(), menu.bounds.getLeft()); // Get the rightmost left bound
int y = Math.max(limitingBounds.getTop(), menu.bounds.getTop()); // Get the bottommost top bound
int x1 = Math.min(limitingBounds.getBottom(), menu.bounds.getBottom()); // Get the topmost bottom bound
int y1 = Math.min(limitingBounds.getRight(), menu.bounds.getRight()); // Get the leftmost right bount
menu.bounds = new Rectangle(x, y, x1, y1, Rectangle.CORNERS); // Reset to the bounds after cut off the exceeded bounds
}

menu.entryBounds = border.subtractFrom(menu.bounds);

menu.titleLoc = titlePos.positionRect(titleDim, menu.bounds);

menu.renderingBounds = renderingBounds == null ? menu.entryBounds : renderingBounds;

if(titlePos.xIndex == 0 && titlePos.yIndex != 1)
menu.titleLoc.x += MinicraftImage.boxWidth;
if(titlePos.xIndex == 2 && titlePos.yIndex != 1)
Expand Down Expand Up @@ -679,6 +767,9 @@ public Builder copy() {
b.setTitleColor = setTitleColor;
b.titleCol = titleCol;
b.searcherBar = searcherBar;
b.limitingBounds = limitingBounds;
b.renderingBounds = renderingBounds;
b.removeEntryPeaks = removeEntryPeaks;

return b;
}
Expand Down
1 change: 1 addition & 0 deletions src/client/java/minicraft/screen/OptionsWorldDisplay.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public OptionsWorldDisplay() {
menus = new Menu[] {
new Menu.Builder(false, 6, RelPos.LEFT, entries)
.setTitle("minicraft.displays.options_world")
.setRemoveEntryPeaks(true)
.createMenu()
};
}
Expand Down
25 changes: 24 additions & 1 deletion src/client/java/minicraft/screen/PopupDisplay.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.studiohartman.jamepad.ControllerButton;
import minicraft.core.Game;
import minicraft.core.io.InputHandler;
import minicraft.gfx.MinicraftImage;
import minicraft.gfx.Rectangle;
import minicraft.gfx.Screen;
import minicraft.screen.entry.InputEntry;
import minicraft.screen.entry.ListEntry;
Expand All @@ -17,6 +19,7 @@ public class PopupDisplay extends Display {
// Using Color codes for coloring in title and plain text messages.

private final ArrayList<PopupActionCallback> callbacks;
private final Menu.Builder builder;

public PopupDisplay(@Nullable PopupConfig config, String... messages) { this(config, false, messages); }
public PopupDisplay(@Nullable PopupConfig config, boolean clearScreen, String... messages) { this(config, clearScreen, true, messages); }
Expand All @@ -26,7 +29,7 @@ public class PopupDisplay extends Display {
public PopupDisplay(@Nullable PopupConfig config, boolean clearScreen, boolean menuFrame, ListEntry... entries) {
super(clearScreen, true);

Menu.Builder builder = new Menu.Builder(menuFrame, 0, RelPos.CENTER, entries);
builder = new Menu.Builder(menuFrame, 0, RelPos.CENTER, entries);

if (config != null) {
if (config.title != null)
Expand All @@ -43,6 +46,26 @@ public PopupDisplay(@Nullable PopupConfig config, boolean clearScreen, boolean m
menus = new Menu[] { builder.createMenu() };
else
menus = new Menu[] { onScreenKeyboardMenu, builder.createMenu() };

Rectangle menuBounds = menus[onScreenKeyboardMenu == null ? 0 : 1].getBounds();
for (ListEntry entry : entries) {
if (entry instanceof InputEntry) {
((InputEntry) entry).setChangeListener(v -> update());
((InputEntry) entry).setRenderingBounds(new ListEntry.IntRange(MinicraftImage.boxWidth * 3, Screen.w - MinicraftImage.boxWidth * 3))
.setEntryPos(RelPos.CENTER)
.setBounds(new ListEntry.IntRange(menuBounds.getLeft() + MinicraftImage.boxWidth * 3, menuBounds.getRight() - MinicraftImage.boxWidth * 3));
}
}
}

private void update() {
menus[onScreenKeyboardMenu == null ? 0 : 1] = builder.createMenu();
Rectangle menuBounds = menus[onScreenKeyboardMenu == null ? 0 : 1].getBounds();
for (ListEntry entry : menus[onScreenKeyboardMenu == null ? 0 : 1].getEntries()) {
if (entry instanceof InputEntry) {
((InputEntry) entry).setBounds(new ListEntry.IntRange(menuBounds.getLeft() + MinicraftImage.boxWidth * 3, menuBounds.getRight() - MinicraftImage.boxWidth * 3));
}
}
}

OnScreenKeyboardMenu onScreenKeyboardMenu;
Expand Down
Loading

0 comments on commit 9df4a4f

Please sign in to comment.