Changeset 1101
- Timestamp:
- 05/10/18 16:04:37 (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/expeditee/items/Text.java
r1095 r1101 19 19 package org.expeditee.items; 20 20 21 import java.awt.BasicStroke;22 import java.awt.Color;23 import java.awt.Dimension;24 import java.awt.Font;25 import java.awt.GradientPaint;26 import java.awt.Graphics2D;27 import java.awt.GraphicsEnvironment;28 import java.awt.Point;29 import java.awt.Polygon;30 import java.awt.Rectangle;31 import java.awt.Shape;32 import java.awt.Stroke;33 import java.awt.event.KeyEvent;34 import java.awt.event.MouseEvent;35 import java.awt.font.FontRenderContext;36 import java.awt.font.LineBreakMeasurer;37 import java.awt.font.TextAttribute;38 import java.awt.font.TextHitInfo;39 import java.awt.font.TextLayout;40 import java.awt.geom.AffineTransform;41 import java.awt.geom.Point2D;42 import java.awt.geom.Rectangle2D;43 21 import java.io.File; 44 22 45 import java.text.AttributedString;46 23 import java.util.ArrayList; 47 24 import java.util.Collection; … … 52 29 import java.util.StringTokenizer; 53 30 31 import org.expeditee.core.Colour; 32 import org.expeditee.core.Dimension; 33 import org.expeditee.core.Fill; 34 import org.expeditee.core.Font; 35 import org.expeditee.core.GradientFill; 36 import org.expeditee.core.Point; 37 import org.expeditee.core.Range; 38 import org.expeditee.core.Stroke; 39 import org.expeditee.core.TextHitInfo; 40 import org.expeditee.core.TextLayout; 41 import org.expeditee.core.bounds.AxisAlignedBoxBounds; 42 import org.expeditee.core.bounds.CombinationBoxBounds; 43 import org.expeditee.core.bounds.PolygonBounds; 44 import org.expeditee.gio.EcosystemManager; 45 import org.expeditee.gio.GraphicsManager; 46 import org.expeditee.gio.gesture.StandardGestureActions; 54 47 import org.expeditee.gui.AttributeValuePair; 55 import org.expeditee.gui.Display IO;48 import org.expeditee.gui.DisplayController; 56 49 import org.expeditee.gui.Frame; 57 import org.expeditee.gui.FrameGraphics;58 50 import org.expeditee.gui.FrameIO; 59 import org.expeditee.gui.FrameKeyboardActions;60 import org.expeditee.gui.FrameMouseActions;61 51 import org.expeditee.gui.FrameUtils; 62 52 import org.expeditee.gui.FreeItems; 53 import org.expeditee.gui.MessageBay; 63 54 import org.expeditee.items.MagneticConstraint.MagneticConstraints; 64 55 import org.expeditee.math.ExpediteeJEP; 65 56 import org.expeditee.settings.experimental.ExperimentalFeatures; 57 import org.expeditee.stats.Formatter; 66 58 import org.nfunk.jep.Node; 67 59 … … 75 67 public class Text extends Item { 76 68 private static final int ADJUST_WIDTH_THRESHOLD = 200; 69 70 public static final char DELETE_CHARACTER = 0x7F; 71 72 public static final char BACKSPACE_CHARACTER = '\b'; 73 74 public static final char TAB_CHARACTER = '\t'; 75 76 public static final char ESC_CHARACTER = 0x1B; 77 77 78 78 public static String LINE_SEPARATOR = System.getProperty("line.separator"); … … 97 97 public static final String FRAME_NAME_SEPARATOR = " on frame "; 98 98 99 /** 100 * The default font used to display text items if no font is specified. 101 */ 99 /** The default font used to display text items if no font is specified. */ 102 100 public static final String DEFAULT_FONT = "Serif-Plain-18"; 103 101 104 public static final Colo r DEFAULT_COLOR = Color.BLACK;102 public static final Colour DEFAULT_COLOR = Colour.BLACK; 105 103 106 104 public static final int MINIMUM_RANGED_CHARS = 2; … … 128 126 public static final int PAGE_UP = 8; 129 127 130 /* 128 /** 131 129 * Set the width to be IMPLICIT, but as wide as possible, a negative width value 132 130 * is one that is implicitly set by the system... a positive value is one 133 131 * explicitly set by the user. 134 132 */ 135 private Integer _maxWidth = Integer.MIN_VALUE + 1; 133 /** 134 * The maximum allowable width of the Text item. Actual width may be less than this 135 * value, subject to text wrapping. Negative values indicate the width was implicitly 136 * set by the system, positive values indicate explicit setting by the user. Initially 137 * set to be as wide as possible. 138 */ 139 private Integer _maxWidth = -Integer.MAX_VALUE; 136 140 137 141 private Justification _justification = Justification.left; … … 150 154 private int _selectionEnd = -1; 151 155 156 /** Keeps track of the last Text item selected. */ 157 private static Text _lastSelected = null; 158 159 // Range selection colours 160 /** Colour of selected range when for selecting text. */ 161 public static final Colour RANGE_SELECT_COLOUR = Colour.FromRGB255(255, 160, 160); 162 /** Colour of selected range when for cutting text. */ 163 public static final Colour RANGE_CUT_COLOUR = Colour.FromRGB255(160, 255, 160); 164 /** Colour of selected range when for copying text. */ 165 public static final Colour RANGE_COPY_COLOUR = Colour.FromRGB255(160, 160, 255); 166 /** Colour of selected range when for deleting text. */ 167 public static final Colour RANGE_DELETE_COLOUR = Colour.FromRGB255(235, 235, 140); 168 169 /** The colour to draw range selections in. */ 170 private Colour _selectionColour = RANGE_SELECT_COLOUR; 171 152 172 // whether autowrap is on/off for this item 153 173 protected boolean _autoWrap = false; … … 158 178 private List<TextLayout> _textLayouts = new LinkedList<TextLayout>(); 159 179 160 private List<Integer> _lineOffsets = new LinkedList<Integer>();161 162 private FontRenderContext frc = null;163 private LineBreakMeasurer _lineBreaker = null;164 165 180 // The font to display this text in 166 181 private Font _font; 167 182 168 protected static void InitFontFamily(GraphicsEnvironment ge, File fontFamilyDir) { 183 protected static void InitFontFamily(File fontFamilyDir) 184 { 169 185 File[] fontFiles = fontFamilyDir.listFiles(); 170 186 … … 183 199 184 200 try { 185 Font font = Font.createFont(Font.TRUETYPE_FONT, fontFile); 186 187 boolean registered_status_ok = ge.registerFont(font); 188 189 if (registered_status_ok) { 190 191 String font_family = font.getFamily(); 192 if (!FONT_WHEEL_ADDITIONAL_LOOKUP.containsKey(font_family)) { 201 Font font = EcosystemManager.getFontManager().registerFontFile(fontFile); 202 203 if (font != null) { 204 205 String font_family = font.getFamilyName(); 206 if (!FONT_WHEEL_ADDITIONAL_LOOKUP.containsKey(font_family)) { 193 207 194 208 if (FONT_WHEEL_ADDITIONAL_LOOKUP.size() > 0) { 195 209 System.out.print(", "); 196 210 } 197 System.out.print("'" + font .getFamily()+ "'");211 System.out.print("'" + font_family + "'"); 198 212 199 213 FONT_WHEEL_ADDITIONAL_LOOKUP.put(font_family, font); 200 214 215 /* 201 216 int cdut = font.canDisplayUpTo("09AZaz"); 202 217 if (cdut >= 0) { … … 205 220 System.out.println(" [Non-ASCII font]"); 206 221 } 222 */ 207 223 System.out.flush(); 208 224 } 209 225 226 System.out.print("'" + font_family + "'"); 210 227 } else { 211 228 System.err.println("Error: Failed to add custom True-Type Font file: " + fontFile); … … 221 238 public static void InitFonts() { 222 239 223 GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 224 225 if (ge != null) { 226 227 File fontDirectory = new File(FrameIO.FONT_PATH); 228 if (fontDirectory != null) { 229 File[] fontFamilyDirs = fontDirectory.listFiles(); 230 if (fontFamilyDirs != null) { 231 232 if (fontFamilyDirs.length > 0) { 233 System.out.println("Loading custom fonts:"); 240 File fontDirectory = new File(FrameIO.FONT_PATH); 241 if (fontDirectory != null) { 242 File[] fontFamilyDirs = fontDirectory.listFiles(); 243 if (fontFamilyDirs != null) { 244 245 if (fontFamilyDirs.length > 0) { 246 System.out.println("Loading custom fonts:"); 247 } 248 249 for (File fontFamilyDir : fontFamilyDirs) { 250 if (fontFamilyDir.isDirectory()) { 251 InitFontFamily(fontFamilyDir); 234 252 } 235 236 boolean first_item = true;237 for (File fontFamilyDir : fontFamilyDirs) {238 if (fontFamilyDir.isDirectory()) {239 InitFontFamily(ge, fontFamilyDir);240 }241 }242 System.out.println();243 253 } 244 } 245 } else { 246 System.err.println("No graphics environment detected. Skipping the loading of the custom fonts"); 254 System.out.println(); 255 } 247 256 } 248 257 } … … 359 368 } 360 369 361 public Text(int i, String string, Colo r foreground, Color background) {370 public Text(int i, String string, Colour foreground, Colour background) { 362 371 this(i, string); 363 372 this.setColor(foreground); … … 366 375 367 376 /** 377 <<<<<<< .mine 378 * Sets the maximum width of this Text item when justification is used. 379 * passing in 0 or -1 means there is no maximum width 380 ||||||| .r1094 381 * Sets the maximum width of this Text item when justifcation is used. 382 * passing in 0 or -1 means there is no maximum width 383 ======= 368 384 * Sets the maximum width of this Text item when justifcation is used. passing 369 385 * in 0 or -1 means there is no maximum width 386 >>>>>>> .r1100 370 387 * 371 388 * @param width … … 379 396 if (width == null) { 380 397 setJustification(Justification.left); 381 setRightMargin( FrameGraphics.getMaxFrameSize().width, false);398 setRightMargin(DisplayController.getFramePaintArea().getWidth(), false); 382 399 return; 383 400 } … … 389 406 390 407 /** 408 <<<<<<< .mine 409 * Returns the maximum width of this Text item when justification is used. If 410 * the width is negative, it means no explicit width has been set 411 ||||||| .r1094 412 * Returns the maximum width of this Text item when justifcation is used. If 413 * the width is negative, it means no explicit width has been set 414 ======= 391 415 * Returns the maximum width of this Text item when justifcation is used. If the 392 416 * width is negative, it means no explicit width has been set 417 >>>>>>> .r1100 393 418 * 394 419 * @return The maximum width of this Text item when justification is used 395 420 */ 396 421 @Override 397 public Integer getWidth() { 398 if (_maxWidth == null || _maxWidth <= 0) 399 return null; 422 public Integer getWidth() 423 { 424 if (_maxWidth == null || _maxWidth <= 0) return null; 425 400 426 return _maxWidth; 401 427 } … … 410 436 411 437 @Override 412 public Colo r getHighlightColor() {413 if (_highlightColo r.equals(getPaintBackgroundColor()))438 public Colour getHighlightColor() { 439 if (_highlightColour.equals(getPaintBackgroundColor())) 414 440 return ALTERNATE_HIGHLIGHT; 415 return _highlightColo r;441 return _highlightColour; 416 442 } 417 443 … … 441 467 * justification. 442 468 * 469 * TODO: Why return null when justification is set to left? cts16 470 * 443 471 * @return The justification of this Text item 444 472 */ 445 public Justification getJustification() { 446 if (_justification == null || _justification.equals(Justification.left)) 447 return null; 473 public Justification getJustification() 474 { 475 if (_justification == null || _justification.equals(Justification.left)) return null; 476 448 477 return _justification; 449 478 } 450 479 480 /** 481 * Gets the distance from the left of the bounding box that the given layout 482 * should be shifted to justify it. 483 * 484 * @param layout 485 * The line of text to calculate the justification offset for. 486 * 487 * @return 488 * The distance to shift the line of text by. 489 */ 451 490 private int getJustOffset(TextLayout layout) { 452 491 if (getJustification() == Justification.center) … … 519 558 * The String to insert. 520 559 */ 521 public void prependText(String text) { 522 560 public void prependText(String text) 561 { 562 invalidateAll(); 523 563 _text.insert(0, text); 524 564 rebuild(false); 565 invalidateAll(); 525 566 } 526 567 … … 534 575 public void removeText(String text) { 535 576 if (_text.length() > 0 && _text.indexOf(text) == 0) { 536 // Need the invalidate all for dateStamp toggling537 577 invalidateAll(); 538 578 _text.delete(0, text.length()); 579 invalidateAll(); 539 580 } 540 581 … … 544 585 int length = _text.length(); 545 586 if (length > 0) { 546 // invalidateAll();547 587 int pos = _text.indexOf(textToRemove); 548 588 int textToRemoveLength = textToRemove.length(); 549 589 if (pos + textToRemoveLength == length) { 590 // Need the invalidate all for dateStamp toggling 591 invalidateAll(); 550 592 _text.delete(pos, length); 593 invalidateAll(); 551 594 } 552 595 } … … 561 604 */ 562 605 public void appendText(String text) { 606 invalidateAll(); 563 607 _text.append(text); 564 608 rebuild(false); 609 invalidateAll(); 565 610 } 566 611 … … 614 659 * The Y position to insert the Strings at. 615 660 */ 616 public Point 2D.FloatinsertChar(char ch, float mouseX, float mouseY) {661 public Point insertChar(char ch, float mouseX, float mouseY) { 617 662 if (ch != '\t') /* && ch != '\n' */ 618 663 return insertText("" + ch, mouseX, mouseY); … … 641 686 } 642 687 643 public Point 2D.FloatgetLineEndPosition(float mouseY) {688 public Point getLineEndPosition(float mouseY) { 644 689 return getEdgePosition(getLinePosition(mouseY), false); 645 690 } 646 691 647 public Point 2D.FloatgetLineStartPosition(float mouseY) {692 public Point getLineStartPosition(float mouseY) { 648 693 return getEdgePosition(getLinePosition(mouseY), true); 649 694 } 650 695 651 public Point 2D.FloatgetParagraphEndPosition() {696 public Point getParagraphEndPosition() { 652 697 return getEdgePosition(_textLayouts.size() - 1, false); 653 698 } 654 699 655 public Point 2D.FloatgetParagraphStartPosition() {700 public Point getParagraphStartPosition() { 656 701 return getEdgePosition(0, true); 657 702 } 658 703 659 private Point 2D.FloatgetEdgePosition(int line, boolean start) {704 private Point getEdgePosition(int line, boolean start) { 660 705 // if there is no text yet, or the line is invalid 661 706 if (_text == null || _text.length() == 0 || line < 0 || line > _textLayouts.size() - 1) 662 return new Point 2D.Float(getX(), getY());707 return new Point(getX(), getY()); 663 708 664 709 TextLayout last = _textLayouts.get(line); … … 674 719 675 720 float x = getX() + caret[0] + getJustOffset(last); 676 x = Math.min(x, (getX() - Item.MARGIN_RIGHT - (2 * getGravity()) + getBoundsWidth())); 677 return new Point2D.Float(x, getY() + y + caret[1]); 678 } 679 721 722 x = Math.min( 723 x, 724 (getX() - Item.MARGIN_RIGHT - (2 * getGravity()) + getBoundsWidth()) 725 ); 726 return new Point((int) x, (int) (getY() + y + caret[1])); 727 } 728 729 public void setSelectionStart(Point p) 730 { 731 setSelectionStart(p.x, p.y); 732 } 733 680 734 public void setSelectionStart(float mouseX, float mouseY) { 681 735 // determine what line is being pointed to … … 684 738 // get the character being pointed to 685 739 TextHitInfo hit = getCharPosition(line, mouseX); 686 _selectionStart = hit.getInsertionIndex() + _lineOffsets.get(line); 687 invalidateAll(); 740 _selectionStart = hit.getInsertionIndex() + _textLayouts.get(line).getStartCharIndex(); 741 742 // Clear the last selected 743 updateLastSelected(); 744 745 invalidateAll(); 746 } 747 748 public void setSelectionEnd(Point p) 749 { 750 setSelectionEnd(p.x, p.y); 688 751 } 689 752 … … 694 757 // get the character being pointed to 695 758 TextHitInfo hit = getCharPosition(line, mouseX); 696 _selectionEnd = hit.getInsertionIndex() + _lineOffsets.get(line); 759 _selectionEnd = hit.getInsertionIndex() + _textLayouts.get(line).getStartCharIndex(); 760 761 // Clear the last selected 762 updateLastSelected(); 763 697 764 invalidateAll(); 698 765 } … … 707 774 _selectionEnd = -1; 708 775 invalidateAll(); 776 } 777 778 /** Makes sure only one text has a selection at a time. */ 779 public void updateLastSelected() 780 { 781 if (_lastSelected != this) { 782 if (_lastSelected != null) _lastSelected.clearSelection(); 783 _lastSelected = this; 784 } 709 785 } 710 786 … … 784 860 * @return The new location that the mouse cursor should be moved to 785 861 */ 786 public Point2D.Float insertText(String text, float mouseX, float mouseY) { 787 final Point2D.Float newPos = insertText(text, mouseX, mouseY, -1); 862 public Point insertText(String text, float mouseX, float mouseY) 863 { 864 final Point newPos = insertText(text, mouseX, mouseY, -1); 788 865 return newPos; 789 866 } 790 867 791 public Point2D.Float insertText(String text, float mouseX, float mouseY, int insertPos) { 868 public Point insertText(String text, float mouseX, float mouseY, int insertPos) 869 { 792 870 TextHitInfo hit; 793 871 TextLayout current = null; 794 int line ;872 int lineIndex; 795 873 796 874 invalidateAll(); … … 798 876 // check for empty string 799 877 if (text == null || text.length() == 0) 800 return new Point 2D.Float(mouseX,mouseY);878 return new Point((int) mouseX, (int) mouseY); 801 879 802 880 // if there is no text yet … … 808 886 current = _textLayouts.get(0); 809 887 hit = current.getNextRightHit(0); 810 line = 0;888 lineIndex = 0; 811 889 812 890 // otherwise, we are inserting text … … 814 892 clearCache(); 815 893 // determine what line is being pointed to 816 line = getLinePosition(mouseY);894 lineIndex = getLinePosition(mouseY); 817 895 818 896 // get the character being pointed to 819 hit = getCharPosition(line , mouseX);820 821 int pos = hit.getInsertionIndex() + _lineOffsets.get(line);822 823 if (line > 0 && hit.getInsertionIndex() == 0) {897 hit = getCharPosition(lineIndex, mouseX); 898 899 int insertionIndex = hit.getInsertionIndex() + _textLayouts.get(lineIndex).getStartCharIndex(); 900 901 if (lineIndex > 0 && hit.getInsertionIndex() == 0) { 824 902 // Only move forward a char if the line begins with a hard line 825 903 // break... not a soft line break 826 if (_text.charAt( pos) == '\n') {827 pos++;904 if (_text.charAt(insertionIndex) == '\n') { 905 insertionIndex++; 828 906 } 829 907 } 830 908 831 909 if (insertPos < 0) 832 insertPos = pos;910 insertPos = insertionIndex; 833 911 834 912 // if this is a backspace key 835 if (text.charAt(0) == KeyEvent.VK_BACK_SPACE) {913 if (text.charAt(0) == '\b') { 836 914 if (hasSelection()) { 837 pos = deleteSelection(pos);915 insertionIndex = deleteSelection(insertionIndex); 838 916 } else if (insertPos > 0) { 839 917 deleteChar(insertPos - 1); 840 if ( pos> 0)841 pos--;918 if (insertionIndex > 0) 919 insertionIndex--; 842 920 } 843 844 } else if (text.charAt(0) == KeyEvent.VK_DELETE) {921 // if this is a delete key 922 } else if (text.charAt(0) == (char) 0x7F) { 845 923 if (hasSelection()) { 846 pos = deleteSelection(pos);924 insertionIndex = deleteSelection(insertionIndex); 847 925 } else if (insertPos < _text.length()) { 848 926 deleteChar(insertPos); 849 927 } 850 851 } else if (text.charAt(0) == KeyEvent.VK_TAB) {928 // this is a tab 929 } else if (text.charAt(0) == '\t') { 852 930 // Text length greater than 1 signals a backwards tab 853 931 if (text.length() > 1) { … … 867 945 if (_text.length() > 0 && Character.isSpaceChar(_text.charAt(0))) { 868 946 deleteChar(0); 869 pos--;947 insertionIndex--; 870 948 } else 871 949 break; 872 950 } 873 _lineBreaker = null;874 951 } else { 875 952 // / Find the first non space char to see if its a bullet … … 887 964 // Insert the spacing at the start 888 965 insertString(TAB_STRING, 0); 889 pos+= TAB_STRING.length();966 insertionIndex += TAB_STRING.length(); 890 967 } 891 968 // this is a normal insert 892 969 } else { 893 970 insertString(text, insertPos); 894 pos+= text.length();971 insertionIndex += text.length(); 895 972 } 896 973 897 974 if (_text.length() == 0) { 898 975 rebuild(false); 899 return new Point 2D.Float(this._x,this._y);900 } 901 902 int newLine = line ;976 return new Point((int) this._x, (int) this._y); 977 } 978 979 int newLine = lineIndex; 903 980 904 981 // if a rebuild is required … … 906 983 907 984 // determine the new position the cursor should have 908 for (int i = 1; i < _lineOffsets.size(); i++) {909 if (_ lineOffsets.get(i) >= pos) {910 newLine = i - 1;985 for (int i = 0; i < _textLayouts.size(); i++) { 986 if (_textLayouts.get(i).getEndCharIndex() + 1 >= insertionIndex) { 987 newLine = i; 911 988 break; 912 989 } … … 914 991 915 992 current = _textLayouts.get(newLine); 916 pos -= _lineOffsets.get(newLine);917 918 if (newLine == line ) {919 if ( pos> 0)920 hit = current.getNextRightHit( pos- 1);993 insertionIndex -= current.getStartCharIndex(); 994 995 if (newLine == lineIndex) { 996 if (insertionIndex > 0) 997 hit = current.getNextRightHit(insertionIndex - 1); 921 998 else 922 999 hit = current.getNextLeftHit(1); 923 } else if (newLine < line ) {924 hit = current.getNextRightHit( pos- 1);1000 } else if (newLine < lineIndex) { 1001 hit = current.getNextRightHit(insertionIndex - 1); 925 1002 } else { 926 hit = current.getNextRightHit( pos- 1);927 } 928 929 line = newLine;1003 hit = current.getNextRightHit(insertionIndex - 1); 1004 } 1005 1006 lineIndex = newLine; 930 1007 } 931 1008 932 1009 // move the cursor to the new location 933 1010 float[] caret = current.getCaretInfo(hit); 934 float y = getLineDrop(current) * line ;1011 float y = getLineDrop(current) * lineIndex; 935 1012 936 1013 float x = getX() + caret[0] + getJustOffset(current); 937 x = Math.min(x, (getX() - Item.MARGIN_RIGHT - (2 * getGravity()) + getBoundsWidth())); 938 939 invalidateAll(); 940 941 return new Point2D.Float(Math.round(x), Math.round(getY() + y + caret[1])); 1014 x = Math.min( 1015 x, 1016 (getX() - Item.MARGIN_RIGHT - (2 * getGravity()) + getBoundsWidth()) 1017 ); 1018 1019 invalidateAll(); 1020 1021 return new Point(Math.round(x), Math.round(getY() + y + caret[1])); 942 1022 } 943 1023 … … 963 1043 } 964 1044 965 public Point 2D.Float moveCursor(int direction, float mouseX, float mouseY, boolean setSelection,966 boolean wholeWord){1045 public Point moveCursor(int direction, float mouseX, float mouseY, boolean setSelection, boolean wholeWord) 1046 { 967 1047 if (setSelection) { 968 1048 if (!hasSelection()) { … … 973 1053 } 974 1054 975 Point 2D.FloatresultPos = null;1055 Point resultPos = null; 976 1056 977 1057 // check for home or end keys … … 996 1076 // if there is no text yet 997 1077 if (_text == null || _text.length() == 0) { 998 return new Point 2D.Float(mouseX,mouseY);1078 return new Point((int) mouseX, (int) mouseY); 999 1079 // otherwise, move the cursor 1000 1080 } else { … … 1024 1104 // Keep going if the char to the left is a 1025 1105 // letterOrDigit 1026 prevChar = _text.charAt(hit.getInsertionIndex() - 1 + _ lineOffsets.get(line));1106 prevChar = _text.charAt(hit.getInsertionIndex() - 1 + _textLayouts.get(line).getStartCharIndex()); 1027 1107 } while (wholeWord && Character.isLetterOrDigit(prevChar)); 1028 // TODO Go to the start of the word instead of before 1029 // the word 1030 char nextChar = _text.charAt(hit.getInsertionIndex() + _lineOffsets.get(line)); 1031 /* 1032 * This takes care of hard line break in 1033 */ 1108 1109 // TODO Go to the start of the word instead of before the word 1110 char nextChar = _text.charAt(hit.getInsertionIndex() + _textLayouts.get(line).getStartCharIndex()); 1111 1112 // This takes care of hard line break in 1034 1113 if (line > 0 && nextChar == '\n') { 1035 1114 line--; 1036 hit = _textLayouts.get(line) 1037 .getNextRightHit(_textLayouts.get(line).getCharacterCount() - 1); 1115 hit = _textLayouts.get(line).getNextRightHit(_textLayouts.get(line).getCharacterCount() - 1); 1038 1116 } 1039 // This takes care of soft line breaks. 1117 1118 // This takes care of soft line breaks. 1040 1119 } else if (line > 0) { 1041 1120 line--; 1042 1121 hit = _textLayouts.get(line).getNextRightHit(_textLayouts.get(line).getCharacterCount() - 1); 1043 /* 1044 * Skip the spaces at the end of a line with soft linebreak 1045 */ 1046 while (hit.getCharIndex() > 0 1047 && _text.charAt(_lineOffsets.get(line) + hit.getCharIndex() - 1) == ' ') { 1122 1123 // Skip the spaces at the end of a line with soft linebreak 1124 while (hit.getCharIndex() > 0 && _text.charAt(_textLayouts.get(line).getStartCharIndex() + hit.getCharIndex() - 1) == ' ') { 1048 1125 hit = _textLayouts.get(line).getNextLeftHit(hit); 1049 1126 } … … 1053 1130 hit = _textLayouts.get(line).getNextRightHit(hit); 1054 1131 // Skip whole word if needs be 1055 while (wholeWord && hit.getCharIndex() > 0 1056 && hit.getCharIndex() < _textLayouts.get(line).getCharacterCount() && Character 1057 .isLetterOrDigit(_text.charAt(_lineOffsets.get(line) + hit.getCharIndex() - 1))) 1132 while (wholeWord 1133 && hit.getCharIndex() > 0 1134 && hit.getCharIndex() < _textLayouts.get(line).getCharacterCount() 1135 && Character.isLetterOrDigit(_text.charAt(_textLayouts.get(line).getStartCharIndex() + hit.getCharIndex() - 1))) 1136 { 1058 1137 hit = _textLayouts.get(line).getNextRightHit(hit); 1138 } 1059 1139 } else if (line < _textLayouts.size() - 1) { 1060 1140 line++; … … 1069 1149 float y = getLineDrop(current) * line; 1070 1150 1071 resultPos = new Point2D.Float(getX() + caret[0] + getJustOffset(current), getY() + y + caret[1]); 1151 resultPos = new Point((int) (getX() + caret[0] + getJustOffset(current)), (int) (getY() + y + caret[1])); 1152 1072 1153 break; 1073 1154 } 1074 if (setSelection) 1075 setSelectionEnd(resultPos.x, resultPos.y); 1155 1156 if (setSelection) setSelectionEnd(resultPos.x, resultPos.y); 1157 1076 1158 return resultPos; 1077 1159 } … … 1098 1180 } 1099 1181 1182 /** 1183 * Gets the index into the <code>_textLayout</code> list which corresponds to the line 1184 * covered by the given <code>mouseY</code> position. 1185 * 1186 * @param mouseY 1187 * The y-coordinate to test for line coverage. 1188 * 1189 * @return 1190 * The line which occupies the given y-coordinate, or the last line if none do. 1191 */ 1100 1192 public int getLinePosition(float mouseY) { 1101 1193 mouseY += getOffset().y; … … 1105 1197 for (TextLayout text : _textLayouts) { 1106 1198 // calculate X to ensure it is in the shape 1107 Rectangle2D bounds = text.getLogicalHighlightShape(0, text.getCharacterCount()).getBounds2D(); 1108 1109 if (bounds.getWidth() < 1) 1110 bounds.setRect(bounds.getMinX(), bounds.getMinY(), 10, bounds.getHeight()); 1111 1112 double x = bounds.getCenterX(); 1113 1114 if (bounds.contains(x, mouseY - getY() - (y - getY()))) 1199 AxisAlignedBoxBounds bounds = text.getLogicalHighlightShape(0, text.getCharacterCount()); 1200 1201 if (bounds.getWidth() < 1) bounds.getSize().width = 10; 1202 1203 double x = bounds.getCentreX(); 1204 1205 if (bounds.contains((int) x, (int) (mouseY - y))) 1115 1206 return _textLayouts.indexOf(text); 1116 1207 1117 1208 // check if the cursor is between lines 1118 if (mouseY - getY() - (y - getY())< bounds.getMinY())1209 if (mouseY - y < bounds.getMinY()) 1119 1210 return Math.max(0, _textLayouts.indexOf(text) - 1); 1120 1211 … … 1131 1222 * The Font to display the Text of this Item in. 1132 1223 */ 1133 public void setFont(Font font) { 1224 public void setFont(Font font) 1225 { 1134 1226 invalidateAll(); 1135 1227 // all decoding occurs in the Utils class … … 1142 1234 1143 1235 /** 1144 * Returns the Font that this Text is currently using when painting to the 1145 * screen 1146 * 1147 * @return The Font used to display this Text on the screen. 1236 * Gets the font of this text item. 1237 * 1238 * @return The Font assigned to this text item, or null if none is assigned. 1148 1239 */ 1149 1240 public Font getFont() { … … 1151 1242 } 1152 1243 1153 public Font getPaintFont() { 1154 if (getFont() == null) 1155 return Font.decode(DEFAULT_FONT); 1244 /** 1245 * Gets the font that should be used to paint this text item during drawing. 1246 * 1247 * @return The font to paint the text item with. 1248 */ 1249 public Font getPaintFont() 1250 { 1251 if (getFont() == null) return EcosystemManager.getFontManager().getDefaultFont(); 1156 1252 1157 1253 return getFont(); … … 1159 1255 1160 1256 public String getFamily() { 1161 return getPaintFont().getFamily ();1162 } 1163 1164 public void setFamily(String newFamily) {1165 String toDecode = newFamily + "-" + getFontStyle() + "-" + Math.round(getSize());1166 setFont( Font.decode(toDecode));1257 return getPaintFont().getFamilyName(); 1258 } 1259 1260 public void setFamily(String newFamily) 1261 { 1262 setFont(new Font(newFamily, getFontStyle(), Math.round(getSize()))); 1167 1263 1168 1264 setLetterSpacing(this._letter_spacing); 1169 1265 } 1170 1266 1171 public StringgetFontStyle() {1267 public Font.Style getFontStyle() { 1172 1268 Font f = getPaintFont(); 1173 String s = ""; 1174 1175 if (f.isPlain()) 1176 s += "Plain"; 1177 1178 if (f.isBold()) 1179 s += "Bold"; 1180 1181 if (f.isItalic()) 1182 s += "Italic"; 1183 1184 return s; 1269 return f.getStyle(); 1185 1270 } 1186 1271 … … 1215 1300 invalidateAll(); 1216 1301 Font currentFont = getPaintFont(); 1217 if (currentFont.isPlain()) 1218 setFont(currentFont.deriveFont(Font.BOLD)); 1219 else if (currentFont.isBold() && currentFont.isItalic()) 1220 setFont(currentFont.deriveFont(Font.PLAIN)); 1221 else if (currentFont.isBold()) 1222 setFont(currentFont.deriveFont(Font.ITALIC)); 1223 else 1224 setFont(currentFont.deriveFont(Font.ITALIC + Font.BOLD)); 1302 Font.Style currentStyle = currentFont.getStyle(); 1303 Font.Style newStyle = Font.Style.PLAIN; 1304 switch (currentStyle) { 1305 case PLAIN: 1306 newStyle = Font.Style.BOLD; 1307 break; 1308 case BOLD: 1309 newStyle = Font.Style.ITALIC; 1310 break; 1311 case ITALIC: 1312 newStyle = Font.Style.BOLD_ITALIC; 1313 break; 1314 default: 1315 newStyle = Font.Style.PLAIN; 1316 break; 1317 } 1318 setFont(new Font(currentFont.getFamilyName(), newStyle, currentFont.getSize())); 1225 1319 rebuild(true); 1226 1320 invalidateAll(); … … 1230 1324 invalidateAll(); 1231 1325 Font currentFont = getPaintFont(); 1232 int newStyle = currentFont.getStyle(); 1233 if (currentFont.isBold()) { 1234 newStyle -= Font.BOLD; 1235 } else { 1236 newStyle += Font.BOLD; 1237 } 1238 setFont(currentFont.deriveFont(newStyle)); 1326 currentFont.toggleBold(); 1327 setFont(currentFont); 1239 1328 rebuild(true); 1240 1329 invalidateAll(); … … 1244 1333 invalidateAll(); 1245 1334 Font currentFont = getPaintFont(); 1246 int newStyle = currentFont.getStyle(); 1247 if (currentFont.isItalic()) { 1248 newStyle -= Font.ITALIC; 1249 } else { 1250 newStyle += Font.ITALIC; 1251 } 1252 setFont(currentFont.deriveFont(newStyle)); 1335 currentFont.toggleItalic(); 1336 setFont(currentFont); 1253 1337 rebuild(true); 1254 1338 invalidateAll(); 1255 1339 } 1256 1340 1257 public void setFontStyle(String newFace) { 1341 public void setFontStyle(String newFace) 1342 { 1343 Font currentFont = getPaintFont(); 1258 1344 if (newFace == null || newFace.trim().length() == 0) { 1259 setFont(getPaintFont().deriveFont(Font.PLAIN)); 1345 currentFont.setStyle(Font.Style.PLAIN); 1346 setFont(currentFont); 1260 1347 return; 1261 1348 } … … 1264 1351 1265 1352 if (newFace.equals("plain") || newFace.equals("p")) { 1266 setFont(getPaintFont().deriveFont(Font.PLAIN));1353 currentFont.setStyle(Font.Style.PLAIN); 1267 1354 } else if (newFace.equals("bold") || newFace.equals("b")) { 1268 setFont(getPaintFont().deriveFont(Font.BOLD));1355 currentFont.setStyle(Font.Style.BOLD); 1269 1356 } else if (newFace.equals("italic") || newFace.equals("i")) { 1270 setFont(getPaintFont().deriveFont(Font.ITALIC)); 1271 } else if (newFace.equals("bolditalic") || newFace.equals("italicbold") || newFace.equals("bi") 1272 || newFace.equals("ib")) { 1273 setFont(getPaintFont().deriveFont(Font.BOLD + Font.ITALIC)); 1274 } 1357 currentFont.setStyle(Font.Style.ITALIC); 1358 } else if (newFace.equals("bolditalic") || newFace.equals("italicbold") || newFace.equals("bi") || newFace.equals("ib")) { 1359 currentFont.setStyle(Font.Style.BOLD_ITALIC); 1360 } 1361 1362 setFont(currentFont); 1275 1363 1276 1364 } … … 1289 1377 1290 1378 // Rebuilding prevents errors when displaying frame bitmaps 1291 if (_ lineOffsets.size() == 0) {1379 if (_textLayouts.size() == 0) { 1292 1380 rebuild(false); 1293 1381 } 1294 1382 1295 int last = 0; 1296 for (int offset : _lineOffsets) { 1297 if (offset != last) { 1298 list.add(_text.substring(last, offset).replaceAll("\n", "")); 1299 } 1300 last = offset; 1383 for (TextLayout layout : _textLayouts) { 1384 String text = layout.getLine().replaceAll("\n", ""); 1385 if (!text.equals("")) list.add(text); 1301 1386 } 1302 1387 … … 1344 1429 public void setSpacing(float spacing) { 1345 1430 _spacing = spacing; 1346 updatePolygon();1431 invalidateBounds(); 1347 1432 } 1348 1433 … … 1356 1441 } 1357 1442 1358 private float getLineDrop(TextLayout layout) { 1359 if (getSpacing() < 0) 1443 /** 1444 * Gets the y-distance that should be advanced between this layout and the next. 1445 * 1446 * @param layout 1447 * The TextLayout to calculate line-drop for. 1448 * 1449 * @return 1450 * The distance to advance in the y-direction before the next line. 1451 */ 1452 private float getLineDrop(TextLayout layout) 1453 { 1454 if (getSpacing() < 0) { 1360 1455 return layout.getAscent() + layout.getDescent() + layout.getLeading(); 1456 } 1361 1457 1362 1458 return layout.getAscent() + layout.getDescent() + getSpacing(); … … 1380 1476 public void setLetterSpacing(float spacing) { 1381 1477 _letter_spacing = spacing; 1382 HashMap<TextAttribute, Object> attr = new HashMap<TextAttribute, Object>(); 1383 attr.put(TextAttribute.TRACKING, spacing); 1384 1385 if (this._font == null) { 1386 this._font = Font.decode(DEFAULT_FONT); 1387 } 1388 1389 this.setFont(this._font.deriveFont(attr)); 1478 1479 Font currentFont = getPaintFont(); 1480 currentFont.setSpacing(spacing); 1481 setFont(currentFont); 1390 1482 } 1391 1483 … … 1407 1499 1408 1500 // @Override 1409 public boolean intersectsOLD(Polygon p) {1501 /* public boolean intersectsOLD(Polygon p) { 1410 1502 if (super.intersects(p)) { 1411 1503 float textY = getY(); … … 1422 1514 } 1423 1515 return false; 1424 } 1516 }*/ 1425 1517 1426 1518 // The following version of intersect uses a tighter definition for the text, 1427 1519 // based on 1428 1520 @Override 1429 public boolean intersects(Polygon p) {1521 public boolean intersects(PolygonBounds p) { 1430 1522 if (super.intersects(p)) { 1431 1523 // float textY = getY(); … … 1433 1525 for (TextLayout text : _textLayouts) { 1434 1526 1435 Rectangle text_pixel_bounds_rect = this.getPixelBounds(text);1527 AxisAlignedBoxBounds text_pixel_bounds_rect = getPixelBounds(text); 1436 1528 1437 1529 if (p.intersects(text_pixel_bounds_rect)) { … … 1445 1537 1446 1538 @Override 1447 public boolean contains(int mouseX, int mouseY) { 1448 return contains(mouseX, mouseY, getGravity() * NEARBY_GRAVITY); 1449 } 1450 1451 public boolean contains(int mouseX, int mouseY, int gravity) { 1539 public boolean contains(Point mousePosition) { 1540 return contains(mousePosition.x, mousePosition.y, getGravity() * NEARBY_GRAVITY); 1541 } 1542 1543 public boolean contains(int mouseX, int mouseY) 1544 { 1545 return contains(new Point(mouseX, mouseY)); 1546 } 1547 1548 public boolean contains(int mouseX, int mouseY, int gravity) 1549 { 1452 1550 mouseX += getOffset().x; 1453 1551 mouseY += getOffset().y; … … 1456 1554 float textX = getX(); 1457 1555 1458 Rectangle2D outline = getPolygon().getBounds2D(); 1556 AxisAlignedBoxBounds outline = getBoundingBox(); 1557 1558 if (outline == null) return false; 1459 1559 1460 1560 // Check if its outside the top and left and bottom bounds 1461 if (outline.getX() - mouseX > gravity || outline.getY() - mouseY > gravity 1462 || mouseY - (outline.getY() + outline.getHeight()) > gravity 1463 || mouseX - (outline.getX() + outline.getWidth()) > gravity) { 1561 if (outline.getMinX() - mouseX > gravity 1562 || outline.getMinY() - mouseY > gravity 1563 || mouseY - (outline.getMinY() + outline.getHeight()) > gravity 1564 || mouseX - (outline.getMinX() + outline.getWidth()) > gravity) { 1464 1565 return false; 1465 1566 } … … 1467 1568 for (TextLayout text : _textLayouts) { 1468 1569 // check left and right of each box 1469 Rectangle2D textOutline = text.getLogicalHighlightShape(0, text.getCharacterCount()).getBounds2D();1570 AxisAlignedBoxBounds textOutline = text.getLogicalHighlightShape(0, text.getCharacterCount()); 1470 1571 1471 1572 // check if the cursor is within the top, bottom and within the … … 1473 1574 int justOffset = getJustOffset(text); 1474 1575 1475 if (mouseY - textY > textOutline.getY() && mouseY - textY < textOutline.getY() + textOutline.getHeight() 1476 && mouseX - textX - justOffset < textOutline.getWidth() + gravity + Item.MARGIN_RIGHT 1477 /* &&(justOffset == 0 || mouseX > textX + justOffset - gravity ) */) 1576 if (mouseY - textY > textOutline.getMinY() && 1577 mouseY - textY < textOutline.getMinY() + textOutline.getHeight() && 1578 mouseX - textX - justOffset < textOutline.getWidth() + gravity + Item.MARGIN_RIGHT) 1579 { 1478 1580 return true; 1581 } 1582 1479 1583 textY += getLineDrop(text); 1480 1584 } … … 1486 1590 * Updates the Polygon (rectangle) that surrounds this Text on the screen. 1487 1591 */ 1488 public void updatePolygon() { 1592 public AxisAlignedBoxBounds updateBounds() 1593 { 1489 1594 // if there is no text, there is nothing to do 1490 if (_text == null) 1491 return; 1595 if (_text == null) return null; 1596 1597 if (_textLayouts == null || _textLayouts.size() < 1) return null; 1492 1598 1493 1599 int preChangeWidth = 0; 1494 if (_poly != null) 1495 preChangeWidth = _poly.getBounds().width; 1496 1497 _poly = new Polygon(); 1498 1499 if (_textLayouts.size() < 1) 1500 return; 1600 if (getOldBounds() != null) { 1601 preChangeWidth = AxisAlignedBoxBounds.getEnclosing(getOldBounds()).getWidth(); 1602 } 1501 1603 1502 1604 int minX = Integer.MAX_VALUE; … … 1515 1617 1516 1618 for (TextLayout layout : tmpTextLayouts) { 1517 Rectangle2D bounds = layout.getLogicalHighlightShape(0, layout.getCharacterCount()).getBounds2D();1619 AxisAlignedBoxBounds bounds = layout.getLogicalHighlightShape(0, layout.getCharacterCount()); 1518 1620 1519 1621 if (y < 0) … … 1536 1638 } 1537 1639 1538 _poly.addPoint(minX - getGravity(), minY - getGravity()); 1539 _poly.addPoint(maxX + getGravity(), minY - getGravity()); 1540 _poly.addPoint(maxX + getGravity(), maxY + getGravity()); 1541 _poly.addPoint(minX - getGravity(), maxY + getGravity()); 1542 1543 _poly.translate(getX(), getY()); 1544 1545 if (preChangeWidth != 0 && preChangeWidth != _poly.getBounds().width) 1546 if (_poly.getBounds().width > preChangeWidth) 1547 MagneticConstraints.getInstance().textGrown(this, _poly.getBounds().width - preChangeWidth); 1548 else 1549 MagneticConstraints.getInstance().textShrunk(this, preChangeWidth - _poly.getBounds().width); 1550 } 1551 1552 // TODO it seems like this method has some exponencial processing which 1640 AxisAlignedBoxBounds ret = new AxisAlignedBoxBounds(getX() + minX - getGravity(), 1641 getY() + minY - getGravity(), 1642 2 * getGravity() + maxX - minX, 1643 2 * getGravity() + maxY - minY); 1644 1645 Dimension polySize = ret.getSize(); 1646 1647 if(preChangeWidth != 0 && preChangeWidth != polySize.width) { 1648 if (polySize.width > preChangeWidth) { 1649 MagneticConstraints.getInstance().textGrown(this, polySize.width - preChangeWidth); 1650 } else { 1651 MagneticConstraints.getInstance().textShrunk(this, preChangeWidth - polySize.width); 1652 } 1653 } 1654 1655 return ret; 1656 } 1657 1658 // TODO it seems like this method has some exponential processing which 1553 1659 // makes items copy really slowly when there are lots of lines of text! 1554 1660 // This needs to be fixed!! … … 1564 1670 */ 1565 1671 private void rebuild(boolean limitWidth, boolean newLinebreakerAlways) { 1566 // TODO make this more efficient so it only clears annotation list when 1567 // it really has to 1672 // TODO make this more efficient so it only clears annotation list when it really has to 1568 1673 if (isAnnotation()) { 1569 1674 Frame parent = getParent(); … … 1582 1687 } 1583 1688 1584 if (_lineBreaker == null || newLinebreakerAlways) { 1585 AttributedString paragraphText = new AttributedString(_text.toString()); 1586 paragraphText.addAttribute(TextAttribute.FONT, getPaintFont()); 1587 frc = new FontRenderContext(null, true, true); 1588 _lineBreaker = new LineBreakMeasurer(paragraphText.getIterator(), frc); 1589 } 1590 1591 /* 1592 * float width = Float.MAX_VALUE; 1593 * 1594 * if (limitWidth) { width = getAbsoluteWidth(); // else if (getMaxWidth() > 0) 1595 * // width = Math.max(50, getMaxWidth() - getX() // - Item.MARGIN_RIGHT); } 1596 */ 1597 1598 _textLayouts.clear(); 1599 _lineOffsets.clear(); 1600 // the first line always has a 0 offset 1601 _lineOffsets.add(0); 1602 1603 TextLayout layout; 1604 1605 float width; 1606 float lineHeight = Float.NaN; 1607 List<Point[]> lines = null; 1608 1609 if (_autoWrap || ExperimentalFeatures.AutoWrap.get()) { 1610 lines = new LinkedList<Point[]>(); 1611 if (DisplayIO.getCurrentFrame() == null) { 1612 return; 1613 } 1614 for (Item item : DisplayIO.getCurrentFrame().getItems()) { 1615 if (item instanceof Line) { 1616 lines.add(new Point[] { ((Line) item).getStartItem().getPosition(), 1617 ((Line) item).getEndItem().getPosition() }); 1618 } 1619 if (item instanceof Picture) { 1620 lines.add( 1621 new Point[] { item.getPosition(), new Point(item.getX(), item.getY() + item.getHeight()) }); 1622 } 1623 } 1624 for (Item item : FreeItems.getInstance()) { 1625 if (item instanceof Line) { 1626 lines.add(new Point[] { ((Line) item).getStartItem().getPosition(), 1627 ((Line) item).getEndItem().getPosition() }); 1628 } 1629 if (item instanceof Picture) { 1630 lines.add( 1631 new Point[] { item.getPosition(), new Point(item.getX(), item.getY() + item.getHeight()) }); 1632 } 1633 } 1634 width = getLineWidth(getX(), getY(), lines); 1635 } else { 1636 width = Float.MAX_VALUE; 1637 if (limitWidth) { 1638 if (_maxWidth == null) { 1639 width = FrameGraphics.getMaxFrameSize().width - getX(); 1640 } else { 1641 width = getAbsoluteWidth(); 1642 } 1643 // else if (getMaxWidth() > 0) 1644 // width = Math.max(50, getMaxWidth() - getX() 1645 // - Item.MARGIN_RIGHT); 1646 } 1647 } 1648 1649 _lineBreaker.setPosition(0); 1650 boolean requireNextWord = false; 1651 1652 // --- Get the output of the LineBreakMeasurer and store it in a 1653 while (_lineBreaker.getPosition() < _text.length()) { 1654 1655 if (_autoWrap || ExperimentalFeatures.AutoWrap.get()) { 1656 requireNextWord = width < FrameGraphics.getMaxFrameSize().width - getX(); 1657 } 1658 1659 layout = _lineBreaker.nextLayout(width, _text.length(), requireNextWord); 1660 1661 // lineBreaker does not break on newline 1662 // characters so they have to be check manually 1663 int start = _lineOffsets.get(_lineOffsets.size() - 1); 1664 1665 // int y = getY() + (getLineDrop(layout) * (_lineOffsets.size() - 1) 1666 1667 // check through the current line for newline characters 1668 for (int i = start + 1; i < _text.length(); i++) { 1669 if (_text.charAt(i) == '\n') {// || c == '\t'){ 1670 _lineBreaker.setPosition(start); 1671 layout = _lineBreaker.nextLayout(width, i, requireNextWord); 1672 break; 1673 } 1674 } 1675 1676 _lineOffsets.add(_lineBreaker.getPosition()); 1677 1678 if (layout == null) { 1679 layout = new TextLayout(" ", getPaintFont(), frc); 1680 } 1681 1682 if (/* hasWidth() && */getJustification() == Justification.full 1683 && _lineBreaker.getPosition() < _text.length()) 1684 layout = layout.getJustifiedLayout(width); 1685 1686 _textLayouts.add(layout); 1687 1688 if (_autoWrap || ExperimentalFeatures.AutoWrap.get()) { 1689 1690 if (lineHeight != Float.NaN) { 1691 lineHeight = getLineDrop(layout); 1692 } 1693 width = getLineWidth(getX(), getY() + (lineHeight * (_textLayouts.size() - 1)), lines); 1694 } 1695 } 1696 1697 updatePolygon(); 1698 1699 } 1700 1701 private float getLineWidth(int x, float y, List<Point[]> lines) { 1689 EcosystemManager.getTextLayoutManager().releaseLayouts(_textLayouts); 1690 if (_textLayouts != null) _textLayouts.clear(); 1691 1692 // Calculate the maximum allowable width of this line of text 1693 List<org.expeditee.core.Line> lines = null; 1694 if(_autoWrap || ExperimentalFeatures.AutoWrap.get()) { 1695 lines = new LinkedList<org.expeditee.core.Line>(); 1696 if(DisplayController.getCurrentFrame() == null) { 1697 return; 1698 } 1699 for(Item item : DisplayController.getCurrentFrame().getItems()) { 1700 if(item instanceof Line) { 1701 lines.add(new org.expeditee.core.Line (((Line) item).getStartItem().getPosition(), ((Line) item).getEndItem().getPosition())); 1702 } 1703 if(item instanceof Picture) { 1704 lines.add(new org.expeditee.core.Line(item.getPosition(), new Point(item.getX(), item.getY() + item.getHeight()))); 1705 } 1706 } 1707 for(Item item : FreeItems.getInstance()) { 1708 if(item instanceof Line) { 1709 lines.add(new org.expeditee.core.Line(((Line) item).getStartItem().getPosition(), ((Line) item).getEndItem().getPosition())); 1710 } 1711 if(item instanceof Picture) { 1712 lines.add(new org.expeditee.core.Line(item.getPosition(), new Point(item.getX(), item.getY() + item.getHeight()))); 1713 } 1714 } 1715 } 1716 1717 float width = Float.MAX_VALUE; 1718 if (limitWidth) { 1719 if(_maxWidth == null) { 1720 width = DisplayController.getFramePaintArea().getWidth() - getX(); 1721 } else { 1722 width = getAbsoluteWidth(); 1723 } 1724 } 1725 1726 _textLayouts = EcosystemManager.getTextLayoutManager().layoutString(_text.toString(), 1727 getPaintFont(), 1728 new Point(getX(), getY()), 1729 lines != null ? lines.toArray(new org.expeditee.core.Line[1]) : null, 1730 (int) width, 1731 (int) getSpacing(), 1732 true, 1733 getJustification() == Justification.full); 1734 1735 invalidateBounds(); 1736 1737 } 1738 1739 /** 1740 * Calculates the maximum possible distance a line can extend to the right from a given (x,y) point 1741 * without crossing any of the lines in the given list. 1742 * 1743 * @param x 1744 * The x-coordinate of the beginning point. 1745 * 1746 * @param y 1747 * The y-coordinate of the beginning point. 1748 * 1749 * @param lines 1750 * A list of pairs of points describing the lines that should stop the extension. 1751 * 1752 * @return 1753 * The length of the extended line. 1754 */ 1755 /* private float getLineWidth(int x, float y, List<Point[]> lines) { 1702 1756 float width = FrameGraphics.getMaxFrameSize().width; 1703 1757 for (Point[] l : lines) { … … 1725 1779 } 1726 1780 return width - x; 1727 } 1781 }*/ 1728 1782 1729 1783 private boolean hasFixedWidth() { … … 1741 1795 } 1742 1796 1743 private PointgetSelectedRange(int line) {1797 private Range<Integer> getSelectedRange(int line) { 1744 1798 if (_selectionEnd >= _text.length()) { 1745 1799 _selectionEnd = _text.length(); … … 1756 1810 1757 1811 // if the selection is after this line, return null 1758 if (_lineOffsets.get(line) > selectionRight) 1759 return null; 1812 if (_textLayouts.get(line).getStartCharIndex() > selectionRight) return null; 1760 1813 1761 1814 // if the selection is before this line, return null 1762 if (_lineOffsets.get(line) < selectionLeft 1763 && _lineOffsets.get(line) + _textLayouts.get(line).getCharacterCount() < selectionLeft) 1764 return null; 1815 if (_textLayouts.get(line).getEndCharIndex() < selectionLeft) return null; 1765 1816 1766 1817 // Dont highlight a single char … … 1770 1821 // the selection occurs on this line, determine where it lies on the 1771 1822 // line 1772 int start = Math.max(0, selectionLeft - _ lineOffsets.get(line));1823 int start = Math.max(0, selectionLeft - _textLayouts.get(line).getStartCharIndex()); 1773 1824 // int end = Math.min(_lineOffsets.get(line) + 1774 1825 // _textLayouts.get(line).getCharacterCount(), _selectionEnd); 1775 int end = Math.min(selectionRight - _ lineOffsets.get(line), +_textLayouts.get(line).getCharacterCount());1826 int end = Math.min(selectionRight - _textLayouts.get(line).getStartCharIndex(), _textLayouts.get(line).getCharacterCount()); 1776 1827 1777 1828 // System.out.println(line + ": " + start + "x" + end + " (" + 1778 1829 // _selectionStart + "x" + _selectionEnd + ")"); 1779 return new Point(start, end); 1780 } 1781 1782 /** 1783 * @param mouseButton 1784 * Either MouseEvent.BUTTON1, MouseEvent.BUTTON2 or 1785 * MouseEvent.BUTTON3. 1786 * 1787 * @return The color for the text selection based on the given mouse click 1788 */ 1789 protected Color getSelectionColor(int mouseButton) { 1790 1791 /* 1792 * Color main = getPaintColor(); Color back = getPaintBackgroundColor(); 1793 * 1794 * if (Math.abs(main.getRed() - back.getRed()) < 10 && Math.abs(main.getGreen() 1795 * - back.getGreen()) < 10 && Math.abs(main.getBlue() - back.getBlue()) < 10) { 1796 * selection = new Color(Math.abs(255 - main.getRed()), Math .abs(255 - 1797 * main.getGreen()), Math.abs(255 - main.getBlue())); } else { selection = new 1798 * Color((main.getRed() + (back.getRed() * 2)) / 3, (main.getGreen() + 1799 * (back.getGreen() * 2)) / 3, (main .getBlue() + (back.getBlue() * 2)) / 3); } 1800 */ 1801 int green = 160; 1802 int red = 160; 1803 int blue = 160; 1804 1805 if (FrameMouseActions.wasDeleteClicked()) { 1806 green = 235; 1807 red = 235; 1808 blue = 140; 1809 } else if (mouseButton == MouseEvent.BUTTON1) { 1810 red = 255; 1811 } else if (mouseButton == MouseEvent.BUTTON2) { 1812 green = 255; 1813 } else if (mouseButton == MouseEvent.BUTTON3) { 1814 blue = 255; 1815 } 1816 1817 return new Color(red, green, blue); 1830 return new Range<Integer>(start, end, true, true); 1831 } 1832 1833 /** Sets the colour that should be used to render the selected range. */ 1834 public void setSelectionColour(Colour colour) 1835 { 1836 if (colour == null) colour = RANGE_SELECT_COLOUR; 1837 1838 _selectionColour = colour; 1839 } 1840 1841 /** Gets the colour that should be used to render the selected range. */ 1842 public Colour getSelectionColour() 1843 { 1844 return _selectionColour; 1818 1845 } 1819 1846 1820 1847 @Override 1821 public void paint( Graphics2D g) {1822 if (!isVisible())1823 1848 public void paint() 1849 { 1850 if (!isVisible()) return; 1824 1851 1825 1852 // if there is no text to paint, do nothing. 1826 if (_text == null || _text.length() == 0) 1827 return; 1853 if (_text == null || _text.length() == 0) return; 1828 1854 1829 1855 if (_autoWrap || ExperimentalFeatures.AutoWrap.get()) { … … 1841 1867 // This will allow for dragging vectors around the place! 1842 1868 if (hasVector() && isFloating()) { 1843 FrameGraphics.requestRefresh(false);1869 DisplayController.requestRefresh(false); 1844 1870 // TODO make this use a more efficient paint method... 1845 1871 // Have the text item return a bigger repaint area if it has an 1846 1872 // associated vector 1847 1873 } 1874 1875 GraphicsManager g = EcosystemManager.getGraphicsManager(); 1876 AxisAlignedBoxBounds bounds = (AxisAlignedBoxBounds) getBounds(); 1848 1877 1849 1878 // the background is only cleared if required 1850 1879 if (getBackgroundColor() != null) { 1851 Colo r bgc = getBackgroundColor();1880 Colour bgc = getBackgroundColor(); 1852 1881 if (_alpha > 0) { 1853 bgc = new Color(bgc.getRed(), bgc.getGreen(), bgc.getBlue(), _alpha); 1854 } 1855 g.setColor(bgc); 1856 1857 Color gradientColor = getGradientColor(); 1858 if (gradientColor != null) { 1859 // The painting is not efficient enough for gradients... 1860 Shape s = getPolygon(); 1861 if (s != null) { 1862 Rectangle b = s.getBounds(); 1863 GradientPaint gp = new GradientPaint((int) (b.x + b.width * 0.3), b.y, bgc, 1864 (int) (b.x + b.width * 1.3), b.y, gradientColor); 1865 g.setPaint(gp); 1866 } 1867 } 1868 1869 g.fillPolygon(getPolygon()); 1882 bgc = new Colour(bgc.getRed(), bgc.getGreen(), bgc.getBlue(), 1883 Colour.FromComponent255(_alpha)); 1884 } 1885 1886 Colour gradientColor = getGradientColor(); 1887 1888 Fill fill; 1889 1890 if (gradientColor != null && bounds != null) { 1891 fill = new GradientFill(bgc, new Point((int) (bounds.getMinX() + bounds.getWidth() * 0.3), bounds.getMinY()), gradientColor, new Point((int) (bounds.getMinX() + bounds.getWidth() * 1.3), bounds.getMinY())); 1892 } else { 1893 fill = new Fill(bgc); 1894 } 1895 1896 g.drawRectangle(bounds, 0.0, fill, null, null, null); 1870 1897 } 1871 1898 1872 1899 if (hasVisibleBorder()) { 1873 g.setColor(getPaintBorderColor()); 1874 Stroke borderStroke = new BasicStroke(getThickness(), CAP, JOIN); 1875 g.setStroke(borderStroke); 1876 g.drawPolygon(getPolygon()); 1900 Stroke borderStroke = new Stroke(getThickness(), DEFAULT_CAP, DEFAULT_JOIN); 1901 g.drawRectangle(bounds, 0.0, null, getPaintBorderColor(), borderStroke, null); 1877 1902 } 1878 1903 1879 1904 if (hasFormula()) { 1880 g.setColor(getPaintHighlightColor()); 1881 Stroke highlightStroke = new BasicStroke(1F, CAP, JOIN); 1882 g.setStroke(highlightStroke); 1883 1884 Point2D.Float start = getEdgePosition(0, true); 1885 Point2D.Float end = getEdgePosition(0, false); 1886 g.drawLine(Math.round(start.x), Math.round(start.y), Math.round(end.x), Math.round(end.y)); 1905 Stroke highlightStroke = new Stroke(1F, DEFAULT_CAP, DEFAULT_JOIN); 1906 Point start = getEdgePosition(0, true); 1907 Point end = getEdgePosition(0, false); 1908 g.drawLine(start, end, getPaintHighlightColor(), highlightStroke); 1887 1909 } 1888 1910 1889 1911 if (isHighlighted()) { 1890 g.setColor(getPaintHighlightColor()); 1891 Stroke highlightStroke = new BasicStroke((float) getHighlightThickness(), CAP, JOIN); 1892 g.setStroke(highlightStroke); 1893 if (HighlightMode.Enclosed.equals(getHighlightMode())) 1894 g.fillPolygon(getPolygon()); 1895 else 1896 g.drawPolygon(getPolygon()); 1912 Stroke highlightStroke = new Stroke((float) getHighlightThickness(), DEFAULT_CAP, DEFAULT_JOIN); 1913 Fill fill; 1914 if (HighlightMode.Enclosed.equals(getHighlightMode())) { 1915 fill = new Fill(getPaintHighlightColor()); 1916 } else { 1917 fill = null; 1918 } 1919 g.drawRectangle(bounds, 0.0, fill, getPaintHighlightColor(), highlightStroke, null); 1897 1920 } 1898 1921 1899 1922 float y = getY(); 1900 Color c = getPaintColor(); 1901 if (_alpha > 0) 1902 c = new Color(c.getRed(), c.getGreen(), c.getBlue(), _alpha); 1903 1904 g.setColor(c); 1905 1906 Color selection = getSelectionColor(FrameMouseActions.getLastMouseButton()); 1923 Colour paintColour = getPaintColor(); 1924 if (_alpha > 0) { 1925 paintColour = new Colour(paintColour); 1926 paintColour.setAlpha(Colour.FromComponent255(_alpha)); 1927 1928 } 1929 1930 Colour selectionColour = getSelectionColour(); 1907 1931 1908 1932 // width -= getX(); … … 1913 1937 TextLayout layout = _textLayouts.get(i); 1914 1938 1915 Point p = getSelectedRange(i); 1916 if (p != null) { 1917 AffineTransform at = new AffineTransform(); 1918 AffineTransform orig = g.getTransform(); 1919 at.translate(getX() + getJustOffset(layout), y); 1920 g.setTransform(at); 1921 1922 g.setColor(selection); 1923 g.fill(layout.getLogicalHighlightShape(p.x, p.y)); 1924 1925 g.setTransform(orig); 1926 g.setColor(c); 1939 Range<Integer> selectedRange = getSelectedRange(i); 1940 if (selectedRange != null) { 1941 AxisAlignedBoxBounds highlight = layout.getLogicalHighlightShape(selectedRange.lowerBound, selectedRange.upperBound); 1942 highlight.getTopLeft().add(getX() + getJustOffset(layout), (int) y); 1943 g.drawRectangle(highlight, 1944 0.0, 1945 new Fill(selectionColour), 1946 null, null, null); 1927 1947 } 1928 1948 1929 1949 int ldx = 1 + getX() + getJustOffset(layout); // Layout draw x 1930 1950 1931 boolean debug = false; 1932 if (debug) { 1933 g.setColor(new Color(c.getRed(), c.getGreen(), c.getBlue(), 40)); 1934 Rectangle layout_rect = layout.getPixelBounds(null, ldx, y); 1935 g.fillRect(layout_rect.x, layout_rect.y, layout_rect.width, layout_rect.height); 1936 g.setColor(c); 1937 } 1938 1939 layout.draw(g, ldx, y); 1940 1941 /* 1942 * AffineTransform at = new AffineTransform(); AffineTransform orig = 1943 * g.getTransform(); at.translate(getX() + getJustOffset(layout), y); 1944 * g.setTransform(at); g.draw(layout.getLogicalHighlightShape(0, 1945 * layout.getCharacterCount())); g.setTransform(orig); /* 1946 * if(_text.charAt(_lineOffsets.get(line) + (layout.getCharacterCount() - 1)) == 1947 * '\t'){ tab = true; x = (int) (getX() + x + 20 + layout.getVisibleAdvance()); 1948 * }else{ 1949 */ 1951 g.drawTextLayout(layout, new Point(ldx, (int) y), paintColour); 1952 1950 1953 y += getLineDrop(layout); 1951 /* 1952 * tab = false; } 1953 * 1954 * line++; 1955 */ 1956 } 1957 } 1958 1959 paintLink(g); 1960 } 1961 1954 } 1955 } 1956 1957 paintLink(); 1958 } 1959 1960 // TODO: Revise 1962 1961 @Override 1963 protected Rectangle getLinkDrawArea() { // TODO: Revise 1964 return getDrawingArea()[0]; 1962 protected AxisAlignedBoxBounds getLinkDrawArea() 1963 { 1964 return getDrawingArea(); 1965 1965 } 1966 1966 … … 1970 1970 * @return True if this Item has no text in it, false otherwise. 1971 1971 */ 1972 public boolean isEmpty() { 1973 if (_text == null || _text.length() == 0) 1974 return true; 1975 1976 return false; 1972 public boolean isEmpty() 1973 { 1974 return (_text == null || _text.length() == 0); 1977 1975 } 1978 1976 … … 2004 2002 @Override 2005 2003 public float getSize() { 2006 return getPaintFont().getSize 2D();2004 return getPaintFont().getSize(); 2007 2005 } 2008 2006 … … 2026 2024 if (size < MINIMUM_FONT_SIZE) 2027 2025 size = MINIMUM_FONT_SIZE; 2028 setFont(getPaintFont().deriveFont(size)); 2026 Font currentFont = getPaintFont(); 2027 currentFont.setSize((int) size); 2028 setFont(currentFont); 2029 2029 rebuild(true); 2030 2030 invalidateAll(); … … 2033 2033 @Override 2034 2034 public void setAnnotation(boolean val) { 2035 float mouseX = Display IO.getFloatMouseX();2036 float mouseY = FrameMouseActions.MouseY;2037 Point 2D.Float newPoint = new Point2D.Float();2035 float mouseX = DisplayController.getFloatMouseX(); 2036 float mouseY = DisplayController.getFloatMouseY(); 2037 Point newPoint = new Point(); 2038 2038 if (val) { 2039 2039 // if this is already an annotation, do nothing … … 2041 2041 return; 2042 2042 if (!isLineEnd() && _text.length() > 0 && _text.charAt(0) == DEFAULT_BULLET) { 2043 newPoint.set Location(insertText("" + (char) KeyEvent.VK_BACK_SPACE, mouseX, mouseY, 1));2043 newPoint.set(insertText("\b", mouseX, mouseY, 1)); 2044 2044 if (_text.length() > 0 && _text.charAt(0) == ' ') 2045 newPoint.set Location(insertText("" + (char) KeyEvent.VK_BACK_SPACE, newPoint.x, newPoint.y, 1));2045 newPoint.set(insertText("\b", newPoint.x, newPoint.y, 1)); 2046 2046 } else { 2047 newPoint.set Location(insertText("@", mouseX, mouseY, 0));2047 newPoint.set(insertText("@", mouseX, mouseY, 0)); 2048 2048 } 2049 2049 } else { … … 2052 2052 return; 2053 2053 if (!isLineEnd() && _text.charAt(0) == '@') { 2054 newPoint.set Location(insertText("" + (char) KeyEvent.VK_BACK_SPACE, mouseX, mouseY, 1));2055 newPoint.set Location(insertText(DEFAULT_BULLET_STRING, newPoint.x, newPoint.y, 0));2054 newPoint.set(insertText("\b", mouseX, mouseY, 1)); 2055 newPoint.set(insertText(DEFAULT_BULLET_STRING, newPoint.x, newPoint.y, 0)); 2056 2056 } else { 2057 newPoint.set Location(insertText("" + (char) KeyEvent.VK_BACK_SPACE, mouseX, mouseY, 1));2057 newPoint.set(insertText("\b", mouseX, mouseY, 1)); 2058 2058 } 2059 2059 } 2060 2060 FrameUtils.setLastEdited(this); 2061 2061 rebuild(true); 2062 Display IO.setCursorPosition(newPoint.x, newPoint.y, false);2062 DisplayController.setCursorPosition(newPoint.x, newPoint.y, false); 2063 2063 } 2064 2064 … … 2068 2068 private void insertString(String toInsert, int pos) { 2069 2069 assert (toInsert.length() > 0); 2070 2070 invalidateAll(); 2071 2071 _text.insert(pos, toInsert); 2072 2073 if (toInsert.length() > 1) { 2074 _lineBreaker = null; 2075 } 2076 2077 if (_lineBreaker != null) { 2078 AttributedString inserting = new AttributedString(_text.toString()); 2079 inserting.addAttribute(TextAttribute.FONT, getPaintFont()); 2080 _lineBreaker.insertChar(inserting.getIterator(), pos); 2081 } 2072 rebuild(false); 2073 invalidateAll(); 2082 2074 } 2083 2075 … … 2088 2080 if (this.isLineEnd()) { 2089 2081 // Remove and replace with a dot 2090 FrameKeyboardActions.replaceText(this);2091 Display IO.setCursorPosition(this._x, this._y);2082 Item.replaceText(this); 2083 DisplayController.setCursorPosition(this._x, this._y); 2092 2084 } 2093 2085 return; 2094 }2095 2096 if (_lineBreaker != null) {2097 AttributedString inserting = new AttributedString(_text.toString());2098 inserting.addAttribute(TextAttribute.FONT, getPaintFont());2099 _lineBreaker.deleteChar(inserting.getIterator(), pos);2100 2086 } 2101 2087 … … 2229 2215 } 2230 2216 2217 /** 2218 * Checks if the given point is 'near' any line of the text item. 2219 */ 2231 2220 @Override 2232 2221 public boolean isNear(int x, int y) { … … 2242 2231 for (TextLayout text : _textLayouts) { 2243 2232 // check left and right of each box 2244 Rectangle2D textOutline = text.getLogicalHighlightShape(0, text.getCharacterCount()).getBounds2D();2233 AxisAlignedBoxBounds textOutline = text.getLogicalHighlightShape(0, text.getCharacterCount()); 2245 2234 2246 2235 // check if the cursor is within the top, bottom and within the 2247 2236 // gravity of right 2248 if (y - textY > textOutline.getY() - NEAR_DISTANCE 2249 && y - textY < textOutline.getY() + textOutline.getHeight() + NEAR_DISTANCE 2250 && x - textX < textOutline.getWidth() + NEAR_DISTANCE) 2237 if (y - textY > textOutline.getMinY() - NEAR_DISTANCE && 2238 y - textY < textOutline.getMinY() + textOutline.getHeight() + NEAR_DISTANCE && 2239 x - textX < textOutline.getWidth() + NEAR_DISTANCE) 2240 { 2251 2241 return true; 2242 } 2243 2252 2244 textY += getLineDrop(text); 2253 2245 } … … 2263 2255 setAlpha(0); 2264 2256 if (isLineEnd()) 2265 Display IO.setCursor(Item.DEFAULT_CURSOR);2257 DisplayController.setCursor(Item.DEFAULT_CURSOR); 2266 2258 2267 2259 String text = _text.toString().trim(); … … 2271 2263 // Show the overlay stuff immediately if this is an overlay item 2272 2264 if (hasLink() && (text.startsWith("@ao") || text.startsWith("@o"))) { 2273 FrameKeyboardActions.Refresh();2265 StandardGestureActions.Refresh(); 2274 2266 } 2275 2267 } … … 2277 2269 private void clipFrameMargin() { 2278 2270 if (!hasFixedWidth()) { 2279 int frameWidth = FrameGraphics.getMaxFrameSize().width;2271 int frameWidth = DisplayController.getFramePaintArea().getWidth(); 2280 2272 /* 2281 2273 * Only change width if it is more than 150 pixels from the right of the screen … … 2292 2284 } 2293 2285 2294 public void justify(boolean fixWidth, Polygon enclosure) {2286 public void justify(boolean fixWidth, PolygonBounds enclosure) { 2295 2287 // if autowrap is on, wrapping is done every time we draw 2296 if (ExperimentalFeatures.AutoWrap.get()) { 2297 return; 2298 } 2299 2300 Integer width = FrameGraphics.getMaxFrameSize().width; 2288 if(ExperimentalFeatures.AutoWrap.get()) return; 2289 2290 Integer width = DisplayController.getFramePaintArea().getWidth(); 2301 2291 2302 2292 // Check if that text item is inside an enclosing rectangle... 2303 2293 // Set its max width accordingly 2304 2294 if (enclosure != null) { 2305 Rectangle bounds = enclosure.getBounds(); 2306 if (bounds.width > 200 && getX() < bounds.width / 3 + bounds.x) { 2307 width = bounds.x + bounds.width; 2308 } 2309 } 2310 2311 if (getWidth() == null) 2312 setRightMargin(width, fixWidth); 2313 2314 // Check for the annotation that restricts the width of text items 2315 // on the frame 2295 AxisAlignedBoxBounds bounds = AxisAlignedBoxBounds.getEnclosing(enclosure); 2296 if (bounds.getWidth() > 200 && getX() < bounds.getWidth() / 3 + bounds.getMinX()) { 2297 width = bounds.getMinX() + bounds.getWidth(); 2298 } 2299 } 2300 2301 if (getWidth() == null) setRightMargin(width, fixWidth); 2302 2303 // Check for the annotation that restricts the width of text items on the frame 2316 2304 String widthString; 2317 2305 if ((widthString = getParentOrCurrentFrame().getAnnotationValue("maxwidth")) != null) { … … 2329 2317 public void justify(boolean fixWidth) { 2330 2318 // if autowrap is on, wrapping is done every time we draw 2331 if (ExperimentalFeatures.AutoWrap.get()) { 2332 return; 2333 } 2319 if(ExperimentalFeatures.AutoWrap.get()) return; 2320 2334 2321 this.justify(fixWidth, FrameUtils.getEnlosingPolygon()); 2335 2322 } 2336 2323 2337 2324 public void resetFrameNamePosition() { 2338 Dimension maxSize = FrameGraphics.getMaxFrameSize();2325 Dimension maxSize = DisplayController.getFramePaintArea().getSize(); 2339 2326 if (maxSize != null) { 2340 2327 // setMaxWidth(maxSize.width); … … 2357 2344 public static final String TAB_STRING = " "; 2358 2345 2359 public Point 2D.FloatinsertTab(char ch, float mouseX, float mouseY) {2346 public Point insertTab(char ch, float mouseX, float mouseY) { 2360 2347 return insertText("" + ch, mouseX, mouseY); 2361 2348 } 2362 2349 2363 public Point 2D.FloatremoveTab(char ch, float mouseX, float mouseY) {2350 public Point removeTab(char ch, float mouseX, float mouseY) { 2364 2351 // Insert a space as a flag that it is a backwards tab 2365 2352 return insertText(ch + " ", mouseX, mouseY); … … 2379 2366 String text = getText().toLowerCase(); 2380 2367 // TODO make it so can just check the _overlay variable 2381 // Mike can t remember the reason _overlay var cant be use! opps2368 // Mike can't remember the reason _overlay var can't be use! oops 2382 2369 if (!text.startsWith("@")) 2383 2370 return false; … … 2401 2388 @Override 2402 2389 public boolean calculate(String formula) { 2403 if ( FrameGraphics.isXRayMode())2390 if (DisplayController.isXRayMode()) 2404 2391 return false; 2405 2392 … … 2553 2540 2554 2541 @Override 2555 public void setAnchorLeft( Floatanchor) {2542 public void setAnchorLeft(Integer anchor) { 2556 2543 if (!isLineEnd()) { 2557 2544 super.setAnchorLeft(anchor); … … 2565 2552 invalidateCommonTrait(ItemAppearence.PreMoved); 2566 2553 2567 this._anchorLeft = anchor; 2568 this._anchorRight = null; 2554 this._anchoring.setLeftAnchor(anchor); 2569 2555 2570 2556 int oldX = getX(); … … 2579 2565 2580 2566 @Override 2581 public void setAnchorRight( Floatanchor) {2567 public void setAnchorRight(Integer anchor) { 2582 2568 if (!isLineEnd()) { 2583 2569 super.setAnchorRight(anchor); 2584 2570 // Subtract off the link width 2585 2571 if (anchor != null) { 2586 setX(FrameGraphics.getMaxFrameSize().width - anchor - getBoundsWidth() + getLeftMargin()); 2572 setX(DisplayController.getFramePaintArea().getWidth() - anchor 2573 - getBoundsWidth() + getLeftMargin()); 2587 2574 } 2588 2575 return; … … 2591 2578 invalidateCommonTrait(ItemAppearence.PreMoved); 2592 2579 2593 this._anchorRight = anchor; 2594 this._anchorLeft = null; 2580 this._anchoring.setRightAnchor(anchor); 2595 2581 2596 2582 int oldX = getX(); 2597 2583 if (anchor != null) { 2598 float deltaX = FrameGraphics.getMaxFrameSize().width - anchor - getBoundsWidth() + getLeftMargin() - oldX; 2584 float deltaX = DisplayController.getFramePaintArea().getWidth() - anchor 2585 - getBoundsWidth() + getLeftMargin() - oldX; 2599 2586 anchorConnected(AnchorEdgeType.Right, deltaX); 2600 2587 } … … 2605 2592 2606 2593 @Override 2607 public void setAnchorTop( Floatanchor) {2594 public void setAnchorTop(Integer anchor) { 2608 2595 if (!isLineEnd()) { 2609 2596 super.setAnchorTop(anchor); … … 2616 2603 invalidateCommonTrait(ItemAppearence.PreMoved); 2617 2604 2618 this._anchorTop = anchor; 2619 this._anchorBottom = null; 2605 this._anchoring.setTopAnchor(anchor); 2620 2606 2621 2607 int oldY = getY(); … … 2630 2616 2631 2617 @Override 2632 public void setAnchorBottom( Floatanchor) {2618 public void setAnchorBottom(Integer anchor) { 2633 2619 if (!isLineEnd()) { 2634 2620 super.setAnchorBottom(anchor); 2635 2621 if (anchor != null) { 2636 setY(FrameGraphics.getMaxFrameSize().height - (anchor + this.getBoundsHeight() 2637 - _textLayouts.get(0).getAscent() - _textLayouts.get(0).getDescent())); 2622 setY(DisplayController.getFramePaintArea().getHeight() - (anchor + this.getBoundsHeight() - _textLayouts.get(0).getAscent() - _textLayouts.get(0).getDescent())); 2638 2623 } 2639 2624 return; … … 2642 2627 invalidateCommonTrait(ItemAppearence.PreMoved); 2643 2628 2644 this._anchorBottom = anchor; 2645 this._anchorTop = null; 2629 this._anchoring.setBottomAnchor(anchor); 2646 2630 2647 2631 int oldY = getY(); 2648 2632 if (anchor != null) { 2649 2633 2650 float deltaY = FrameGraphics.getMaxFrameSize().height- anchor - oldY;2634 float deltaY = DisplayController.getFramePaintArea().getHeight() - anchor - oldY; 2651 2635 anchorConnected(AnchorEdgeType.Bottom, deltaY); 2652 2636 } … … 2669 2653 } 2670 2654 2671 protected Rectangle getPixelBounds(TextLayout layout) { 2655 protected AxisAlignedBoxBounds getPixelBounds(TextLayout layout) 2656 { 2672 2657 // Does 'layout' need to be synchronized (similar to _textLayouts below)?? 2673 2658 int x = getX(); … … 2675 2660 2676 2661 int ldx = 1 + x + getJustOffset(layout); // Layout draw x 2677 Rectangle layout_rect = layout.getPixelBounds(null,ldx, y);2662 AxisAlignedBoxBounds layout_rect = layout.getPixelBounds(ldx, y); 2678 2663 2679 2664 return layout_rect; 2680 2665 } 2681 2666 2682 2667 /** 2683 2668 * Creates the smallest possible rectangle object to enclose the Text Item … … 2689 2674 * @see #getPixelBoundsUnionTight() 2690 2675 */ 2691 public Rectangle getPixelBoundsUnion() { 2692 final Rectangle rect = getPixelBounds(_textLayouts.get(0)); 2693 2694 int cumulativeHeight = rect.height; 2695 int maxWidth = rect.width; 2676 public AxisAlignedBoxBounds getPixelBoundsUnion() 2677 { 2678 final AxisAlignedBoxBounds rect = getPixelBounds(_textLayouts.get(0)); 2679 2680 int cumulativeHeight = rect.getSize().height; 2681 int maxWidth = rect.getSize().width; 2696 2682 2697 2683 if (_textLayouts.size() > 1) { 2698 2684 for (int i = 1; i < _textLayouts.size(); i++) { 2699 final Rectangler = getPixelBounds(_textLayouts.get(i));2685 final AxisAlignedBoxBounds r = getPixelBounds(_textLayouts.get(i)); 2700 2686 cumulativeHeight += _textLayouts.get(i).getDescent() + _textLayouts.get(i).getAscent(); 2701 if (r.width > maxWidth) 2702 maxWidth = r.width; 2703 } 2704 } 2705 2706 rect.setSize(maxWidth, cumulativeHeight); 2687 if (r.getSize().width > maxWidth) 2688 maxWidth = r.getSize().width; 2689 } 2690 } 2691 2692 rect.getSize().width = maxWidth; 2693 rect.getSize().height = cumulativeHeight; 2707 2694 2708 2695 return rect; … … 2717 2704 * @see #getPixelBoundsUnion() 2718 2705 */ 2719 public Polygon getPixelBoundsUnionTight() { 2720 final Rectangle rect = getPixelBounds(_textLayouts.get(0)); 2706 public PolygonBounds getPixelBoundsUnionTight() 2707 { 2708 final AxisAlignedBoxBounds rect = getPixelBounds(_textLayouts.get(0)); 2721 2709 if (_textLayouts.size() == 1) { 2722 int x = (int) rect.getX(); 2723 int y = (int) rect.getY(); 2724 return new Polygon(new int[] { x, x + rect.width, x + rect.width, x }, 2725 new int[] { y, y, y + rect.height, y + rect.height }, 4); 2710 return PolygonBounds.fromBox(rect); 2726 2711 } else { 2727 final Polygon poly = new Polygon();2728 poly.addPoint(rect. x, rect.y);2729 poly.addPoint(rect. x + rect.width, rect.y);2730 poly.addPoint(rect. x + rect.width, Math.round(rect.y + rect.height+ _textLayouts.get(0).getDescent()));2731 int y = (int) (rect. y + rect.height+ _textLayouts.get(0).getDescent());2712 final PolygonBounds poly = new PolygonBounds(); 2713 poly.addPoint(rect.getMinX(), rect.getMinY()); 2714 poly.addPoint(rect.getMaxX(), rect.getMinY()); 2715 poly.addPoint(rect.getMaxX(), Math.round(rect.getMaxY() + _textLayouts.get(0).getDescent())); 2716 int y = (int) (rect.getMaxY() + _textLayouts.get(0).getDescent()); 2732 2717 for (int i = 1; i < _textLayouts.size(); i++) { 2733 final Rectangler = getPixelBounds(_textLayouts.get(i));2734 poly.addPoint(r. x + r.width, y);2735 poly.addPoint(r. x + r.width, Math.round(y + r.height+ _textLayouts.get(i).getDescent()));2736 y = Math.round(y + r. height+ _textLayouts.get(i).getDescent());2737 } 2738 poly.addPoint(rect. x + getPixelBounds(_textLayouts.get(_textLayouts.size() - 1)).width, Math.round(y + _textLayouts.get(_textLayouts.size() - 1).getDescent()));2739 poly.addPoint(rect. x, Math.round(y + _textLayouts.get(_textLayouts.size() - 1).getDescent()));2718 final AxisAlignedBoxBounds r = getPixelBounds(_textLayouts.get(i)); 2719 poly.addPoint(r.getMaxX(), y); 2720 poly.addPoint(r.getMaxX(), Math.round(y + r.getHeight() + _textLayouts.get(i).getDescent())); 2721 y = Math.round(y + r.getHeight() + _textLayouts.get(i).getDescent()); 2722 } 2723 poly.addPoint(rect.getMinX() + getPixelBounds(_textLayouts.get(_textLayouts.size() - 1)).getWidth(), Math.round(y + _textLayouts.get(_textLayouts.size() - 1).getDescent())); 2724 poly.addPoint(rect.getMinX(), Math.round(y + _textLayouts.get(_textLayouts.size() - 1).getDescent())); 2740 2725 return poly; 2741 2726 } 2742 2727 } 2728 2729 /* 2730 public AxisAlignedBoxBounds getPixelBoundsUnion() 2731 { 2732 synchronized (_textLayouts) { 2733 2734 CombinationBoxBounds c = null; 2735 2736 for (TextLayout layout: _textLayouts) { 2737 if (c == null) { 2738 c = new CombinationBoxBounds(getPixelBounds(layout)); 2739 } else { 2740 c.add(getPixelBounds(layout)); 2741 } 2742 } 2743 2744 return AxisAlignedBoxBounds.getEnclosing(c); 2745 2746 } 2747 } 2748 */ 2743 2749 2744 2750 // public Rectangle getPixelBoundsUnion() … … 2809 2815 _autoWrap = autoWrap; 2810 2816 } 2817 2818 /** 2819 * Creates a new Text Item whose text contains the given character. This 2820 * method also moves the mouse cursor to be pointing at the newly created 2821 * Text Item ready to insert the next character. 2822 * 2823 * @param start 2824 * The character to use as the initial text of this Item. 2825 * @return The newly created Text Item 2826 */ 2827 public static Text createText(char start) { 2828 Text t = DisplayController.getCurrentFrame().createBlankText( 2829 "" + start); 2830 2831 Point newMouse = t.insertChar(start, DisplayController.getMouseX(), DisplayController.getMouseY()); 2832 DisplayController.setCursorPosition(newMouse.x, newMouse.y, false); 2833 2834 return t; 2835 } 2836 2837 /** 2838 * Creates a new Text Item with no text. The newly created Item is a copy of 2839 * any ItemTemplate if one is present, and inherits all the attributes of 2840 * the Template 2841 * 2842 * @return The newly created Text Item 2843 */ 2844 public static Text createText() { 2845 return DisplayController.getCurrentFrame().createNewText(); 2846 } 2847 2848 /** 2849 * If the given Item is null, then a new Text item is created with the 2850 * current date. If the given Item is not null, then the current date is 2851 * prepended to the Item's text 2852 * 2853 * @param toAdd 2854 * The Item to prepend the date to, or null 2855 */ 2856 public static void AddDate(Item toAdd) { 2857 String date1 = Formatter.getDateTime(); 2858 String date2 = Formatter.getDate(); 2859 final String leftSeparator = " :"; 2860 final String rightSeparator = ": "; 2861 String dateToAdd = date1 + rightSeparator; 2862 boolean prepend = false; 2863 boolean append = false; 2864 2865 // if the user is pointing at an item, add the date where ever the 2866 // cursor is pointing 2867 if (toAdd != null && toAdd instanceof Text) { 2868 // permission check 2869 if (!toAdd.hasPermission(UserAppliedPermission.full)) { 2870 MessageBay.displayMessage("Insufficicent permission to add the date to that item"); 2871 return; 2872 } 2873 2874 Text textItem = (Text) toAdd; 2875 2876 String text = textItem.getText(); 2877 2878 // check if the default date has already been put on this item 2879 if (text.startsWith(date1 + rightSeparator)) { 2880 textItem.removeText(date1 + rightSeparator); 2881 dateToAdd = date2 + rightSeparator; 2882 prepend = true; 2883 } else if (text.startsWith(date2 + rightSeparator)) { 2884 textItem.removeText(date2 + rightSeparator); 2885 dateToAdd = leftSeparator + date2; 2886 append = true; 2887 } else if (text.endsWith(leftSeparator + date2)) { 2888 textItem.removeEndText(leftSeparator + date2); 2889 append = true; 2890 dateToAdd = leftSeparator + date1; 2891 } else if (text.endsWith(leftSeparator + date1)) { 2892 textItem.removeEndText(leftSeparator + date1); 2893 if (textItem.getLength() > 0) { 2894 dateToAdd = ""; 2895 prepend = true; 2896 } else { 2897 // use the default date format 2898 prepend = true; 2899 } 2900 } 2901 2902 if (prepend) { 2903 // add the date to the text item 2904 textItem.prependText(dateToAdd); 2905 if (dateToAdd.length() == textItem.getLength()) 2906 DisplayController.setCursorPosition(textItem.getParagraphEndPosition()); 2907 } else if (append) { 2908 textItem.appendText(dateToAdd); 2909 if (dateToAdd.length() == textItem.getLength()) 2910 DisplayController.setCursorPosition(textItem.getPosition()); 2911 } else { 2912 for (int i = 0; i < date1.length(); i++) { 2913 StandardGestureActions.processChar(date1.charAt(i), false); 2914 } 2915 } 2916 2917 textItem.getParent().setChanged(true); 2918 DisplayController.requestRefresh(true); 2919 // } else { 2920 // MessageBay 2921 // .displayMessage("Only text items can have the date prepended to 2922 // them"); 2923 // } 2924 // otherwise, create a new text item 2925 } else { 2926 Text newText = createText(); 2927 newText.setText(dateToAdd); 2928 DisplayController.getCurrentFrame().addItem(newText); 2929 DisplayController.getCurrentFrame().setChanged(true); 2930 DisplayController.requestRefresh(true); 2931 2932 DisplayController.setCursorPosition(newText.getParagraphEndPosition()); 2933 } 2934 2935 } 2811 2936 }
Note:
See TracChangeset
for help on using the changeset viewer.