243 lines
8.4 KiB
Java
243 lines
8.4 KiB
Java
package net.minecraft.client.gui.components.tabs;
|
|
|
|
import com.google.common.collect.ImmutableList;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.client.gui.ComponentPath;
|
|
import net.minecraft.client.gui.GuiGraphics;
|
|
import net.minecraft.client.gui.components.AbstractWidget;
|
|
import net.minecraft.client.gui.components.Renderable;
|
|
import net.minecraft.client.gui.components.TabButton;
|
|
import net.minecraft.client.gui.components.events.AbstractContainerEventHandler;
|
|
import net.minecraft.client.gui.components.events.GuiEventListener;
|
|
import net.minecraft.client.gui.layouts.LinearLayout;
|
|
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.gui.screens.Screen;
|
|
import net.minecraft.client.renderer.RenderType;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraftforge.api.distmarker.Dist;
|
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
|
|
@OnlyIn(Dist.CLIENT)
|
|
public class TabNavigationBar extends AbstractContainerEventHandler implements Renderable, NarratableEntry {
|
|
private static final int NO_TAB = -1;
|
|
private static final int MAX_WIDTH = 400;
|
|
private static final int HEIGHT = 24;
|
|
private static final int MARGIN = 14;
|
|
private static final Component USAGE_NARRATION = Component.translatable("narration.tab_navigation.usage");
|
|
private final LinearLayout layout = LinearLayout.horizontal();
|
|
private int width;
|
|
private final TabManager tabManager;
|
|
private final ImmutableList<Tab> tabs;
|
|
private final ImmutableList<TabButton> tabButtons;
|
|
|
|
TabNavigationBar(int p_275379_, TabManager p_275624_, Iterable<Tab> p_275279_) {
|
|
this.width = p_275379_;
|
|
this.tabManager = p_275624_;
|
|
this.tabs = ImmutableList.copyOf(p_275279_);
|
|
this.layout.defaultCellSetting().alignHorizontallyCenter();
|
|
ImmutableList.Builder<TabButton> builder = ImmutableList.builder();
|
|
|
|
for (Tab tab : p_275279_) {
|
|
builder.add(this.layout.addChild(new TabButton(p_275624_, tab, 0, 24)));
|
|
}
|
|
|
|
this.tabButtons = builder.build();
|
|
}
|
|
|
|
public static TabNavigationBar.Builder builder(TabManager p_268126_, int p_268070_) {
|
|
return new TabNavigationBar.Builder(p_268126_, p_268070_);
|
|
}
|
|
|
|
public void setWidth(int p_268094_) {
|
|
this.width = p_268094_;
|
|
}
|
|
|
|
@Override
|
|
public boolean isMouseOver(double p_378802_, double p_376598_) {
|
|
return p_378802_ >= this.layout.getX()
|
|
&& p_376598_ >= this.layout.getY()
|
|
&& p_378802_ < this.layout.getX() + this.layout.getWidth()
|
|
&& p_376598_ < this.layout.getY() + this.layout.getHeight();
|
|
}
|
|
|
|
@Override
|
|
public void setFocused(boolean p_275488_) {
|
|
super.setFocused(p_275488_);
|
|
if (this.getFocused() != null) {
|
|
this.getFocused().setFocused(p_275488_);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setFocused(@Nullable GuiEventListener p_275675_) {
|
|
super.setFocused(p_275675_);
|
|
if (p_275675_ instanceof TabButton tabbutton) {
|
|
this.tabManager.setCurrentTab(tabbutton.tab(), true);
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public ComponentPath nextFocusPath(FocusNavigationEvent p_275418_) {
|
|
if (!this.isFocused()) {
|
|
TabButton tabbutton = this.currentTabButton();
|
|
if (tabbutton != null) {
|
|
return ComponentPath.path(this, ComponentPath.leaf(tabbutton));
|
|
}
|
|
}
|
|
|
|
return p_275418_ instanceof FocusNavigationEvent.TabNavigation ? null : super.nextFocusPath(p_275418_);
|
|
}
|
|
|
|
@Override
|
|
public List<? extends GuiEventListener> children() {
|
|
return this.tabButtons;
|
|
}
|
|
|
|
@Override
|
|
public NarratableEntry.NarrationPriority narrationPriority() {
|
|
return this.tabButtons.stream().map(AbstractWidget::narrationPriority).max(Comparator.naturalOrder()).orElse(NarratableEntry.NarrationPriority.NONE);
|
|
}
|
|
|
|
@Override
|
|
public void updateNarration(NarrationElementOutput p_275583_) {
|
|
Optional<TabButton> optional = this.tabButtons.stream().filter(AbstractWidget::isHovered).findFirst().or(() -> Optional.ofNullable(this.currentTabButton()));
|
|
optional.ifPresent(p_274663_ -> {
|
|
this.narrateListElementPosition(p_275583_.nest(), p_274663_);
|
|
p_274663_.updateNarration(p_275583_);
|
|
});
|
|
if (this.isFocused()) {
|
|
p_275583_.add(NarratedElementType.USAGE, USAGE_NARRATION);
|
|
}
|
|
}
|
|
|
|
protected void narrateListElementPosition(NarrationElementOutput p_275386_, TabButton p_275397_) {
|
|
if (this.tabs.size() > 1) {
|
|
int i = this.tabButtons.indexOf(p_275397_);
|
|
if (i != -1) {
|
|
p_275386_.add(NarratedElementType.POSITION, Component.translatable("narrator.position.tab", i + 1, this.tabs.size()));
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void render(GuiGraphics p_281720_, int p_282085_, int p_281687_, float p_283048_) {
|
|
p_281720_.blit(
|
|
RenderType::guiTextured,
|
|
Screen.HEADER_SEPARATOR,
|
|
0,
|
|
this.layout.getY() + this.layout.getHeight() - 2,
|
|
0.0F,
|
|
0.0F,
|
|
this.tabButtons.get(0).getX(),
|
|
2,
|
|
32,
|
|
2
|
|
);
|
|
int i = this.tabButtons.get(this.tabButtons.size() - 1).getRight();
|
|
p_281720_.blit(
|
|
RenderType::guiTextured, Screen.HEADER_SEPARATOR, i, this.layout.getY() + this.layout.getHeight() - 2, 0.0F, 0.0F, this.width, 2, 32, 2
|
|
);
|
|
|
|
for (TabButton tabbutton : this.tabButtons) {
|
|
tabbutton.render(p_281720_, p_282085_, p_281687_, p_283048_);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public ScreenRectangle getRectangle() {
|
|
return this.layout.getRectangle();
|
|
}
|
|
|
|
public void arrangeElements() {
|
|
int i = Math.min(400, this.width) - 28;
|
|
int j = Mth.roundToward(i / this.tabs.size(), 2);
|
|
|
|
for (TabButton tabbutton : this.tabButtons) {
|
|
tabbutton.setWidth(j);
|
|
}
|
|
|
|
this.layout.arrangeElements();
|
|
this.layout.setX(Mth.roundToward((this.width - i) / 2, 2));
|
|
this.layout.setY(0);
|
|
}
|
|
|
|
public void selectTab(int p_276107_, boolean p_276125_) {
|
|
if (this.isFocused()) {
|
|
this.setFocused(this.tabButtons.get(p_276107_));
|
|
} else {
|
|
this.tabManager.setCurrentTab(this.tabs.get(p_276107_), p_276125_);
|
|
}
|
|
}
|
|
|
|
public boolean keyPressed(int p_270495_) {
|
|
if (Screen.hasControlDown()) {
|
|
int i = this.getNextTabIndex(p_270495_);
|
|
if (i != -1) {
|
|
this.selectTab(Mth.clamp(i, 0, this.tabs.size() - 1), true);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private int getNextTabIndex(int p_270508_) {
|
|
if (p_270508_ >= 49 && p_270508_ <= 57) {
|
|
return p_270508_ - 49;
|
|
} else {
|
|
if (p_270508_ == 258) {
|
|
int i = this.currentTabIndex();
|
|
if (i != -1) {
|
|
int j = Screen.hasShiftDown() ? i - 1 : i + 1;
|
|
return Math.floorMod(j, this.tabs.size());
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
private int currentTabIndex() {
|
|
Tab tab = this.tabManager.getCurrentTab();
|
|
int i = this.tabs.indexOf(tab);
|
|
return i != -1 ? i : -1;
|
|
}
|
|
|
|
@Nullable
|
|
private TabButton currentTabButton() {
|
|
int i = this.currentTabIndex();
|
|
return i != -1 ? this.tabButtons.get(i) : null;
|
|
}
|
|
|
|
@OnlyIn(Dist.CLIENT)
|
|
public static class Builder {
|
|
private final int width;
|
|
private final TabManager tabManager;
|
|
private final List<Tab> tabs = new ArrayList<>();
|
|
|
|
Builder(TabManager p_268334_, int p_267986_) {
|
|
this.tabManager = p_268334_;
|
|
this.width = p_267986_;
|
|
}
|
|
|
|
public TabNavigationBar.Builder addTabs(Tab... p_268144_) {
|
|
Collections.addAll(this.tabs, p_268144_);
|
|
return this;
|
|
}
|
|
|
|
public TabNavigationBar build() {
|
|
return new TabNavigationBar(this.width, this.tabManager, this.tabs);
|
|
}
|
|
}
|
|
} |