ChatSelectionScreen.java

net.minecraft.client.gui.screens.reporting.ChatSelectionScreen

信息

  • 全限定名:net.minecraft.client.gui.screens.reporting.ChatSelectionScreen
  • 类型:public class
  • 包:net.minecraft.client.gui.screens.reporting
  • 源码路径:src/main/java/net/minecraft/client/gui/screens/reporting/ChatSelectionScreen.java
  • 起始行号:L42
  • 继承:Screen
  • 职责:

    TODO

字段/常量

  • CHECKMARK_SPRITE

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

      TODO

  • TITLE

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

      TODO

  • CONTEXT_INFO

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

      TODO

  • lastScreen

    • 类型: Screen
    • 修饰符: private final
    • 源码定位: L46
    • 说明:

      TODO

  • reportingContext

    • 类型: ReportingContext
    • 修饰符: private final
    • 源码定位: L47
    • 说明:

      TODO

  • confirmSelectedButton

    • 类型: Button
    • 修饰符: private
    • 源码定位: L48
    • 说明:

      TODO

  • contextInfoLabel

    • 类型: MultiLineLabel
    • 修饰符: private
    • 源码定位: L49
    • 说明:

      TODO

  • chatSelectionList

    • 类型: ChatSelectionScreen.ChatSelectionList
    • 修饰符: private
    • 源码定位: L50
    • 说明:

      TODO

  • report

    • 类型: ChatReport.Builder
    • 修饰符: private final
    • 源码定位: L51
    • 说明:

      TODO

  • onSelected

    • 类型: Consumer<ChatReport.Builder>
    • 修饰符: private final
    • 源码定位: L52
    • 说明:

      TODO

  • chatLogFiller

    • 类型: ChatSelectionLogFiller
    • 修饰符: private
    • 源码定位: L53
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList

    • 类型: class
    • 修饰符: public
    • 源码定位: L124
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.DividerEntry

    • 类型: class
    • 修饰符: public
    • 源码定位: L228
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.Entry

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

      TODO

  • net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.Heading

    • 类型: record
    • 修饰符: private
    • 源码定位: L279
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.MessageEntry

    • 类型: class
    • 修饰符: public
    • 源码定位: L286
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.MessageHeadingEntry

    • 类型: class
    • 修饰符: public
    • 源码定位: L409
    • 说明:

      TODO

  • net.minecraft.client.gui.screens.reporting.ChatSelectionScreen.ChatSelectionList.PaddingEntry

    • 类型: class
    • 修饰符: public static
    • 源码定位: L435
    • 说明:

      TODO

构造器

public ChatSelectionScreen(Screen lastScreen, ReportingContext reportingContext, ChatReport.Builder report, Consumer<ChatReport.Builder> onSelected) @ L55

  • 构造器名:ChatSelectionScreen
  • 源码定位:L55
  • 修饰符:public

参数:

  • lastScreen: Screen
  • reportingContext: ReportingContext
  • report: ChatReport.Builder
  • onSelected: Consumer<ChatReport.Builder>

说明:

TODO

方法

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

protected void init() @ L65

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

参数:

说明:

TODO

private boolean canReport(LoggedChatMessage message) @ L82

  • 方法名:canReport
  • 源码定位:L82
  • 返回类型:boolean
  • 修饰符:private

参数:

  • message: LoggedChatMessage

说明:

TODO

private void extendLog() @ L86

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

参数:

说明:

TODO

private void onReachedScrollTop() @ L91

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

参数:

说明:

TODO

private void updateConfirmSelectedButton() @ L95

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

参数:

说明:

TODO

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

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

参数:

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

说明:

TODO

public void onClose() @ L113

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

参数:

说明:

TODO

public Component getNarrationMessage() @ L118

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

