TabNavigationBar.java

net.minecraft.client.gui.components.tabs.TabNavigationBar

信息

  • 全限定名:net.minecraft.client.gui.components.tabs.TabNavigationBar
  • 类型:public class
  • 包:net.minecraft.client.gui.components.tabs
  • 源码路径:src/main/java/net/minecraft/client/gui/components/tabs/TabNavigationBar.java
  • 起始行号:L33
  • 继承:AbstractContainerEventHandler
  • 实现:NarratableEntry, Renderable
  • 职责:

    TODO

字段/常量

  • NO_TAB

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L34
    • 说明:

      TODO

  • MAX_WIDTH

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L35
    • 说明:

      TODO

  • HEIGHT

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L36
    • 说明:

      TODO

  • MARGIN

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L37
    • 说明:

      TODO

  • USAGE_NARRATION

    • 类型: Component
    • 修饰符: private static final
    • 源码定位: L38
    • 说明:

      TODO

  • layout

    • 类型: LinearLayout
    • 修饰符: private final
    • 源码定位: L39
    • 说明:

      TODO

  • width

    • 类型: int
    • 修饰符: private
    • 源码定位: L40
    • 说明:

      TODO

  • tabManager

    • 类型: TabManager
    • 修饰符: private final
    • 源码定位: L41
    • 说明:

      TODO

  • tabs

    • 类型: ImmutableList<Tab>
    • 修饰符: private final
    • 源码定位: L42
    • 说明:

      TODO

  • tabButtons

    • 类型: ImmutableList<TabButton>
    • 修饰符: private final
    • 源码定位: L43
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.gui.components.tabs.TabNavigationBar.Builder
    • 类型: class
    • 修饰符: public static
    • 源码定位: L256
    • 说明:

      TODO

构造器

private TabNavigationBar(int width, TabManager tabManager, Iterable<Tab> tabs) @ L45

  • 构造器名:TabNavigationBar
  • 源码定位:L45
  • 修饰符:private

参数:

  • width: int
  • tabManager: TabManager
  • tabs: Iterable

说明:

TODO

方法

下面的方法块按源码顺序生成。

public static TabNavigationBar.Builder builder(TabManager tabManager, int width) @ L59

  • 方法名:builder
  • 源码定位:L59
  • 返回类型:TabNavigationBar.Builder
  • 修饰符:public static

参数:

  • tabManager: TabManager
  • width: int

说明:

TODO

public void updateWidth(int width) @ L63

  • 方法名:updateWidth
  • 源码定位:L63
  • 返回类型:void
  • 修饰符:public

参数:

  • width: int

说明:

TODO

public boolean isMouseOver(double mouseX, double mouseY) @ L68

  • 方法名:isMouseOver
  • 源码定位:L68
  • 返回类型:boolean
  • 修饰符:public

参数:

  • mouseX: double
  • mouseY: double

说明:

TODO

public void setFocused(boolean focused) @ L76

  • 方法名:setFocused
  • 源码定位:L76
  • 返回类型:void
  • 修饰符:public

参数:

  • focused: boolean

说明:

TODO

public void setFocused(GuiEventListener focused) @ L84

  • 方法名:setFocused
  • 源码定位:L84
  • 返回类型:void
  • 修饰符:public

参数:

  • focused: GuiEventListener

说明:

TODO

public ComponentPath nextFocusPath(FocusNavigationEvent navigationEvent) @ L92

  • 方法名:nextFocusPath
  • 源码定位:L92
  • 返回类型:ComponentPath
  • 修饰符:public

参数:

  • navigationEvent: FocusNavigationEvent

说明:

TODO

public List<?extends GuiEventListener> children() @ L104

  • 方法名:children
  • 源码定位:L104
  • 返回类型:List<?extends GuiEventListener>
  • 修饰符:public

参数:

说明:

TODO

public List<Tab> getTabs() @ L109

  • 方法名:getTabs
  • 源码定位:L109
  • 返回类型:List
  • 修饰符:public

参数:

说明:

TODO

public NarratableEntry.NarrationPriority narrationPriority() @ L113

  • 方法名:narrationPriority
  • 源码定位:L113
  • 返回类型:NarratableEntry.NarrationPriority
  • 修饰符:public

参数:

说明:

TODO

public void updateNarration(NarrationElementOutput output) @ L118

  • 方法名:updateNarration
  • 源码定位:L118
  • 返回类型:void
  • 修饰符:public

参数:

  • output: NarrationElementOutput

说明:

TODO

protected void narrateListElementPosition(NarrationElementOutput output, TabButton widget) @ L134

  • 方法名:narrateListElementPosition
  • 源码定位:L134
  • 返回类型:void
  • 修饰符:protected

参数:

  • output: NarrationElementOutput
  • widget: TabButton

说明:

TODO

public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) @ L143

  • 方法名:extractRenderState
  • 源码定位:L143
  • 返回类型:void
  • 修饰符:public

