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 tabs; private final ImmutableList tabButtons; TabNavigationBar(int p_275379_, TabManager p_275624_, Iterable p_275279_) { this.width = p_275379_; this.tabManager = p_275624_; this.tabs = ImmutableList.copyOf(p_275279_); this.layout.defaultCellSetting().alignHorizontallyCenter(); ImmutableList.Builder 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 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 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 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); } } }