324 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			324 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.narration.NarratableEntry.NarrationPriority;
 | |
| 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) && this.areCoordinatesInRectangle(mouseX, mouseY);
 | |
| 			this.renderWidget(guiGraphics, mouseX, mouseY, partialTick);
 | |
| 			this.tooltip.refreshTooltipForNextRenderPass(guiGraphics, mouseX, mouseY, this.isHovered(), this.isFocused(), this.getRectangle());
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void setTooltip(@Nullable Tooltip tooltip) {
 | |
| 		this.tooltip.set(tooltip);
 | |
| 	}
 | |
| 
 | |
| 	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 padding, int color) {
 | |
| 		int i = this.getX() + padding;
 | |
| 		int j = this.getX() + this.getWidth() - padding;
 | |
| 		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 && this.areCoordinatesInRectangle(mouseX, mouseY);
 | |
| 	}
 | |
| 
 | |
| 	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 NarrationPriority narrationPriority() {
 | |
| 		if (this.isFocused()) {
 | |
| 			return NarrationPriority.FOCUSED;
 | |
| 		} else {
 | |
| 			return this.isHovered ? NarrationPriority.HOVERED : 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();
 | |
| 	}
 | |
| 
 | |
| 	private boolean areCoordinatesInRectangle(double x, double y) {
 | |
| 		return x >= this.getX() && y >= this.getY() && x < this.getRight() && y < this.getBottom();
 | |
| 	}
 | |
| 
 | |
| 	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;
 | |
| 	}
 | |
| }
 |