参数:

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class ChatSelectionScreen extends Screen {
    private static final Identifier CHECKMARK_SPRITE = Identifier.withDefaultNamespace("icon/checkmark");
    private static final Component TITLE = Component.translatable("gui.chatSelection.title");
    private static final Component CONTEXT_INFO = Component.translatable("gui.chatSelection.context");
    private final @Nullable Screen lastScreen;
    private final ReportingContext reportingContext;
    private Button confirmSelectedButton;
    private MultiLineLabel contextInfoLabel;
    private ChatSelectionScreen.@Nullable ChatSelectionList chatSelectionList;
    private final ChatReport.Builder report;
    private final Consumer<ChatReport.Builder> onSelected;
    private ChatSelectionLogFiller chatLogFiller;
 
    public ChatSelectionScreen(
        @Nullable Screen lastScreen, ReportingContext reportingContext, ChatReport.Builder report, Consumer<ChatReport.Builder> onSelected
    ) {
        super(TITLE);
        this.lastScreen = lastScreen;
        this.reportingContext = reportingContext;
        this.report = report.copy();
        this.onSelected = onSelected;
    }
 
    @Override
    protected void init() {
        this.chatLogFiller = new ChatSelectionLogFiller(this.reportingContext, this::canReport);
        this.contextInfoLabel = MultiLineLabel.create(this.font, CONTEXT_INFO, this.width - 16);
        this.chatSelectionList = this.addRenderableWidget(
            new ChatSelectionScreen.ChatSelectionList(this.minecraft, (this.contextInfoLabel.getLineCount() + 1) * 9)
        );
        this.addRenderableWidget(Button.builder(CommonComponents.GUI_BACK, b -> this.onClose()).bounds(this.width / 2 - 155, this.height - 32, 150, 20).build());
        this.confirmSelectedButton = this.addRenderableWidget(Button.builder(CommonComponents.GUI_DONE, b -> {
            this.onSelected.accept(this.report);
            this.onClose();
        }).bounds(this.width / 2 - 155 + 160, this.height - 32, 150, 20).build());
        this.updateConfirmSelectedButton();
        this.extendLog();
        this.chatSelectionList.setScrollAmount(this.chatSelectionList.maxScrollAmount());
    }
 
    private boolean canReport(LoggedChatMessage message) {
        return message.canReport(this.report.reportedProfileId());
    }
 
    private void extendLog() {
        int pageSize = this.chatSelectionList.getMaxVisibleEntries();
        this.chatLogFiller.fillNextPage(pageSize, this.chatSelectionList);
    }
 
    private void onReachedScrollTop() {
        this.extendLog();
    }
 
    private void updateConfirmSelectedButton() {
        this.confirmSelectedButton.active = !this.report.reportedMessages().isEmpty();
    }
 
    @Override
    public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) {
        super.extractRenderState(graphics, mouseX, mouseY, a);
        ActiveTextCollector textRenderer = graphics.textRenderer();
        graphics.centeredText(this.font, this.title, this.width / 2, 10, -1);
        AbuseReportLimits reportLimits = this.reportingContext.sender().reportLimits();
        int messageCount = this.report.reportedMessages().size();
        int maxMessageCount = reportLimits.maxReportedMessageCount();
        Component selectedText = Component.translatable("gui.chatSelection.selected", messageCount, maxMessageCount);
        graphics.centeredText(this.font, selectedText, this.width / 2, 26, -1);
        int topY = this.chatSelectionList.getFooterTop();
        this.contextInfoLabel.visitLines(TextAlignment.CENTER, this.width / 2, topY, 9, textRenderer);
    }
 
    @Override
    public void onClose() {
        this.minecraft.setScreen(this.lastScreen);
    }
 
    @Override
    public Component getNarrationMessage() {
        return CommonComponents.joinForNarration(super.getNarrationMessage(), CONTEXT_INFO);
    }
 
    @OnlyIn(Dist.CLIENT)
    public class ChatSelectionList extends ObjectSelectionList<ChatSelectionScreen.ChatSelectionList.Entry> implements ChatSelectionLogFiller.Output {
        public static final int ITEM_HEIGHT = 16;
        private ChatSelectionScreen.ChatSelectionList.@Nullable Heading previousHeading;
 
        public ChatSelectionList(Minecraft minecraft, int upperMargin) {
            Objects.requireNonNull(ChatSelectionScreen.this);
            super(minecraft, ChatSelectionScreen.this.width, ChatSelectionScreen.this.height - upperMargin - 80, 40, 16);
        }
 
        @Override
        public void setScrollAmount(double scrollAmount) {
            double prevScrollAmount = this.scrollAmount();
            super.setScrollAmount(scrollAmount);
            if (this.maxScrollAmount() > 1.0E-5F && scrollAmount <= 1.0E-5F && !Mth.equal(scrollAmount, prevScrollAmount)) {
                ChatSelectionScreen.this.onReachedScrollTop();
            }
        }
 
        @Override
        public void acceptMessage(int id, LoggedChatMessage.Player message) {
            boolean canReport = message.canReport(ChatSelectionScreen.this.report.reportedProfileId());
            ChatTrustLevel trustLevel = message.trustLevel();
            GuiMessageTag tag = trustLevel.createTag(message.message());
            ChatSelectionScreen.ChatSelectionList.Entry entry = new ChatSelectionScreen.ChatSelectionList.MessageEntry(
                id, message.toContentComponent(), message.toNarrationComponent(), tag, canReport, true
            );
            this.addEntryToTop(entry);
            this.updateHeading(message, canReport);
        }
 
        private void updateHeading(LoggedChatMessage.Player message, boolean canReport) {
            ChatSelectionScreen.ChatSelectionList.Entry entry = new ChatSelectionScreen.ChatSelectionList.MessageHeadingEntry(
                message.profile(), message.toHeadingComponent(), canReport
            );
            this.addEntryToTop(entry);
            ChatSelectionScreen.ChatSelectionList.Heading heading = new ChatSelectionScreen.ChatSelectionList.Heading(message.profileId(), entry);
            if (this.previousHeading != null && this.previousHeading.canCombine(heading)) {
                this.removeEntryFromTop(this.previousHeading.entry());
            }
 
            this.previousHeading = heading;
        }
 
        @Override
        public void acceptDivider(Component text) {
            this.addEntryToTop(new ChatSelectionScreen.ChatSelectionList.PaddingEntry());
            this.addEntryToTop(new ChatSelectionScreen.ChatSelectionList.DividerEntry(text));
            this.addEntryToTop(new ChatSelectionScreen.ChatSelectionList.PaddingEntry());
            this.previousHeading = null;
        }
 
        @Override
        public int getRowWidth() {
            return Math.min(350, this.width - 50);
        }
 
        public int getMaxVisibleEntries() {
            return Mth.positiveCeilDiv(this.height, 16);
        }
 
        protected void extractItem(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a, ChatSelectionScreen.ChatSelectionList.Entry entry) {
            if (this.shouldHighlightEntry(entry)) {
                boolean selected = this.getSelected() == entry;
                int outlineColor = this.isFocused() && selected ? -1 : -8355712;
                this.extractSelection(graphics, entry, outlineColor);
            }
 
            entry.extractContent(graphics, mouseX, mouseY, this.getHovered() == entry, a);
        }
 
        private boolean shouldHighlightEntry(ChatSelectionScreen.ChatSelectionList.Entry entry) {
            if (entry.canSelect()) {
                boolean entrySelected = this.getSelected() == entry;
                boolean nothingSelected = this.getSelected() == null;
                boolean entryHovered = this.getHovered() == entry;
                return entrySelected || nothingSelected && entryHovered && entry.canReport();
            } else {
                return false;
            }
        }
 
        protected ChatSelectionScreen.ChatSelectionList.@Nullable Entry nextEntry(ScreenDirection dir) {
            return this.nextEntry(dir, ChatSelectionScreen.ChatSelectionList.Entry::canSelect);
        }
 
        public void setSelected(ChatSelectionScreen.ChatSelectionList.@Nullable Entry selected) {
            super.setSelected(selected);
            ChatSelectionScreen.ChatSelectionList.Entry entry = this.nextEntry(ScreenDirection.UP);
            if (entry == null) {
                ChatSelectionScreen.this.onReachedScrollTop();
            }
        }
 
        @Override
        public boolean keyPressed(KeyEvent event) {
            ChatSelectionScreen.ChatSelectionList.Entry selected = this.getSelected();
            return selected != null && selected.keyPressed(event) ? true : super.keyPressed(event);
        }
 
        public int getFooterTop() {
            return this.getBottom() + 9;
        }
 
        @OnlyIn(Dist.CLIENT)
        public class DividerEntry extends ChatSelectionScreen.ChatSelectionList.Entry {
            private final Component text;
 
            public DividerEntry(Component text) {
                Objects.requireNonNull(ChatSelectionList.this);
                super();
                this.text = text;
            }
 
            @Override
            public void extractContent(GuiGraphicsExtractor graphics, int mouseX, int mouseY, boolean hovered, float a) {
                int centerY = this.getContentYMiddle();
                int rowRight = this.getContentRight() - 8;
                int textWidth = ChatSelectionScreen.this.font.width(this.text);
                int textLeft = (this.getContentX() + rowRight - textWidth) / 2;
                int textTop = centerY - 9 / 2;
                graphics.text(ChatSelectionScreen.this.font, this.text, textLeft, textTop, -6250336);
            }
 
            @Override
            public Component getNarration() {
                return this.text;
            }
        }
 
        @OnlyIn(Dist.CLIENT)
        public abstract static class Entry extends ObjectSelectionList.Entry<ChatSelectionScreen.ChatSelectionList.Entry> {
            @Override
            public Component getNarration() {
                return CommonComponents.EMPTY;
            }
 
            public boolean isSelected() {
                return false;
            }
 
            public boolean canSelect() {
                return false;
            }
 
            public boolean canReport() {
                return this.canSelect();
            }
 
            @Override
            public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) {
                return this.canSelect();
            }
        }
 
        @OnlyIn(Dist.CLIENT)
        private record Heading(UUID sender, ChatSelectionScreen.ChatSelectionList.Entry entry) {
            public boolean canCombine(ChatSelectionScreen.ChatSelectionList.Heading other) {
                return other.sender.equals(this.sender);
            }
        }
 
        @OnlyIn(Dist.CLIENT)
        public class MessageEntry extends ChatSelectionScreen.ChatSelectionList.Entry {
            private static final int CHECKMARK_WIDTH = 9;
            private static final int CHECKMARK_HEIGHT = 8;
            private static final int INDENT_AMOUNT = 11;
            private static final int TAG_MARGIN_LEFT = 4;
            private final int chatId;
            private final FormattedText text;
            private final Component narration;
            private final @Nullable List<FormattedCharSequence> hoverText;
            private final GuiMessageTag.@Nullable Icon tagIcon;
            private final @Nullable List<FormattedCharSequence> tagHoverText;
            private final boolean canReport;
            private final boolean playerMessage;
 
            public MessageEntry(int chatId, Component text, Component narration, @Nullable GuiMessageTag tag, boolean canReport, boolean playerMessage) {
                this.chatId = chatId;
                this.tagIcon = Optionull.map(tag, GuiMessageTag::icon);
                this.tagHoverText = tag != null && tag.text() != null
                    ? ChatSelectionScreen.this.font.split(tag.text(), ChatSelectionList.this.getRowWidth())
                    : null;
                this.canReport = canReport;
                this.playerMessage = playerMessage;
                FormattedText shortText = ChatSelectionScreen.this.font
                    .substrByWidth(text, this.getMaximumTextWidth() - ChatSelectionScreen.this.font.width(CommonComponents.ELLIPSIS));
                if (text != shortText) {
                    this.text = FormattedText.composite(shortText, CommonComponents.ELLIPSIS);
                    this.hoverText = ChatSelectionScreen.this.font.split(text, ChatSelectionList.this.getRowWidth());
                } else {
                    this.text = text;
                    this.hoverText = null;
                }
 
                this.narration = narration;
            }
 
            @Override
            public void extractContent(GuiGraphicsExtractor graphics, int mouseX, int mouseY, boolean hovered, float a) {
                if (this.isSelected() && this.canReport) {
                    this.extractSelectedCheckmark(graphics, this.getContentY(), this.getContentX(), this.getContentHeight());
                }
 
                int textX = this.getContentX() + this.getTextIndent();
                int textY = this.getContentY() + 1 + (this.getContentHeight() - 9) / 2;
                graphics.text(ChatSelectionScreen.this.font, Language.getInstance().getVisualOrder(this.text), textX, textY, this.canReport ? -1 : -1593835521);
                if (this.hoverText != null && hovered) {
                    graphics.setTooltipForNextFrame(this.hoverText, mouseX, mouseY);
                }
 
                int textWidth = ChatSelectionScreen.this.font.width(this.text);
                this.extractTag(graphics, textX + textWidth + 4, this.getContentY(), this.getContentHeight(), mouseX, mouseY);
            }
 
            private void extractTag(GuiGraphicsExtractor graphics, int iconLeft, int rowTop, int rowHeight, int mouseX, int mouseY) {
                if (this.tagIcon != null) {
                    int iconTop = rowTop + (rowHeight - this.tagIcon.height) / 2;
                    this.tagIcon.extractRenderState(graphics, iconLeft, iconTop);
                    if (this.tagHoverText != null
                        && mouseX >= iconLeft
                        && mouseX <= iconLeft + this.tagIcon.width
                        && mouseY >= iconTop
                        && mouseY <= iconTop + this.tagIcon.height) {
                        graphics.setTooltipForNextFrame(this.tagHoverText, mouseX, mouseY);
                    }
                }
            }
 
            private void extractSelectedCheckmark(GuiGraphicsExtractor graphics, int rowTop, int rowLeft, int rowHeight) {
                int top = rowTop + (rowHeight - 8) / 2;
                graphics.blitSprite(RenderPipelines.GUI_TEXTURED, ChatSelectionScreen.CHECKMARK_SPRITE, rowLeft, top, 9, 8);
            }
 
            private int getMaximumTextWidth() {
                int tagMargin = this.tagIcon != null ? this.tagIcon.width + 4 : 0;
                return ChatSelectionList.this.getRowWidth() - this.getTextIndent() - 4 - tagMargin;
            }
 
            private int getTextIndent() {
                return this.playerMessage ? 11 : 0;
            }
 
            @Override
            public Component getNarration() {
                return (Component)(this.isSelected() ? Component.translatable("narrator.select", this.narration) : this.narration);
            }
 
            @Override
            public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) {
                ChatSelectionList.this.setSelected(null);
                return this.toggleReport();
            }
 
            @Override
            public boolean keyPressed(KeyEvent event) {
                return event.isSelection() ? this.toggleReport() : false;
            }
 
            @Override
            public boolean isSelected() {
                return ChatSelectionScreen.this.report.isReported(this.chatId);
            }
 
            @Override
            public boolean canSelect() {
                return true;
            }
 
            @Override
            public boolean canReport() {
                return this.canReport;
            }
 
            private boolean toggleReport() {
                if (this.canReport) {
                    ChatSelectionScreen.this.report.toggleReported(this.chatId);
                    ChatSelectionScreen.this.updateConfirmSelectedButton();
                    return true;
                } else {
                    return false;
                }
            }
        }
 
        @OnlyIn(Dist.CLIENT)
        public class MessageHeadingEntry extends ChatSelectionScreen.ChatSelectionList.Entry {
            private static final int FACE_SIZE = 12;
            private static final int PADDING = 4;
            private final Component heading;
            private final Supplier<PlayerSkin> skin;
            private final boolean canReport;
 
            public MessageHeadingEntry(GameProfile profile, Component heading, boolean canReport) {
                Objects.requireNonNull(ChatSelectionList.this);
                super();
                this.heading = heading;
                this.canReport = canReport;
                this.skin = ChatSelectionList.this.minecraft.getSkinManager().createLookup(profile, true);
            }
 
            @Override
            public void extractContent(GuiGraphicsExtractor graphics, int mouseX, int mouseY, boolean hovered, float a) {
                int faceX = this.getContentX() - 12 + 4;
                int faceY = this.getContentY() + (this.getContentHeight() - 12) / 2;
                PlayerFaceExtractor.extractRenderState(graphics, this.skin.get(), faceX, faceY, 12);
                int textY = this.getContentY() + 1 + (this.getContentHeight() - 9) / 2;
                graphics.text(ChatSelectionScreen.this.font, this.heading, faceX + 12 + 4, textY, this.canReport ? -1 : -1593835521);
            }
        }
 
        @OnlyIn(Dist.CLIENT)
        public static class PaddingEntry extends ChatSelectionScreen.ChatSelectionList.Entry {
            @Override
            public void extractContent(GuiGraphicsExtractor graphics, int mouseX, int mouseY, boolean hovered, float a) {
            }
        }
    }
}

