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 }