AbstractSelectionList.java

net.minecraft.client.gui.components.AbstractSelectionList

信息

  • 全限定名:net.minecraft.client.gui.components.AbstractSelectionList
  • 类型:public abstract class
  • 包:net.minecraft.client.gui.components
  • 源码路径:src/main/java/net/minecraft/client/gui/components/AbstractSelectionList.java
  • 起始行号:L34
  • 继承:AbstractContainerWidget
  • 职责:

    TODO

字段/常量

  • MENU_LIST_BACKGROUND

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

      TODO

  • INWORLD_MENU_LIST_BACKGROUND

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

      TODO

  • SEPARATOR_HEIGHT

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

      TODO

  • minecraft

    • 类型: Minecraft
    • 修饰符: protected final
    • 源码定位: L38
    • 说明:

      TODO

  • defaultEntryHeight

    • 类型: int
    • 修饰符: protected final
    • 源码定位: L39
    • 说明:

      TODO

  • children

    • 类型: List<E>
    • 修饰符: private final
    • 源码定位: L40
    • 说明:

      TODO

  • centerListVertically

    • 类型: boolean
    • 修饰符: protected
    • 源码定位: L41
    • 说明:

      TODO

  • selected

    • 类型: E
    • 修饰符: private
    • 源码定位: L42
    • 说明:

      TODO

  • hovered

    • 类型: E
    • 修饰符: private
    • 源码定位: L43
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.gui.components.AbstractSelectionList.Entry

    • 类型: class
    • 修饰符: protected abstract static
    • 源码定位: L432
    • 说明:

      TODO

  • net.minecraft.client.gui.components.AbstractSelectionList.TrackedList

    • 类型: class
    • 修饰符: private
    • 源码定位: L538
    • 说明:

      TODO

构造器

public AbstractSelectionList(Minecraft minecraft, int width, int height, int y, int defaultEntryHeight) @ L45

  • 构造器名:AbstractSelectionList
  • 源码定位:L45
  • 修饰符:public

参数:

  • minecraft: Minecraft
  • width: int
  • height: int
  • y: int
  • defaultEntryHeight: int

说明:

TODO

方法

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

public E getSelected() @ L51

  • 方法名:getSelected
  • 源码定位:L51
  • 返回类型:E
  • 修饰符:public

参数:

说明:

TODO

public void setSelected(E selected) @ L55

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

参数:

  • selected: E

说明:

TODO

public E getFocused() @ L66

  • 方法名:getFocused
  • 源码定位:L66
  • 返回类型:E
  • 修饰符:public

参数:

说明:

TODO

public final List<E> children() @ L70

  • 方法名:children
  • 源码定位:L70
  • 返回类型:List
  • 修饰符:public final

参数:

说明:

TODO

protected void sort(Comparator<E> comparator) @ L75

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

参数:

  • comparator: Comparator

说明:

TODO

protected void swap(int firstIndex, int secondIndex) @ L80

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

参数:

  • firstIndex: int
  • secondIndex: int

说明:

TODO

protected void clearEntries() @ L86

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

参数:

说明:

TODO

protected void clearEntriesExcept(E exception) @ L91

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

参数:

  • exception: E

说明:

TODO

public void replaceEntries(Collection<E> newChildren) @ L98

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

参数:

  • newChildren: Collection

说明:

TODO

private int getFirstEntryY() @ L106

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

参数:

说明:

TODO

public int getNextY() @ L110

  • 方法名:getNextY
  • 源码定位:L110
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

protected int addEntry(E entry) @ L120

  • 方法名:addEntry
  • 源码定位:L120
  • 返回类型:int
  • 修饰符:protected

参数:

  • entry: E

说明:

TODO

protected int addEntry(E entry, int height) @ L124

  • 方法名:addEntry
  • 源码定位:L124
  • 返回类型:int
  • 修饰符:protected

参数:

  • entry: E
  • height: int

说明:

TODO

protected void addEntryToTop(E entry) @ L133

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

参数:

  • entry: E

说明:

TODO

protected void addEntryToTop(E entry, int height) @ L137

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

参数:

  • entry: E
  • height: int

说明:

TODO

private void repositionEntries() @ L145

  • 方法名:repositionEntries
  • 源码定位:L145
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

protected void removeEntryFromTop(E entry) @ L156

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

参数:

  • entry: E

说明:

TODO

