MultiLineEditBox.java

net.minecraft.client.gui.components.MultiLineEditBox

信息

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

    TODO

字段/常量

  • CURSOR_COLOR

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

      TODO

  • PLACEHOLDER_TEXT_COLOR

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

      TODO

  • font

    • 类型: Font
    • 修饰符: private final
    • 源码定位: L26
    • 说明:

      TODO

  • placeholder

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

      TODO

  • textField

    • 类型: MultilineTextField
    • 修饰符: private final
    • 源码定位: L28
    • 说明:

      TODO

  • textColor

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

      TODO

  • textShadow

    • 类型: boolean
    • 修饰符: private final
    • 源码定位: L30
    • 说明:

      TODO

  • cursorColor

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

      TODO

  • preeditOverlay

    • 类型: IMEPreeditOverlay
    • 修饰符: private
    • 源码定位: L32
    • 说明:

      TODO

  • focusedTime

    • 类型: long
    • 修饰符: private
    • 源码定位: L33
    • 说明:

      TODO

内部类/嵌套类型

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

      TODO

构造器

private MultiLineEditBox(Font font, int x, int y, int width, int height, Component placeholder, Component narration, int textColor, boolean textShadow, int cursorColor, boolean showBackground, boolean showDecorations) @ L35

  • 构造器名:MultiLineEditBox
  • 源码定位:L35
  • 修饰符:private

参数:

  • font: Font
  • x: int
  • y: int
  • width: int
  • height: int
  • placeholder: Component
  • narration: Component
  • textColor: int
  • textShadow: boolean
  • cursorColor: int
  • showBackground: boolean
  • showDecorations: boolean

说明:

TODO

方法

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

public void setCharacterLimit(int characterLimit) @ L59

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

参数:

  • characterLimit: int

说明:

TODO

public void setLineLimit(int lineLimit) @ L63

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

参数:

  • lineLimit: int

说明:

TODO

public void setValueListener(Consumer<String> valueListener) @ L67

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

参数:

  • valueListener: Consumer

说明:

TODO

public void setValue(String value) @ L71

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

参数:

  • value: String

说明:

TODO

public void setValue(String value, boolean allowOverflowLineLimit) @ L75

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

参数:

  • value: String
  • allowOverflowLineLimit: boolean

说明:

TODO

public String getValue() @ L79

  • 方法名:getValue
  • 源码定位:L79
  • 返回类型:String
  • 修饰符:public

参数:

说明:

TODO

public void updateWidgetNarration(NarrationElementOutput output) @ L83

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

参数:

  • output: NarrationElementOutput

说明:

TODO

public void onClick(MouseButtonEvent event, boolean doubleClick) @ L88

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

参数:

  • event: MouseButtonEvent
  • doubleClick: boolean

说明:

TODO

protected void onDrag(MouseButtonEvent event, double dx, double dy) @ L98

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

参数:

  • event: MouseButtonEvent
  • dx: double
  • dy: double

说明:

TODO

public boolean keyPressed(KeyEvent event) @ L105

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

参数:

  • event: KeyEvent

说明:

TODO

public boolean charTyped(CharacterEvent event) @ L110

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

参数:

  • event: CharacterEvent

说明:

TODO

public boolean preeditUpdated(PreeditEvent event) @ L120

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

参数:

  • event: PreeditEvent

说明:

TODO

protected void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) @ L126

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

参数:

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

说明:

TODO

protected void extractDecorations(GuiGraphicsExtractor graphics) @ L218

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

参数:

  • graphics: GuiGraphicsExtractor

说明:

TODO

public int getInnerHeight() @ L228

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

参数:

说明:

TODO

private void scrollToCursor() @ L233

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

参数:

说明:

TODO

private void seekCursorScreen(double x, double y) @ L248

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

参数:

  • x: double
  • y: double

说明:

TODO

public void setFocused(boolean focused) @ L254

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

参数:

  • focused: boolean

说明:

TODO

public static MultiLineEditBox.Builder builder() @ L264

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

