Mercurial > projects > dwt2
comparison org.eclipse.swt.gtk.linux.x86/src/org/eclipse/swt/custom/StyledText.d @ 120:536e43f63c81
Comprehensive update for Win32/Linux32 dmd-2.053/dmd-1.068+Tango-r5661
===D2===
* added [Try]Immutable/Const/Shared templates to work with differenses in D1/D2 instead of version statements
used these templates to work with strict type storage rules of dmd-2.053
* com.ibm.icu now also compilable with D2, but not tested yet
* small fixes
Snippet288 - shared data is in TLS
===Phobos===
* fixed critical bugs in Phobos implemention
completely incorrect segfault prone fromStringz (Linux's port ruthless killer)
terrible, incorrect StringBuffer realization (StyledText killer)
* fixed small bugs as well
Snippet72 - misprint in the snippet
* implemented missed functionality for Phobos
ByteArrayOutputStream implemented (image loading available)
formatting correctly works for all DWT's cases
As a result, folowing snippets now works with Phobos (Snippet### - what is fixed):
Snippet24, 42, 111, 115, 130, 235, 276 - bad string formatting
Snippet48, 282 - crash on image loading
Snippet163, 189, 211, 213, 217, 218, 222 - crash on copy/cut in StyledText
Snippet244 - hang-up
===Tango===
* few changes for the latest Tango trunc-r5661
* few small performance improvments
===General===
* implMissing-s for only one version changed to implMissingInTango/InPhobos
* incorrect calls to Format in toString-s fixed
* fixed loading \uXXXX characters in ResourceBundle
* added good UTF-8 support for StyledText, TextLayout (Win32) and friends
UTF functions revised and tested. It is now in java.nonstandard.*Utf modules
StyledText and TextLayout (Win32) modules revised for UTF-8 support
* removed small diferences in most identical files in *.swt.* folders
*.swt.internal.image, *.swt.events and *.swt.custom are identical in Win32/Linux32
now 179 of 576 (~31%) files in *.swt.* folders are fully identical
* Win32: snippets now have right subsystem, pretty icons and native system style controls
* small fixes in snippets
Snippet44 - it's not Snippet44
Snippet212 - functions work with different images and offsets arrays
Win32: Snippet282 - crash on close if the button has an image
Snippet293 - setGrayed is commented
and others
Win32: As a result, folowing snippets now works
Snippet68 - color doesn't change
Snippet163, 189, 211, 213, 217, 218, 222 - UTF-8 issues (see above)
Snippet193 - no tabel headers
author | Denis Shelomovskij <verylonglogin.reg@gmail.com> |
---|---|
date | Sat, 09 Jul 2011 15:50:20 +0300 |
parents | fb3aa8075988 |
children |
comparison
equal
deleted
inserted
replaced
119:d00e8db0a568 | 120:536e43f63c81 |
---|---|
80 import org.eclipse.swt.custom.DefaultContent; | 80 import org.eclipse.swt.custom.DefaultContent; |
81 import org.eclipse.swt.custom.StyledTextDropTargetEffect; | 81 import org.eclipse.swt.custom.StyledTextDropTargetEffect; |
82 import org.eclipse.swt.custom.StyledTextListener; | 82 import org.eclipse.swt.custom.StyledTextListener; |
83 import org.eclipse.swt.custom.ST; | 83 import org.eclipse.swt.custom.ST; |
84 | 84 |
85 import java.lang.all; | |
86 import java.nonstandard.UnsafeUtf; | |
87 | |
85 version(Tango){ | 88 version(Tango){ |
86 static import tango.io.model.IFile; | 89 static import tango.io.model.IFile; |
87 import tango.util.Convert; | |
88 } else { // Phobos | 90 } else { // Phobos |
89 import std.conv; | |
90 static import std.string; | 91 static import std.string; |
91 } | 92 } |
92 import java.lang.all; | |
93 | 93 |
94 | 94 |
95 /** | 95 /** |
96 * A StyledText is an editable user interface object that displays lines | 96 * A StyledText is an editable user interface object that displays lines |
97 * of text. The following style attributes can be defined for the text: | 97 * of text. The following style attributes can be defined for the text: |
148 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: CustomControlExample, TextEditor</a> | 148 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: CustomControlExample, TextEditor</a> |
149 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> | 149 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> |
150 */ | 150 */ |
151 public class StyledText : Canvas { | 151 public class StyledText : Canvas { |
152 alias Canvas.computeSize computeSize; | 152 alias Canvas.computeSize computeSize; |
153 package: | |
153 | 154 |
154 static const char TAB = '\t'; | 155 static const char TAB = '\t'; |
155 version(Tango){ | 156 version(Tango){ |
156 static const String PlatformLineDelimiter = tango.io.model.IFile.FileConst.NewlineString; | 157 static const String PlatformLineDelimiter = tango.io.model.IFile.FileConst.NewlineString; |
157 } else { // Phobos | 158 } else { // Phobos |
194 int leftMargin; | 195 int leftMargin; |
195 int topMargin; | 196 int topMargin; |
196 int rightMargin; | 197 int rightMargin; |
197 int bottomMargin; | 198 int bottomMargin; |
198 int columnX; // keep track of the horizontal caret position when changing lines/pages. Fixes bug 5935 | 199 int columnX; // keep track of the horizontal caret position when changing lines/pages. Fixes bug 5935 |
199 int caretOffset = 0; | 200 int/*UTF8index*/ caretOffset = 0; |
200 int caretAlignment; | 201 int caretAlignment; |
201 Point selection; // x and y are start and end caret offsets of selection | 202 Point selection; // x and y are start and end caret offsets of selection |
202 Point clipboardSelection; // x and y are start and end caret offsets of previous selection | 203 Point clipboardSelection; // x and y are start and end caret offsets of previous selection |
203 int selectionAnchor; // position of selection anchor. 0 based offset from beginning of text | 204 bool selectedTextValid = true; // DWT: false if we just changed a text witch was selected |
205 int/*UTF8index*/ selectionAnchor; // position of selection anchor. 0 based offset from beginning of text | |
204 Point doubleClickSelection; // selection after last mouse double click | 206 Point doubleClickSelection; // selection after last mouse double click |
205 bool editable = true; | 207 bool editable = true; |
206 bool wordWrap = false; | 208 bool wordWrap = false; |
207 bool doubleClickEnabled = true; // see getDoubleClickEnabled | 209 bool doubleClickEnabled = true; // see getDoubleClickEnabled |
208 bool overwrite = false; // insert/overwrite edit mode | 210 bool overwrite = false; // insert/overwrite edit mode |
209 int textLimit = -1; // limits the number of characters the user can type in the widget. Unlimited by default. | 211 int/*UTF8index*/ textLimit = -1; // limits the number of characters the user can type in the widget. Unlimited by default. |
210 int[int] keyActionMap; | 212 int[int] keyActionMap; |
211 Color background = null; // workaround for bug 4791 | 213 Color background = null; // workaround for bug 4791 |
212 Color foreground = null; // | 214 Color foreground = null; // |
213 Clipboard clipboard; | 215 Clipboard clipboard; |
214 int clickCount; | 216 int clickCount; |
236 bool justify; | 238 bool justify; |
237 int indent; | 239 int indent; |
238 int lineSpacing; | 240 int lineSpacing; |
239 | 241 |
240 const static bool IS_CARBON, IS_GTK, IS_MOTIF; | 242 const static bool IS_CARBON, IS_GTK, IS_MOTIF; |
241 static this(){ | 243 mixin(sharedStaticThis!(`{ |
242 String platform = SWT.getPlatform(); | 244 String platform = SWT.getPlatform(); |
243 IS_CARBON = ("carbon" == platform); | 245 IS_CARBON = ("carbon" == platform); |
244 IS_GTK = ("gtk" == platform); | 246 IS_GTK = ("gtk" == platform); |
245 IS_MOTIF = ("motif" == platform); | 247 IS_MOTIF = ("motif" == platform); |
246 } | 248 }`)); |
247 | 249 |
248 /** | 250 /** |
249 * The Printing class : printing of a range of text. | 251 * The Printing class : printing of a range of text. |
250 * An instance of <code>Printing</code> is returned in the | 252 * An instance of <code>Printing</code> is returned in the |
251 * StyledText#print(Printer) API. The run() method may be | 253 * StyledText#print(Printer) API. The run() method may be |
510 int pageSize = clientArea.height / lineHeight;//WRONG | 512 int pageSize = clientArea.height / lineHeight;//WRONG |
511 startLine = (startPage - 1) * pageSize; | 513 startLine = (startPage - 1) * pageSize; |
512 } else if (data.scope_ is PrinterData.SELECTION) { | 514 } else if (data.scope_ is PrinterData.SELECTION) { |
513 startLine = content.getLineAtOffset(selection.x); | 515 startLine = content.getLineAtOffset(selection.x); |
514 if (selection.y > 0) { | 516 if (selection.y > 0) { |
517 // DWT: index isn't a valid UTF-8 index | |
515 endLine = content.getLineAtOffset(selection.x + selection.y - 1); | 518 endLine = content.getLineAtOffset(selection.x + selection.y - 1); |
516 } else { | 519 } else { |
517 endLine = startLine - 1; | 520 endLine = startLine - 1; |
518 } | 521 } |
519 } | 522 } |
706 printLayout.setText(lineLabels[index]); | 709 printLayout.setText(lineLabels[index]); |
707 } else { | 710 } else { |
708 printLayout.setText(""); | 711 printLayout.setText(""); |
709 } | 712 } |
710 } else { | 713 } else { |
711 printLayout.setText(to!(String)(index)); | 714 printLayout.setText(String_valueOf(index)); |
712 } | 715 } |
713 int paintX = x - printMargin - printLayout.getBounds().width; | 716 int paintX = x - printMargin - printLayout.getBounds().width; |
714 printLayout.draw(gc, paintX, y); | 717 printLayout.draw(gc, paintX, y); |
715 printLayout.setAscent(-1); | 718 printLayout.setAscent(-1); |
716 printLayout.setDescent(-1); | 719 printLayout.setDescent(-1); |
834 } | 837 } |
835 /** | 838 /** |
836 * Determines if Unicode RTF should be written. | 839 * Determines if Unicode RTF should be written. |
837 * Don't write Unicode RTF on Windows 95/98/ME or NT. | 840 * Don't write Unicode RTF on Windows 95/98/ME or NT. |
838 */ | 841 */ |
839 void setUnicode() { | 842 void setUnicode() {/*!!!*/ |
840 // const String Win95 = "windows 95"; | 843 // const String Win95 = "windows 95"; |
841 // const String Win98 = "windows 98"; | 844 // const String Win98 = "windows 98"; |
842 // const String WinME = "windows me"; | 845 // const String WinME = "windows me"; |
843 // const String WinNT = "windows nt"; | 846 // const String WinNT = "windows nt"; |
844 // String osName = System.getProperty("os.name").toLowerCase(); | 847 // String osName = System.getProperty("os.name").toLowerCase(); |
871 * line breaks. Line breaks should be written using writeLineDelimiter() | 874 * line breaks. Line breaks should be written using writeLineDelimiter() |
872 * @param start start offset of segment. 0 based. | 875 * @param start start offset of segment. 0 based. |
873 * @param end end offset of segment | 876 * @param end end offset of segment |
874 */ | 877 */ |
875 void write(String string, int start, int end) { | 878 void write(String string, int start, int end) { |
876 start = 0; | 879 int incr; |
877 end = string.length; | 880 for (int index = start; index < end; index += incr) { |
878 int incr = 1; | 881 dchar ch = string.dcharAt(index, incr); |
879 for (int index = start; index < end; index+=incr) { | |
880 dchar ch = firstCodePoint( string[index .. $], incr ); | |
881 if (ch > 0xFF && WriteUnicode) { | 882 if (ch > 0xFF && WriteUnicode) { |
882 // write the sub string from the last escaped character | 883 // write the sub string from the last escaped character |
883 // to the current one. Fixes bug 21698. | 884 // to the current one. Fixes bug 21698. |
884 if (index > start) { | 885 if (index > start) { |
885 write( string[start .. index ] ); | 886 write( string[start .. index ] ); |
886 } | 887 } |
887 write("\\u"); | 888 write("\\u"); |
888 write( to!(String)( cast(short)ch )); | 889 write( String_valueOf( cast(short)ch )); |
889 write(' '); // control word delimiter | 890 write(' '); // control word delimiter |
890 start = index + incr; | 891 start = index + incr; |
891 } else if (ch is '}' || ch is '{' || ch is '\\') { | 892 } else if (ch is '}' || ch is '{' || ch is '\\') { |
892 // write the sub string from the last escaped character | 893 // write the sub string from the last escaped character |
893 // to the current one. Fixes bug 21698. | 894 // to the current one. Fixes bug 21698. |
894 if (index > start) { | 895 if (index > start) { |
895 write(string[start .. index]); | 896 write(string[start .. index]); |
896 } | 897 } |
897 write('\\'); | 898 write('\\'); |
898 write(cast(char)ch); // ok because one of {}\ | 899 write(cast(char)ch); // ok because one of {}\ |
900 assert(incr == 1); | |
899 start = index + 1; | 901 start = index + 1; |
900 } | 902 } |
901 } | 903 } |
902 // write from the last escaped character to the end. | 904 // write from the last escaped character to the end. |
903 // Fixes bug 21698. | 905 // Fixes bug 21698. |
913 FontData fontData = getFont().getFontData()[0]; | 915 FontData fontData = getFont().getFontData()[0]; |
914 header.append("{\\rtf1\\ansi"); | 916 header.append("{\\rtf1\\ansi"); |
915 // specify code page, necessary for copy to work in bidi | 917 // specify code page, necessary for copy to work in bidi |
916 // systems that don't support Unicode RTF. | 918 // systems that don't support Unicode RTF. |
917 // PORTING_TODO: String cpg = System.getProperty("file.encoding").toLowerCase(); | 919 // PORTING_TODO: String cpg = System.getProperty("file.encoding").toLowerCase(); |
918 String cpg = "UTF16"; | 920 //String cpg = "UTF16"; |
919 /+ | 921 /+ |
920 if (cpg.startsWith("cp") || cpg.startsWith("ms")) { | 922 if (cpg.startsWith("cp") || cpg.startsWith("ms")) { |
921 cpg = cpg.substring(2, cpg.length()); | 923 cpg = cpg.substring(2, cpg.length()); |
922 header.append("\\ansicpg"); | 924 header.append("\\ansicpg"); |
923 header.append(cpg); | 925 header.append(cpg); |
1762 int length = content.getCharCount(); | 1764 int length = content.getCharCount(); |
1763 // called internally to remove selection after text is removed | 1765 // called internally to remove selection after text is removed |
1764 // therefore make sure redraw range is valid. | 1766 // therefore make sure redraw range is valid. |
1765 int redrawStart = Math.min(selectionStart, length); | 1767 int redrawStart = Math.min(selectionStart, length); |
1766 int redrawEnd = Math.min(selectionEnd, length); | 1768 int redrawEnd = Math.min(selectionEnd, length); |
1767 if (redrawEnd - redrawStart > 0) { | 1769 if (redrawEnd - redrawStart > 0 && selectedTextValid) { |
1768 internalRedrawRange(redrawStart, redrawEnd - redrawStart); | 1770 internalRedrawRange(redrawStart, redrawEnd - redrawStart); |
1769 } | 1771 } |
1770 if (sendEvent) { | 1772 if (sendEvent) { |
1771 sendSelectionEvent(); | 1773 sendSelectionEvent(); |
1772 } | 1774 } |
1773 } | 1775 } |
1776 selectedTextValid = true; | |
1774 } | 1777 } |
1775 public override Point computeSize (int wHint, int hHint, bool changed) { | 1778 public override Point computeSize (int wHint, int hHint, bool changed) { |
1776 checkWidget(); | 1779 checkWidget(); |
1777 int lineCount = (getStyle() & SWT.SINGLE) !is 0 ? 1 : content.getLineCount(); | 1780 int lineCount = (getStyle() & SWT.SINGLE) !is 0 ? 1 : content.getLineCount(); |
1778 int width = 0; | 1781 int width = 0; |
2241 sendKeyEvent(event); | 2244 sendKeyEvent(event); |
2242 } else if (caretOffset > 0) { | 2245 } else if (caretOffset > 0) { |
2243 int lineIndex = content.getLineAtOffset(caretOffset); | 2246 int lineIndex = content.getLineAtOffset(caretOffset); |
2244 int lineOffset = content.getOffsetAtLine(lineIndex); | 2247 int lineOffset = content.getOffsetAtLine(lineIndex); |
2245 if (caretOffset is lineOffset) { | 2248 if (caretOffset is lineOffset) { |
2246 // SWT: on line start, delete line break | 2249 // DWT: on line start, delete line break |
2247 lineOffset = content.getOffsetAtLine(lineIndex - 1); | 2250 lineOffset = content.getOffsetAtLine(lineIndex - 1); |
2248 event.start = lineOffset + content.getLine(lineIndex - 1).length; | 2251 event.start = lineOffset + content.getLine(lineIndex - 1).length; |
2249 event.end = caretOffset; | 2252 event.end = caretOffset; |
2250 } else { | 2253 } else { |
2251 TextLayout layout = renderer.getTextLayout(lineIndex); | 2254 TextLayout layout = renderer.getTextLayout(lineIndex); |
2252 int start = layout.getPreviousOffset(caretOffset - lineOffset, SWT.MOVEMENT_CLUSTER); | 2255 int start = layout.getPreviousOffset(caretOffset - lineOffset, SWT.MOVEMENT_CHAR); |
2253 renderer.disposeTextLayout(layout); | 2256 renderer.disposeTextLayout(layout); |
2254 event.start = start + lineOffset; | 2257 event.start = start + lineOffset; |
2255 event.end = caretOffset; | 2258 event.end = caretOffset; |
2256 } | 2259 } |
2257 sendKeyEvent(event); | 2260 sendKeyEvent(event); |
2285 int lineOffset = content.getOffsetAtLine(lineIndex); | 2288 int lineOffset = content.getOffsetAtLine(lineIndex); |
2286 String line = content.getLine(lineIndex); | 2289 String line = content.getLine(lineIndex); |
2287 // replace character at caret offset if the caret is not at the | 2290 // replace character at caret offset if the caret is not at the |
2288 // end of the line | 2291 // end of the line |
2289 if (event.end < lineOffset + line.length) { | 2292 if (event.end < lineOffset + line.length) { |
2290 event.end+=dcharToString( key ).length; | 2293 event.end += line.UTF8strideAt(event.end - lineOffset); |
2291 } | 2294 } |
2292 event.text = dcharToString( key ); | 2295 event.text = dcharToString( key ); |
2293 } else { | 2296 } else { |
2294 event.text = dcharToString( key ); | 2297 event.text = dcharToString( key ); |
2295 } | 2298 } |
2770 index--; | 2773 index--; |
2771 } | 2774 } |
2772 if (index is -1 && lineIndex > 0) { | 2775 if (index is -1 && lineIndex > 0) { |
2773 bottomOffset = content.getOffsetAtLine(lineIndex - 1) + content.getLine(lineIndex - 1).length; | 2776 bottomOffset = content.getOffsetAtLine(lineIndex - 1) + content.getLine(lineIndex - 1).length; |
2774 } else { | 2777 } else { |
2775 bottomOffset = content.getOffsetAtLine(lineIndex) + Math.max(0, layout.getLineOffsets()[index + 1] - 1); | 2778 bottomOffset = content.getOffsetAtLine(lineIndex) + Math.max(0, getPreviousCharOffset(lineIndex, layout.getLineOffsets()[index + 1])); |
2776 } | 2779 } |
2777 renderer.disposeTextLayout(layout); | 2780 renderer.disposeTextLayout(layout); |
2778 } else { | 2781 } else { |
2779 int lineIndex = getBottomIndex(); | 2782 int lineIndex = getBottomIndex(); |
2780 bottomOffset = content.getOffsetAtLine(lineIndex) + content.getLine(lineIndex).length; | 2783 bottomOffset = content.getOffsetAtLine(lineIndex) + content.getLine(lineIndex).length; |
3966 public int getOffsetAtLocation(Point point) { | 3969 public int getOffsetAtLocation(Point point) { |
3967 checkWidget(); | 3970 checkWidget(); |
3968 if (point is null) { | 3971 if (point is null) { |
3969 SWT.error(SWT.ERROR_NULL_ARGUMENT); | 3972 SWT.error(SWT.ERROR_NULL_ARGUMENT); |
3970 } | 3973 } |
3971 int[] trailing = new int[1]; | 3974 int[1] trailing; |
3972 int offset = getOffsetAtPoint(point.x, point.y, trailing, true); | 3975 int offset = getOffsetAtPoint(point.x, point.y, trailing, true); |
3973 if (offset is -1) { | 3976 if (offset is -1) { |
3974 SWT.error(SWT.ERROR_INVALID_ARGUMENT); | 3977 SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
3975 } | 3978 } |
3976 return offset + trailing[0]; | 3979 return offset + trailing[0]; |
4002 caretAlignment = PREVIOUS_OFFSET_TRAILING; | 4005 caretAlignment = PREVIOUS_OFFSET_TRAILING; |
4003 } else { | 4006 } else { |
4004 String line = content.getLine(lineIndex); | 4007 String line = content.getLine(lineIndex); |
4005 int level; | 4008 int level; |
4006 int offset = offsetInLine; | 4009 int offset = offsetInLine; |
4007 while (offset > 0 && Character.isDigit(line.dcharAt(offset))) offset--; | 4010 while (offset > 0 && Character.isDigit(line.dcharAt(offset))) |
4011 offset = line.offsetBefore(offset); | |
4008 if (offset is 0 && Character.isDigit(line.dcharAt(offset))) { | 4012 if (offset is 0 && Character.isDigit(line.dcharAt(offset))) { |
4009 level = isMirrored() ? 1 : 0; | 4013 level = isMirrored() ? 1 : 0; |
4010 } else { | 4014 } else { |
4011 level = layout.getLevel(offset) & 0x1; | 4015 level = layout.getLevel(offset) & 0x1; |
4012 } | 4016 } |
4632 checkWidget(); | 4636 checkWidget(); |
4633 int contentLength = getCharCount(); | 4637 int contentLength = getCharCount(); |
4634 if (start < 0 || start >= contentLength || end < 0 || end >= contentLength || start > end) { | 4638 if (start < 0 || start >= contentLength || end < 0 || end >= contentLength || start > end) { |
4635 SWT.error(SWT.ERROR_INVALID_RANGE); | 4639 SWT.error(SWT.ERROR_INVALID_RANGE); |
4636 } | 4640 } |
4637 return content.getTextRange(start, end - start + 1); | 4641 auto res = content.getTextRange(start, content.getCharCount() - start); |
4642 return res[0 .. res.offsetAfter(end - start)]; | |
4638 } | 4643 } |
4639 /** | 4644 /** |
4640 * Returns the smallest bounding rectangle that includes the characters between two offsets. | 4645 * Returns the smallest bounding rectangle that includes the characters between two offsets. |
4641 * | 4646 * |
4642 * @param start offset of the first character included in the bounding box | 4647 * @param start offset of the first character included in the bounding box |
4806 int lineOffset = content.getOffsetAtLine(caretLine); | 4811 int lineOffset = content.getOffsetAtLine(caretLine); |
4807 String line = content.getLine(caretLine); | 4812 String line = content.getLine(caretLine); |
4808 int offset = caretOffset - lineOffset; | 4813 int offset = caretOffset - lineOffset; |
4809 int lineLength = line.length; | 4814 int lineLength = line.length; |
4810 if (lineLength is 0) return isMirrored() ? SWT.RIGHT : SWT.LEFT; | 4815 if (lineLength is 0) return isMirrored() ? SWT.RIGHT : SWT.LEFT; |
4811 if (caretAlignment is PREVIOUS_OFFSET_TRAILING && offset > 0) offset--; | 4816 if (caretAlignment is PREVIOUS_OFFSET_TRAILING && offset > 0) |
4812 if (offset is lineLength && offset > 0) offset--; | 4817 offset = line.offsetBefore(offset); |
4813 while (offset > 0 && Character.isDigit(line.dcharAt(offset))) offset--; | 4818 if (offset is lineLength && offset > 0) |
4819 offset = line.offsetBefore(offset); | |
4820 while (offset > 0 && Character.isDigit(line.dcharAt(offset))) | |
4821 offset = line.offsetBefore(offset); | |
4814 if (offset is 0 && Character.isDigit(line.dcharAt(offset))) { | 4822 if (offset is 0 && Character.isDigit(line.dcharAt(offset))) { |
4815 return isMirrored() ? SWT.RIGHT : SWT.LEFT; | 4823 return isMirrored() ? SWT.RIGHT : SWT.LEFT; |
4816 } | 4824 } |
4817 TextLayout layout = renderer.getTextLayout(caretLine); | 4825 TextLayout layout = renderer.getTextLayout(caretLine); |
4818 int level = layout.getLevel(offset); | 4826 int level = layout.getLevel(offset); |
4902 String line = content.getLine(lineIndex); | 4910 String line = content.getLine(lineIndex); |
4903 int lineOffset = content.getOffsetAtLine(lineIndex); | 4911 int lineOffset = content.getOffsetAtLine(lineIndex); |
4904 int offsetInLine = offset - lineOffset; | 4912 int offsetInLine = offset - lineOffset; |
4905 int lineLength = line.length; | 4913 int lineLength = line.length; |
4906 if (lineIndex < content.getLineCount() - 1) { | 4914 if (lineIndex < content.getLineCount() - 1) { |
4907 int endLineOffset = content.getOffsetAtLine(lineIndex + 1) - 1; | 4915 int afterEndLineOffset = content.getOffsetAtLine(lineIndex + 1); |
4908 if (lineLength < offsetInLine && offsetInLine <= endLineOffset) { | 4916 if (lineLength < offsetInLine && offsetInLine < afterEndLineOffset) { |
4909 offsetInLine = lineLength; | 4917 offsetInLine = lineLength; |
4910 } | 4918 } |
4911 } | 4919 } |
4912 Point point; | 4920 Point point; |
4913 TextLayout layout = renderer.getTextLayout(lineIndex); | 4921 TextLayout layout = renderer.getTextLayout(lineIndex); |
4914 if (lineLength !is 0 && offsetInLine <= lineLength) { | 4922 if (lineLength !is 0 && offsetInLine <= lineLength) { |
4915 if (offsetInLine is lineLength) { | 4923 if (offsetInLine is lineLength) { |
4916 // SWT: Instead of go back one byte, go back one codepoint | 4924 point = layout.getLocation(getPreviousCharOffset(lineIndex, offsetInLine), true); |
4917 int offsetInLine_m1 = layout.getPreviousOffset(offsetInLine, SWT.MOVEMENT_CLUSTER); | |
4918 point = layout.getLocation(offsetInLine_m1, true); | |
4919 } else { | 4925 } else { |
4920 switch (caretAlignment) { | 4926 switch (caretAlignment) { |
4921 case OFFSET_LEADING: | 4927 case OFFSET_LEADING: |
4922 point = layout.getLocation(offsetInLine, false); | 4928 point = layout.getLocation(offsetInLine, false); |
4923 break; | 4929 break; |
4924 case PREVIOUS_OFFSET_TRAILING: | 4930 case PREVIOUS_OFFSET_TRAILING: |
4925 default: | 4931 default: |
4926 if (offsetInLine is 0) { | 4932 if (offsetInLine is 0) { |
4927 point = layout.getLocation(offsetInLine, false); | 4933 point = layout.getLocation(offsetInLine, false); |
4928 } else { | 4934 } else { |
4929 // SWT: Instead of go back one byte, go back one codepoint | 4935 point = layout.getLocation(getPreviousCharOffset(lineIndex, offsetInLine), true); |
4930 int offsetInLine_m1 = layout.getPreviousOffset(offsetInLine, SWT.MOVEMENT_CLUSTER); | |
4931 point = layout.getLocation(offsetInLine_m1, true); | |
4932 } | 4936 } |
4933 break; | 4937 break; |
4934 } | 4938 } |
4935 } | 4939 } |
4936 } else { | 4940 } else { |
5075 | 5079 |
5076 if (startLine is endLine) { | 5080 if (startLine is endLine) { |
5077 int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length)); | 5081 int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length)); |
5078 if (startIndex is endIndex) { | 5082 if (startIndex is endIndex) { |
5079 /* Redraw rect between start and end offset if start and end offsets are in same wrapped line */ | 5083 /* Redraw rect between start and end offset if start and end offsets are in same wrapped line */ |
5080 Rectangle rect = layout.getBounds(start, end - 1); | 5084 Rectangle rect = layout.getBounds( start, getPreviousCharOffset(startLine, end) ); |
5081 rect.x += lineX; | 5085 rect.x += lineX; |
5082 rect.y += startLineY; | 5086 rect.y += startLineY; |
5083 super.redraw(rect.x, rect.y, rect.width, rect.height, false); | 5087 super.redraw(rect.x, rect.y, rect.width, rect.height, false); |
5084 renderer.disposeTextLayout(layout); | 5088 renderer.disposeTextLayout(layout); |
5085 return; | 5089 return; |
5086 } | 5090 } |
5087 } | 5091 } |
5088 | 5092 |
5089 /* Redraw start line from the start offset to the end of client area */ | 5093 /* Redraw start line from the start offset to the end of client area */ |
5090 Rectangle startRect = layout.getBounds(start, offsets[startIndex + 1] - 1); | 5094 Rectangle startRect = layout.getBounds( start, getPreviousCharOffset(startLine, offsets[startIndex + 1]) ); |
5091 if (startRect.height is 0) { | 5095 if (startRect.height is 0) { |
5092 Rectangle bounds = layout.getLineBounds(startIndex); | 5096 Rectangle bounds = layout.getLineBounds(startIndex); |
5093 startRect.x = bounds.width; | 5097 startRect.x = bounds.width; |
5094 startRect.y = bounds.y; | 5098 startRect.y = bounds.y; |
5095 startRect.height = bounds.height; | 5099 startRect.height = bounds.height; |
5104 renderer.disposeTextLayout(layout); | 5108 renderer.disposeTextLayout(layout); |
5105 layout = renderer.getTextLayout(endLine); | 5109 layout = renderer.getTextLayout(endLine); |
5106 offsets = layout.getLineOffsets(); | 5110 offsets = layout.getLineOffsets(); |
5107 } | 5111 } |
5108 int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length)); | 5112 int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length)); |
5109 Rectangle endRect = layout.getBounds(offsets[endIndex], end - 1); | 5113 Rectangle endRect = layout.getBounds(offsets[endIndex], getPreviousCharOffset(endLine, end)); |
5110 if (endRect.height is 0) { | 5114 if (endRect.height is 0) { |
5111 Rectangle bounds = layout.getLineBounds(endIndex); | 5115 Rectangle bounds = layout.getLineBounds(endIndex); |
5112 endRect.y = bounds.y; | 5116 endRect.y = bounds.y; |
5113 endRect.height = bounds.height; | 5117 endRect.height = bounds.height; |
5114 } | 5118 } |
5122 if (endRect.y > y) { | 5126 if (endRect.y > y) { |
5123 super.redraw(leftMargin, y, clientAreaWidth - rightMargin - leftMargin, endRect.y - y, false); | 5127 super.redraw(leftMargin, y, clientAreaWidth - rightMargin - leftMargin, endRect.y - y, false); |
5124 } | 5128 } |
5125 } | 5129 } |
5126 void handleCompositionOffset (Event event) { | 5130 void handleCompositionOffset (Event event) { |
5127 int[] trailing = new int [1]; | 5131 int[1] trailing; |
5128 event.index = getOffsetAtPoint(event.x, event.y, trailing, true); | 5132 event.index = getOffsetAtPoint(event.x, event.y, trailing, true); |
5129 event.count = trailing[0]; | 5133 event.count = trailing[0]; |
5130 } | 5134 } |
5131 void handleCompositionSelection (Event event) { | 5135 void handleCompositionSelection (Event event) { |
5132 event.start = selection.x; | 5136 event.start = selection.x; |
5149 if (ime.getWideCaret()) { | 5153 if (ime.getWideCaret()) { |
5150 start = ime.getCompositionOffset(); | 5154 start = ime.getCompositionOffset(); |
5151 int lineIndex = getCaretLine(); | 5155 int lineIndex = getCaretLine(); |
5152 int lineOffset = content.getOffsetAtLine(lineIndex); | 5156 int lineOffset = content.getOffsetAtLine(lineIndex); |
5153 TextLayout layout = renderer.getTextLayout(lineIndex); | 5157 TextLayout layout = renderer.getTextLayout(lineIndex); |
5154 caretWidth = layout.getBounds(start - lineOffset, start + length - 1 - lineOffset).width; | 5158 caretWidth = layout.getBounds(start - lineOffset, getPreviousCharOffset(lineIndex, start + length - lineOffset)).width; |
5155 renderer.disposeTextLayout(layout); | 5159 renderer.disposeTextLayout(layout); |
5156 } | 5160 } |
5157 } | 5161 } |
5158 showCaret(); | 5162 showCaret(); |
5159 } | 5163 } |
5664 if (label !is null) { | 5668 if (label !is null) { |
5665 String text = label.getText (); | 5669 String text = label.getText (); |
5666 if (text !is null) { | 5670 if (text !is null) { |
5667 dchar mnemonic = _findMnemonic (text); | 5671 dchar mnemonic = _findMnemonic (text); |
5668 if (mnemonic !is '\0') { | 5672 if (mnemonic !is '\0') { |
5669 shortcut = Format("Alt+{}", mnemonic ); //$NON-NLS-1$ | 5673 shortcut = "Alt+"~dcharToString(mnemonic); //$NON-NLS-1$ |
5670 } | 5674 } |
5671 } | 5675 } |
5672 } | 5676 } |
5673 e.result = shortcut; | 5677 e.result = shortcut; |
5674 } | 5678 } |
5745 int index = 0; | 5749 int index = 0; |
5746 int length_ = string.length; | 5750 int length_ = string.length; |
5747 do { | 5751 do { |
5748 while (index < length_ && string[index] !is '&') index++; | 5752 while (index < length_ && string[index] !is '&') index++; |
5749 if (++index >= length_) return '\0'; | 5753 if (++index >= length_) return '\0'; |
5750 if (string[index] !is '&') return CharacterFirstToLower(string[index .. $ ] ); | 5754 if (string[index] !is '&') return Character.toLowerCase (string.dcharAt (index)); |
5751 index++; | 5755 index++; |
5752 } while (index < length_); | 5756 } while (index < length_); |
5753 return '\0'; | 5757 return '\0'; |
5754 } | 5758 } |
5755 /** | 5759 /** |
7825 * @param sendEvent a Selection event is sent when set to true and when | 7829 * @param sendEvent a Selection event is sent when set to true and when |
7826 * the selection is reset. | 7830 * the selection is reset. |
7827 */ | 7831 */ |
7828 void setSelection(int start, int length, bool sendEvent) { | 7832 void setSelection(int start, int length, bool sendEvent) { |
7829 int end = start + length; | 7833 int end = start + length; |
7830 start = content.utf8AdjustOffset(start); | |
7831 end = content.utf8AdjustOffset(end); | |
7832 if (start > end) { | 7834 if (start > end) { |
7833 int temp = end; | 7835 int temp = end; |
7834 end = start; | 7836 end = start; |
7835 start = temp; | 7837 start = temp; |
7836 } | 7838 } |
8325 } | 8327 } |
8326 setScrollBars(true); | 8328 setScrollBars(true); |
8327 setCaretLocation(); | 8329 setCaretLocation(); |
8328 super.redraw(); | 8330 super.redraw(); |
8329 } | 8331 } |
8330 // SWT: If necessary, scroll to show the location | 8332 // DWT: If necessary, scroll to show the location |
8331 bool showLocation(Rectangle rect, bool scrollPage) { | 8333 bool showLocation(Rectangle rect, bool scrollPage) { |
8332 int clientAreaWidth = this.clientAreaWidth - leftMargin - rightMargin; | 8334 int clientAreaWidth = this.clientAreaWidth - leftMargin - rightMargin; |
8333 int clientAreaHeight = this.clientAreaHeight - topMargin - bottomMargin; | 8335 int clientAreaHeight = this.clientAreaHeight - topMargin - bottomMargin; |
8334 bool scrolled = false; | 8336 bool scrolled = false; |
8335 if (rect.y <= topMargin) { | 8337 if (rect.y <= topMargin) { |
8442 // change. Selection is only affected if it intersects the change (1GDY217). | 8444 // change. Selection is only affected if it intersects the change (1GDY217). |
8443 int netNewLength = newLength - replacedLength; | 8445 int netNewLength = newLength - replacedLength; |
8444 int redrawStart = startOffset + newLength; | 8446 int redrawStart = startOffset + newLength; |
8445 internalRedrawRange(redrawStart, selection.y + netNewLength - redrawStart); | 8447 internalRedrawRange(redrawStart, selection.y + netNewLength - redrawStart); |
8446 } | 8448 } |
8449 selectedTextValid = false; | |
8447 if (selection.y > startOffset && selection.x < startOffset + replacedLength) { | 8450 if (selection.y > startOffset && selection.x < startOffset + replacedLength) { |
8448 // selection intersects replaced text. set caret behind text change | 8451 // selection intersects replaced text. set caret behind text change |
8449 setSelection(startOffset + newLength, 0, true); | 8452 setSelection(startOffset + newLength, 0, true); |
8450 } else { | 8453 } else { |
8451 // move selection to keep same text selected | 8454 // move selection to keep same text selected |
8452 setSelection(selection.x + newLength - replacedLength, selection.y - selection.x, true); | 8455 setSelection(selection.x + newLength - replacedLength, selection.y - selection.x, true); |
8453 } | 8456 } |
8454 setCaretLocation(); | 8457 setCaretLocation(); |
8455 } | 8458 } |
8456 } | 8459 |
8460 // DWT: to use instead of "offsetInLine - 1" | |
8461 int getPreviousCharOffset(String F = __FILE__, uint L = __LINE__)(int lineIndex, int offsetInLine) { | |
8462 String line = content.getLine(lineIndex); | |
8463 if(offsetInLine < 0 || offsetInLine > line.length) { | |
8464 getDwtLogger().warn(F, L, Format("Clamped UTF-8 offset:\noffsetInLine = {}, line.length = {}, line = {}", offsetInLine, line.length, line)); | |
8465 return offsetInLine - 1; | |
8466 } | |
8467 return line.offsetBefore(offsetInLine); | |
8468 } | |
8469 } |