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