    001package net.minecraft.client.gui;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import net.minecraft.client.renderer.Tessellator;
    006import net.minecraft.util.ChatAllowedCharacters;
    007import org.lwjgl.opengl.GL11;
    008
    009@SideOnly(Side.CLIENT)
    010public class GuiTextField extends Gui
    011{
    012    /**
    013     * Have the font renderer from GuiScreen to render the textbox text into the screen.
    014     */
    015    private final FontRenderer fontRenderer;
    016    private final int xPos;
    017    private final int yPos;
    018
    019    /** The width of this text field. */
    020    private final int width;
    021    private final int height;
    022
    023    /** Have the current text beign edited on the textbox. */
    024    private String text = "";
    025    private int maxStringLength = 32;
    026    private int cursorCounter;
    027    private boolean enableBackgroundDrawing = true;
    028
    029    /**
    030     * if true the textbox can lose focus by clicking elsewhere on the screen
    031     */
    032    private boolean canLoseFocus = true;
    033
    034    /**
    035     * If this value is true along isEnabled, keyTyped will process the keys.
    036     */
    037    private boolean isFocused = false;
    038
    039    /**
    040     * If this value is true along isFocused, keyTyped will process the keys.
    041     */
    042    private boolean isEnabled = true;
    043
    044    /**
    045     * The current character index that should be used as start of the rendered text.
    046     */
    047    private int lineScrollOffset = 0;
    048    private int cursorPosition = 0;
    049
    050    /** other selection position, maybe the same as the cursor */
    051    private int selectionEnd = 0;
    052    private int enabledColor = 14737632;
    053    private int disabledColor = 7368816;
    054
    055    /** True if this textbox is visible */
    056    private boolean visible = true;
    057
    058    public GuiTextField(FontRenderer par1FontRenderer, int par2, int par3, int par4, int par5)
    059    {
    060        this.fontRenderer = par1FontRenderer;
    061        this.xPos = par2;
    062        this.yPos = par3;
    063        this.width = par4;
    064        this.height = par5;
    065    }
    066
    067    /**
    068     * Increments the cursor counter
    069     */
    070    public void updateCursorCounter()
    071    {
    072        ++this.cursorCounter;
    073    }
    074
    075    /**
    076     * Sets the text of the textbox.
    077     */
    078    public void setText(String par1Str)
    079    {
    080        if (par1Str.length() > this.maxStringLength)
    081        {
    082            this.text = par1Str.substring(0, this.maxStringLength);
    083        }
    084        else
    085        {
    086            this.text = par1Str;
    087        }
    088
    089        this.setCursorPositionEnd();
    090    }
    091
    092    /**
    093     * Returns the text beign edited on the textbox.
    094     */
    095    public String getText()
    096    {
    097        return this.text;
    098    }
    099
    100    /**
    101     * @return returns the text between the cursor and selectionEnd
    102     */
    103    public String getSelectedtext()
    104    {
    105        int i = this.cursorPosition < this.selectionEnd ? this.cursorPosition : this.selectionEnd;
    106        int j = this.cursorPosition < this.selectionEnd ? this.selectionEnd : this.cursorPosition;
    107        return this.text.substring(i, j);
    108    }
    109
    110    /**
    111     * replaces selected text, or inserts text at the position on the cursor
    112     */
    113    public void writeText(String par1Str)
    114    {
    115        String s1 = "";
    116        String s2 = ChatAllowedCharacters.filerAllowedCharacters(par1Str);
    117        int i = this.cursorPosition < this.selectionEnd ? this.cursorPosition : this.selectionEnd;
    118        int j = this.cursorPosition < this.selectionEnd ? this.selectionEnd : this.cursorPosition;
    119        int k = this.maxStringLength - this.text.length() - (i - this.selectionEnd);
    120        boolean flag = false;
    121
    122        if (this.text.length() > 0)
    123        {
    124            s1 = s1 + this.text.substring(0, i);
    125        }
    126
    127        int l;
    128
    129        if (k < s2.length())
    130        {
    131            s1 = s1 + s2.substring(0, k);
    132            l = k;
    133        }
    134        else
    135        {
    136            s1 = s1 + s2;
    137            l = s2.length();
    138        }
    139
    140        if (this.text.length() > 0 && j < this.text.length())
    141        {
    142            s1 = s1 + this.text.substring(j);
    143        }
    144
    145        this.text = s1;
    146        this.moveCursorBy(i - this.selectionEnd + l);
    147    }
    148
    149    /**
    150     * Deletes the specified number of words starting at the cursor position. Negative numbers will delete words left of
    151     * the cursor.
    152     */
    153    public void deleteWords(int par1)
    154    {
    155        if (this.text.length() != 0)
    156        {
    157            if (this.selectionEnd != this.cursorPosition)
    158            {
    159                this.writeText("");
    160            }
    161            else
    162            {
    163                this.deleteFromCursor(this.getNthWordFromCursor(par1) - this.cursorPosition);
    164            }
    165        }
    166    }
    167
    168    /**
    169     * delete the selected text, otherwsie deletes characters from either side of the cursor. params: delete num
    170     */
    171    public void deleteFromCursor(int par1)
    172    {
    173        if (this.text.length() != 0)
    174        {
    175            if (this.selectionEnd != this.cursorPosition)
    176            {
    177                this.writeText("");
    178            }
    179            else
    180            {
    181                boolean flag = par1 < 0;
    182                int j = flag ? this.cursorPosition + par1 : this.cursorPosition;
    183                int k = flag ? this.cursorPosition : this.cursorPosition + par1;
    184                String s = "";
    185
    186                if (j >= 0)
    187                {
    188                    s = this.text.substring(0, j);
    189                }
    190
    191                if (k < this.text.length())
    192                {
    193                    s = s + this.text.substring(k);
    194                }
    195
    196                this.text = s;
    197
    198                if (flag)
    199                {
    200                    this.moveCursorBy(par1);
    201                }
    202            }
    203        }
    204    }
    205
    206    /**
    207     * see @getNthNextWordFromPos() params: N, position
    208     */
    209    public int getNthWordFromCursor(int par1)
    210    {
    211        return this.getNthWordFromPos(par1, this.getCursorPosition());
    212    }
    213
    214    /**
    215     * gets the position of the nth word. N may be negative, then it looks backwards. params: N, position
    216     */
    217    public int getNthWordFromPos(int par1, int par2)
    218    {
    219        return this.func_73798_a(par1, this.getCursorPosition(), true);
    220    }
    221
    222    public int func_73798_a(int par1, int par2, boolean par3)
    223    {
    224        int k = par2;
    225        boolean flag1 = par1 < 0;
    226        int l = Math.abs(par1);
    227
    228        for (int i1 = 0; i1 < l; ++i1)
    229        {
    230            if (flag1)
    231            {
    232                while (par3 && k > 0 && this.text.charAt(k - 1) == 32)
    233                {
    234                    --k;
    235                }
    236
    237                while (k > 0 && this.text.charAt(k - 1) != 32)
    238                {
    239                    --k;
    240                }
    241            }
    242            else
    243            {
    244                int j1 = this.text.length();
    245                k = this.text.indexOf(32, k);
    246
    247                if (k == -1)
    248                {
    249                    k = j1;
    250                }
    251                else
    252                {
    253                    while (par3 && k < j1 && this.text.charAt(k) == 32)
    254                    {
    255                        ++k;
    256                    }
    257                }
    258            }
    259        }
    260
    261        return k;
    262    }
    263
    264    /**
    265     * Moves the text cursor by a specified number of characters and clears the selection
    266     */
    267    public void moveCursorBy(int par1)
    268    {
    269        this.setCursorPosition(this.selectionEnd + par1);
    270    }
    271
    272    /**
    273     * sets the position of the cursor to the provided index
    274     */
    275    public void setCursorPosition(int par1)
    276    {
    277        this.cursorPosition = par1;
    278        int j = this.text.length();
    279
    280        if (this.cursorPosition < 0)
    281        {
    282            this.cursorPosition = 0;
    283        }
    284
    285        if (this.cursorPosition > j)
    286        {
    287            this.cursorPosition = j;
    288        }
    289
    290        this.setSelectionPos(this.cursorPosition);
    291    }
    292
    293    /**
    294     * sets the cursors position to the beginning
    295     */
    296    public void setCursorPositionZero()
    297    {
    298        this.setCursorPosition(0);
    299    }
    300
    301    /**
    302     * sets the cursors position to after the text
    303     */
    304    public void setCursorPositionEnd()
    305    {
    306        this.setCursorPosition(this.text.length());
    307    }
    308
    309    /**
    310     * Call this method from you GuiScreen to process the keys into textbox.
    311     */
    312    public boolean textboxKeyTyped(char par1, int par2)
    313    {
    314        if (this.isEnabled && this.isFocused)
    315        {
    316            switch (par1)
    317            {
    318                case 1:
    319                    this.setCursorPositionEnd();
    320                    this.setSelectionPos(0);
    321                    return true;
    322                case 3:
    323                    GuiScreen.setClipboardString(this.getSelectedtext());
    324                    return true;
    325                case 22:
    326                    this.writeText(GuiScreen.getClipboardString());
    327                    return true;
    328                case 24:
    329                    GuiScreen.setClipboardString(this.getSelectedtext());
    330                    this.writeText("");
    331                    return true;
    332                default:
    333                    switch (par2)
    334                    {
    335                        case 14:
    336                            if (GuiScreen.isCtrlKeyDown())
    337                            {
    338                                this.deleteWords(-1);
    339                            }
    340                            else
    341                            {
    342                                this.deleteFromCursor(-1);
    343                            }
    344
    345                            return true;
    346                        case 199:
    347                            if (GuiScreen.isShiftKeyDown())
    348                            {
    349                                this.setSelectionPos(0);
    350                            }
    351                            else
    352                            {
    353                                this.setCursorPositionZero();
    354                            }
    355
    356                            return true;
    357                        case 203:
    358                            if (GuiScreen.isShiftKeyDown())
    359                            {
    360                                if (GuiScreen.isCtrlKeyDown())
    361                                {
    362                                    this.setSelectionPos(this.getNthWordFromPos(-1, this.getSelectionEnd()));
    363                                }
    364                                else
    365                                {
    366                                    this.setSelectionPos(this.getSelectionEnd() - 1);
    367                                }
    368                            }
    369                            else if (GuiScreen.isCtrlKeyDown())
    370                            {
    371                                this.setCursorPosition(this.getNthWordFromCursor(-1));
    372                            }
    373                            else
    374                            {
    375                                this.moveCursorBy(-1);
    376                            }
    377
    378                            return true;
    379                        case 205:
    380                            if (GuiScreen.isShiftKeyDown())
    381                            {
    382                                if (GuiScreen.isCtrlKeyDown())
    383                                {
    384                                    this.setSelectionPos(this.getNthWordFromPos(1, this.getSelectionEnd()));
    385                                }
    386                                else
    387                                {
    388                                    this.setSelectionPos(this.getSelectionEnd() + 1);
    389                                }
    390                            }
    391                            else if (GuiScreen.isCtrlKeyDown())
    392                            {
    393                                this.setCursorPosition(this.getNthWordFromCursor(1));
    394                            }
    395                            else
    396                            {
    397                                this.moveCursorBy(1);
    398                            }
    399
    400                            return true;
    401                        case 207:
    402                            if (GuiScreen.isShiftKeyDown())
    403                            {
    404                                this.setSelectionPos(this.text.length());
    405                            }
    406                            else
    407                            {
    408                                this.setCursorPositionEnd();
    409                            }
    410
    411                            return true;
    412                        case 211:
    413                            if (GuiScreen.isCtrlKeyDown())
    414                            {
    415                                this.deleteWords(1);
    416                            }
    417                            else
    418                            {
    419                                this.deleteFromCursor(1);
    420                            }
    421
    422                            return true;
    423                        default:
    424                            if (ChatAllowedCharacters.isAllowedCharacter(par1))
    425                            {
    426                                this.writeText(Character.toString(par1));
    427                                return true;
    428                            }
    429                            else
    430                            {
    431                                return false;
    432                            }
    433                    }
    434            }
    435        }
    436        else
    437        {
    438            return false;
    439        }
    440    }
    441
    442    /**
    443     * Args: x, y, buttonClicked
    444     */
    445    public void mouseClicked(int par1, int par2, int par3)
    446    {
    447        boolean flag = par1 >= this.xPos && par1 < this.xPos + this.width && par2 >= this.yPos && par2 < this.yPos + this.height;
    448
    449        if (this.canLoseFocus)
    450        {
    451            this.setFocused(this.isEnabled && flag);
    452        }
    453
    454        if (this.isFocused && par3 == 0)
    455        {
    456            int l = par1 - this.xPos;
    457
    458            if (this.enableBackgroundDrawing)
    459            {
    460                l -= 4;
    461            }
    462
    463            String s = this.fontRenderer.trimStringToWidth(this.text.substring(this.lineScrollOffset), this.getWidth());
    464            this.setCursorPosition(this.fontRenderer.trimStringToWidth(s, l).length() + this.lineScrollOffset);
    465        }
    466    }
    467
    468    /**
    469     * Draws the textbox
    470     */
    471    public void drawTextBox()
    472    {
    473        if (this.getVisible())
    474        {
    475            if (this.getEnableBackgroundDrawing())
    476            {
    477                drawRect(this.xPos - 1, this.yPos - 1, this.xPos + this.width + 1, this.yPos + this.height + 1, -6250336);
    478                drawRect(this.xPos, this.yPos, this.xPos + this.width, this.yPos + this.height, -16777216);
    479            }
    480
    481            int i = this.isEnabled ? this.enabledColor : this.disabledColor;
    482            int j = this.cursorPosition - this.lineScrollOffset;
    483            int k = this.selectionEnd - this.lineScrollOffset;
    484            String s = this.fontRenderer.trimStringToWidth(this.text.substring(this.lineScrollOffset), this.getWidth());
    485            boolean flag = j >= 0 && j <= s.length();
    486            boolean flag1 = this.isFocused && this.cursorCounter / 6 % 2 == 0 && flag;
    487            int l = this.enableBackgroundDrawing ? this.xPos + 4 : this.xPos;
    488            int i1 = this.enableBackgroundDrawing ? this.yPos + (this.height - 8) / 2 : this.yPos;
    489            int j1 = l;
    490
    491            if (k > s.length())
    492            {
    493                k = s.length();
    494            }
    495
    496            if (s.length() > 0)
    497            {
    498                String s1 = flag ? s.substring(0, j) : s;
    499                j1 = this.fontRenderer.drawStringWithShadow(s1, l, i1, i);
    500            }
    501
    502            boolean flag2 = this.cursorPosition < this.text.length() || this.text.length() >= this.getMaxStringLength();
    503            int k1 = j1;
    504
    505            if (!flag)
    506            {
    507                k1 = j > 0 ? l + this.width : l;
    508            }
    509            else if (flag2)
    510            {
    511                k1 = j1 - 1;
    512                --j1;
    513            }
    514
    515            if (s.length() > 0 && flag && j < s.length())
    516            {
    517                this.fontRenderer.drawStringWithShadow(s.substring(j), j1, i1, i);
    518            }
    519
    520            if (flag1)
    521            {
    522                if (flag2)
    523                {
    524                    Gui.drawRect(k1, i1 - 1, k1 + 1, i1 + 1 + this.fontRenderer.FONT_HEIGHT, -3092272);
    525                }
    526                else
    527                {
    528                    this.fontRenderer.drawStringWithShadow("_", k1, i1, i);
    529                }
    530            }
    531
    532            if (k != j)
    533            {
    534                int l1 = l + this.fontRenderer.getStringWidth(s.substring(0, k));
    535                this.drawCursorVertical(k1, i1 - 1, l1 - 1, i1 + 1 + this.fontRenderer.FONT_HEIGHT);
    536            }
    537        }
    538    }
    539
    540    /**
    541     * draws the vertical line cursor in the textbox
    542     */
    543    private void drawCursorVertical(int par1, int par2, int par3, int par4)
    544    {
    545        int i1;
    546
    547        if (par1 < par3)
    548        {
    549            i1 = par1;
    550            par1 = par3;
    551            par3 = i1;
    552        }
    553
    554        if (par2 < par4)
    555        {
    556            i1 = par2;
    557            par2 = par4;
    558            par4 = i1;
    559        }
    560
    561        Tessellator tessellator = Tessellator.instance;
    562        GL11.glColor4f(0.0F, 0.0F, 255.0F, 255.0F);
    563        GL11.glDisable(GL11.GL_TEXTURE_2D);
    564        GL11.glEnable(GL11.GL_COLOR_LOGIC_OP);
    565        GL11.glLogicOp(GL11.GL_OR_REVERSE);
    566        tessellator.startDrawingQuads();
    567        tessellator.addVertex((double)par1, (double)par4, 0.0D);
    568        tessellator.addVertex((double)par3, (double)par4, 0.0D);
    569        tessellator.addVertex((double)par3, (double)par2, 0.0D);
    570        tessellator.addVertex((double)par1, (double)par2, 0.0D);
    571        tessellator.draw();
    572        GL11.glDisable(GL11.GL_COLOR_LOGIC_OP);
    573        GL11.glEnable(GL11.GL_TEXTURE_2D);
    574    }
    575
    576    public void setMaxStringLength(int par1)
    577    {
    578        this.maxStringLength = par1;
    579
    580        if (this.text.length() > par1)
    581        {
    582            this.text = this.text.substring(0, par1);
    583        }
    584    }
    585
    586    /**
    587     * returns the maximum number of character that can be contained in this textbox
    588     */
    589    public int getMaxStringLength()
    590    {
    591        return this.maxStringLength;
    592    }
    593
    594    /**
    595     * returns the current position of the cursor
    596     */
    597    public int getCursorPosition()
    598    {
    599        return this.cursorPosition;
    600    }
    601
    602    /**
    603     * get enable drawing background and outline
    604     */
    605    public boolean getEnableBackgroundDrawing()
    606    {
    607        return this.enableBackgroundDrawing;
    608    }
    609
    610    /**
    611     * enable drawing background and outline
    612     */
    613    public void setEnableBackgroundDrawing(boolean par1)
    614    {
    615        this.enableBackgroundDrawing = par1;
    616    }
    617
    618    /**
    619     * Sets the text colour for this textbox (disabled text will not use this colour)
    620     */
    621    public void setTextColor(int par1)
    622    {
    623        this.enabledColor = par1;
    624    }
    625
    626    public void func_82266_h(int par1)
    627    {
    628        this.disabledColor = par1;
    629    }
    630
    631    /**
    632     * setter for the focused field
    633     */
    634    public void setFocused(boolean par1)
    635    {
    636        if (par1 && !this.isFocused)
    637        {
    638            this.cursorCounter = 0;
    639        }
    640
    641        this.isFocused = par1;
    642    }
    643
    644    /**
    645     * getter for the focused field
    646     */
    647    public boolean isFocused()
    648    {
    649        return this.isFocused;
    650    }
    651
    652    public void func_82265_c(boolean par1)
    653    {
    654        this.isEnabled = par1;
    655    }
    656
    657    /**
    658     * the side of the selection that is not the cursor, maye be the same as the cursor
    659     */
    660    public int getSelectionEnd()
    661    {
    662        return this.selectionEnd;
    663    }
    664
    665    /**
    666     * returns the width of the textbox depending on if the the box is enabled
    667     */
    668    public int getWidth()
    669    {
    670        return this.getEnableBackgroundDrawing() ? this.width - 8 : this.width;
    671    }
    672
    673    /**
    674     * Sets the position of the selection anchor (i.e. position the selection was started at)
    675     */
    676    public void setSelectionPos(int par1)
    677    {
    678        int j = this.text.length();
    679
    680        if (par1 > j)
    681        {
    682            par1 = j;
    683        }
    684
    685        if (par1 < 0)
    686        {
    687            par1 = 0;
    688        }
    689
    690        this.selectionEnd = par1;
    691
    692        if (this.fontRenderer != null)
    693        {
    694            if (this.lineScrollOffset > j)
    695            {
    696                this.lineScrollOffset = j;
    697            }
    698
    699            int k = this.getWidth();
    700            String s = this.fontRenderer.trimStringToWidth(this.text.substring(this.lineScrollOffset), k);
    701            int l = s.length() + this.lineScrollOffset;
    702
    703            if (par1 == this.lineScrollOffset)
    704            {
    705                this.lineScrollOffset -= this.fontRenderer.trimStringToWidth(this.text, k, true).length();
    706            }
    707
    708            if (par1 > l)
    709            {
    710                this.lineScrollOffset += par1 - l;
    711            }
    712            else if (par1 <= this.lineScrollOffset)
    713            {
    714                this.lineScrollOffset -= this.lineScrollOffset - par1;
    715            }
    716
    717            if (this.lineScrollOffset < 0)
    718            {
    719                this.lineScrollOffset = 0;
    720            }
    721
    722            if (this.lineScrollOffset > j)
    723            {
    724                this.lineScrollOffset = j;
    725            }
    726        }
    727    }
    728
    729    /**
    730     * if true the textbox can lose focus by clicking elsewhere on the screen
    731     */
    732    public void setCanLoseFocus(boolean par1)
    733    {
    734        this.canLoseFocus = par1;
    735    }
    736
    737    /**
    738     * @return {@code true} if this textbox is visible
    739     */
    740    public boolean getVisible()
    741    {
    742        return this.visible;
    743    }
    744
    745    /**
    746     * Sets whether or not this textbox is visible
    747     */
    748    public void setVisible(boolean par1)
    749    {
    750        this.visible = par1;
    751    }
    752}