package net.minecraft.client.gui.components; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.renderer.RenderType; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; @Environment(EnvType.CLIENT) public abstract class AbstractScrollArea extends AbstractWidget { public static final int SCROLLBAR_WIDTH = 6; private double scrollAmount; private static final ResourceLocation SCROLLER_SPRITE = ResourceLocation.withDefaultNamespace("widget/scroller"); private static final ResourceLocation SCROLLER_BACKGROUND_SPRITE = ResourceLocation.withDefaultNamespace("widget/scroller_background"); private boolean scrolling; public AbstractScrollArea(int i, int j, int k, int l, Component component) { super(i, j, k, l, component); } @Override public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) { if (!this.visible) { return false; } else { this.setScrollAmount(this.scrollAmount() - scrollY * this.scrollRate()); return true; } } @Override public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) { if (this.scrolling) { if (mouseY < this.getY()) { this.setScrollAmount(0.0); } else if (mouseY > this.getBottom()) { this.setScrollAmount(this.maxScrollAmount()); } else { double d = Math.max(1, this.maxScrollAmount()); int i = this.scrollerHeight(); double e = Math.max(1.0, d / (this.height - i)); this.setScrollAmount(this.scrollAmount() + dragY * e); } return true; } else { return super.mouseDragged(mouseX, mouseY, button, dragX, dragY); } } @Override public void onRelease(double mouseX, double mouseY) { this.scrolling = false; } public double scrollAmount() { return this.scrollAmount; } public void setScrollAmount(double scrollAmount) { this.scrollAmount = Mth.clamp(scrollAmount, 0.0, (double)this.maxScrollAmount()); } public boolean updateScrolling(double mouseX, double mouseY, int button) { this.scrolling = this.scrollbarVisible() && this.isValidClickButton(button) && mouseX >= this.scrollBarX() && mouseX <= this.scrollBarX() + 6 && mouseY >= this.getY() && mouseY < this.getBottom(); return this.scrolling; } public void refreshScrollAmount() { this.setScrollAmount(this.scrollAmount); } public int maxScrollAmount() { return Math.max(0, this.contentHeight() - this.height); } protected boolean scrollbarVisible() { return this.maxScrollAmount() > 0; } protected int scrollerHeight() { return Mth.clamp((int)((float)(this.height * this.height) / this.contentHeight()), 32, this.height - 8); } protected int scrollBarX() { return this.getRight() - 6; } protected int scrollBarY() { return Math.max(this.getY(), (int)this.scrollAmount * (this.height - this.scrollerHeight()) / this.maxScrollAmount() + this.getY()); } protected void renderScrollbar(GuiGraphics guiGraphics) { if (this.scrollbarVisible()) { int i = this.scrollBarX(); int j = this.scrollerHeight(); int k = this.scrollBarY(); guiGraphics.blitSprite(RenderType::guiTextured, SCROLLER_BACKGROUND_SPRITE, i, this.getY(), 6, this.getHeight()); guiGraphics.blitSprite(RenderType::guiTextured, SCROLLER_SPRITE, i, k, 6, j); } } protected abstract int contentHeight(); protected abstract double scrollRate(); }