diff options
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom')
12 files changed, 473 insertions, 335 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CCombo.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CCombo.java index 18fc637809..50b0a55f86 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CCombo.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CCombo.java @@ -84,6 +84,7 @@ public CCombo (Composite parent, int style) { int listStyle = SWT.SINGLE | SWT.V_SCROLL; if ((style & SWT.FLAT) != 0) listStyle |= SWT.FLAT; + if ((style & SWT.RIGHT_TO_LEFT) != 0) listStyle |= SWT.RIGHT_TO_LEFT; list = new List (popup, listStyle); int arrowStyle = SWT.ARROW | SWT.DOWN; @@ -134,7 +135,7 @@ public CCombo (Composite parent, int style) { initAccessible(); } static int checkStyle (int style) { - int mask = SWT.BORDER | SWT.READ_ONLY | SWT.FLAT; + int mask = SWT.BORDER | SWT.READ_ONLY | SWT.FLAT | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; return style & mask; } /** @@ -341,15 +342,17 @@ void dropDown (boolean drop) { text.setFocus(); return; } + int index = list.getSelectionIndex (); if (index != -1) list.setTopIndex (index); Rectangle listRect = list.getBounds (); - Point point = getParent().toDisplay (getLocation ()); - Point comboSize = getSize(); + Display display = getDisplay (); + Rectangle rect = display.map (getParent (), null, getBounds ()); + Point comboSize = getSize (); int width = Math.max (comboSize.x, listRect.width + 2); - popup.setBounds (point.x, point.y + comboSize.y, width, listRect.height + 2); + popup.setBounds (rect.x, rect.y + comboSize.y, width, listRect.height + 2); popup.setVisible (true); - list.setFocus(); + list.setFocus (); } public Control [] getChildren () { checkWidget(); diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CLabel.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CLabel.java index 9c8cfff482..7b0fdea9b0 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CLabel.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CLabel.java @@ -120,7 +120,7 @@ public CLabel(Composite parent, int style) { * Check the style bits to ensure that no invalid styles are applied. */ private static int checkStyle (int style) { - int mask = SWT.SHADOW_IN | SWT.SHADOW_OUT | SWT.SHADOW_NONE; + int mask = SWT.SHADOW_IN | SWT.SHADOW_OUT | SWT.SHADOW_NONE | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; style = style & mask; style |= SWT.NO_FOCUS; if ((style & (SWT.CENTER | SWT.RIGHT)) == 0) style |= SWT.LEFT; diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java index 7ccc95452f..4fcea2fdbe 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java @@ -237,7 +237,7 @@ public CTabFolder(Composite parent, int style) { } private static int checkStyle (int style) { - int mask = SWT.TOP | SWT.BOTTOM | SWT.FLAT; + int mask = SWT.TOP | SWT.BOTTOM | SWT.FLAT | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; style = style & mask; // TOP and BOTTOM are mutually exlusive. // TOP is the default @@ -509,12 +509,13 @@ void destroyItem (CTabItem item) { redrawTabArea(-1); } private void onKeyDown(Event e) { - if (e.keyCode == SWT.ARROW_LEFT) { + if (e.keyCode != SWT.ARROW_LEFT && e.keyCode != SWT.ARROW_RIGHT) return; + int leadKey = (getStyle() & SWT.MIRRORED) != 0 ? SWT.ARROW_RIGHT : SWT.ARROW_LEFT; + if (e.keyCode == leadKey) { if (selectedIndex > 0) { setSelection(selectedIndex - 1, true); } - } - if (e.keyCode == SWT.ARROW_RIGHT) { + } else { if (selectedIndex < items.length - 1) { setSelection(selectedIndex + 1, true); } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/DisplayRenderer.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/DisplayRenderer.java index 424413010b..38aeda8c10 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/DisplayRenderer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/DisplayRenderer.java @@ -76,6 +76,7 @@ protected void drawLineSelectionBackground(String line, int lineOffset, StyleRan int lineEndSpaceWidth = getLineEndSpaceWidth(); int lineHeight = getLineHeight(); boolean wordWrap = parent.internalGetWordWrap(); + boolean isRightOriented = (parent.getStyle() & SWT.MIRRORED) != 0; if (selectionEnd == selectionStart || selectionEnd < 0 || selectionStart > lineLength) { return; @@ -129,7 +130,7 @@ protected void drawLineSelectionBackground(String line, int lineOffset, StyleRan // if the selection extends past this line, render an additional // whitespace background at the end of the line to represent the // selected line break - if (bidi != null && selectionEnd > 0 && bidi.isRightToLeft(selectionEnd - 1)) { + if (bidi != null && selectionEnd > 0 && (bidi.isRightToLeft(selectionEnd - 1) || (isRightOriented && bidi.isRightToLeft(selectionEnd - 1) == false))) { int lineEndX = bidi.getTextWidth(); gc.fillRectangle(lineEndX - horizontalScrollOffset + leftMargin, paintY, lineEndSpaceWidth, lineHeight); } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/PopupList.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/PopupList.java index e624ca2d71..81e39cd9d2 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/PopupList.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/PopupList.java @@ -31,8 +31,18 @@ public class PopupList { * Creates a PopupList above the specified shell. */ public PopupList(Shell parent) { - - shell = new Shell(parent, 0); + this (parent, 0); +} +/** +* Creates a PopupList above the specified shell. +* +* @param parent a widget which will be the parent of the new instance (cannot be null) +* @param style the style of widget to construct +* +* @since 2.1.2 +*/ +public PopupList(Shell parent, int style) { + shell = new Shell(parent, checkStyle(style)); list = new List(shell, SWT.SINGLE | SWT.V_SCROLL); @@ -70,6 +80,10 @@ public PopupList(Shell parent) { }); } +private static int checkStyle (int style) { + int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; + return style & mask; +} /** * Gets the widget font. * <p> diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/SashForm.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/SashForm.java index a017acac2e..3aa8f773ca 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/SashForm.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/SashForm.java @@ -85,7 +85,7 @@ public SashForm(Composite parent, int style) { }; } private static int checkStyle (int style) { - int mask = SWT.BORDER; + int mask = SWT.BORDER | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; return style & mask; } public Point computeSize (int wHint, int hHint, boolean changed) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/ScrolledComposite.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/ScrolledComposite.java index 9f3cef8c20..70e9d401f5 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/ScrolledComposite.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/ScrolledComposite.java @@ -173,7 +173,7 @@ public ScrolledComposite(Composite parent, int style) { } private static int checkStyle (int style) { - int mask = SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER; + int mask = SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; return style & mask; } diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java index 80353beea8..03513c4915 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java @@ -140,6 +140,7 @@ public class StyledText extends Canvas { int lastTextChangeReplaceLineCount; // text changed handler int lastTextChangeReplaceCharCount; boolean isBidi; + boolean isMirrored; boolean bidiColoring = false; // apply the BIDI algorithm on text segments of the same color Image leftCaretBitmap = null; Image rightCaretBitmap = null; @@ -1590,7 +1591,8 @@ public StyledText(Composite parent, int style) { super.setForeground(getForeground()); super.setBackground(getBackground()); Display display = getDisplay(); - isBidi = StyledTextBidi.isBidiPlatform(); + isMirrored = (getStyle() & SWT.MIRRORED) != 0; + isBidi = StyledTextBidi.isBidiPlatform() || isMirrored; if ((style & SWT.READ_ONLY) != 0) { setEditable(false); } @@ -1612,6 +1614,9 @@ public StyledText(Composite parent, int style) { } else { createCaretBitmaps(); + if (isMirrored) { + BidiUtil.setKeyboardLanguage(BidiUtil.KEYBOARD_BIDI); + } new Caret(this, SWT.NULL); setBidiCaretDirection(); Runnable runnable = new Runnable() { @@ -2233,32 +2238,49 @@ void createKeyBindings() { setKeyBinding(SWT.ARROW_DOWN, ST.LINE_DOWN); setKeyBinding(SWT.HOME, ST.LINE_START); setKeyBinding(SWT.END, ST.LINE_END); - setKeyBinding(SWT.ARROW_LEFT, ST.COLUMN_PREVIOUS); - setKeyBinding(SWT.ARROW_RIGHT, ST.COLUMN_NEXT); setKeyBinding(SWT.PAGE_UP, ST.PAGE_UP); setKeyBinding(SWT.PAGE_DOWN, ST.PAGE_DOWN); - setKeyBinding(SWT.ARROW_LEFT | SWT.MOD1, ST.WORD_PREVIOUS); - setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD1, ST.WORD_NEXT); setKeyBinding(SWT.HOME | SWT.MOD1, ST.TEXT_START); setKeyBinding(SWT.END | SWT.MOD1, ST.TEXT_END); setKeyBinding(SWT.PAGE_UP | SWT.MOD1, ST.WINDOW_START); setKeyBinding(SWT.PAGE_DOWN | SWT.MOD1, ST.WINDOW_END); + if (isMirrored()) { + setKeyBinding(SWT.ARROW_LEFT, ST.COLUMN_NEXT); + setKeyBinding(SWT.ARROW_RIGHT, ST.COLUMN_PREVIOUS); + setKeyBinding(SWT.ARROW_LEFT | SWT.MOD1, ST.WORD_NEXT); + setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD1, ST.WORD_PREVIOUS); + } + else { + setKeyBinding(SWT.ARROW_LEFT, ST.COLUMN_PREVIOUS); + setKeyBinding(SWT.ARROW_RIGHT, ST.COLUMN_NEXT); + setKeyBinding(SWT.ARROW_LEFT | SWT.MOD1, ST.WORD_PREVIOUS); + setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD1, ST.WORD_NEXT); + } + // Selection setKeyBinding(SWT.ARROW_UP | SWT.MOD2, ST.SELECT_LINE_UP); setKeyBinding(SWT.ARROW_DOWN | SWT.MOD2, ST.SELECT_LINE_DOWN); setKeyBinding(SWT.HOME | SWT.MOD2, ST.SELECT_LINE_START); setKeyBinding(SWT.END | SWT.MOD2, ST.SELECT_LINE_END); - setKeyBinding(SWT.ARROW_LEFT | SWT.MOD2, ST.SELECT_COLUMN_PREVIOUS); - setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD2, ST.SELECT_COLUMN_NEXT); setKeyBinding(SWT.PAGE_UP | SWT.MOD2, ST.SELECT_PAGE_UP); setKeyBinding(SWT.PAGE_DOWN | SWT.MOD2, ST.SELECT_PAGE_DOWN); - setKeyBinding(SWT.ARROW_LEFT | SWT.MOD1 | SWT.MOD2, ST.SELECT_WORD_PREVIOUS); - setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD1 | SWT.MOD2, ST.SELECT_WORD_NEXT); setKeyBinding(SWT.HOME | SWT.MOD1 | SWT.MOD2, ST.SELECT_TEXT_START); setKeyBinding(SWT.END | SWT.MOD1 | SWT.MOD2, ST.SELECT_TEXT_END); setKeyBinding(SWT.PAGE_UP | SWT.MOD1 | SWT.MOD2, ST.SELECT_WINDOW_START); setKeyBinding(SWT.PAGE_DOWN | SWT.MOD1 | SWT.MOD2, ST.SELECT_WINDOW_END); - + if (isMirrored()) { + setKeyBinding(SWT.ARROW_LEFT | SWT.MOD2, ST.SELECT_COLUMN_NEXT); + setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD2, ST.SELECT_COLUMN_PREVIOUS); + setKeyBinding(SWT.ARROW_LEFT | SWT.MOD1 | SWT.MOD2, ST.SELECT_WORD_NEXT); + setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD1 | SWT.MOD2, ST.SELECT_WORD_PREVIOUS); + } + else { + setKeyBinding(SWT.ARROW_LEFT | SWT.MOD2, ST.SELECT_COLUMN_PREVIOUS); + setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD2, ST.SELECT_COLUMN_NEXT); + setKeyBinding(SWT.ARROW_LEFT | SWT.MOD1 | SWT.MOD2, ST.SELECT_WORD_PREVIOUS); + setKeyBinding(SWT.ARROW_RIGHT | SWT.MOD1 | SWT.MOD2, ST.SELECT_WORD_NEXT); + } + // Modification // Cut, Copy, Paste setKeyBinding('X' | SWT.MOD1, ST.CUT); @@ -2285,6 +2307,7 @@ void createKeyBindings() { */ void createCaretBitmaps() { int caretWidth = BIDI_CARET_WIDTH; + int gcStyle = isMirrored() ? SWT.RIGHT_TO_LEFT : SWT.LEFT_TO_RIGHT; Display display = getDisplay(); if (caretPalette == null) { @@ -2295,7 +2318,9 @@ void createCaretBitmaps() { } ImageData imageData = new ImageData(caretWidth, lineHeight, 1, caretPalette); leftCaretBitmap = new Image(display, imageData); - GC gc = new GC (leftCaretBitmap); + // mirror the caret gc because when the bitmap is rendered on the screen it will be + // mirrored since the GC for the canvas is mirrored + GC gc = new GC (leftCaretBitmap, gcStyle); gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); gc.drawLine(0,0,0,lineHeight); gc.drawLine(0,0,caretWidth-1,0); @@ -2306,7 +2331,9 @@ void createCaretBitmaps() { rightCaretBitmap.dispose(); } rightCaretBitmap = new Image(display, imageData); - gc = new GC (rightCaretBitmap); + // mirror the caret gc because when the bitmap is rendered on the screen it will be + // mirrored since the GC for the canvas is mirrored + gc = new GC (rightCaretBitmap, gcStyle); gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); gc.drawLine(caretWidth-1,0,caretWidth-1,lineHeight); gc.drawLine(0,0,caretWidth-1,0); @@ -2363,11 +2390,11 @@ void doAutoScroll(Event event) { } else if (event.x < leftMargin && wordWrap == false) { - doAutoScroll(SWT.LEFT); + doAutoScroll(ST.COLUMN_PREVIOUS); } else if (event.x > area.width - leftMargin - rightMargin && wordWrap == false) { - doAutoScroll(SWT.RIGHT); + doAutoScroll(ST.COLUMN_NEXT); } else { endAutoScroll(); @@ -2377,7 +2404,7 @@ void doAutoScroll(Event event) { * Initiates autoscrolling. * <p> * - * @param direction SWT.UP, SWT.DOWN, SWT.RIGHT, SWT.LEFT + * @param direction SWT.UP, SWT.DOWN, SWT.COLUMN_NEXT, SWT.COLUMN_PREVIOUS */ void doAutoScroll(int direction) { Runnable timer = null; @@ -2409,24 +2436,24 @@ void doAutoScroll(int direction) { } } }; - } else if (direction == SWT.RIGHT) { + } else if (direction == ST.COLUMN_NEXT) { timer = new Runnable() { public void run() { - if (autoScrollDirection == SWT.RIGHT) { - doColumnRight(); + if (autoScrollDirection == ST.COLUMN_NEXT) { + doVisualNext(); setMouseWordSelectionAnchor(); - doSelection(SWT.RIGHT); + doMouseSelection(); display.timerExec(TIMER_INTERVAL, this); } } }; - } else if (direction == SWT.LEFT) { + } else if (direction == ST.COLUMN_PREVIOUS) { timer = new Runnable() { public void run() { - if (autoScrollDirection == SWT.LEFT) { - doColumnLeft(); + if (autoScrollDirection == ST.COLUMN_PREVIOUS) { + doVisualPrevious(); setMouseWordSelectionAnchor(); - doSelection(SWT.LEFT); + doMouseSelection(); display.timerExec(TIMER_INTERVAL, this); } } @@ -2467,208 +2494,6 @@ void doBackspace() { } } /** - * Moves the caret one character to the left. Do not go to the previous line. - * When in a bidi locale and at a R2L character the caret is moved to the - * beginning of the R2L segment (visually right) and then one character to the - * left (visually left because it's now in a L2R segment). - */ -void doColumnLeft() { - int line = content.getLineAtOffset(caretOffset); - int lineOffset = content.getOffsetAtLine(line); - int offsetInLine = caretOffset - lineOffset; - - if (isBidi()) { - String lineText = content.getLine(line); - int lineLength = lineText.length(); - GC gc = getGC(); - StyledTextBidi bidi = getStyledTextBidi(lineText, lineOffset, gc); - - if (horizontalScrollOffset > 0 || offsetInLine > 0) { - if (offsetInLine < lineLength && bidi.isRightToLeft(offsetInLine)) { - // advance caret logically if in R2L segment (move visually left) - caretOffset++; - doSelection(SWT.RIGHT); - if (caretOffset - lineOffset == lineLength) { - // if the line end is reached in a R2L segment, make the - // caret position (visual left border) visible before - // jumping to segment start - showCaret(); - } - // end of R2L segment reached (visual left side)? - if (bidi.isRightToLeft(caretOffset - lineOffset) == false) { - if (bidi.getTextPosition(caretOffset - lineOffset) < horizontalScrollOffset) { - // make beginning of R2L segment visible before going - // left, to L2R segment important if R2L segment ends - // at visual left in order to scroll all the way to the - // left. Fixes 1GKM3XS - showCaret(); - } - // go to beginning of R2L segment (visually end of next L2R - // segment)/beginning of line - caretOffset--; - while (caretOffset - lineOffset > 0 && - bidi.isRightToLeft(caretOffset - lineOffset)) { - caretOffset--; - } - } - } - else - if (offsetInLine == lineLength && - bidi.getTextPosition(lineLength) != XINSET) { - // at logical line end in R2L segment but there's more text (a - // L2R segment) go to end of R2L segment (visually left of next - // L2R segment)/end of line - caretOffset--; - while (caretOffset - lineOffset > 0 && - bidi.isRightToLeft(caretOffset - lineOffset)) { - caretOffset--; - } - } - else - if (offsetInLine > 0 && bidi.isRightToLeft(offsetInLine) == false) { - // decrease caret logically if in L2R segment (move visually left) - caretOffset--; - doSelection(SWT.LEFT); - // end of L2R segment reached (visual left side of preceeding R2L - // segment)? - if (caretOffset - lineOffset > 0 && - bidi.isRightToLeft(caretOffset - lineOffset - 1)) { - // go to beginning of R2L segment (visually start of next L2R - // segment)/beginning of line - caretOffset--; - while (caretOffset - lineOffset > 0 && - bidi.isRightToLeft(caretOffset - lineOffset - 1)) { - caretOffset--; - } - } - } - // if new caret position is to the left of the client area - if (bidi.getTextPosition(caretOffset - lineOffset) < horizontalScrollOffset) { - // scroll to the caret position - showCaret(); - } - else { - // otherwise just update caret position without scrolling it into view - setBidiCaretLocation(null); - setBidiKeyboardLanguage(); - } - // Beginning of line reached (auto scroll finished) but not scrolled - // completely to the left? Fixes 1GKM193 - if (caretOffset - lineOffset == 0 && horizontalScrollOffset > 0 && - horizontalScrollOffset <= XINSET) { - scrollHorizontalBar(-horizontalScrollOffset); - } - } - gc.dispose(); - } - else - if (offsetInLine > 0) { - caretOffset--; - showCaret(); - } -} -/** - * Moves the caret one character to the right. Do not go to the next line. - * When in a bidi locale and at a R2L character the caret is moved to the - * end of the R2L segment (visually left) and then one character to the - * right (visually right because it's now in a L2R segment). - */ -void doColumnRight() { - int line = content.getLineAtOffset(caretOffset); - int lineOffset = content.getOffsetAtLine(line); - int offsetInLine = caretOffset - lineOffset; - String lineText = content.getLine(line); - int lineLength = lineText.length(); - - if (isBidi()) { - GC gc = getGC(); - StyledTextBidi bidi = getStyledTextBidi(lineText, lineOffset, gc); - if (bidi.getTextWidth() + leftMargin > horizontalScrollOffset + getClientArea().width || - offsetInLine < lineLength) { - if (bidi.isRightToLeft(offsetInLine) == false && - offsetInLine < lineLength) { - // advance caret logically if in L2R segment (move visually right) - caretOffset++; - doSelection(SWT.RIGHT); - // end of L2R segment reached (visual right side)? - if (bidi.isRightToLeft(caretOffset - lineOffset)) { - // go to end of R2L segment (visually left of next R2L segment)/ - // end of line - caretOffset++; - while (caretOffset < lineOffset + lineLength && - bidi.isRightToLeft(caretOffset - lineOffset)) { - caretOffset++; - } - } - } - else - if (offsetInLine > 0 && - (bidi.isRightToLeft(offsetInLine) || - bidi.getTextWidth() + leftMargin > horizontalScrollOffset + getClientArea().width || - offsetInLine < lineLength)) { - // advance caret visually if in R2L segment or logically at line end - // but right end of line is not fully visible yet - caretOffset--; - doSelection(SWT.LEFT); - offsetInLine = caretOffset - lineOffset; - // end of R2L segment reached (visual right side)? - if (offsetInLine > 0 && bidi.isRightToLeft(offsetInLine) == false) { - // go to end of R2L segment (visually left of next L2R segment)/ - // end of line - caretOffset++; - while (caretOffset < lineOffset + lineLength && - bidi.isRightToLeft(caretOffset - lineOffset)) { - caretOffset++; - } - } - } - else - if (offsetInLine == 0 && bidi.getTextPosition(0) != bidi.getTextWidth()) { - // at logical line start in R2L segment but there's more text (a L2R - // segment) go to end of R2L segment (visually left of next L2R - // segment)/end of line - caretOffset++; - while (caretOffset < lineOffset + lineLength && - bidi.isRightToLeft(caretOffset - lineOffset - 1)) { - caretOffset++; - } - } - offsetInLine = caretOffset - lineOffset; - // if new caret position is to the right of the client area - if (bidi.getTextPosition(offsetInLine) >= horizontalScrollOffset) { - // scroll to the caret position - showCaret(); - } - else { - // otherwise just update caret position without scrolling it into view - setBidiCaretLocation(null); - setBidiKeyboardLanguage(); - } - if (offsetInLine > 0 && offsetInLine < lineLength - 1) { - int clientAreaEnd = horizontalScrollOffset + getClientArea().width; - boolean directionChange = bidi.isRightToLeft(offsetInLine - 1) == false && bidi.isRightToLeft(offsetInLine); - int textWidth = bidi.getTextWidth() + leftMargin; - // between L2R and R2L segment and second character of R2L segment is - // left of right border and logical line end is left of right border - // but visual line end is not left of right border - if (directionChange && - bidi.isRightToLeft(offsetInLine + 1) && - bidi.getTextPosition(offsetInLine + 1) + leftMargin < clientAreaEnd && - bidi.getTextPosition(lineLength) + leftMargin < clientAreaEnd && textWidth > clientAreaEnd) { - // make visual line end visible - scrollHorizontalBar(textWidth - clientAreaEnd); - } - } - } - gc.dispose(); - } - else - if (offsetInLine < lineLength) { - caretOffset++; - showCaret(); - } -} -/** * Replaces the selection with the character or insert the character at the * current caret position if no selection exists. * If a carriage return was typed replace it with the line break character @@ -2860,7 +2685,9 @@ int doLineDown() { if (caretLine < content.getLineCount() - 1) { caretLine++; if (isBidi()) { - caretOffset = getBidiOffsetAtMouseLocation(columnX, caretLine); + int offsetDirection[] = getBidiOffsetAtMouseLocation(columnX, caretLine); + caretOffset = offsetDirection[0]; + lastCaretDirection = offsetDirection[1]; } else { caretOffset = getOffsetAtMouseLocation(columnX, caretLine); @@ -2907,7 +2734,9 @@ int doLineUp() { if (caretLine > 0) { caretLine--; if (isBidi()) { - caretOffset = getBidiOffsetAtMouseLocation(columnX, caretLine); + int offsetDirection[] = getBidiOffsetAtMouseLocation(columnX, caretLine); + caretOffset = offsetDirection[0]; + lastCaretDirection = offsetDirection[1]; } else { caretOffset = getOffsetAtMouseLocation(columnX, caretLine); @@ -2929,6 +2758,7 @@ void doMouseLocationChange(int x, int y, boolean select) { int lineCount = content.getLineCount(); int newCaretOffset; int newCaretLine; + int newCaretDirection = lastCaretDirection; if (line > lineCount - 1) { line = lineCount - 1; @@ -2939,7 +2769,9 @@ void doMouseLocationChange(int x, int y, boolean select) { return; } if (isBidi()) { - newCaretOffset = getBidiOffsetAtMouseLocation(x, line); + int offsetDirection[] = getBidiOffsetAtMouseLocation(x, line); + newCaretOffset = offsetDirection[0]; + newCaretDirection = offsetDirection[1]; } else { newCaretOffset = getOffsetAtMouseLocation(x, line); @@ -2953,8 +2785,9 @@ void doMouseLocationChange(int x, int y, boolean select) { // a different line? If not the autoscroll selection // could be incorrectly reset. Fixes 1GKM3XS if (y >= 0 && y < getClientArea().height && - (x >= 0 || newCaretLine != content.getLineAtOffset(caretOffset))) { + (x >= 0 && x < getClientArea().width || newCaretLine != content.getLineAtOffset(caretOffset))) { if (newCaretOffset != caretOffset) { + lastCaretDirection = newCaretDirection; caretOffset = newCaretOffset; if (select) { doMouseSelection(); @@ -2963,6 +2796,7 @@ void doMouseLocationChange(int x, int y, boolean select) { } } if (select == false) { + lastCaretDirection = newCaretDirection; clearSelection(true); } } @@ -2973,10 +2807,10 @@ void doMouseSelection() { if (caretOffset <= selection.x || (caretOffset > selection.x && caretOffset < selection.y && selectionAnchor == selection.x)) { - doSelection(SWT.LEFT); + doSelection(ST.COLUMN_PREVIOUS); } else { - doSelection(SWT.RIGHT); + doSelection(ST.COLUMN_NEXT); } } /** @@ -3053,13 +2887,15 @@ void doPageDown(boolean select) { scrollLines = Math.max(1, scrollLines); caretLine += scrollLines; if (isBidi()) { - caretOffset = getBidiOffsetAtMouseLocation(columnX, caretLine); + int offsetDirection[] = getBidiOffsetAtMouseLocation(columnX, caretLine); + caretOffset = offsetDirection[0]; + lastCaretDirection = offsetDirection[1]; } else { caretOffset = getOffsetAtMouseLocation(columnX, caretLine); } if (select) { - doSelection(SWT.RIGHT); + doSelection(ST.COLUMN_NEXT); } // scroll one page down or to the bottom scrollOffset = verticalScrollOffset + scrollLines * getVerticalIncrement(); @@ -3125,7 +2961,9 @@ void doPageUp() { caretLine -= scrollLines; if (isBidi()) { - caretOffset = getBidiOffsetAtMouseLocation(columnX, caretLine); + int offsetDirection[] = getBidiOffsetAtMouseLocation(columnX, caretLine); + caretOffset = offsetDirection[0]; + lastCaretDirection = offsetDirection[1]; } else { caretOffset = getOffsetAtMouseLocation(columnX, caretLine); @@ -3152,7 +2990,7 @@ void doSelection(int direction) { if (selectionAnchor == -1) { selectionAnchor = selection.x; } - if (direction == SWT.LEFT) { + if (direction == ST.COLUMN_PREVIOUS) { if (caretOffset < selection.x) { // grow selection redrawEnd = selection.x; @@ -3281,7 +3119,7 @@ void doSelectionLineDown() { setMouseWordSelectionAnchor(); // select first and then scroll to reduce flash when key // repeat scrolls lots of lines - doSelection(SWT.RIGHT); + doSelection(ST.COLUMN_NEXT); // explicitly go to the calculated caret line. may be different // from content.getLineAtOffset(caretOffset) when in word wrap mode showCaret(caretLine); @@ -3316,7 +3154,7 @@ void doSelectionLineUp() { // explicitly go to the calculated caret line. may be different // from content.getLineAtOffset(caretOffset) when in word wrap mode showCaret(caretLine); - doSelection(SWT.LEFT); + doSelection(ST.COLUMN_PREVIOUS); // save the original horizontal caret position columnX = oldColumnX; } @@ -3401,6 +3239,159 @@ void doSelectionWordPrevious() { showCaret(caretLine); } /** + * Moves the caret one character to the left. Do not go to the previous line. + * When in a bidi locale and at a R2L character the caret is moved to the + * beginning of the R2L segment (visually right) and then one character to the + * left (visually left because it's now in a L2R segment). + */ +void doVisualPrevious() { + int line = content.getLineAtOffset(caretOffset); + int lineOffset = content.getOffsetAtLine(line); + int offsetInLine = caretOffset - lineOffset; + + if (isBidi()) { + // check if caret location is at the visual beginning of the line + if (columnX <= XINSET && horizontalScrollOffset == 0) { + return; + } + String lineText = content.getLine(line); + int lineLength = lineText.length(); + GC gc = getGC(); + StyledTextBidi bidi = getStyledTextBidi(lineText, lineOffset, gc); + int visualOffset = -1; + + if (offsetInLine == lineLength) { + //logical end of line may not be visual end, setup visualOffset to process as usual + visualOffset = bidi.getVisualOffset(offsetInLine - 1); + } + else + if (offsetInLine < lineLength) { + visualOffset = bidi.getVisualOffset(offsetInLine); + } + if (visualOffset != -1) { + if (visualOffset > 0) { + visualOffset--; + offsetInLine = bidi.getLogicalOffset(visualOffset); + } + else + if (visualOffset == 0) { + boolean isRightOriented = isMirrored(); + + //move to visual line end (i.e., behind L2R character/in front of R2L character at visual 0) + if ((isRightOriented && bidi.isRightToLeft(offsetInLine) == false) || + (isRightOriented == false && bidi.isRightToLeft(offsetInLine))) { + offsetInLine++; + } + + if (offsetInLine > 0 && offsetInLine < lineLength) { + if (isRightOriented) { + boolean rightToLeftStart = bidi.isRightToLeft(offsetInLine) && bidi.isRightToLeft(offsetInLine - 1) == false; + if (rightToLeftStart) { + //moving from LtoR segment to RtoL segment + lastCaretDirection = ST.COLUMN_NEXT; + } + } + else { + boolean leftToRightStart = bidi.isRightToLeft(offsetInLine) == false && bidi.isRightToLeft(offsetInLine - 1); + if (bidi.isLatinNumber(offsetInLine) && bidi.isRightToLeftInput(offsetInLine - 1)) { + //moving from LtoR segment to latin number + lastCaretDirection = ST.COLUMN_PREVIOUS; + } + else + if (leftToRightStart) { + //moving from RtoL segment to LtoR segment + lastCaretDirection = ST.COLUMN_NEXT; + } + } + } + } + caretOffset = lineOffset + offsetInLine; + showCaret(); + } + if (bidi.getTextPosition(offsetInLine, ST.COLUMN_NEXT) == XINSET) { + //scroll to origin if caret is at origin + scrollHorizontalBar(-horizontalScrollOffset); + } + gc.dispose(); + } + else + if (offsetInLine > 0) { + caretOffset--; + showCaret(); + } +} +/** + * Moves the caret one character to the right. Do not go to the next line. + * When in a bidi locale and at a R2L character the caret is moved to the + * end of the R2L segment (visually left) and then one character to the + * right (visually right because it's now in a L2R segment). + */ +void doVisualNext() { + int line = content.getLineAtOffset(caretOffset); + int lineOffset = content.getOffsetAtLine(line); + int offsetInLine = caretOffset - lineOffset; + String lineText = content.getLine(line); + int lineLength = lineText.length(); + + if (isBidi()) { + GC gc = getGC(); + StyledTextBidi bidi = getStyledTextBidi(lineText, lineOffset, gc); + // Fixes bug 39032 + int lineEndPixel = Math.max(bidi.getTextWidth(), XINSET); + + // check if caret location is at the visual end of the line (can't use + // caret location here since it's location is dependent on current keyboard + // language direction) + if (bidi.getTextPosition(offsetInLine, lastCaretDirection) == lineEndPixel) { + gc.dispose(); + return; + } + int visualOffset = -1; + if (offsetInLine == lineLength) { + //logical end of line may not be visual end, setup visualOffset to process as usual + visualOffset = bidi.getVisualOffset(offsetInLine - 1); + } + else + if (offsetInLine < lineLength) { + visualOffset = bidi.getVisualOffset(offsetInLine); + } + if (visualOffset != -1) { + visualOffset++; + offsetInLine = bidi.getLogicalOffset(visualOffset); + if (offsetInLine > 0 && offsetInLine < lineLength) { + boolean isRightOriented = isMirrored(); + if (isRightOriented) { + boolean leftToRightStart = bidi.isRightToLeft(offsetInLine) == false && bidi.isRightToLeft(offsetInLine - 1); + if (leftToRightStart) { + //moving from RtoL segment to LtoR segment + lastCaretDirection = ST.COLUMN_PREVIOUS; + } + } + else { + boolean rightToLeftStart = bidi.isRightToLeft(offsetInLine) && bidi.isRightToLeft(offsetInLine - 1) == false; + if (bidi.isRightToLeftInput(offsetInLine) && bidi.isLatinNumber(offsetInLine - 1)) { + //moving from latin number to RtoL segment + lastCaretDirection = ST.COLUMN_NEXT; + } + else + if (rightToLeftStart) { + //moving from LtoR segment to RtoL segment + lastCaretDirection = ST.COLUMN_PREVIOUS; + } + } + } + caretOffset = lineOffset + offsetInLine; + showCaret(); + } + gc.dispose(); + } + else + if (offsetInLine < lineLength) { + caretOffset++; + showCaret(); + } +} +/** * Moves the caret to the end of the next word. * If a selection exists, move the caret to the end of the selection * and remove the selection. @@ -3511,30 +3502,28 @@ public boolean getBidiColoring() { return bidiColoring; } /** - * Returns the offset at the specified x location in the specified line. - * Also sets the caret direction so that the caret is placed correctly - * depending on whether the mouse location is in a R2L or L2R segment. + * Returns the offset and caret direction at the specified x location + * in the specified line. + * The returned caret direction needs to be set in order to place the + * caret correctly based on whether the mouse location is in a R2L + * or L2R segment. * <p> * * @param x x location of the mouse location * @param line line the mouse location is in - * @return the offset at the specified x location in the specified line, - * relative to the beginning of the document + * @return int array, first element is the offset at the specified x + * location in the specified line, relative to the beginning of the + * document. second element is the caret direction. */ -int getBidiOffsetAtMouseLocation(int x, int line) { +int[] getBidiOffsetAtMouseLocation(int x, int line) { String lineText = content.getLine(line); int lineOffset = content.getOffsetAtLine(line); GC gc = getGC(); StyledTextBidi bidi = getStyledTextBidi(lineText, lineOffset, gc); - int[] values; - int offsetInLine; - x += horizontalScrollOffset; - values = bidi.getCaretOffsetAndDirectionAtX(x - leftMargin); - offsetInLine = values[0]; - lastCaretDirection = values[1]; - gc.dispose(); + int[] values = bidi.getCaretOffsetAndDirectionAtX(x + horizontalScrollOffset - leftMargin); - return lineOffset + offsetInLine; + gc.dispose(); + return new int[] {lineOffset + values[0], values[1]}; } /** * Returns the x position of the character at the specified offset @@ -5561,50 +5550,50 @@ public void invokeAction(int action) { break; case ST.SELECT_LINE_START: doLineStart(); - doSelection(SWT.LEFT); + doSelection(ST.COLUMN_PREVIOUS); break; case ST.SELECT_LINE_END: doLineEnd(); - doSelection(SWT.RIGHT); + doSelection(ST.COLUMN_NEXT); break; case ST.SELECT_COLUMN_PREVIOUS: doSelectionCursorPrevious(); - doSelection(SWT.LEFT); + doSelection(ST.COLUMN_PREVIOUS); break; case ST.SELECT_COLUMN_NEXT: doSelectionCursorNext(); - doSelection(SWT.RIGHT); + doSelection(ST.COLUMN_NEXT); break; case ST.SELECT_PAGE_UP: doSelectionPageUp(); - doSelection(SWT.LEFT); + doSelection(ST.COLUMN_PREVIOUS); break; case ST.SELECT_PAGE_DOWN: doSelectionPageDown(); break; case ST.SELECT_WORD_PREVIOUS: doSelectionWordPrevious(); - doSelection(SWT.LEFT); + doSelection(ST.COLUMN_PREVIOUS); break; case ST.SELECT_WORD_NEXT: doSelectionWordNext(); - doSelection(SWT.RIGHT); + doSelection(ST.COLUMN_NEXT); break; case ST.SELECT_TEXT_START: doContentStart(); - doSelection(SWT.LEFT); + doSelection(ST.COLUMN_PREVIOUS); break; case ST.SELECT_TEXT_END: doContentEnd(); - doSelection(SWT.RIGHT); + doSelection(ST.COLUMN_NEXT); break; case ST.SELECT_WINDOW_START: doPageStart(); - doSelection(SWT.LEFT); + doSelection(ST.COLUMN_PREVIOUS); break; case ST.SELECT_WINDOW_END: doPageEnd(); - doSelection(SWT.RIGHT); + doSelection(ST.COLUMN_NEXT); break; // Modification case ST.CUT: @@ -5658,6 +5647,16 @@ boolean isLineDelimiter(int offset) { return offsetInLine > content.getLine(line).length(); } /** + * Returns whether the widget is mirrored (right oriented/right to left + * writing order). + * + * @return isMirrored true=the widget is right oriented, false=the widget + * is left oriented + */ +boolean isMirrored() { + return isMirrored; +} +/** * Returns whether or not the given lines are visible. * <p> * @@ -5894,6 +5893,7 @@ void performPaint(GC gc,int startLine,int startY, int renderHeight) { Color foreground = getForeground(); int lineCount = content.getLineCount(); int paintY = 0; + int gcStyle = isMirrored() ? SWT.RIGHT_TO_LEFT : SWT.LEFT_TO_RIGHT; if (isSingleLine()) { lineCount = 1; @@ -5902,7 +5902,7 @@ void performPaint(GC gc,int startLine,int startY, int renderHeight) { } } Image lineBuffer = new Image(getDisplay(), clientArea.width, renderHeight); - GC lineGC = new GC(lineBuffer); + GC lineGC = new GC(lineBuffer, gcStyle); lineGC.setFont(getFont()); renderer.setCurrentFontStyle(SWT.NORMAL); @@ -6056,7 +6056,12 @@ public void redraw() { * @see Control#update */ public void redraw(int x, int y, int width, int height, boolean all) { - super.redraw(x, y, width, height, all); + if (isBidi()) { + // workaround for bug 4776 + super.redraw(x, y, width + 1, height, all); + } else { + super.redraw(x, y, width, height, all); + } if (height > 0) { int lineCount = content.getLineCount(); int startLine = (getTopPixel() + y) / lineHeight; @@ -6092,9 +6097,9 @@ void redrawBidiLines(int firstLine, int offsetInFirstLine, int lastLine, int end String line = content.getLine(firstLine); GC gc = getGC(); StyledTextBidi bidi = getStyledTextBidi(line, firstLineOffset, gc); - + bidi.redrawRange( - this, offsetInFirstLine, + this, offsetInFirstLine, Math.min(line.length(), endOffset) - offsetInFirstLine, leftMargin - horizontalScrollOffset, redrawY + topMargin, lineHeight); // redraw line break marker (either space or full client area width) @@ -6903,6 +6908,7 @@ void setBidiCaretLocation(StyledTextBidi bidi, int caretLine) { int lineStartOffset = content.getOffsetAtLine(caretLine); int offsetInLine = caretOffset - lineStartOffset; GC gc = null; + boolean isRightOriented = isMirrored(); if (bidi == null) { gc = getGC(); @@ -6913,7 +6919,10 @@ void setBidiCaretLocation(StyledTextBidi bidi, int caretLine) { } else { columnX = bidi.getTextPosition(offsetInLine, lastCaretDirection) + leftMargin - horizontalScrollOffset; } - if (StyledTextBidi.getKeyboardLanguageDirection() == SWT.RIGHT) { + // take the width of the caret into account + int keyboardDirection = StyledTextBidi.getKeyboardLanguageDirection(); + if ((keyboardDirection == SWT.RIGHT && isRightOriented == false) || + (keyboardDirection == SWT.LEFT && isRightOriented)){ columnX -= (getCaretWidth() - 1); } if (caret != null) { @@ -7407,6 +7416,42 @@ void setMouseWordSelectionAnchor() { } } /** + * Sets the widget orientation (writing order). Text will be right aligned + * for right to left writing order. + * <p> + * + * @param newOrientation one of SWT.RIGHT_TO_LEFT or SWT.LEFT_TO_RIGHT + */ +void setOrientation(int orientation) { + if ((orientation & (SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT)) == 0) { + return; + } + if ((orientation & SWT.RIGHT_TO_LEFT) != 0 && (orientation & SWT.LEFT_TO_RIGHT) != 0) { + return; + } + if ((orientation & SWT.RIGHT_TO_LEFT) != 0 && isMirrored()) { + return; + } + if ((orientation & SWT.LEFT_TO_RIGHT) != 0 && isMirrored() == false) { + return; + } + if (StyledTextBidi.setOrientation(this, orientation) == false) { + return; + } + isMirrored = (orientation & SWT.RIGHT_TO_LEFT) != 0; + isBidi = StyledTextBidi.isBidiPlatform() || isMirrored(); + initializeRenderer(); + if (isBidi()) { + caretDirection = SWT.NULL; + createCaretBitmaps(); + setBidiCaretDirection(); + } + setCaretLocation(); + keyActionMap.clear(); + createKeyBindings(); + super.redraw(); +} +/** * Adjusts the maximum and the page size of the scroll bars to * reflect content width/length changes. */ diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextBidi.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextBidi.java index c443b65772..e097698ded 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextBidi.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextBidi.java @@ -31,6 +31,7 @@ class StyledTextBidi { private int[] dx; // distance between character cells. in visual order. renderPositions[iV + 1] = renderPositions[iV] + dx[iV] private byte[] classBuffer; // the character types in logical order, see BidiUtil for the possible types private char[] glyphBuffer; // the glyphs in visual order as they will be rendered on screen. + private boolean isRightOriented;// writing orientation /** * This class describes a text segment of a single direction, either @@ -106,6 +107,7 @@ class StyledTextBidi { */ public StyledTextBidi(GC gc, int tabWidth, String text, StyleRange[] ranges, Font boldFont, int[] offsets) { int length = text.length(); + isRightOriented = (gc.getStyle() & SWT.MIRRORED) != 0; this.gc = gc; bidiSegments = offsets; @@ -155,6 +157,7 @@ public StyledTextBidi(GC gc, int tabWidth, String text, StyleRange[] ranges, Fon */ public StyledTextBidi(GC gc, String text, int[] offsets) { int length = text.length(); + isRightOriented = (gc.getStyle() & SWT.MIRRORED) != 0; this.gc = gc; bidiSegments = offsets; order = new int[length]; @@ -381,8 +384,6 @@ void fillBackground(int logicalStart, int length, int xOffset, int yOffset, int */ int[] getCaretOffsetAndDirectionAtX(int x) { int lineLength = getTextLength(); - int offset; - int direction; if (lineLength == 0) { return new int[] {0, 0}; @@ -395,9 +396,16 @@ int[] getCaretOffsetAndDirectionAtX(int x) { int visualOffset = getVisualOffsetAtX(x); // figure out if the character was clicked on the right or left int halfway = renderPositions[visualOffset] + dx[visualOffset] / 2; - boolean visualLeft = (x <= halfway); - offset = getLogicalOffset(visualOffset); + boolean visualLeft; + int offset = getLogicalOffset(visualOffset); + int direction; + if (isRightOriented) { + visualLeft = (x > halfway); + } + else { + visualLeft = (x <= halfway); + } if (isRightToLeft(offset)) { if (visualLeft) { if (isLigated(gc)) { @@ -413,23 +421,23 @@ int[] getCaretOffsetAndDirectionAtX(int x) { } else { // position the caret as if the caret is to the left - // of the character at location x and the PREVIOUS key is - // pressed - direction = ST.COLUMN_PREVIOUS; + // of the character at location x and the PREVIOUS + // key is pressed + direction = ST.COLUMN_PREVIOUS; } } else { if (visualLeft) { - // position the caret as if the caret is to the right - // of the character at location x and the PREVIOUS key is - // pressed - direction = ST.COLUMN_PREVIOUS; + // position the caret as if the caret is to the left + // of the character at location x and the PREVIOUS + // key is pressed + direction = ST.COLUMN_PREVIOUS; } else { - // position the caret as if the caret is to the left + offset++; + // position the caret as if the caret is to the right // of the character at location x and the NEXT key is // pressed - offset++; direction = ST.COLUMN_NEXT; } } @@ -457,6 +465,7 @@ private Vector getDirectionRuns(int logicalStart, int length) { int logicalEnd = logicalStart + length - 1; int segmentLogicalStart = logicalStart; int segmentLogicalEnd = segmentLogicalStart; + int checkSide = isRightOriented ? -1 : 1; if (logicalEnd < getTextLength()) { int bidiSegmentIndex = 0; @@ -481,8 +490,9 @@ private Vector getDirectionRuns(int logicalStart, int length) { // is no direction change. // If our segment type is LtoR, the order index for the next character will be one more if there is // no direction change. - ((isRightToLeftSegment && (order[segmentLogicalEnd + 1]+ 1 == order[segmentLogicalEnd])) || - (isRightToLeftSegment == false && (order[segmentLogicalEnd + 1]- 1 == order[segmentLogicalEnd]))) && + (order[segmentLogicalEnd + 1] == order[segmentLogicalEnd] || // treat ligatures as part of the direction segment + (isRightToLeftSegment && (order[segmentLogicalEnd + 1] + checkSide == order[segmentLogicalEnd])) || + (isRightToLeftSegment == false && (order[segmentLogicalEnd + 1] - checkSide == order[segmentLogicalEnd]))) && segmentLogicalEnd + 1 < bidiSegmentEnd) { segmentLogicalEnd++; } @@ -555,7 +565,7 @@ int getLigatureStartOffset(int offset) { * @param visualOffset the visual offset * @return the logical offset of the character at <code>visualOffset</code>. */ -private int getLogicalOffset(int visualOffset) { +int getLogicalOffset(int visualOffset) { int logicalOffset = 0; while (logicalOffset < order.length && order[logicalOffset] != visualOffset) { @@ -697,26 +707,29 @@ int getTextPosition(int logicalOffset, int direction) { if (getTextLength() == 0 || logicalOffset < 0) { return StyledText.XINSET; } + + boolean isRightToLeft = isRightToLeft(logicalOffset); // at or past end of line? if (logicalOffset >= order.length) { logicalOffset = Math.min(logicalOffset, order.length - 1); + isRightToLeft = isRightToLeft(logicalOffset); int visualOffset = order[logicalOffset]; - if (isRightToLeft(logicalOffset)) { - caretX = renderPositions[visualOffset]; + if ((!isRightOriented && !isRightToLeft) || (isRightOriented && isRightToLeft)) { + caretX = renderPositions[visualOffset] + dx[visualOffset]; } else { - caretX = renderPositions[visualOffset] + dx[visualOffset]; + caretX = renderPositions[visualOffset]; } } else // at beginning of line? if (logicalOffset == 0) { int visualOffset = order[logicalOffset]; - if (isRightToLeft(logicalOffset)) { - caretX = renderPositions[visualOffset] + dx[visualOffset]; + if ((!isRightOriented && !isRightToLeft) || (isRightOriented && isRightToLeft)) { + caretX = renderPositions[visualOffset]; } else { - caretX = renderPositions[visualOffset]; + caretX = renderPositions[visualOffset] + dx[visualOffset]; } } else @@ -733,14 +746,12 @@ int getTextPosition(int logicalOffset, int direction) { // do not consider local numbers as R2L here, to determine position, // because local numbers are navigated L2R and we want the caret to // be to the right of the number. see 1GK9API - if (isRightToLeft(logicalOffset - 1)) { - // moving from RtoL to LtoR - caretX = renderPositions[visualOffset]; - } - else { - // moving from LtoR to RtoL + isRightToLeft = isRightToLeft(logicalOffset - 1); + if ((!isRightOriented && !isRightToLeft) || (isRightOriented && isRightToLeft)) { caretX = renderPositions[visualOffset] + dx[visualOffset]; - } + } else { + caretX = renderPositions[visualOffset]; + } } else // consider local numbers as R2L in determining direction boundaries. @@ -752,23 +763,22 @@ int getTextPosition(int logicalOffset, int direction) { // consider local numbers as R2L here, to determine position, because // we want to stay in L2R segment and place the cursor to the left of // first L2R character. see 1GK9API - if (isRightToLeftInput(logicalOffset - 1)) { - // moving from LtoR to RtoL + isRightToLeft = isRightToLeft(logicalOffset - 1); + if ((!isRightOriented && !isRightToLeft) || (isRightOriented && isRightToLeft)) { + caretX = renderPositions[visualOffset] + dx[visualOffset]; + } else { + caretX = renderPositions[visualOffset]; + } + } + else { + int visualOffset = order[logicalOffset]; + if ((!isRightOriented && !isRightToLeft) || (isRightOriented && isRightToLeft)) { caretX = renderPositions[visualOffset]; } else { - // moving from RtoL to LtoR caretX = renderPositions[visualOffset] + dx[visualOffset]; } } - else - if (isRightToLeft(logicalOffset)) { - int visualOffset = order[logicalOffset]; - caretX = renderPositions[visualOffset] + dx[visualOffset]; - } - else { - caretX = renderPositions[order[logicalOffset]]; - } return caretX; } /** @@ -786,6 +796,17 @@ int getTextWidth() { return width; } /** + * Returns the visual offset of the character at the specified + * logical offset. + * <p> + * + * @param logicalOffset the logical offset + * @return the visual offset of the character at <code>logicalOffset</code>. + */ +int getVisualOffset(int logicalOffset) { + return order[logicalOffset]; +} +/** * Returns the visual offset of the character at the specified x * location. * <p> @@ -820,6 +841,23 @@ private int getVisualOffsetAtX(int x) { return high; } /** + * Returns if the character at the given offset is a latin number. + * <p> + * + * @param logicalIndex the index of the character + * @return + * true=the character at the specified index is a latin number + * false=the character at the specified index is not a latin number + */ +boolean isLatinNumber(int logicalIndex) { + boolean isLatinNumber = false; + + if (logicalIndex >= 0 && logicalIndex < classBuffer.length) { + isLatinNumber = classBuffer[logicalIndex] == BidiUtil.CLASS_LATINNUMBER; + } + return isLatinNumber; +} +/** * Returns if the character at the given offset is a local number. * <p> * @@ -968,7 +1006,6 @@ private void prepareFontStyledText(String textline, int logicalStart, int length */ void redrawRange(Control parent, int logicalStart, int length, int xOffset, int yOffset, int height) { Enumeration directionRuns; - if (logicalStart < 0 || logicalStart + length > getTextLength()) { return; } @@ -976,8 +1013,22 @@ void redrawRange(Control parent, int logicalStart, int length, int xOffset, int while (directionRuns.hasMoreElements()) { DirectionRun run = (DirectionRun) directionRuns.nextElement(); int startX = run.getRenderStartX(); + int endX = run.getRenderStopX(); + int runStartOffset = run.getVisualStart(); + int runEndOffset = run.getVisualEnd(); - parent.redraw(xOffset + startX, yOffset, run.getRenderStopX() - startX, height, true); + // expand the redraw area by one character in both directions. + // fixes bug 40019 + if (runStartOffset > 0) { + startX = renderPositions[runStartOffset - 1]; + } + else { + startX = 0; + } + if (runEndOffset < renderPositions.length - 1) { + endX = renderPositions[runEndOffset + 1] + dx[runEndOffset + 1]; + } + parent.redraw(xOffset + startX, yOffset, endX - startX, height, true); } } /** @@ -1011,6 +1062,18 @@ void setKeyboardLanguage(int logicalIndex) { BidiUtil.setKeyboardLanguage(language); } /** + * Sets the orientation (writing order) of the specified control. Text will + * be right aligned for right to left writing order. + * <p> + * + * @param orientation one of SWT.RIGHT_TO_LEFT or SWT.LEFT_TO_RIGHT + * @return true if the orientation was changed, false if the orientation + * could not be changed + */ +static boolean setOrientation(Control control, int orientation) { + return BidiUtil.setOrientation(control.handle, orientation); +} +/** * Returns a string representation of the receiver. * <p> * @@ -1059,4 +1122,4 @@ public String toString() { buf.append("}}"); return buf.toString(); } -} +}
\ No newline at end of file diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/TableCursor.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/TableCursor.java index 8055dc73fb..714a1b80ac 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/TableCursor.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/TableCursor.java @@ -298,12 +298,17 @@ void keyDown(Event event) { case SWT.ARROW_DOWN : setRowColumn(row + 1, column, true); break; - case SWT.ARROW_LEFT : - setRowColumn(row, column - 1, true); - break; - case SWT.ARROW_RIGHT : - setRowColumn(row, column + 1, true); - break; + case SWT.ARROW_LEFT : + case SWT.ARROW_RIGHT : + { + int leadKey = (getStyle() & SWT.RIGHT_TO_LEFT) != 0 ? SWT.ARROW_RIGHT : SWT.ARROW_LEFT; + if (event.keyCode == leadKey) { + setRowColumn(row, column - 1, true); + } else { + setRowColumn(row, column + 1, true); + } + break; + } case SWT.HOME : setRowColumn(0, column, true); break; diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/TableTree.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/TableTree.java index 4c8f74cd0f..f118229914 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/TableTree.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/TableTree.java @@ -91,7 +91,7 @@ public class TableTree extends Composite { * @see #getStyle */ public TableTree(Composite parent, int style) { - super(parent, SWT.NONE); + super(parent, checkStyle (style)); table = new Table(this, style); Listener tableListener = new Listener() { public void handleEvent(Event e) { @@ -196,7 +196,12 @@ public void addTreeListener(TreeListener listener) { TypedListener typedListener = new TypedListener (listener); addListener (SWT.Expand, typedListener); addListener (SWT.Collapse, typedListener); -} +} +private static int checkStyle (int style) { + int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; + style = style & mask; + return style; +} public Point computeSize (int wHint, int hHint, boolean changed) { checkWidget(); return table.computeSize (wHint, hHint, changed); @@ -502,7 +507,8 @@ void onKeyDown (Event e) { TableTreeItem item = selection[0]; int type = 0; if (e.keyCode == SWT.ARROW_RIGHT || e.keyCode == SWT.ARROW_LEFT) { - if (e.keyCode == SWT.ARROW_RIGHT) { + int trailKey = (getStyle() & SWT.MIRRORED) != 0 ? SWT.ARROW_LEFT : SWT.ARROW_RIGHT; + if (e.keyCode == trailKey) { if (item.getItemCount() == 0) return; if (item.getExpanded()) { TableTreeItem newSelection = item.getItems()[0]; diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/ViewForm.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/ViewForm.java index 6acbd1cb1a..b9583196cb 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/ViewForm.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/ViewForm.java @@ -147,7 +147,7 @@ public ViewForm(Composite parent, int style) { * @private */ private static int checkStyle (int style) { - int mask = SWT.FLAT; + int mask = SWT.FLAT | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; return style & mask | SWT.NO_REDRAW_RESIZE; } public Point computeSize(int wHint, int hHint, boolean changed) { |