/******************************************************************************* * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.graphics; import intrinsic.flash.text.TextField; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Device; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontMetrics; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.graphics.Resource; import org.eclipse.swt.internal.Compatibility; import org.eclipse.swt.widgets.Display; //UNSUPPORTED - cannot use package private super type constructor //public final class TextLayout extends Resource { public final class TextLayout { Font font; String text; int lineSpacing; int ascent, descent; int alignment; int wrapWidth; int orientation; int indent; boolean justify; int[] tabs; int[] segments; StyleItem[] styles; TextField textField; static final int BORDER = 2; static final int TAB_COUNT = 32; static class StyleItem { TextStyle style; int start; public String toString () { return "StyleItem {" + start + ", " + style + "}"; } } //BEGIN Resource API final Device device; private boolean disposed; /** * Returns the <code>Device</code> where this resource was * created. * * @return <code>Device</code> the device of the receiver * * @since 1.3 */ public Device getDevice() { if( disposed ) { SWT.error( SWT.ERROR_GRAPHIC_DISPOSED ); } Device result = device; // Currently, factory-managed resources (device == null) return the current // display. This is done under the assumption that resource methods are // only called from the UI thread. This way also shared resources appear to // belong to the current session. // Note that this is still under investigation. if( result == null ) { result = Display.getCurrent(); } return result; } /** * Disposes of the resource. Applications must dispose of all resources * which they allocate. * This method does nothing if the resource is already disposed. * * @since 1.3 */ public void dispose() { if( device == null ) { String msg = "A factory-created resource cannot be disposed."; throw new IllegalStateException( msg ); } destroy(); disposed = true; } static Device checkDevice( final Device device ) { Device result = device; if( result == null ) { result = Display.getCurrent(); } if( result == null ) { SWT.error( SWT.ERROR_NULL_ARGUMENT ); } return result; } //END Resource API public TextLayout (Device device) { this.device = device; ascent = descent = wrapWidth = -1; text = ""; styles = new StyleItem[2]; styles[0] = new StyleItem(); styles[1] = new StyleItem(); } void checkLayout () { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); } void destroy () { freeRuns(); font = null; text = null; tabs = null; styles = null; } void computeRuns () { computeRuns (null); } int [] computePolyline(int left, int top, int right, int bottom) { int height = bottom - top; // can be any number int width = 2 * height; // must be even int peaks = Compatibility.ceil(right - left, width); if (peaks == 0 && right - left > 2) { peaks = 1; } int length = ((2 * peaks) + 1) * 2; if (length < 0) return new int[0]; int[] coordinates = new int[length]; for (int i = 0; i < peaks; i++) { int index = 4 * i; coordinates[index] = left + (width * i); coordinates[index+1] = bottom; coordinates[index+2] = coordinates[index] + width / 2; coordinates[index+3] = top; } coordinates[length-2] = left + (width * peaks); coordinates[length-1] = bottom; return coordinates; } void computeRuns (GCData data) { // if (textField != null) { // if (data == null) return; // if (textField.parent == null) { // intrinsic.Number currentFg = (intrinsic.Number)textField.defaultTextFormat.color; // intrinsic.Number newFg = new intrinsic.Number(data.foreground.handle); // if (newFg.equals(currentFg)) return; // } // } // int length = text.length(); // textField = new TextField(); // textField.text = length == 0 ? " " : text; // if (length == 0) length = 1; // textField.autoSize = TextFieldAutoSize.LEFT; // textField.multiline = true; // textField.selectable = false; // textField.mouseEnabled = false; // textField.alwaysShowSelection = true; // textField.background = false; // TextFormat format = new TextFormat(); // textField.defaultTextFormat = format; // Font defaultFont = this.font != null ? this.font : device.systemFont; // format.font = defaultFont.fontFamily; // format.size = new intrinsic.Number(defaultFont.fontSize); // if (data != null) { // format.color = new intrinsic.Number(data.foreground.handle); // } // if (defaultFont.fontStyle.equals("italic")) format.italic = defaultFont.fontStyle; // if (defaultFont.fontWeight.equals("bold")) format.bold = defaultFont.fontWeight; // if (wrapWidth != -1) { // String align = TextFormatAlign.LEFT; // if (justify) { // align = TextFormatAlign.JUSTIFY; // } else { // switch (alignment) { // case SWT.CENTER: // align = TextFormatAlign.CENTER; // break; // case SWT.RIGHT: // align = TextFormatAlign.RIGHT; // } // } // format.align = align; // textField.width = wrapWidth; // textField.wordWrap = true; // } // format.leading = new intrinsic.Number(lineSpacing); // format.indent = new intrinsic.Number(indent); // int tabWidth = 0; // int tabX = 0; // Array tabArray = new Array(); // int tabCount = TAB_COUNT; // if (tabs != null) { // tabCount = Math.max(TAB_COUNT, tabs.length); // if (tabs.length == 1) { // tabWidth = tabs[0]; // } // if (tabs.length > 1) { // tabWidth = tabs[tabs.length - 1] - tabs[tabs.length - 2]; // } // for (int i = 0; i < tabs.length; i++) { // tabX += tabs[i]; // tabArray.push(tabX); // tabCount--; // } // } // while (tabCount > 0) { // tabX += tabWidth; // tabArray.push(tabX); // tabCount--; // } // format.tabStops = tabArray; // textField.setTextFormat(format, 0, length); // //TODO lineSpacing, ascent, descent, orientation, segments // int start, end; // for (int i = 0; i < styles.length - 1; i++) { // StyleItem run = styles[i]; // if (run.style == null) continue; // TextStyle style = run.style; // start = translateOffset(run.start); // end = translateOffset(styles[i + 1].start); // format = new TextFormat(); // Font font = style.font; // if (font != null) { // format.font = font.fontFamily; // format.size = new intrinsic.Number(font.fontSize); // if (font.fontStyle.equals("italic")) format.italic = font.fontStyle; // if (font.fontWeight.equals("bold")) format.bold = font.fontWeight; // } // Color foreground = style.foreground; // if (foreground != null) { // format.color = new intrinsic.Number(foreground.handle); // } // if (style.rise != 0) { // //TODO rise // } // if (style.metrics != null) { // //TODO metrics // } // textField.setTextFormat(format, start, end); // } } public void draw (GC gc, int x, int y) { draw(gc, x, y, -1, -1, null, null); } public void draw (GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground) { draw(gc, x, y, selectionStart, selectionEnd, selectionForeground, selectionBackground, 0); } public void draw (GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground, int flags) { checkLayout(); if (gc == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); gc.drawText( text, x, y, true ); // GCData data = gc.data; // computeRuns(data); // if (selectionForeground != null && selectionForeground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); // if (selectionBackground != null && selectionBackground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); // int length = text.length(); // if (length == 0 && flags == 0) return; // //TODO flags, selection // boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1; // if (hasSelection) { // textField.setSelection(selectionStart, selectionEnd + 1); // } else { // textField.setSelection(-1, -1); // } // y -= BORDER; // x -= BORDER; // if (data.matrix != null) { // intrinsic.flash.geom.Point point = new intrinsic.flash.geom.Point(x, y); // point = data.matrix.transformPoint(point); // textField.x = point.x; // textField.y = point.y; // } else { // textField.x = x; // textField.y = y; // } // if (data.matrix != null) textField.transform.matrix = data.matrix; // if (data.clip != null) textField.mask = data.clip; // // /* Draw background */ // for (int i = 0; i < styles.length - 1; i++) { // StyleItem run = styles[i]; // TextStyle style = run.style; // if (style == null || style.background == null) continue; // int start = translateOffset(run.start); // int end = translateOffset(styles[i + 1].start); // double lineY = y + BORDER; // for (int lineIndex = 0; lineIndex < textField.numLines; lineIndex++) { // int lineStart = textField.getLineOffset(lineIndex); // int lineEnd = lineStart + textField.getLineLength(lineIndex); // TextLineMetrics metrics = textField.getLineMetrics(lineIndex); // if (!(start > lineEnd || end < lineStart)) { // int highStart = Math.max(lineStart, start); // int highEnd = Math.min(lineEnd, end); // if (highStart != highEnd) { // intrinsic.flash.geom.Rectangle startRect = textField.getCharBoundaries(highStart); // intrinsic.flash.geom.Rectangle endRect = textField.getCharBoundaries(highEnd - 1); // Shape shape = new Shape(); // if (data.matrix != null) shape.transform.matrix = data.matrix; // if (data.clip != null) shape.mask = data.clip; // Graphics graphics = shape.graphics; // graphics.beginFill(style.background.handle, data.alpha / 255f); // graphics.drawRect(x + startRect.x, lineY, endRect.right - startRect.left, metrics.height); // graphics.endFill(); // data.sprite.addChild(shape); // } // } // if (lineEnd > end) break; // lineY += metrics.height; // } // } // // /* Draw Text */ // data.sprite.addChild(textField); // // /* Draw underline and border */ // for (int j = 0; j < styles.length - 1; j++) { // StyleItem run = styles[j]; // TextStyle style = run.style; // if (style == null) continue; // boolean drawUnderline = style.underline && (j + 1 >= styles.length || !style.isAdherentUnderline(styles[j + 1].style)); // boolean drawBorder = style.borderStyle != SWT.NONE && (j + 1 >= styles.length || !style.isAdherentBorder(styles[j + 1].style)); // boolean drawStrikeout = style.strikeout; // if (!drawUnderline && !drawBorder && !drawStrikeout) continue; // // int end = translateOffset(styles[j + 1].start); // double lineY = y + BORDER; // for (int lineIndex = 0; lineIndex < textField.numLines; lineIndex++) { // int lineStart = textField.getLineOffset(lineIndex); // int lineEnd = lineStart + textField.getLineLength(lineIndex); // TextLineMetrics metrics = textField.getLineMetrics(lineIndex); // if (drawUnderline) { // int start = run.start; // for (int k = j; k > 0 && style.isAdherentUnderline(styles[k - 1].style); k--) { // start = styles[k - 1].start; // } // start = translateOffset(start); // if (!(start > lineEnd || end < lineStart)) { // int highStart = Math.max(lineStart, start); // int highEnd = Math.min(lineEnd, end); // if (highStart != highEnd) { // /* Draw Underline */ // intrinsic.flash.geom.Rectangle startRect = textField.getCharBoundaries(highStart); // intrinsic.flash.geom.Rectangle endRect = textField.getCharBoundaries(highEnd - 1); // Shape shape = new Shape(); // if (data.matrix != null) shape.transform.matrix = data.matrix; // if (data.clip != null) shape.mask = data.clip; // Graphics graphics = shape.graphics; // int color = data.foreground.handle; // if (style.foreground != null) color = style.foreground.handle; // if (style.underlineColor != null) color = style.underlineColor.handle; // double underlineX = x + startRect.x; // double underlineY = lineY + metrics.ascent + 1; // double underlineThickness = 0.5; // graphics.lineStyle(0, color, data.alpha / 255f, false, "normal", CapsStyle.ROUND, JointStyle.MITER, data.lineMiterLimit); // switch (style.underlineStyle) { // case SWT.UNDERLINE_ERROR: // case SWT.UNDERLINE_SQUIGGLE: // int squigglyThickness = 1; // double squigglyHeight = 2 * squigglyThickness; // double lineBottom = lineY + metrics.height; // double squigglyY = Math.min(underlineY - squigglyHeight / 2, lineBottom - squigglyHeight - 1); // int[] points = computePolyline((int)underlineX, (int)squigglyY, (int)(underlineX + endRect.right - startRect.left), (int)(squigglyY + squigglyHeight)); // graphics.moveTo(points[0] + 0.5, points[1] + 0.5); // for (int i = 2; i < points.length; i+= 2) { // graphics.lineTo(points[i] + 0.5, points[i+1] + 0.5); // } // break; // case SWT.UNDERLINE_DOUBLE: // graphics.drawRect(underlineX, underlineY + underlineThickness * 4, endRect.right - startRect.left, underlineThickness); // //FALLTHROUGH // case SWT.UNDERLINE_SINGLE: // graphics.drawRect(underlineX, underlineY, endRect.right - startRect.left, underlineThickness); // break; // } // data.sprite.addChild(shape); // } // } // } // // if (drawBorder) { // int start = run.start; // for (int k = j; k > 0 && style.isAdherentBorder(styles[k - 1].style); k--) { // start = styles[k - 1].start; // } // start = translateOffset(start); // if (!(start > lineEnd || end < lineStart)) { // int highStart = Math.max(lineStart, start); // int highEnd = Math.min(lineEnd, end); // if (highStart != highEnd) { // /* Draw Border */ // intrinsic.flash.geom.Rectangle startRect = textField.getCharBoundaries(highStart); // intrinsic.flash.geom.Rectangle endRect = textField.getCharBoundaries(highEnd - 1); // Shape shape = new Shape(); // if (data.matrix != null) shape.transform.matrix = data.matrix; // if (data.clip != null) shape.mask = data.clip; // int color = data.foreground.handle; // if (style.foreground != null) color = style.foreground.handle; // if (style.borderColor != null) color = style.borderColor.handle; // //TODO border style // Graphics graphics = shape.graphics; // graphics.lineStyle(0, color, data.alpha / 255f, false, "normal", CapsStyle.ROUND, JointStyle.MITER, data.lineMiterLimit); // graphics.drawRect(x + startRect.x, lineY, endRect.right - startRect.left - 1, metrics.height - 1); // data.sprite.addChild(shape); // } // } // } // // if (drawStrikeout) { // int start = translateOffset(run.start); // if (!(start > lineEnd || end < lineStart)) { // int highStart = Math.max(lineStart, start); // int highEnd = Math.min(lineEnd, end); // if (highStart != highEnd) { // /* Draw Strikeout */ // intrinsic.flash.geom.Rectangle startRect = textField.getCharBoundaries(highStart); // intrinsic.flash.geom.Rectangle endRect = textField.getCharBoundaries(highEnd - 1); // Shape shape = new Shape(); // if (data.matrix != null) shape.transform.matrix = data.matrix; // if (data.clip != null) shape.mask = data.clip; // int color = data.foreground.handle; // if (style.foreground != null) color = style.foreground.handle; // if (style.strikeoutColor != null) color = style.strikeoutColor.handle; // Graphics graphics = shape.graphics; // graphics.lineStyle(0, color, data.alpha / 255f, false, "normal", CapsStyle.ROUND, JointStyle.MITER, data.lineMiterLimit); // double striteoutY = lineY + metrics.height / 3 * 2; // graphics.moveTo(x + startRect.x, striteoutY); // graphics.lineTo(x + startRect.x + endRect.right - startRect.left, striteoutY); // data.sprite.addChild(shape); // } // } // } // if (lineEnd > end) break; // lineY += metrics.height; // } // } } void freeRuns () { textField = new TextField(); } public int getAlignment () { checkLayout(); return alignment; } public int getAscent () { checkLayout(); return ascent; } public Rectangle getBounds () { checkLayout(); computeRuns(); int width = text.length() > 0 ? (int)textField.textWidth : 0; int height = (int)textField.textHeight; if (wrapWidth != -1) width = wrapWidth; if (ascent != -1 && descent != -1) { height = Math.max (height, ascent + descent); } return new Rectangle(0, 0, width, height); } public Rectangle getBounds (int start, int end) { checkLayout(); computeRuns(); int length = text.length(); if (length == 0) return new Rectangle(0, 0, 0, 0); if (start > end) return new Rectangle(0, 0, 0, 0); start = Math.min(Math.max(0, start), length - 1); end = Math.min(Math.max(0, end), length - 1); start = translateOffset(start); end = translateOffset(end); // intrinsic.flash.geom.Rectangle startRect = textField.getCharBoundaries(start); // intrinsic.flash.geom.Rectangle endRect = textField.getCharBoundaries(end); // intrinsic.flash.geom.Rectangle rect = startRect.union(endRect); // if (textField.getLineIndexOfChar(start) != textField.getLineIndexOfChar(end)) { // rect.x = BORDER; // rect.width = textField.width; // } // return new Rectangle((int)rect.x - BORDER, (int)rect.y - BORDER, (int)Math.ceil(rect.width), (int)Math.ceil(rect.height)); return new Rectangle(0,0,10,10); } public int getDescent () { checkLayout(); return descent; } public Font getFont () { checkLayout(); return font; } public int getIndent () { checkLayout(); return indent; } public boolean getJustify () { checkLayout(); return justify; } public int getLevel (int offset) { checkLayout(); return 0; } public Rectangle getLineBounds (int lineIndex) { checkLayout(); computeRuns(); if (!(0 <= lineIndex && lineIndex < textField.numLines)) SWT.error(SWT.ERROR_INVALID_RANGE); if (text.length() == 0) { return getBounds(); } int start = textField.getLineOffset(lineIndex); // intrinsic.flash.geom.Rectangle rect = textField.getCharBoundaries(start); // TextLineMetrics metrics = textField.getLineMetrics(lineIndex); // int height = (int)metrics.height; // if (ascent != -1 && descent != -1) { // height = Math.max (height, ascent + descent); // } // return new Rectangle((int)rect.x - BORDER, (int)rect.y - BORDER, (int)metrics.width, height); return new Rectangle(0,0,10,10); } public int getLineCount () { checkLayout (); computeRuns(); return textField.numLines; } public int getLineIndex (int offset) { checkLayout (); computeRuns(); int length = text.length(); if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); if (offset == length) return textField.numLines - 1; offset = translateOffset(offset); return textField.getLineIndexOfChar(offset); } public FontMetrics getLineMetrics (int lineIndex) { checkLayout (); computeRuns(); int lineCount = getLineCount(); if (!(0 <= lineIndex && lineIndex < lineCount)) SWT.error(SWT.ERROR_INVALID_RANGE); // TextLineMetrics metrics = textField.getLineMetrics(lineIndex); // int ascent = Math.max(this.ascent, (int)metrics.ascent); // int descent = Math.max(this.descent, (int)metrics.descent); // return FontMetrics.internal_new(ascent, descent, ascent + descent, 0); return null; } public int[] getLineOffsets () { checkLayout (); computeRuns(); int[] offsets = new int[textField.numLines + 1]; for (int i = 0; i < offsets.length - 1; i++) { offsets[i] = untranslateOffset(textField.getLineOffset(i)); } offsets[offsets.length - 1] = text.length(); return offsets; } public Point getLocation (int offset, boolean trailing) { checkLayout(); computeRuns(); int length = text.length(); if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); if (length == 0) return new Point(0, 0); offset = translateOffset(offset); // intrinsic.flash.geom.Rectangle rect = textField.getCharBoundaries(offset); // int x = (int)rect.x; // if (trailing) x += rect.width; // return new Point(x - BORDER, (int)rect.y - BORDER); return new Point(0,0); } public int getNextOffset (int offset, int movement) { checkLayout(); return _getOffset (offset, movement, true); } int _getOffset(int offset, int movement, boolean forward) { computeRuns(); int length = text.length(); if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); if (forward && offset == length) return length; if (!forward && offset == 0) return 0; int step = forward ? 1 : -1; if ((movement & org.eclipse.draw2d.rap.swt.SWT.MOVEMENT_CHAR) != 0) return offset + step; if ((movement & org.eclipse.draw2d.rap.swt.SWT.MOVEMENT_CLUSTER) != 0) return offset + step; offset = translateOffset(offset); int lineIndex = textField.getLineIndexOfChar(Math.max(0, Math.min(length - 1, offset))); int lineStart = textField.getLineOffset(lineIndex); int lineLength = textField.getLineLength(lineIndex); int lineBreak = 0;//TODO while (lineStart <= offset && offset <= lineStart + lineLength) { int newOffset = offset + step; int trailing = 0; if (forward) { if (newOffset + trailing >= lineStart + lineLength - lineBreak) { int lineEnd = lineStart + lineLength; if (trailing != 0) lineEnd -= lineBreak; return untranslateOffset(Math.min(length, lineEnd)); } } else { if (newOffset + trailing == lineStart) { if (lineIndex == 0) return 0; int lineEnd = 0; //if (newOffset + trailing == offset) lineEnd = OS.TextLine_NewlineLength(lines[lineIndex - 1]); return untranslateOffset(Math.max(0, newOffset + trailing - lineEnd)); } } offset = newOffset + trailing; switch (movement) { case org.eclipse.draw2d.rap.swt.SWT.MOVEMENT_CLUSTER: return untranslateOffset(offset); case org.eclipse.draw2d.rap.swt.SWT.MOVEMENT_WORD: case org.eclipse.draw2d.rap.swt.SWT.MOVEMENT_WORD_START: { if (offset > 0) { boolean letterOrDigit = Character.isLetterOrDigit(text.charAt(offset)); boolean previousLetterOrDigit = Character.isLetterOrDigit(text.charAt(offset - 1)); if (letterOrDigit != previousLetterOrDigit || !letterOrDigit) { if (!Character.isWhitespace(text.charAt(offset))) { return untranslateOffset(offset); } } } break; } case org.eclipse.draw2d.rap.swt.SWT.MOVEMENT_WORD_END: { if (offset > 0) { boolean isLetterOrDigit = Character.isLetterOrDigit(text.charAt(offset)); boolean previousLetterOrDigit = Character.isLetterOrDigit(text.charAt(offset - 1)); if (!isLetterOrDigit && previousLetterOrDigit) { return untranslateOffset(offset); } } break; } } } return forward ? length : 0; } public int getOffset (Point point, int[] trailing) { checkLayout(); computeRuns(); if (point == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); return getOffset(point.x, point.y, trailing); } public int getOffset (int x, int y, int[] trailing) { checkLayout(); computeRuns(); if (trailing != null && trailing.length < 1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); int length = text.length(); if (length == 0) return 0; double nx = Math.max(BORDER, Math.min(x + BORDER, textField.textWidth + BORDER - 1)); double ny = Math.max(BORDER, Math.min(y + BORDER, textField.textHeight + BORDER - 1)); int offset = textField.getCharIndexAtPoint(nx, ny); /* * Bug in Flex. For some reason getCharIndexAtPoint() fails * for a valid input. The fix is to test char by char. */ // if (offset == -1) { // intrinsic.flash.geom.Rectangle rect; // for (int i = 0; i < text.length(); i++) { // rect = textField.getCharBoundaries(i); // if (rect != null && rect.contains(nx, ny)) { // offset = i; // break; // } // } // } // if (offset == -1) return 0; // // if (trailing != null) { // intrinsic.flash.geom.Rectangle rect = textField.getCharBoundaries(offset); // trailing[0] = (nx - rect.x) > rect.width / 2 ? 1 : 0; // } return Math.min(untranslateOffset(offset), length - 1); } public int getOrientation () { checkLayout(); return orientation; } public int getPreviousOffset (int offset, int movement) { checkLayout(); return _getOffset (offset, movement, false); } public int[] getRanges () { checkLayout(); int[] result = new int[styles.length * 2]; int count = 0; for (int i=0; i<styles.length - 1; i++) { if (styles[i].style != null) { result[count++] = styles[i].start; result[count++] = styles[i + 1].start - 1; } } if (count != result.length) { int[] newResult = new int[count]; System.arraycopy(result, 0, newResult, 0, count); result = newResult; } return result; } public int[] getSegments () { checkLayout(); return segments; } public int getSpacing () { checkLayout(); return lineSpacing; } public TextStyle getStyle (int offset) { checkLayout(); int length = text.length(); if (!(0 <= offset && offset < length)) SWT.error(SWT.ERROR_INVALID_RANGE); for (int i=1; i<styles.length; i++) { if (styles[i].start > offset) { return styles[i - 1].style; } } return null; } public TextStyle[] getStyles () { checkLayout(); TextStyle[] result = new TextStyle[styles.length]; int count = 0; for (int i=0; i<styles.length; i++) { if (styles[i].style != null) { result[count++] = styles[i].style; } } if (count != result.length) { TextStyle[] newResult = new TextStyle[count]; System.arraycopy(result, 0, newResult, 0, count); result = newResult; } return result; } public int[] getTabs () { checkLayout(); return tabs; } public String getText () { checkLayout(); return text; } public int getWidth () { checkLayout(); return wrapWidth; } public boolean isDisposed () { return device == null; } public void setAlignment (int alignment) { checkLayout(); int mask = SWT.LEFT | SWT.CENTER | SWT.RIGHT; alignment &= mask; if (alignment == 0) return; if ((alignment & SWT.LEFT) != 0) alignment = SWT.LEFT; if ((alignment & SWT.RIGHT) != 0) alignment = SWT.RIGHT; if (this.alignment == alignment) return; freeRuns(); this.alignment = alignment; } public void setAscent (int ascent) { checkLayout(); if (ascent < -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); if (this.ascent == ascent) return; freeRuns(); this.ascent = ascent; } public void setDescent (int descent) { checkLayout(); if (descent < -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); if (this.descent == descent) return; freeRuns(); this.descent = descent; } public void setFont (Font font) { checkLayout(); if (font != null && font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); if (this.font == font) return; if (font != null && font.equals(this.font)) return; freeRuns(); this.font = font; } public void setIndent (int indent) { checkLayout(); if (indent < 0) return; if (this.indent == indent) return; freeRuns(); this.indent = indent; } public void setJustify (boolean justify) { checkLayout(); if (this.justify == justify) return; freeRuns(); this.justify = justify; } public void setOrientation (int orientation) { checkLayout(); int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; orientation &= mask; if (orientation == 0) return; if ((orientation & SWT.LEFT_TO_RIGHT) != 0) orientation = SWT.LEFT_TO_RIGHT; if (this.orientation == orientation) return; this.orientation = orientation; freeRuns(); } public void setSegments (int[] segments) { checkLayout(); if (this.segments == null && segments == null) return; if (this.segments != null && segments != null) { if (this.segments.length == segments.length) { int i; for (i = 0; i <segments.length; i++) { if (this.segments[i] != segments[i]) break; } if (i == segments.length) return; } } freeRuns(); this.segments = segments; } public void setSpacing (int spacing) { checkLayout(); if (spacing < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); if (this.lineSpacing == spacing) return; freeRuns(); this.lineSpacing = spacing; } public void setStyle (TextStyle style, int start, int end) { checkLayout(); int length = text.length(); if (length == 0) return; if (start > end) return; start = Math.min(Math.max(0, start), length - 1); end = Math.min(Math.max(0, end), length - 1); int low = -1; int high = styles.length; while (high - low > 1) { int index = (high + low) / 2; if (styles[index + 1].start > start) { high = index; } else { low = index; } } if (0 <= high && high < styles.length) { StyleItem item = styles[high]; if (item.start == start && styles[high + 1].start - 1 == end) { if (style == null) { if (item.style == null) return; } else { if (style.equals(item.style)) return; } } } freeRuns(); int modifyStart = high; int modifyEnd = modifyStart; while (modifyEnd < styles.length) { if (styles[modifyEnd + 1].start > end) break; modifyEnd++; } if (modifyStart == modifyEnd) { int styleStart = styles[modifyStart].start; int styleEnd = styles[modifyEnd + 1].start - 1; if (styleStart == start && styleEnd == end) { styles[modifyStart].style = style; return; } if (styleStart != start && styleEnd != end) { StyleItem[] newStyles = new StyleItem[styles.length + 2]; System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); StyleItem item = new StyleItem(); item.start = start; item.style = style; newStyles[modifyStart + 1] = item; item = new StyleItem(); item.start = end + 1; item.style = styles[modifyStart].style; newStyles[modifyStart + 2] = item; System.arraycopy(styles, modifyEnd + 1, newStyles, modifyEnd + 3, styles.length - modifyEnd - 1); styles = newStyles; return; } } if (start == styles[modifyStart].start) modifyStart--; if (end == styles[modifyEnd + 1].start - 1) modifyEnd++; int newLength = styles.length + 1 - (modifyEnd - modifyStart - 1); StyleItem[] newStyles = new StyleItem[newLength]; System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); StyleItem item = new StyleItem(); item.start = start; item.style = style; newStyles[modifyStart + 1] = item; styles[modifyEnd].start = end + 1; System.arraycopy(styles, modifyEnd, newStyles, modifyStart + 2, styles.length - modifyEnd); styles = newStyles; } public void setTabs (int[] tabs) { checkLayout(); if (this.tabs == null && tabs == null) return; if (this.tabs != null && tabs !=null) { if (this.tabs.length == tabs.length) { int i; for (i = 0; i <tabs.length; i++) { if (this.tabs[i] != tabs[i]) break; } if (i == tabs.length) return; } } freeRuns(); this.tabs = tabs; } public void setText (String text) { checkLayout(); if (text == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (text.equals(this.text)) return; freeRuns(); this.text = text; styles = new StyleItem[2]; styles[0] = new StyleItem(); styles[1] = new StyleItem(); styles[1].start = text.length(); } public void setWidth (int width) { checkLayout(); if (width < -1 || width == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); if (this.wrapWidth == width) return; freeRuns(); this.wrapWidth = width; } public String toString () { if (isDisposed()) return "TextLayout {*DISPOSED*}"; return "TextLayout {}"; } /* * Translate a client offset to an internal offset */ int translateOffset (int offset) { return offset; } /* * Translate an internal offset to a client offset */ int untranslateOffset (int offset) { return offset; } }