protected int getItemCount() @ L162

  • 方法名:getItemCount
  • 源码定位:L162
  • 返回类型:int
  • 修饰符:protected

参数:

说明:

TODO

protected boolean entriesCanBeSelected() @ L166

  • 方法名:entriesCanBeSelected
  • 源码定位:L166
  • 返回类型:boolean
  • 修饰符:protected

参数:

说明:

TODO

protected final E getEntryAtPosition(double posX, double posY) @ L170

  • 方法名:getEntryAtPosition
  • 源码定位:L170
  • 返回类型:E
  • 修饰符:protected final

参数:

  • posX: double
  • posY: double

说明:

TODO

public void updateSize(int width, HeaderAndFooterLayout layout) @ L180

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

参数:

  • width: int
  • layout: HeaderAndFooterLayout

说明:

TODO

public void updateSizeAndPosition(int width, int height, int y) @ L184

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

参数:

  • width: int
  • height: int
  • y: int

说明:

TODO

public void updateSizeAndPosition(int width, int height, int x, int y) @ L188

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

参数:

  • width: int
  • height: int
  • x: int
  • y: int

说明:

TODO

protected int contentHeight() @ L199

  • 方法名:contentHeight
  • 源码定位:L199
  • 返回类型:int
  • 修饰符:protected

参数:

说明:

TODO

public void extractWidgetRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) @ L210

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

参数:

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

说明:

TODO

protected void extractListSeparators(GuiGraphicsExtractor graphics) @ L221

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

参数:

  • graphics: GuiGraphicsExtractor

说明:

TODO

protected void extractListBackground(GuiGraphicsExtractor graphics) @ L228

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

参数:

  • graphics: GuiGraphicsExtractor

说明:

TODO

protected void enableScissor(GuiGraphicsExtractor graphics) @ L244

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

参数:

  • graphics: GuiGraphicsExtractor

说明:

TODO

protected void scrollToEntry(E entry) @ L248

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

参数:

  • entry: E

说明:

TODO

protected void centerScrollOn(E entry) @ L260

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

参数:

  • entry: E

说明:

TODO

private void scroll(int amount) @ L275

  • 方法名:scroll
  • 源码定位:L275
  • 返回类型:void
  • 修饰符:private

参数:

  • amount: int

说明:

TODO

public void setScrollAmount(double scrollAmount) @ L279

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

参数:

  • scrollAmount: double

说明:

TODO

protected int scrollBarX() @ L285

  • 方法名:scrollBarX
  • 源码定位:L285
  • 返回类型:int
  • 修饰符:protected

参数:

说明:

TODO

public Optional<GuiEventListener> getChildAt(double x, double y) @ L290

  • 方法名:getChildAt
  • 源码定位:L290
  • 返回类型:Optional
  • 修饰符:public

参数:

  • x: double
  • y: double

说明:

TODO

public void setFocused(GuiEventListener focused) @ L295

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

参数:

  • focused: GuiEventListener

说明:

TODO

protected E nextEntry(ScreenDirection dir) @ L310

  • 方法名:nextEntry
  • 源码定位:L310
  • 返回类型:E
  • 修饰符:protected

参数:

  • dir: ScreenDirection

说明:

TODO

protected E nextEntry(ScreenDirection dir, Predicate<E> canSelect) @ L314

  • 方法名:nextEntry
  • 源码定位:L314
  • 返回类型:E
  • 修饰符:protected

参数:

  • dir: ScreenDirection
  • canSelect: Predicate

说明:

TODO

protected E nextEntry(ScreenDirection dir, Predicate<E> canSelect, E startEntry) @ L318

  • 方法名:nextEntry
  • 源码定位:L318
  • 返回类型:E
  • 修饰符:protected

参数:

  • dir: ScreenDirection
  • canSelect: Predicate
  • startEntry: E

说明:

TODO

protected void extractListItems(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) @ L343

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

参数:

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

说明:

TODO

protected void extractItem(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a, E entry) @ L351

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

参数:

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

说明:

TODO

protected void extractSelection(GuiGraphicsExtractor graphics, E entry, int outlineColor) @ L360

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

参数:

  • graphics: GuiGraphicsExtractor
  • entry: E
  • outlineColor: int

说明:

TODO

public int getRowLeft() @ L369

  • 方法名:getRowLeft
  • 源码定位:L369
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public int getRowRight() @ L373

  • 方法名:getRowRight
  • 源码定位:L373
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public int getRowTop(int row) @ L377

  • 方法名:getRowTop
  • 源码定位:L377
  • 返回类型:int
  • 修饰符:public

