224 lines
6.8 KiB
Java
224 lines
6.8 KiB
Java
package net.minecraft.client.gui.components;
|
|
|
|
import java.util.List;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.gui.ComponentPath;
|
|
import net.minecraft.client.gui.components.events.ContainerEventHandler;
|
|
import net.minecraft.client.gui.components.events.GuiEventListener;
|
|
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.ScreenAxis;
|
|
import net.minecraft.client.gui.navigation.ScreenDirection;
|
|
import net.minecraft.client.gui.navigation.FocusNavigationEvent.ArrowNavigation;
|
|
import net.minecraft.client.gui.screens.Screen;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.util.Mth;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public abstract class ContainerObjectSelectionList<E extends ContainerObjectSelectionList.Entry<E>> extends AbstractSelectionList<E> {
|
|
public ContainerObjectSelectionList(Minecraft minecraft, int i, int j, int k, int l) {
|
|
super(minecraft, i, j, k, l);
|
|
}
|
|
|
|
public ContainerObjectSelectionList(Minecraft minecraft, int i, int j, int k, int l, int m) {
|
|
super(minecraft, i, j, k, l, m);
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public ComponentPath nextFocusPath(FocusNavigationEvent event) {
|
|
if (this.getItemCount() == 0) {
|
|
return null;
|
|
} else if (!(event instanceof ArrowNavigation arrowNavigation)) {
|
|
return super.nextFocusPath(event);
|
|
} else {
|
|
E entry = this.getFocused();
|
|
if (arrowNavigation.direction().getAxis() == ScreenAxis.HORIZONTAL && entry != null) {
|
|
return ComponentPath.path(this, entry.nextFocusPath(event));
|
|
} else {
|
|
int i = -1;
|
|
ScreenDirection screenDirection = arrowNavigation.direction();
|
|
if (entry != null) {
|
|
i = entry.children().indexOf(entry.getFocused());
|
|
}
|
|
|
|
if (i == -1) {
|
|
switch (screenDirection) {
|
|
case LEFT:
|
|
i = Integer.MAX_VALUE;
|
|
screenDirection = ScreenDirection.DOWN;
|
|
break;
|
|
case RIGHT:
|
|
i = 0;
|
|
screenDirection = ScreenDirection.DOWN;
|
|
break;
|
|
default:
|
|
i = 0;
|
|
}
|
|
}
|
|
|
|
E entry2 = entry;
|
|
|
|
ComponentPath componentPath;
|
|
do {
|
|
entry2 = this.nextEntry(screenDirection, entryx -> !entryx.children().isEmpty(), entry2);
|
|
if (entry2 == null) {
|
|
return null;
|
|
}
|
|
|
|
componentPath = entry2.focusPathAtIndex(arrowNavigation, i);
|
|
} while (componentPath == null);
|
|
|
|
return ComponentPath.path(this, componentPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setFocused(@Nullable GuiEventListener focused) {
|
|
if (this.getFocused() != focused) {
|
|
super.setFocused(focused);
|
|
if (focused == null) {
|
|
this.setSelected(null);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public NarrationPriority narrationPriority() {
|
|
return this.isFocused() ? NarrationPriority.FOCUSED : super.narrationPriority();
|
|
}
|
|
|
|
@Override
|
|
protected boolean isSelectedItem(int index) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void updateWidgetNarration(NarrationElementOutput narrationElementOutput) {
|
|
E entry = this.getHovered();
|
|
if (entry != null) {
|
|
entry.updateNarration(narrationElementOutput.nest());
|
|
this.narrateListElementPosition(narrationElementOutput, entry);
|
|
} else {
|
|
E entry2 = this.getFocused();
|
|
if (entry2 != null) {
|
|
entry2.updateNarration(narrationElementOutput.nest());
|
|
this.narrateListElementPosition(narrationElementOutput, entry2);
|
|
}
|
|
}
|
|
|
|
narrationElementOutput.add(NarratedElementType.USAGE, Component.translatable("narration.component_list.usage"));
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public abstract static class Entry<E extends ContainerObjectSelectionList.Entry<E>>
|
|
extends net.minecraft.client.gui.components.AbstractSelectionList.Entry<E>
|
|
implements ContainerEventHandler {
|
|
@Nullable
|
|
private GuiEventListener focused;
|
|
@Nullable
|
|
private NarratableEntry lastNarratable;
|
|
private boolean dragging;
|
|
|
|
@Override
|
|
public boolean isDragging() {
|
|
return this.dragging;
|
|
}
|
|
|
|
@Override
|
|
public void setDragging(boolean isDragging) {
|
|
this.dragging = isDragging;
|
|
}
|
|
|
|
@Override
|
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
|
return ContainerEventHandler.super.mouseClicked(mouseX, mouseY, button);
|
|
}
|
|
|
|
@Override
|
|
public void setFocused(@Nullable GuiEventListener focused) {
|
|
if (this.focused != null) {
|
|
this.focused.setFocused(false);
|
|
}
|
|
|
|
if (focused != null) {
|
|
focused.setFocused(true);
|
|
}
|
|
|
|
this.focused = focused;
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public GuiEventListener getFocused() {
|
|
return this.focused;
|
|
}
|
|
|
|
@Nullable
|
|
public ComponentPath focusPathAtIndex(FocusNavigationEvent event, int index) {
|
|
if (this.children().isEmpty()) {
|
|
return null;
|
|
} else {
|
|
ComponentPath componentPath = ((GuiEventListener)this.children().get(Math.min(index, this.children().size() - 1))).nextFocusPath(event);
|
|
return ComponentPath.path(this, componentPath);
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public ComponentPath nextFocusPath(FocusNavigationEvent event) {
|
|
if (event instanceof ArrowNavigation arrowNavigation) {
|
|
int i = switch (arrowNavigation.direction()) {
|
|
case LEFT -> -1;
|
|
case RIGHT -> 1;
|
|
case UP, DOWN -> 0;
|
|
};
|
|
if (i == 0) {
|
|
return null;
|
|
}
|
|
|
|
int j = Mth.clamp(i + this.children().indexOf(this.getFocused()), 0, this.children().size() - 1);
|
|
|
|
for (int k = j; k >= 0 && k < this.children().size(); k += i) {
|
|
GuiEventListener guiEventListener = (GuiEventListener)this.children().get(k);
|
|
ComponentPath componentPath = guiEventListener.nextFocusPath(event);
|
|
if (componentPath != null) {
|
|
return ComponentPath.path(this, componentPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ContainerEventHandler.super.nextFocusPath(event);
|
|
}
|
|
|
|
public abstract List<? extends NarratableEntry> narratables();
|
|
|
|
void updateNarration(NarrationElementOutput narrationElementOutput) {
|
|
List<? extends NarratableEntry> list = this.narratables();
|
|
Screen.NarratableSearchResult narratableSearchResult = Screen.findNarratableWidget(list, this.lastNarratable);
|
|
if (narratableSearchResult != null) {
|
|
if (narratableSearchResult.priority.isTerminal()) {
|
|
this.lastNarratable = narratableSearchResult.entry;
|
|
}
|
|
|
|
if (list.size() > 1) {
|
|
narrationElementOutput.add(
|
|
NarratedElementType.POSITION, Component.translatable("narrator.position.object_list", narratableSearchResult.index + 1, list.size())
|
|
);
|
|
if (narratableSearchResult.priority == NarrationPriority.FOCUSED) {
|
|
narrationElementOutput.add(NarratedElementType.USAGE, Component.translatable("narration.component_list.usage"));
|
|
}
|
|
}
|
|
|
|
narratableSearchResult.entry.updateNarration(narrationElementOutput.nest());
|
|
}
|
|
}
|
|
}
|
|
}
|