参数:

  • graphics: GuiGraphicsExtractor
  • mouseX: int
  • mouseY: int
  • a: float

说明:

TODO

public ScreenRectangle getRectangle() @ L176

  • 方法名:getRectangle
  • 源码定位:L176
  • 返回类型:ScreenRectangle
  • 修饰符:public

参数:

说明:

TODO

public void arrangeElements() @ L181

  • 方法名:arrangeElements
  • 源码定位:L181
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void selectTab(int index, boolean playSound) @ L194

  • 方法名:selectTab
  • 源码定位:L194
  • 返回类型:void
  • 修饰符:public

参数:

  • index: int
  • playSound: boolean

说明:

TODO

public void setTabActiveState(int index, boolean active) @ L202

  • 方法名:setTabActiveState
  • 源码定位:L202
  • 返回类型:void
  • 修饰符:public

参数:

  • index: int
  • active: boolean

说明:

TODO

public void setTabTooltip(int index, Tooltip hint) @ L208

  • 方法名:setTabTooltip
  • 源码定位:L208
  • 返回类型:void
  • 修饰符:public

参数:

  • index: int
  • hint: Tooltip

说明:

TODO

public boolean keyPressed(KeyEvent event) @ L214

  • 方法名:keyPressed
  • 源码定位:L214
  • 返回类型:boolean
  • 修饰符:public

参数:

  • event: KeyEvent

说明:

TODO

private int getNextTabIndex(KeyEvent event) @ L227

  • 方法名:getNextTabIndex
  • 源码定位:L227
  • 返回类型:int
  • 修饰符:private

参数:

  • event: KeyEvent

说明:

TODO

private int getNextTabIndex(int currentTab, KeyEvent event) @ L231

  • 方法名:getNextTabIndex
  • 源码定位:L231
  • 返回类型:int
  • 修饰符:private

参数:

  • currentTab: int
  • event: KeyEvent

说明:

TODO

private int currentTabIndex() @ L244

  • 方法名:currentTabIndex
  • 源码定位:L244
  • 返回类型:int
  • 修饰符:private

参数:

说明:

TODO

private TabButton currentTabButton() @ L250

  • 方法名:currentTabButton
  • 源码定位:L250
  • 返回类型:TabButton
  • 修饰符:private

