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}