minecraft-src/net/minecraft/client/gui/components/AbstractWidget.java
2025-07-04 03:15:13 +03:00

328 lines
8.9 KiB
Java

package net.minecraft.client.gui.components;
import java.time.Duration;
import java.util.function.Consumer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ComponentPath;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.layouts.LayoutElement;
import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.client.gui.narration.NarratedElementType;
import net.minecraft.client.gui.narration.NarrationElementOutput;
import net.minecraft.client.gui.navigation.FocusNavigationEvent;
import net.minecraft.client.gui.navigation.ScreenRectangle;
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
import net.minecraft.client.sounds.SoundManager;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.Mth;
import org.jetbrains.annotations.Nullable;
@Environment(EnvType.CLIENT)
public abstract class AbstractWidget implements Renderable, GuiEventListener, LayoutElement, NarratableEntry {
private static final double PERIOD_PER_SCROLLED_PIXEL = 0.5;
private static final double MIN_SCROLL_PERIOD = 3.0;
protected int width;
protected int height;
private int x;
private int y;
private Component message;
protected boolean isHovered;
public boolean active = true;
public boolean visible = true;
protected float alpha = 1.0F;
private int tabOrderGroup;
private boolean focused;
private final WidgetTooltipHolder tooltip = new WidgetTooltipHolder();
public AbstractWidget(int x, int y, int width, int height, Component message) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.message = message;
}
@Override
public int getHeight() {
return this.height;
}
@Override
public final void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
if (this.visible) {
this.isHovered = guiGraphics.containsPointInScissor(mouseX, mouseY)
&& mouseX >= this.getX()
&& mouseY >= this.getY()
&& mouseX < this.getX() + this.width
&& mouseY < this.getY() + this.height;
this.renderWidget(guiGraphics, mouseX, mouseY, partialTick);
this.tooltip.refreshTooltipForNextRenderPass(this.isHovered(), this.isFocused(), this.getRectangle());
}
}
public void setTooltip(@Nullable Tooltip tooltip) {
this.tooltip.set(tooltip);
}
@Nullable
public Tooltip getTooltip() {
return this.tooltip.get();
}
public void setTooltipDelay(Duration tooltipDelay) {
this.tooltip.setDelay(tooltipDelay);
}
protected MutableComponent createNarrationMessage() {
return wrapDefaultNarrationMessage(this.getMessage());
}
public static MutableComponent wrapDefaultNarrationMessage(Component message) {
return Component.translatable("gui.narrate.button", message);
}
protected abstract void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick);
protected static void renderScrollingString(GuiGraphics guiGraphics, Font font, Component text, int minX, int minY, int maxX, int maxY, int color) {
renderScrollingString(guiGraphics, font, text, (minX + maxX) / 2, minX, minY, maxX, maxY, color);
}
protected static void renderScrollingString(GuiGraphics guiGraphics, Font font, Component text, int centerX, int minX, int minY, int maxX, int maxY, int color) {
int i = font.width(text);
int j = (minY + maxY - 9) / 2 + 1;
int k = maxX - minX;
if (i > k) {
int l = i - k;
double d = Util.getMillis() / 1000.0;
double e = Math.max(l * 0.5, 3.0);
double f = Math.sin((Math.PI / 2) * Math.cos((Math.PI * 2) * d / e)) / 2.0 + 0.5;
double g = Mth.lerp(f, 0.0, (double)l);
guiGraphics.enableScissor(minX, minY, maxX, maxY);
guiGraphics.drawString(font, text, minX - (int)g, j, color);
guiGraphics.disableScissor();
} else {
int l = Mth.clamp(centerX, minX + i / 2, maxX - i / 2);
guiGraphics.drawCenteredString(font, text, l, j, color);
}
}
protected void renderScrollingString(GuiGraphics guiGraphics, Font font, int width, int color) {
int i = this.getX() + width;
int j = this.getX() + this.getWidth() - width;
renderScrollingString(guiGraphics, font, this.getMessage(), i, this.getY(), j, this.getY() + this.getHeight(), color);
}
public void onClick(double mouseX, double mouseY) {
}
public void onRelease(double mouseX, double mouseY) {
}
protected void onDrag(double mouseX, double mouseY, double dragX, double dragY) {
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (this.active && this.visible) {
if (this.isValidClickButton(button)) {
boolean bl = this.isMouseOver(mouseX, mouseY);
if (bl) {
this.playDownSound(Minecraft.getInstance().getSoundManager());
this.onClick(mouseX, mouseY);
return true;
}
}
return false;
} else {
return false;
}
}
@Override
public boolean mouseReleased(double mouseX, double mouseY, int button) {
if (this.isValidClickButton(button)) {
this.onRelease(mouseX, mouseY);
return true;
} else {
return false;
}
}
protected boolean isValidClickButton(int button) {
return button == 0;
}
@Override
public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) {
if (this.isValidClickButton(button)) {
this.onDrag(mouseX, mouseY, dragX, dragY);
return true;
} else {
return false;
}
}
@Nullable
@Override
public ComponentPath nextFocusPath(FocusNavigationEvent event) {
if (!this.active || !this.visible) {
return null;
} else {
return !this.isFocused() ? ComponentPath.leaf(this) : null;
}
}
@Override
public boolean isMouseOver(double mouseX, double mouseY) {
return this.active && this.visible && mouseX >= this.getX() && mouseY >= this.getY() && mouseX < this.getRight() && mouseY < this.getBottom();
}
public void playDownSound(SoundManager handler) {
playButtonClickSound(handler);
}
public static void playButtonClickSound(SoundManager soundManager) {
soundManager.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
}
@Override
public int getWidth() {
return this.width;
}
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public void setAlpha(float alpha) {
this.alpha = alpha;
}
public void setMessage(Component message) {
this.message = message;
}
public Component getMessage() {
return this.message;
}
@Override
public boolean isFocused() {
return this.focused;
}
public boolean isHovered() {
return this.isHovered;
}
public boolean isHoveredOrFocused() {
return this.isHovered() || this.isFocused();
}
@Override
public boolean isActive() {
return this.visible && this.active;
}
@Override
public void setFocused(boolean focused) {
this.focused = focused;
}
@Override
public NarratableEntry.NarrationPriority narrationPriority() {
if (this.isFocused()) {
return NarratableEntry.NarrationPriority.FOCUSED;
} else {
return this.isHovered ? NarratableEntry.NarrationPriority.HOVERED : NarratableEntry.NarrationPriority.NONE;
}
}
@Override
public final void updateNarration(NarrationElementOutput narrationElementOutput) {
this.updateWidgetNarration(narrationElementOutput);
this.tooltip.updateNarration(narrationElementOutput);
}
protected abstract void updateWidgetNarration(NarrationElementOutput narrationElementOutput);
protected void defaultButtonNarrationText(NarrationElementOutput narrationElementOutput) {
narrationElementOutput.add(NarratedElementType.TITLE, this.createNarrationMessage());
if (this.active) {
if (this.isFocused()) {
narrationElementOutput.add(NarratedElementType.USAGE, Component.translatable("narration.button.usage.focused"));
} else {
narrationElementOutput.add(NarratedElementType.USAGE, Component.translatable("narration.button.usage.hovered"));
}
}
}
@Override
public int getX() {
return this.x;
}
@Override
public void setX(int x) {
this.x = x;
}
@Override
public int getY() {
return this.y;
}
@Override
public void setY(int y) {
this.y = y;
}
public int getRight() {
return this.getX() + this.getWidth();
}
public int getBottom() {
return this.getY() + this.getHeight();
}
@Override
public void visitWidgets(Consumer<AbstractWidget> consumer) {
consumer.accept(this);
}
public void setSize(int width, int height) {
this.width = width;
this.height = height;
}
@Override
public ScreenRectangle getRectangle() {
return LayoutElement.super.getRectangle();
}
public void setRectangle(int width, int height, int x, int y) {
this.setSize(width, height);
this.setPosition(x, y);
}
@Override
public int getTabOrderGroup() {
return this.tabOrderGroup;
}
public void setTabOrderGroup(int tabOrderGroup) {
this.tabOrderGroup = tabOrderGroup;
}
}