参数:

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class TabNavigationBar extends AbstractContainerEventHandler implements NarratableEntry, Renderable {
    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;
 
    private TabNavigationBar(int width, TabManager tabManager, Iterable<Tab> tabs) {
        this.width = width;
        this.tabManager = tabManager;
        this.tabs = ImmutableList.copyOf(tabs);
        this.layout.defaultCellSetting().alignHorizontallyCenter();
        ImmutableList.Builder<TabButton> tabButtonsBuilder = ImmutableList.builder();
 
        for (Tab tab : tabs) {
            tabButtonsBuilder.add(this.layout.addChild(new TabButton(tabManager, tab, 0, 24)));
        }
 
        this.tabButtons = tabButtonsBuilder.build();
    }
 
    public static TabNavigationBar.Builder builder(TabManager tabManager, int width) {
        return new TabNavigationBar.Builder(tabManager, width);
    }
 
    public void updateWidth(int width) {
        this.width = width;
        this.arrangeElements();
    }
 
    @Override
    public boolean isMouseOver(double mouseX, double mouseY) {
        return mouseX >= this.layout.getX()
            && mouseY >= this.layout.getY()
            && mouseX < this.layout.getX() + this.layout.getWidth()
            && mouseY < this.layout.getY() + this.layout.getHeight();
    }
 
    @Override
    public void setFocused(boolean focused) {
        super.setFocused(focused);
        if (this.getFocused() != null) {
            this.setFocused(null);
        }
    }
 
    @Override
    public void setFocused(@Nullable GuiEventListener focused) {
        super.setFocused(focused);
        if (focused instanceof TabButton button && button.isActive()) {
            this.tabManager.setCurrentTab(button.tab(), true);
        }
    }
 
    @Override
    public @Nullable ComponentPath nextFocusPath(FocusNavigationEvent navigationEvent) {
        if (!this.isFocused()) {
            TabButton button = this.currentTabButton();
            if (button != null) {
                return ComponentPath.path(this, ComponentPath.leaf(button));
            }
        }
 
        return navigationEvent instanceof FocusNavigationEvent.TabNavigation ? null : super.nextFocusPath(navigationEvent);
    }
 
    @Override
    public List<? extends GuiEventListener> children() {
        return this.tabButtons;
    }
 
    public List<Tab> getTabs() {
        return this.tabs;
    }
 
    @Override
    public NarratableEntry.NarrationPriority narrationPriority() {
        return this.tabButtons.stream().map(AbstractWidget::narrationPriority).max(Comparator.naturalOrder()).orElse(NarratableEntry.NarrationPriority.NONE);
    }
 
    @Override
    public void updateNarration(NarrationElementOutput output) {
        Optional<TabButton> selected = this.tabButtons
            .stream()
            .filter(AbstractWidget::isHovered)
            .findFirst()
            .or(() -> Optional.ofNullable(this.currentTabButton()));
        selected.ifPresent(button -> {
            this.narrateListElementPosition(output.nest(), button);
            button.updateNarration(output);
        });
        if (this.isFocused()) {
            output.add(NarratedElementType.USAGE, USAGE_NARRATION);
        }
    }
 
    protected void narrateListElementPosition(NarrationElementOutput output, TabButton widget) {
        if (this.tabs.size() > 1) {
            int index = this.tabButtons.indexOf(widget);
            if (index != -1) {
                output.add(NarratedElementType.POSITION, Component.translatable("narrator.position.tab", index + 1, this.tabs.size()));
            }
        }
    }
 
    @Override
    public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) {
        graphics.blit(
            RenderPipelines.GUI_TEXTURED,
            Screen.HEADER_SEPARATOR,
            0,
            this.layout.getY() + this.layout.getHeight() - 2,
            0.0F,
            0.0F,
            this.tabButtons.get(0).getX(),
            2,
            32,
            2
        );
        int afterLastTab = this.tabButtons.get(this.tabButtons.size() - 1).getRight();
        graphics.blit(
            RenderPipelines.GUI_TEXTURED,
            Screen.HEADER_SEPARATOR,
            afterLastTab,
            this.layout.getY() + this.layout.getHeight() - 2,
            0.0F,
            0.0F,
            this.width,
            2,
            32,
            2
        );
 
        for (TabButton value : this.tabButtons) {
            value.extractRenderState(graphics, mouseX, mouseY, a);
        }
    }
 
    @Override
    public ScreenRectangle getRectangle() {
        return this.layout.getRectangle();
    }
 
    public void arrangeElements() {
        int tabsWidth = Math.min(400, this.width) - 28;
        int tabWidth = Mth.roundToward(tabsWidth / this.tabs.size(), 2);
 
        for (TabButton button : this.tabButtons) {
            button.setWidth(tabWidth);
        }
 
        this.layout.arrangeElements();
        this.layout.setX(Mth.roundToward((this.width - tabsWidth) / 2, 2));
        this.layout.setY(0);
    }
 
    public void selectTab(int index, boolean playSound) {
        if (this.isFocused()) {
            this.setFocused(this.tabButtons.get(index));
        } else if (this.tabButtons.get(index).isActive()) {
            this.tabManager.setCurrentTab(this.tabs.get(index), playSound);
        }
    }
 
    public void setTabActiveState(int index, boolean active) {
        if (index >= 0 && index < this.tabButtons.size()) {
            this.tabButtons.get(index).active = active;
        }
    }
 
    public void setTabTooltip(int index, @Nullable Tooltip hint) {
        if (index >= 0 && index < this.tabButtons.size()) {
            this.tabButtons.get(index).setTooltip(hint);
        }
    }
 
    @Override
    public boolean keyPressed(KeyEvent event) {
        if (event.hasControlDownWithQuirk()) {
            int tabIndex = this.getNextTabIndex(event);
            if (tabIndex != -1) {
                this.selectTab(Mth.clamp(tabIndex, 0, this.tabs.size() - 1), true);
                return true;
            }
        }
 
        return false;
    }
 
    private int getNextTabIndex(KeyEvent event) {
        return this.getNextTabIndex(this.currentTabIndex(), event);
    }
 
    private int getNextTabIndex(int currentTab, KeyEvent event) {
        int digit = event.getDigit();
        if (digit != -1) {
            return Math.floorMod(digit - 1, 10);
        } else if (event.isCycleFocus() && currentTab != -1) {
            int nextTabIndex = event.hasShiftDown() ? currentTab - 1 : currentTab + 1;
            int index = Math.floorMod(nextTabIndex, this.tabs.size());
            return this.tabButtons.get(index).active ? index : this.getNextTabIndex(index, event);
        } else {
            return -1;
        }
    }
 
    private int currentTabIndex() {
        Tab currentTab = this.tabManager.getCurrentTab();
        int index = this.tabs.indexOf(currentTab);
        return index != -1 ? index : -1;
    }
 
    private @Nullable TabButton currentTabButton() {
        int index = this.currentTabIndex();
        return index != -1 ? this.tabButtons.get(index) : null;
    }
 
    @OnlyIn(Dist.CLIENT)
    public static class Builder {
        private final int width;
        private final TabManager tabManager;
        private final List<Tab> tabs = new ArrayList<>();
 
        private Builder(TabManager tabManager, int width) {
            this.tabManager = tabManager;
            this.width = width;
        }
 
        public TabNavigationBar.Builder addTabs(Tab... tabs) {
            Collections.addAll(this.tabs, tabs);
            return this;
        }
 
        public TabNavigationBar build() {
            return new TabNavigationBar(this.width, this.tabManager, this.tabs);
        }
    }
}

引用的其他类