参数:

  • row: int

说明:

TODO

public int getRowBottom(int row) @ L381

  • 方法名:getRowBottom
  • 源码定位:L381
  • 返回类型:int
  • 修饰符:public

参数:

  • row: int

说明:

TODO

public int getRowWidth() @ L386

  • 方法名:getRowWidth
  • 源码定位:L386
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public NarratableEntry.NarrationPriority narrationPriority() @ L390

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

参数:

说明:

TODO

protected void removeEntries(List<E> entries) @ L399

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

参数:

  • entries: List

说明:

TODO

protected void removeEntry(E entry) @ L403

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

参数:

  • entry: E

说明:

TODO

protected E getHovered() @ L413

  • 方法名:getHovered
  • 源码定位:L413
  • 返回类型:E
  • 修饰符:protected

参数:

说明:

TODO

private void bindEntryToSelf(AbstractSelectionList.Entry<E> entry) @ L417

  • 方法名:bindEntryToSelf
  • 源码定位:L417
  • 返回类型:void
  • 修饰符:private

参数:

  • entry: AbstractSelectionList.Entry

说明:

TODO

protected void narrateListElementPosition(NarrationElementOutput output, E element) @ L421

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

参数:

  • output: NarrationElementOutput
  • element: E

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public abstract class AbstractSelectionList<E extends AbstractSelectionList.Entry<E>> extends AbstractContainerWidget {
    private static final Identifier MENU_LIST_BACKGROUND = Identifier.withDefaultNamespace("textures/gui/menu_list_background.png");
    private static final Identifier INWORLD_MENU_LIST_BACKGROUND = Identifier.withDefaultNamespace("textures/gui/inworld_menu_list_background.png");
    private static final int SEPARATOR_HEIGHT = 2;
    protected final Minecraft minecraft;
    protected final int defaultEntryHeight;
    private final List<E> children = new AbstractSelectionList.TrackedList();
    protected boolean centerListVertically = true;
    private @Nullable E selected;
    private @Nullable E hovered;
 
    public AbstractSelectionList(Minecraft minecraft, int width, int height, int y, int defaultEntryHeight) {
        super(0, y, width, height, CommonComponents.EMPTY, AbstractScrollArea.defaultSettings(defaultEntryHeight / 2));
        this.minecraft = minecraft;
        this.defaultEntryHeight = defaultEntryHeight;
    }
 
    public @Nullable E getSelected() {
        return this.selected;
    }
 
    public void setSelected(@Nullable E selected) {
        this.selected = selected;
        if (selected != null) {
            boolean topClipped = selected.getContentY() < this.getY();
            boolean bottomClipped = selected.getContentBottom() > this.getBottom();
            if (this.minecraft.getLastInputType().isKeyboard() || topClipped || bottomClipped) {
                this.scrollToEntry(selected);
            }
        }
    }
 
    public @Nullable E getFocused() {
        return (E)super.getFocused();
    }
 
    @Override
    public final List<E> children() {
        return Collections.unmodifiableList(this.children);
    }
 
    protected void sort(Comparator<E> comparator) {
        this.children.sort(comparator);
        this.repositionEntries();
    }
 
    protected void swap(int firstIndex, int secondIndex) {
        Collections.swap(this.children, firstIndex, secondIndex);
        this.repositionEntries();
        this.scrollToEntry(this.children.get(secondIndex));
    }
 
    protected void clearEntries() {
        this.children.clear();
        this.selected = null;
    }
 
    protected void clearEntriesExcept(E exception) {
        this.children.removeIf(entry -> entry != exception);
        if (this.selected != exception) {
            this.setSelected(null);
        }
    }
 
    public void replaceEntries(Collection<E> newChildren) {
        this.clearEntries();
 
        for (E newChild : newChildren) {
            this.addEntry(newChild);
        }
    }
 
    private int getFirstEntryY() {
        return this.getY() + 2;
    }
 
    public int getNextY() {
        int y = this.getFirstEntryY() - (int)this.scrollAmount();
 
        for (E child : this.children) {
            y += child.getHeight();
        }
 
        return y;
    }
 
    protected int addEntry(E entry) {
        return this.addEntry(entry, this.defaultEntryHeight);
    }
 
    protected int addEntry(E entry, int height) {
        entry.setX(this.getRowLeft());
        entry.setWidth(this.getRowWidth());
        entry.setY(this.getNextY());
        entry.setHeight(height);
        this.children.add(entry);
        return this.children.size() - 1;
    }
 
    protected void addEntryToTop(E entry) {
        this.addEntryToTop(entry, this.defaultEntryHeight);
    }
 
    protected void addEntryToTop(E entry, int height) {
        double scrollFromBottom = this.maxScrollAmount() - this.scrollAmount();
        entry.setHeight(height);
        this.children.addFirst(entry);
        this.repositionEntries();
        this.setScrollAmount(this.maxScrollAmount() - scrollFromBottom);
    }
 
    private void repositionEntries() {
        int y = this.getFirstEntryY() - (int)this.scrollAmount();
 
        for (E child : this.children) {
            child.setY(y);
            y += child.getHeight();
            child.setX(this.getRowLeft());
            child.setWidth(this.getRowWidth());
        }
    }
 
    protected void removeEntryFromTop(E entry) {
        double scrollFromBottom = this.maxScrollAmount() - this.scrollAmount();
        this.removeEntry(entry);
        this.setScrollAmount(this.maxScrollAmount() - scrollFromBottom);
    }
 
    protected int getItemCount() {
        return this.children().size();
    }
 
    protected boolean entriesCanBeSelected() {
        return true;
    }
 
    protected final @Nullable E getEntryAtPosition(double posX, double posY) {
        for (E child : this.children) {
            if (child.isMouseOver(posX, posY)) {
                return child;
            }
        }
 
        return null;
    }
 
    public void updateSize(int width, HeaderAndFooterLayout layout) {
        this.updateSizeAndPosition(width, layout.getContentHeight(), layout.getHeaderHeight());
    }
 
    public void updateSizeAndPosition(int width, int height, int y) {
        this.updateSizeAndPosition(width, height, 0, y);
    }
 
    public void updateSizeAndPosition(int width, int height, int x, int y) {
        this.setSize(width, height);
        this.setPosition(x, y);
        this.repositionEntries();
        if (this.getSelected() != null) {
            this.scrollToEntry(this.getSelected());
        }
 
        this.refreshScrollAmount();
    }
 
    @Override
    protected int contentHeight() {
        int totalHeight = 0;
 
        for (E child : this.children) {
            totalHeight += child.getHeight();
        }
 
        return totalHeight + 4;
    }
 
    @Override
    public void extractWidgetRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) {
        this.hovered = this.isMouseOver(mouseX, mouseY) ? this.getEntryAtPosition(mouseX, mouseY) : null;
        this.extractListBackground(graphics);
        this.enableScissor(graphics);
        this.extractListItems(graphics, mouseX, mouseY, a);
        graphics.disableScissor();
        this.extractListSeparators(graphics);
        this.extractScrollbar(graphics, mouseX, mouseY);
    }
 
    protected void extractListSeparators(GuiGraphicsExtractor graphics) {
        Identifier headerSeparator = this.minecraft.level == null ? Screen.HEADER_SEPARATOR : Screen.INWORLD_HEADER_SEPARATOR;
        Identifier footerSeparator = this.minecraft.level == null ? Screen.FOOTER_SEPARATOR : Screen.INWORLD_FOOTER_SEPARATOR;
        graphics.blit(RenderPipelines.GUI_TEXTURED, headerSeparator, this.getX(), this.getY() - 2, 0.0F, 0.0F, this.getWidth(), 2, 32, 2);
        graphics.blit(RenderPipelines.GUI_TEXTURED, footerSeparator, this.getX(), this.getBottom(), 0.0F, 0.0F, this.getWidth(), 2, 32, 2);
    }
 
    protected void extractListBackground(GuiGraphicsExtractor graphics) {
        Identifier menuListBackground = this.minecraft.level == null ? MENU_LIST_BACKGROUND : INWORLD_MENU_LIST_BACKGROUND;
        graphics.blit(
            RenderPipelines.GUI_TEXTURED,
            menuListBackground,
            this.getX(),
            this.getY(),
            (float)this.getRight(),
            (float)(this.getBottom() + (int)this.scrollAmount()),
            this.getWidth(),
            this.getHeight(),
            32,
            32
        );
    }
 
    protected void enableScissor(GuiGraphicsExtractor graphics) {
        graphics.enableScissor(this.getX(), this.getY(), this.getRight(), this.getBottom());
    }
 
    protected void scrollToEntry(E entry) {
        int topDelta = entry.getY() - this.getY() - 2;
        if (topDelta < 0) {
            this.scroll(topDelta);
        }
 
        int bottomDelta = this.getBottom() - entry.getY() - entry.getHeight() - 2;
        if (bottomDelta < 0) {
            this.scroll(-bottomDelta);
        }
    }
 
    protected void centerScrollOn(E entry) {
        int y = 0;
 
        for (E child : this.children) {
            if (child == entry) {
                y += child.getHeight() / 2;
                break;
            }
 
            y += child.getHeight();
        }
 
        this.setScrollAmount(y - this.height / 2.0);
    }
 
    private void scroll(int amount) {
        this.setScrollAmount(this.scrollAmount() + amount);
    }
 
    @Override
    public void setScrollAmount(double scrollAmount) {
        super.setScrollAmount(scrollAmount);
        this.repositionEntries();
    }
 
    @Override
    protected int scrollBarX() {
        return this.getRowRight() + this.scrollbarWidth() + 2;
    }
 
    @Override
    public Optional<GuiEventListener> getChildAt(double x, double y) {
        return Optional.ofNullable(this.getEntryAtPosition(x, y));
    }
 
    @Override
    public void setFocused(@Nullable GuiEventListener focused) {
        E oldFocus = this.getFocused();
        if (oldFocus != focused && oldFocus instanceof ContainerEventHandler oldFocusContainer) {
            oldFocusContainer.setFocused(null);
        }
 
        super.setFocused(focused);
        int index = this.children.indexOf(focused);
        if (index >= 0) {
            E magicallyCastEntry = this.children.get(index);
            this.setSelected(magicallyCastEntry);
        }
    }
 
    protected @Nullable E nextEntry(ScreenDirection dir) {
        return this.nextEntry(dir, entry -> true);
    }
 
    protected @Nullable E nextEntry(ScreenDirection dir, Predicate<E> canSelect) {
        return this.nextEntry(dir, canSelect, this.getSelected());
    }
 
    protected @Nullable E nextEntry(ScreenDirection dir, Predicate<E> canSelect, @Nullable E startEntry) {
        int delta = switch (dir) {
            case RIGHT, LEFT -> 0;
            case UP -> -1;
            case DOWN -> 1;
        };
        if (!this.children().isEmpty() && delta != 0) {
            int index;
            if (startEntry == null) {
                index = delta > 0 ? 0 : this.children().size() - 1;
            } else {
                index = this.children().indexOf(startEntry) + delta;
            }
 
            for (int i = index; i >= 0 && i < this.children.size(); i += delta) {
                E selected = this.children().get(i);
                if (canSelect.test(selected)) {
                    return selected;
                }
            }
        }
 
        return null;
    }
 
    protected void extractListItems(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) {
        for (E child : this.children) {
            if (child.getY() + child.getHeight() >= this.getY() && child.getY() <= this.getBottom()) {
                this.extractItem(graphics, mouseX, mouseY, a, child);
            }
        }
    }
 
    protected void extractItem(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a, E entry) {
        if (this.entriesCanBeSelected() && this.getSelected() == entry) {
            int outlineColor = this.isFocused() ? -1 : -8355712;
            this.extractSelection(graphics, entry, outlineColor);
        }
 
        entry.extractContent(graphics, mouseX, mouseY, Objects.equals(this.hovered, entry), a);
    }
 
    protected void extractSelection(GuiGraphicsExtractor graphics, E entry, int outlineColor) {
        int outlineX0 = entry.getX();
        int outlineY0 = entry.getY();
        int outlineX1 = outlineX0 + entry.getWidth();
        int outlineY1 = outlineY0 + entry.getHeight();
        graphics.fill(outlineX0, outlineY0, outlineX1, outlineY1, outlineColor);
        graphics.fill(outlineX0 + 1, outlineY0 + 1, outlineX1 - 1, outlineY1 - 1, -16777216);
    }
 
    public int getRowLeft() {
        return this.getX() + this.width / 2 - this.getRowWidth() / 2;
    }
 
    public int getRowRight() {
        return this.getRowLeft() + this.getRowWidth();
    }
 
    public int getRowTop(int row) {
        return this.children.get(row).getY();
    }
 
    public int getRowBottom(int row) {
        E child = this.children.get(row);
        return child.getY() + child.getHeight();
    }
 
    public int getRowWidth() {
        return 220;
    }
 
    @Override
    public NarratableEntry.NarrationPriority narrationPriority() {
        if (this.isFocused()) {
            return NarratableEntry.NarrationPriority.FOCUSED;
        } else {
            return this.hovered != null ? NarratableEntry.NarrationPriority.HOVERED : NarratableEntry.NarrationPriority.NONE;
        }
    }
 
    protected void removeEntries(List<E> entries) {
        entries.forEach(this::removeEntry);
    }
 
    protected void removeEntry(E entry) {
        boolean removed = this.children.remove(entry);
        if (removed) {
            this.repositionEntries();
            if (entry == this.getSelected()) {
                this.setSelected(null);
            }
        }
    }
 
    protected @Nullable E getHovered() {
        return this.hovered;
    }
 
    private void bindEntryToSelf(AbstractSelectionList.Entry<E> entry) {
        entry.list = this;
    }
 
    protected void narrateListElementPosition(NarrationElementOutput output, E element) {
        List<E> children = this.children();
        if (children.size() > 1) {
            int index = children.indexOf(element);
            if (index != -1) {
                output.add(NarratedElementType.POSITION, Component.translatable("narrator.position.list", index + 1, children.size()));
            }
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    protected abstract static class Entry<E extends AbstractSelectionList.Entry<E>> implements LayoutElement, GuiEventListener {
        public static final int CONTENT_PADDING = 2;
        private int x = 0;
        private int y = 0;
        private int width = 0;
        private int height;
        @Deprecated
        private AbstractSelectionList<E> list;
 
        @Override
        public void setFocused(boolean focused) {
        }
 
        @Override
        public boolean isFocused() {
            return this.list.getFocused() == this;
        }
 
        public abstract void extractContent(final GuiGraphicsExtractor graphics, int mouseX, int mouseY, boolean hovered, float a);
 
        @Override
        public boolean isMouseOver(double mx, double my) {
            return this.getRectangle().containsPoint((int)mx, (int)my);
        }
 
        @Override
        public void setX(int x) {
            this.x = x;
        }
 
        @Override
        public void setY(int y) {
            this.y = y;
        }
 
        public void setWidth(int width) {
            this.width = width;
        }
 
        public void setHeight(int height) {
            this.height = height;
        }
 
        public int getContentX() {
            return this.getX() + 2;
        }
 
        public int getContentY() {
            return this.getY() + 2;
        }
 
        public int getContentHeight() {
            return this.getHeight() - 4;
        }
 
        public int getContentYMiddle() {
            return this.getContentY() + this.getContentHeight() / 2;
        }
 
        public int getContentBottom() {
            return this.getContentY() + this.getContentHeight();
        }
 
        public int getContentWidth() {
            return this.getWidth() - 4;
        }
 
        public int getContentXMiddle() {
            return this.getContentX() + this.getContentWidth() / 2;
        }
 
        public int getContentRight() {
            return this.getContentX() + this.getContentWidth();
        }
 
        @Override
        public int getX() {
            return this.x;
        }
 
        @Override
        public int getY() {
            return this.y;
        }
 
        @Override
        public int getWidth() {
            return this.width;
        }
 
        @Override
        public int getHeight() {
            return this.height;
        }
 
        @Override
        public void visitWidgets(Consumer<AbstractWidget> widgetVisitor) {
        }
 
        @Override
        public ScreenRectangle getRectangle() {
            return LayoutElement.super.getRectangle();
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    private class TrackedList extends AbstractList<E> {
        private final List<E> delegate;
 
        private TrackedList() {
            Objects.requireNonNull(AbstractSelectionList.this);
            super();
            this.delegate = Lists.newArrayList();
        }
 
        public E get(int index) {
            return this.delegate.get(index);
        }
 
        @Override
        public int size() {
            return this.delegate.size();
        }
 
        public E set(int index, E element) {
            E entry = this.delegate.set(index, element);
            AbstractSelectionList.this.bindEntryToSelf(element);
            return entry;
        }
 
        public void add(int index, E element) {
            this.delegate.add(index, element);
            AbstractSelectionList.this.bindEntryToSelf(element);
        }
 
        public E remove(int index) {
            return this.delegate.remove(index);
        }
    }
}

引用的其他类