参数:

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class MultiLineEditBox extends AbstractTextAreaWidget {
    private static final int CURSOR_COLOR = -3092272;
    private static final int PLACEHOLDER_TEXT_COLOR = ARGB.color(204, -2039584);
    private final Font font;
    private final Component placeholder;
    private final MultilineTextField textField;
    private final int textColor;
    private final boolean textShadow;
    private final int cursorColor;
    private @Nullable IMEPreeditOverlay preeditOverlay;
    private long focusedTime = Util.getMillis();
 
    private MultiLineEditBox(
        Font font,
        int x,
        int y,
        int width,
        int height,
        Component placeholder,
        Component narration,
        int textColor,
        boolean textShadow,
        int cursorColor,
        boolean showBackground,
        boolean showDecorations
    ) {
        super(x, y, width, height, narration, AbstractScrollArea.defaultSettings((int)(9.0 / 2.0)), showBackground, showDecorations);
        this.font = font;
        this.textShadow = textShadow;
        this.textColor = textColor;
        this.cursorColor = cursorColor;
        this.placeholder = placeholder;
        this.textField = new MultilineTextField(font, width - this.totalInnerPadding());
        this.textField.setCursorListener(this::scrollToCursor);
    }
 
    public void setCharacterLimit(int characterLimit) {
        this.textField.setCharacterLimit(characterLimit);
    }
 
    public void setLineLimit(int lineLimit) {
        this.textField.setLineLimit(lineLimit);
    }
 
    public void setValueListener(Consumer<String> valueListener) {
        this.textField.setValueListener(valueListener);
    }
 
    public void setValue(String value) {
        this.setValue(value, false);
    }
 
    public void setValue(String value, boolean allowOverflowLineLimit) {
        this.textField.setValue(value, allowOverflowLineLimit);
    }
 
    public String getValue() {
        return this.textField.value();
    }
 
    @Override
    public void updateWidgetNarration(NarrationElementOutput output) {
        output.add(NarratedElementType.TITLE, Component.translatable("gui.narrate.editBox", this.getMessage(), this.getValue()));
    }
 
    @Override
    public void onClick(MouseButtonEvent event, boolean doubleClick) {
        if (doubleClick) {
            this.textField.selectWordAtCursor();
        } else {
            this.textField.setSelecting(event.hasShiftDown());
            this.seekCursorScreen(event.x(), event.y());
        }
    }
 
    @Override
    protected void onDrag(MouseButtonEvent event, double dx, double dy) {
        this.textField.setSelecting(true);
        this.seekCursorScreen(event.x(), event.y());
        this.textField.setSelecting(event.hasShiftDown());
    }
 
    @Override
    public boolean keyPressed(KeyEvent event) {
        return this.textField.keyPressed(event);
    }
 
    @Override
    public boolean charTyped(CharacterEvent event) {
        if (this.visible && this.isFocused() && event.isAllowedChatCharacter()) {
            this.textField.insertText(event.codepointAsString());
            return true;
        } else {
            return false;
        }
    }
 
    @Override
    public boolean preeditUpdated(@Nullable PreeditEvent event) {
        this.preeditOverlay = event != null ? new IMEPreeditOverlay(event, this.font, 9 + 1) : null;
        return true;
    }
 
    @Override
    protected void extractContents(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) {
        String value = this.textField.value();
        if (value.isEmpty() && !this.isFocused()) {
            graphics.textWithWordWrap(
                this.font, this.placeholder, this.getInnerLeft(), this.getInnerTop(), this.width - this.totalInnerPadding(), PLACEHOLDER_TEXT_COLOR
            );
        } else {
            int cursor = this.textField.cursor();
            boolean showCursor = this.isFocused() && TextCursorUtils.isCursorVisible(Util.getMillis() - this.focusedTime);
            boolean needsValidCursorPos = this.preeditOverlay != null;
            boolean insertCursor = cursor < value.length();
            int cursorX = 0;
            int cursorY = 0;
            int drawTop = this.getInnerTop();
            int innerLeft = this.getInnerLeft();
            boolean hasDrawnCursor = false;
 
            for (MultilineTextField.StringView lineView : this.textField.iterateLines()) {
                boolean lineWithinVisibleBounds = this.withinContentAreaTopBottom(drawTop, drawTop + 9);
                if (!hasDrawnCursor && (needsValidCursorPos || showCursor) && insertCursor && cursor >= lineView.beginIndex() && cursor <= lineView.endIndex()) {
                    if (lineWithinVisibleBounds) {
                        String textBeforeCursor = value.substring(lineView.beginIndex(), cursor);
                        int textBeforeCursorPosRight = innerLeft + this.font.width(textBeforeCursor);
                        String textAfterCursor = value.substring(cursor, lineView.endIndex());
                        graphics.text(this.font, textBeforeCursor, innerLeft, drawTop, this.textColor, this.textShadow);
                        graphics.text(this.font, textAfterCursor, textBeforeCursorPosRight, drawTop, this.textColor, this.textShadow);
                        cursorX = textBeforeCursorPosRight;
                        cursorY = drawTop;
                        if (showCursor) {
                            TextCursorUtils.extractInsertCursor(graphics, textBeforeCursorPosRight, drawTop, this.cursorColor, 9 + 1);
                        }
 
                        hasDrawnCursor = true;
                    }
                } else if (lineWithinVisibleBounds) {
                    String substring = value.substring(lineView.beginIndex(), lineView.endIndex());
                    graphics.text(this.font, substring, innerLeft, drawTop, this.textColor, this.textShadow);
                    if ((needsValidCursorPos || showCursor) && !insertCursor) {
                        cursorX = innerLeft + this.font.width(substring);
                        cursorY = drawTop;
                    }
                }
 
                drawTop += 9;
            }
 
            if (showCursor && !insertCursor && this.withinContentAreaTopBottom(cursorY, cursorY + 9)) {
                TextCursorUtils.extractAppendCursor(graphics, this.font, cursorX, cursorY, this.cursorColor, this.textShadow);
            }
 
            if (this.textField.hasSelection()) {
                MultilineTextField.StringView selection = this.textField.getSelected();
                int drawX = this.getInnerLeft();
                drawTop = this.getInnerTop();
 
                for (MultilineTextField.StringView lineView : this.textField.iterateLines()) {
                    if (selection.beginIndex() > lineView.endIndex()) {
                        drawTop += 9;
                    } else {
                        if (lineView.beginIndex() > selection.endIndex()) {
                            break;
                        }
 
                        if (this.withinContentAreaTopBottom(drawTop, drawTop + 9)) {
                            int drawBegin = this.font.width(value.substring(lineView.beginIndex(), Math.max(selection.beginIndex(), lineView.beginIndex())));
                            int drawEnd;
                            if (selection.endIndex() > lineView.endIndex()) {
                                drawEnd = this.width - this.innerPadding();
                            } else {
                                drawEnd = this.font.width(value.substring(lineView.beginIndex(), selection.endIndex()));
                            }
 
                            graphics.textHighlight(drawX + drawBegin, drawTop, drawX + drawEnd, drawTop + 9, true);
                        }
 
                        drawTop += 9;
                    }
                }
            }
 
            if (this.isHovered()) {
                graphics.requestCursor(CursorTypes.IBEAM);
            }
 
            if (this.preeditOverlay != null) {
                this.preeditOverlay.updateInputPosition(cursorX, cursorY);
                graphics.setPreeditOverlay(this.preeditOverlay);
            }
        }
    }
 
    @Override
    protected void extractDecorations(GuiGraphicsExtractor graphics) {
        super.extractDecorations(graphics);
        if (this.textField.hasCharacterLimit()) {
            int characterLimit = this.textField.characterLimit();
            Component countText = Component.translatable("gui.multiLineEditBox.character_limit", this.textField.value().length(), characterLimit);
            graphics.text(this.font, countText, this.getX() + this.width - this.font.width(countText), this.getY() + this.height + 4, -6250336);
        }
    }
 
    @Override
    public int getInnerHeight() {
        return 9 * this.textField.getLineCount();
    }
 
    private void scrollToCursor() {
        double scrollAmount = this.scrollAmount();
        MultilineTextField.StringView firstFullyVisibleLine = this.textField.getLineView((int)(scrollAmount / 9.0));
        if (this.textField.cursor() <= firstFullyVisibleLine.beginIndex()) {
            scrollAmount = this.textField.getLineAtCursor() * 9;
        } else {
            MultilineTextField.StringView lastFullyVisibleLine = this.textField.getLineView((int)((scrollAmount + this.height) / 9.0) - 1);
            if (this.textField.cursor() > lastFullyVisibleLine.endIndex()) {
                scrollAmount = this.textField.getLineAtCursor() * 9 - this.height + 9 + this.totalInnerPadding();
            }
        }
 
        this.setScrollAmount(scrollAmount);
    }
 
    private void seekCursorScreen(double x, double y) {
        double mouseX = x - this.getX() - this.innerPadding();
        double mouseY = y - this.getY() - this.innerPadding() + this.scrollAmount();
        this.textField.seekCursorToPoint(mouseX, mouseY);
    }
 
    @Override
    public void setFocused(boolean focused) {
        super.setFocused(focused);
        if (focused) {
            this.focusedTime = Util.getMillis();
        }
 
        Minecraft.getInstance().onTextInputFocusChange(this, focused);
    }
 
    public static MultiLineEditBox.Builder builder() {
        return new MultiLineEditBox.Builder();
    }
 
    @OnlyIn(Dist.CLIENT)
    public static class Builder {
        private int x;
        private int y;
        private Component placeholder = CommonComponents.EMPTY;
        private int textColor = -2039584;
        private boolean textShadow = true;
        private int cursorColor = -3092272;
        private boolean showBackground = true;
        private boolean showDecorations = true;
 
        public MultiLineEditBox.Builder setX(int x) {
            this.x = x;
            return this;
        }
 
        public MultiLineEditBox.Builder setY(int y) {
            this.y = y;
            return this;
        }
 
        public MultiLineEditBox.Builder setPlaceholder(Component placeholder) {
            this.placeholder = placeholder;
            return this;
        }
 
        public MultiLineEditBox.Builder setTextColor(int textColor) {
            this.textColor = textColor;
            return this;
        }
 
        public MultiLineEditBox.Builder setTextShadow(boolean textShadow) {
            this.textShadow = textShadow;
            return this;
        }
 
        public MultiLineEditBox.Builder setCursorColor(int cursorColor) {
            this.cursorColor = cursorColor;
            return this;
        }
 
        public MultiLineEditBox.Builder setShowBackground(boolean showBackground) {
            this.showBackground = showBackground;
            return this;
        }
 
        public MultiLineEditBox.Builder setShowDecorations(boolean showDecorations) {
            this.showDecorations = showDecorations;
            return this;
        }
 
        public MultiLineEditBox build(Font font, int width, int height, Component narration) {
            return new MultiLineEditBox(
                font,
                this.x,
                this.y,
                width,
                height,
                this.placeholder,
                narration,
                this.textColor,
                this.textShadow,
                this.cursorColor,
                this.showBackground,
                this.showDecorations
            );
        }
    }
}

引用的其他类