引用的其他类

  • Optionull

    • 引用位置: 方法调用
    • 关联成员: Optionull.map()
  • GuiGraphicsExtractor

    • 引用位置: 参数
  • Button

    • 引用位置: 字段/方法调用
    • 关联成员: Button.builder()
  • MultiLineLabel

    • 引用位置: 字段/方法调用
    • 关联成员: MultiLineLabel.create()
  • PlayerFaceExtractor

    • 引用位置: 方法调用
    • 关联成员: PlayerFaceExtractor.extractRenderState()
  • Screen

    • 引用位置: 参数/字段/继承
  • ChatSelectionLogFiller

    • 引用位置: 字段/构造调用
    • 关联成员: ChatSelectionLogFiller()
  • LoggedChatMessage

    • 引用位置: 参数
  • ChatReport

    • 引用位置: 参数/字段
  • ReportingContext

    • 引用位置: 参数/字段
  • Language

    • 引用位置: 方法调用
    • 关联成员: Language.getInstance()
  • CommonComponents

    • 引用位置: 方法调用
    • 关联成员: CommonComponents.joinForNarration()
  • Component

    • 引用位置: 字段/方法调用/返回值
    • 关联成员: Component.translatable()
  • FormattedText

    • 引用位置: 方法调用
    • 关联成员: FormattedText.composite()
  • Identifier

    • 引用位置: 字段/方法调用
    • 关联成员: Identifier.withDefaultNamespace()
  • Mth

    • 引用位置: 方法调用
    • 关联成员: Mth.equal(), Mth.positiveCeilDiv()