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}