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 }