Skip to content

Commit

Permalink
Simplify creation of scrollbox widgets
Browse files Browse the repository at this point in the history
  • Loading branch information
mezz committed Sep 22, 2024
1 parent 0f7bde7 commit a7d7a18
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import mezz.jei.api.gui.drawable.IDrawableStatic;

public record DrawableBlank(int width, int height) implements IDrawableStatic, IDrawableAnimated, IScalableDrawable {
public static final DrawableBlank EMPTY = new DrawableBlank(0, 0);

@Override
public int getWidth() {
return width;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package mezz.jei.common.gui.elements;

import mezz.jei.api.gui.drawable.IDrawable;
import mezz.jei.common.util.StringUtil;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.locale.Language;
import net.minecraft.network.chat.FormattedText;
import net.minecraft.util.FormattedCharSequence;

import java.util.List;

public class DrawableWrappedText implements IDrawable {
private static final int lineSpacing = 2;

private final List<FormattedText> descriptionLines;
private final int lineHeight;
private final int width;
private final int height;

public DrawableWrappedText(List<FormattedText> text, int maxWidth) {
Minecraft minecraft = Minecraft.getInstance();
this.lineHeight = minecraft.font.lineHeight + lineSpacing;
this.descriptionLines = StringUtil.splitLines(text, maxWidth);
this.width = maxWidth;
this.height = lineHeight * descriptionLines.size() - lineSpacing;
}

@Override
public int getWidth() {
return width;
}

@Override
public int getHeight() {
return height;
}

@Override
public void draw(GuiGraphics guiGraphics, int xOffset, int yOffset) {
Language language = Language.getInstance();
Minecraft minecraft = Minecraft.getInstance();
Font font = minecraft.font;

int yPos = 0;
for (FormattedText descriptionLine : descriptionLines) {
FormattedCharSequence charSequence = language.getVisualOrder(descriptionLine);
guiGraphics.drawString(font, charSequence, 0, yPos, 0xFF000000, false);
yPos += lineHeight;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,14 @@ public interface IRecipeExtrasBuilder {
* @since 19.6.0
*/
void addGuiEventListener(IJeiGuiEventListener guiEventListener);

/**
* Create and add a new scroll box widget.
* Handles displaying drawable contents in a scrolling area with a scrollbar.
*
* Set the contents by using the methods in {@link IScrollBoxWidget}.
*
* @since 19.18.9
*/
IScrollBoxWidget addScrollBoxWidget(int width, int height, int xPos, int yPos);
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,48 @@
package mezz.jei.api.gui.widgets;

import mezz.jei.api.gui.drawable.IDrawable;
import mezz.jei.api.gui.inputs.IJeiInputHandler;
import mezz.jei.api.helpers.IGuiHelper;
import mezz.jei.api.recipe.category.IRecipeCategory;
import net.minecraft.network.chat.FormattedText;

import java.util.List;

/**
* A smooth-scrolling area with a scrollbar.
*
* Create one with {@link IGuiHelper#createScrollBoxWidget}, and then
* add it to your recipe in {@link IRecipeCategory#createRecipeExtras}
* using {@link IRecipeExtrasBuilder#addWidget} and {@link IRecipeExtrasBuilder#addInputHandler}.
* Create one with {@link IRecipeExtrasBuilder#addScrollBoxWidget}.
*
* @since 19.8.0
*/
public interface IScrollBoxWidget extends IRecipeWidget, IJeiInputHandler {
/**
* Get the width available for displaying contents in the scroll box.
* The scroll bar takes up some of the space, so this can be used in order to create accurately-sized contents.
*
* @since 19.18.9
*/
int getContentAreaWidth();

/**
* Get the visible height for displaying contents in the scroll box.
* The actual height of the contents can be taller, because the box can scroll to show more.
*
* @since 19.18.9
*/
int getContentAreaHeight();

/**
* Set the contents to display inside the scroll box.
* The drawable width should match {@link #getContentAreaWidth()}, and the height can be any height.
*
* @since 19.18.9
*/
IScrollBoxWidget setContents(IDrawable contents);

/**
* Display text in the scroll box.
* Text will be automatically wrapped in order to fit inside of {@link #getContentAreaWidth()}.
*
* @since 19.18.9
*/
IScrollBoxWidget setContents(List<FormattedText> text);
}
7 changes: 7 additions & 0 deletions CommonApi/src/main/java/mezz/jei/api/helpers/IGuiHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import mezz.jei.api.gui.drawable.IDrawableBuilder;
import mezz.jei.api.gui.drawable.IDrawableStatic;
import mezz.jei.api.gui.ingredient.ICraftingGridHelper;
import mezz.jei.api.gui.widgets.IRecipeExtrasBuilder;
import mezz.jei.api.gui.widgets.IRecipeWidget;
import mezz.jei.api.gui.widgets.IScrollBoxWidget;
import mezz.jei.api.gui.widgets.IScrollGridWidgetFactory;
Expand Down Expand Up @@ -186,14 +187,20 @@ default IDrawable createDrawableItemLike(ItemLike itemLike) {
* Handles displaying drawable contents in a scrolling area.
*
* @since 19.8.0
*
* @deprecated use {@link IRecipeExtrasBuilder#addScrollBoxWidget}
*/
@Deprecated(since = "19.18.9", forRemoval = true)
IScrollBoxWidget createScrollBoxWidget(IDrawable contents, int visibleHeight, int xPos, int yPos);

/**
* The amount of extra horizontal space that a {@link IScrollBoxWidget} takes up with its scroll bar.
*
* @since 19.8.0
*
* @deprecated use {@link IRecipeExtrasBuilder#addScrollBoxWidget}
*/
@Deprecated(since = "19.18.9", forRemoval = true)
int getScrollBoxScrollbarExtraWidth();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,15 @@ public IScrollGridWidgetFactory<?> createScrollGridFactory(int columns, int visi
return new ScrollGridWidgetFactory<>(this, columns, visibleRows);
}

@SuppressWarnings("removal")
@Override
public IScrollBoxWidget createScrollBoxWidget(IDrawable contents, int visibleHeight, int xPos, int yPos) {
return new ScrollBoxRecipeWidget(contents, visibleHeight, xPos, yPos);
ScrollBoxRecipeWidget widget = new ScrollBoxRecipeWidget(contents.getWidth() + getScrollBoxScrollbarExtraWidth(), visibleHeight, xPos, yPos);
widget.setContents(contents);
return widget;
}

@SuppressWarnings("removal")
@Override
public int getScrollBoxScrollbarExtraWidth() {
return AbstractScrollWidget.getScrollBoxScrollbarExtraWidth();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import mezz.jei.api.gui.inputs.IJeiInputHandler;
import mezz.jei.api.gui.widgets.IRecipeExtrasBuilder;
import mezz.jei.api.gui.widgets.IRecipeWidget;
import mezz.jei.api.gui.widgets.IScrollBoxWidget;
import mezz.jei.api.gui.widgets.ISlottedRecipeWidget;
import mezz.jei.api.gui.widgets.ISlottedWidgetFactory;
import mezz.jei.api.ingredients.ITypedIngredient;
Expand All @@ -30,6 +31,7 @@
import mezz.jei.library.gui.recipes.OutputSlotTooltipCallback;
import mezz.jei.library.gui.recipes.RecipeLayout;
import mezz.jei.library.gui.recipes.ShapelessIcon;
import mezz.jei.library.gui.widgets.ScrollBoxRecipeWidget;
import mezz.jei.library.ingredients.DisplayIngredientAcceptor;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -128,6 +130,14 @@ public void addGuiEventListener(IJeiGuiEventListener guiEventListener) {
this.guiEventListeners.add(guiEventListener);
}

@Override
public IScrollBoxWidget addScrollBoxWidget(int width, int height, int xPos, int yPos) {
ScrollBoxRecipeWidget widget = new ScrollBoxRecipeWidget(width, height, xPos, yPos);
addWidget(widget);
addInputHandler(widget);
return widget;
}

@Override
public void moveRecipeTransferButton(int posX, int posY) {
this.recipeTransferX = posX;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ protected static ImmutableRect2i calculateScrollArea(int width, int height) {
);
}

private final ScreenRectangle area;
protected final ScreenRectangle area;
protected final ScreenRectangle contentsArea;

private final ImmutableRect2i scrollArea;
private final DrawableNineSliceTexture scrollbarMarker;
private final DrawableNineSliceTexture scrollbarBackground;
Expand All @@ -50,6 +52,12 @@ public AbstractScrollWidget(ScreenRectangle area) {
Textures textures = Internal.getTextures();
this.scrollbarMarker = textures.getScrollbarMarker();
this.scrollbarBackground = textures.getScrollbarBackground();
this.contentsArea = new ScreenRectangle(
0,
0,
area.width() - getScrollBoxScrollbarExtraWidth(),
area.height()
);
}

protected ImmutableRect2i calculateScrollbarMarkerArea() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,53 @@
import mezz.jei.common.Internal;
import mezz.jei.common.config.IClientConfig;
import mezz.jei.common.config.IJeiClientConfigs;
import mezz.jei.common.gui.elements.DrawableBlank;
import mezz.jei.common.gui.elements.DrawableWrappedText;
import mezz.jei.common.util.MathUtil;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.navigation.ScreenRectangle;
import net.minecraft.network.chat.FormattedText;
import org.joml.Matrix4f;

import java.util.List;

public class ScrollBoxRecipeWidget extends AbstractScrollWidget implements IScrollBoxWidget, IJeiInputHandler {
private final int visibleHeight;
private final int hiddenHeight;
private final ScreenRectangle contentsArea;
private final IDrawable contents;
private IDrawable contents = DrawableBlank.EMPTY;

public ScrollBoxRecipeWidget(int width, int height, int xPos, int yPos) {
super(new ScreenRectangle(xPos, yPos, width, height));
}

@Override
public int getContentAreaWidth() {
return contentsArea.width();
}

@Override
public int getContentAreaHeight() {
return contentsArea.height();
}

public ScrollBoxRecipeWidget(IDrawable contents, int visibleHeight, int xPos, int yPos) {
super(new ScreenRectangle(
xPos,
yPos,
contents.getWidth() + AbstractScrollWidget.getScrollBoxScrollbarExtraWidth(),
visibleHeight
));
@Override
public IScrollBoxWidget setContents(IDrawable contents) {
this.contents = contents;
this.visibleHeight = visibleHeight;
this.contentsArea = new ScreenRectangle(
0,
0,
contents.getWidth(),
visibleHeight
);
this.hiddenHeight = Math.max(contents.getHeight() - visibleHeight, 0);
return this;
}

@Override
public IScrollBoxWidget setContents(List<FormattedText> text) {
this.contents = new DrawableWrappedText(text, getContentAreaWidth());
return this;
}

@Override
protected int getVisibleAmount() {
return visibleHeight;
return contentsArea.height();
}

@Override
protected int getHiddenAmount() {
return hiddenHeight;
return Math.max(contents.getHeight() - contentsArea.height(), 0);
}

@Override
Expand All @@ -60,7 +70,7 @@ protected void drawContents(GuiGraphics guiGraphics, double mouseX, double mouse
scissorArea.bottom()
);
poseStack.pushPose();
float scrollAmount = hiddenHeight * scrollOffsetY;
float scrollAmount = getHiddenAmount() * scrollOffsetY;
poseStack.translate(0.0, -scrollAmount, 0.0);
try {
contents.draw(guiGraphics);
Expand Down
Loading

0 comments on commit a7d7a18

Please sign in to comment.