public TextLayout add(Css css) { TextLayout newL = clone(); for (P p : css.getProperties()) { newL.getProperties().add(p); } return newL; }
@Override protected void drawText(java.awt.Graphics2D g) { if (getText() != null || isEditable()) { TextLayout layout = getTextLayout(); layout.draw(g, (float) origin.x, (float) (origin.y + layout.getAscent())); } }
/** * Shorten the given text <code>t</code> so that its length doesn't exceed the given width. The * default implementation replaces characters in the center of the original string with an * ellipsis ("..."). Override if you need a different strategy. * * @param gc the gc to use for text measurement * @param t the text to shorten * @param width the width to shorten the text to, in pixels * @return the shortened text */ protected String shortenText(GC gc, String t, int width) { if (t == null) return null; int w = gc.textExtent(ELLIPSIS, DRAW_FLAGS).x; if (width <= w) return t; int l = t.length(); int max = l / 2; int min = 0; int mid = (max + min) / 2 - 1; if (mid <= 0) return t; TextLayout layout = new TextLayout(getDisplay()); layout.setText(t); mid = validateOffset(layout, mid); while (min < mid && mid < max) { String s1 = t.substring(0, mid); String s2 = t.substring(validateOffset(layout, l - mid), l); int l1 = gc.textExtent(s1, DRAW_FLAGS).x; int l2 = gc.textExtent(s2, DRAW_FLAGS).x; if (l1 + w + l2 > width) { max = mid; mid = validateOffset(layout, (max + min) / 2); } else if (l1 + w + l2 < width) { min = mid; mid = validateOffset(layout, (max + min) / 2); } else { min = max; } } String result = mid == 0 ? t : t.substring(0, mid) + ELLIPSIS + t.substring(validateOffset(layout, l - mid), l); layout.dispose(); return result; }
LRESULT WM_MOUSEMOVE(int /*long*/ wParam, int /*long*/ lParam) { LRESULT result = super.WM_MOUSEMOVE(wParam, lParam); if (OS.COMCTL32_MAJOR < 6) { int x = OS.GET_X_LPARAM(lParam); int y = OS.GET_Y_LPARAM(lParam); if (OS.GetKeyState(OS.VK_LBUTTON) < 0) { int oldSelection = selection.y; selection.y = layout.getOffset(x, y, null); if (selection.y != oldSelection) { int newSelection = selection.y; if (oldSelection > newSelection) { int temp = oldSelection; oldSelection = newSelection; newSelection = temp; } Rectangle rect = layout.getBounds(oldSelection, newSelection); redraw(rect.x, rect.y, rect.width, rect.height, false); } } else { for (int j = 0; j < offsets.length; j++) { Rectangle[] rects = getRectangles(j); for (int i = 0; i < rects.length; i++) { Rectangle rect = rects[i]; if (rect.contains(x, y)) { setCursor(display.getSystemCursor(SWT.CURSOR_HAND)); return result; } } } setCursor(null); } } return result; }
/** * This implementation calls <code>super.hitTest</code> and returns the result if non-null (this * should be a HitInfo.Point), then returns a HitInfo.Interior if the mouse-click occured inside * the text bound (as defined by text layout) * * @return a HitInfo corresponding to the given mouse-event */ public HitInfo hitTest(PEMouseEvent e) { // from Bitmap: if (image != null) { if (getBounds().contains(e.getPicPoint())) { return new HitInfo.Interior((PicText) element, e); } return null; } // from TextLayout: if (!getBounds().contains(e.getPicPoint())) return null; PicText te = (PicText) element; // recompute textlayout b-box, but store it in a temporary field ! Rectangle2D tb = textLayout.getBounds(); Shape text_bounds = text2ModelTr.createTransformedShape(tb); if (text_bounds.contains(e.getPicPoint())) { // [SR:pending] for the hitInfo to be reliable, getPicPoint() should first be transformed by // inverse text2ModelTr ! (especially when rotationAngle != 0) TextHitInfo thi = textLayout.hitTestChar( (float) (e.getPicPoint().x - strx), (float) (e.getPicPoint().y - stry)); // guaranteed to return a non-null thi return new HitInfo.Text((PicText) element, thi, e); } // test hit on textlayout's bounding rectangle : // else if (bounds.contains(e.getPicPoint())) return new HitInfo.Interior(element,e); return null; }
/** * Sets the receiver's text. * * <p>The string can contain both regular text and hyperlinks. A hyperlink is delimited by an * anchor tag, <A> and </A>. Within an anchor, a single HREF attribute is supported. * When a hyperlink is selected, the text field of the selection event contains either the text of * the hyperlink or the value of its HREF, if one was specified. In the rare case of identical * hyperlinks within the same string, the HREF attribute can be used to distinguish between them. * The string may include the mnemonic character and line delimiters. The only delimiter the HREF * attribute supports is the quotation mark ("). * * <p>Mnemonics are indicated by an '&' that causes the next character to be the mnemonic. The * receiver can have a mnemonic in the text preceding each link. When the user presses a key * sequence that matches the mnemonic, focus is assigned to the link that follows the text. * Mnemonics in links and in the trailing text are ignored. On most platforms, the mnemonic * appears underlined but may be emphasised in a platform specific manner. The mnemonic indicator * character '&' can be escaped by doubling it in the string, causing a single '&' to be * displayed. * * @param string the new text * @exception IllegalArgumentException * <ul> * <li>ERROR_NULL_ARGUMENT - if the text is null * </ul> * * @exception SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver * </ul> */ public void setText(String string) { checkWidget(); if (string == null) error(SWT.ERROR_NULL_ARGUMENT); if (string.equals(text)) return; text = string; layout.setText(parse(string)); focusIndex = offsets.length > 0 ? 0 : -1; selection.x = selection.y = -1; boolean enabled = (state & DISABLED) == 0; TextStyle linkStyle = new TextStyle(null, enabled ? linkColor : disabledColor, null); linkStyle.underline = true; int[] bidiSegments = new int[offsets.length * 2]; for (int i = 0; i < offsets.length; i++) { Point point = offsets[i]; layout.setStyle(linkStyle, point.x, point.y); bidiSegments[i * 2] = point.x; bidiSegments[i * 2 + 1] = point.y + 1; } layout.setSegments(bidiSegments); TextStyle mnemonicStyle = new TextStyle(null, null, null); mnemonicStyle.underline = true; for (int i = 0; i < mnemonics.length; i++) { int mnemonic = mnemonics[i]; if (mnemonic != -1) { layout.setStyle(mnemonicStyle, mnemonic, mnemonic); } } redraw(); }
@Override public Rectangle2D.Double getBounds() { TextLayout layout = getTextLayout(); Rectangle2D.Double r = new Rectangle2D.Double( origin.x, origin.y, layout.getAdvance(), layout.getAscent() + layout.getDescent()); return r; }
public static void DrawString(Surface g, TextLayout layout, int x, int y) { CanvasImage c = Global.m_graphics.createImage( (int) Math.ceil(layout.width()), (int) Math.ceil(layout.height())); Canvas gc = c.canvas(); gc.drawText(layout, 0, 0); g.drawImage(c, x, y); }
/** * update strx stry = location of TextLayout's bottom-Left corner with respect to PicText's * anchor-point */ protected void syncStringLocation() { PicText te = (PicText) element; PicPoint anchor = te.getCtrlPt(TextEditable.P_ANCHOR, ptBuf); if (image == null) { if (!areDimensionsComputed) { te.setDimensions( textLayout.getBounds().getWidth(), textLayout.getAscent(), textLayout.getDescent()); } strx = te.getLeftX() - anchor.x; stry = te.getBaseLineY() - anchor.y; } else { // image not null strx = te.getLeftX() - anchor.x; stry = te.getBottomY() - anchor.y; } }
public void drawPage(Graphics2D g2, PageFormat pf, int page) { if (message.equals("")) return; page--; // account for cover page drawCropMarks(g2, pf); g2.clip(new Rectangle2D.Double(0, 0, pf.getImageableWidth(), pf.getImageableHeight())); g2.translate(-page * pf.getImageableWidth(), 0); g2.scale(scale, scale); FontRenderContext context = g2.getFontRenderContext(); Font f = new Font("Serif", Font.PLAIN, 72); TextLayout layout = new TextLayout(message, f, context); AffineTransform transform = AffineTransform.getTranslateInstance(0, layout.getAscent()); Shape outline = layout.getOutline(transform); g2.draw(outline); }
/** * Synchronize the textLayout and the shape (=frame box, by calling syncFrame) with the model When * <code>TextLayout</code> is used, this delegates to <code>getRotation()</code> where computing * rotation angle is concerned, and updates the AffineTransform returned by <code> * getTextToModelTransform()</code>. */ protected void syncShape() { PicText te = (PicText) element; // textLayout = new TextLayout(te.getText().length()==0 ? " " : te.getText(), // textFont, // new FontRenderContext(null,false,false)); text2ModelTr.setToIdentity(); // reset PicPoint anchor = te.getCtrlPt(TextEditable.P_ANCHOR, ptBuf); text2ModelTr.rotate(getRotation(), anchor.x, anchor.y); // rotate along P_ANCHOR ! // the reference point of an image is the top-left one, but the refpoint of a text layout is on // the baseline if (image != null) { text2ModelTr.translate(te.getLeftX(), te.getTopY()); if (te.getWidth() != 0 && image.getWidth() != 0 && (te.getDepth() + te.getHeight()) != 0 && image.getHeight() != 0) text2ModelTr.scale( te.getWidth() / image.getWidth(), -(te.getHeight() + te.getDepth()) / image.getHeight()); } else { // Hack ? Just cheating a little bit ? Ou juste ruse ? // we want here to use the dimensions of the textLayout instead of latex dimensions if // areDimensionsComputed // sinon on va aligner le textlayout en fonction des parametres latex, et l'Utilisateur (qui // est bien bete) ne va rien comprendre. double latexH = 0; double latexD = 0; double latexW = 0; if (areDimensionsComputed) { // store latex dimensions, and setDimensions to textLayout ones latexH = te.getHeight(); latexD = te.getDepth(); latexW = te.getWidth(); te.setDimensions( textLayout.getBounds().getWidth(), textLayout.getAscent(), textLayout.getDescent()); } text2ModelTr.translate(te.getLeftX(), te.getBaseLineY()); if (areDimensionsComputed) { // restore latex dimensions te.setDimensions(latexW, latexH, latexD); } // Autre possibilite= comprimer le texte pour qu'il rentre dans la boite (evite le hack // ci-dessus): // text2ModelTr.scale(te.getWidth()/textLayout.getWidth(),-(te.getHeight()+te.getDepth())/textLayout.getHeight()); text2ModelTr.scale(1.0, -1.0); } syncFrame(); }
void enableWidget(boolean enabled) { if (OS.COMCTL32_MAJOR >= 6) { LITEM item = new LITEM(); item.mask = OS.LIF_ITEMINDEX | OS.LIF_STATE; item.stateMask = OS.LIS_ENABLED; item.state = enabled ? OS.LIS_ENABLED : 0; while (OS.SendMessage(handle, OS.LM_SETITEM, 0, item) != 0) { item.iLink++; } } else { TextStyle linkStyle = new TextStyle(null, enabled ? linkColor : disabledColor, null); linkStyle.underline = true; for (int i = 0; i < offsets.length; i++) { Point point = offsets[i]; layout.setStyle(linkStyle, point.x, point.y); } redraw(); } /* * Feature in Windows. For some reason, setting * LIS_ENABLED state using LM_SETITEM causes the * SysLink to become enabled. To be specific, * calling IsWindowEnabled() returns true. The * fix is disable the SysLink after LM_SETITEM. */ super.enableWidget(enabled); }
void drawWidget(GC gc, RECT rect) { drawBackground(gc.handle, rect); int selStart = selection.x; int selEnd = selection.y; if (selStart > selEnd) { selStart = selection.y; selEnd = selection.x; } // temporary code to disable text selection selStart = selEnd = -1; if (!OS.IsWindowEnabled(handle)) gc.setForeground(disabledColor); layout.draw(gc, 0, 0, selStart, selEnd, null, null); if (hasFocus() && focusIndex != -1) { Rectangle[] rects = getRectangles(focusIndex); for (int i = 0; i < rects.length; i++) { Rectangle rectangle = rects[i]; gc.drawFocus(rectangle.x, rectangle.y, rectangle.width, rectangle.height); } } if (hooks(SWT.Paint) || filters(SWT.Paint)) { Event event = new Event(); event.gc = gc; event.x = rect.left; event.y = rect.top; event.width = rect.right - rect.left; event.height = rect.bottom - rect.top; sendEvent(SWT.Paint, event); event.gc = null; } }
/** * Render the View to the given graphic context. This implementation render the interior first, * then the outline. */ public void paint(Graphics2D g, Rectangle2D a) { if (!a.intersects(getBounds())) return; if (image != null) { // paint bitmap g.drawImage(image, text2ModelTr, null); // debug: g.setPaint(Color.red); g.draw(this.bounds); super.paint(g, a); // possibly paint framebox if non-null } else { // paint textlayout super.paint(g, a); // possibly paint framebox if non-null AffineTransform oldAT = g.getTransform(); // paint text in black g.setPaint(Color.black); // from now on, we work in Y-direct (<0) coordinates to avoid inextricable problems with font // being mirrored... g.transform(text2ModelTr); // also include rotation textLayout.draw(g, 0.0f, 0.0f); // [pending] ajouter un cadre si areDimensionsComputed (wysiwyg du pauvre) // get back to previous transform g.setTransform(oldAT); if (DEBUG) { g.setPaint(Color.red); g.draw(bounds); } } }
LRESULT WM_SETFONT(int /*long*/ wParam, int /*long*/ lParam) { if (OS.COMCTL32_MAJOR < 6) { layout.setFont(Font.win32_new(display, wParam)); } if (lParam != 0) OS.InvalidateRect(handle, null, true); return super.WM_SETFONT(font = wParam, lParam); }
public int stringWidth(String message) { if (LSystem.base() == null) { return 0; } initLayout(message); return textLayout.stringWidth(message); }
@Override void createWidget(int index) { super.createWidget(index); layout.setFont(getFont()); text = ""; initAccessible(); }
/** * Sets the receiver's text. * * <p>The string can contain both regular text and hyperlinks. A hyperlink is delimited by an * anchor tag, <A> and </A>. Within an anchor, a single HREF attribute is supported. * When a hyperlink is selected, the text field of the selection event contains either the text of * the hyperlink or the value of its HREF, if one was specified. In the rare case of identical * hyperlinks within the same string, the HREF attribute can be used to distinguish between them. * The string may include the mnemonic character and line delimiters. The only delimiter the HREF * attribute supports is the quotation mark ("). * * <p>Mnemonics are indicated by an '&' that causes the next character to be the mnemonic. The * receiver can have a mnemonic in the text preceding each link. When the user presses a key * sequence that matches the mnemonic, focus is assigned to the link that follows the text. * Mnemonics in links and in the trailing text are ignored. On most platforms, the mnemonic * appears underlined but may be emphasised in a platform specific manner. The mnemonic indicator * character '&' can be escaped by doubling it in the string, causing a single '&' to be * displayed. * * @param string the new text * @exception IllegalArgumentException * <ul> * <li>ERROR_NULL_ARGUMENT - if the text is null * </ul> * * @exception SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver * </ul> */ public void setText(String string) { checkWidget(); if (string == null) error(SWT.ERROR_NULL_ARGUMENT); if (string.equals(text)) return; text = string; if (OS.COMCTL32_MAJOR >= 6) { boolean enabled = OS.IsWindowEnabled(handle); /* * Bug in Windows. For some reason, when SetWindowText() * is used to set the text of a link control to the empty * string, the old text remains. The fix is to set the * text to a space instead. */ if (string.length() == 0) string = " "; // $NON-NLS-1$ TCHAR buffer = new TCHAR(getCodePage(), string, true); OS.SetWindowText(handle, buffer); parse(text); enableWidget(enabled); } else { layout.setText(parse(text)); focusIndex = offsets.length > 0 ? 0 : -1; selection.x = selection.y = -1; int bits = OS.GetWindowLong(handle, OS.GWL_STYLE); if (offsets.length > 0) { bits |= OS.WS_TABSTOP; } else { bits &= ~OS.WS_TABSTOP; } OS.SetWindowLong(handle, OS.GWL_STYLE, bits); boolean enabled = OS.IsWindowEnabled(handle); TextStyle linkStyle = new TextStyle(null, enabled ? linkColor : disabledColor, null); linkStyle.underline = true; for (int i = 0; i < offsets.length; i++) { Point point = offsets[i]; layout.setStyle(linkStyle, point.x, point.y); } TextStyle mnemonicStyle = new TextStyle(null, null, null); mnemonicStyle.underline = true; for (int i = 0; i < mnemonics.length; i++) { int mnemonic = mnemonics[i]; if (mnemonic != -1) { layout.setStyle(mnemonicStyle, mnemonic, mnemonic); } } redraw(); } }
/** * Give notification from the model that a change occured to the text this view is responsible for * rendering. * * <p> */ public void changedUpdate(DrawingEvent.EventType eventType) { PicText text = (PicText) element; if (textLayout == null) { // new *************************** begin (by ss & bp) textLayout = new TextLayout( text.getText(text.getTextMode()).length() == 0 ? " " : text.getText(text.getTextMode()), // new *************************** end (by ss & bp) DefaultViewFactory.textFont, // static field new FontRenderContext(null, false, false)); } if (eventType == DrawingEvent.EventType.TEXT_CHANGE) { // new *************************** begin (by ss & bp) textLayout = new TextLayout( text.getText(text.getTextMode()).length() == 0 ? " " : text.getText(text.getTextMode()), // new *************************** end (by ss & bp) DefaultViewFactory.textFont, new FontRenderContext(null, false, false)); // first try to create a bitmap image = null; // aka "reset" image => we might temporarily resort to TextLayout until the image is // ready areDimensionsComputed = false; // reset dimensions to the textlayout dimensions text.setDimensions( textLayout.getBounds().getWidth(), textLayout.getAscent(), textLayout.getDescent()); // new *************************** begin (by ss & bp) if (wantToComputeLatexDimensions && text.getText(text.getTextMode()).length() > 0) { // new *************************** end (by ss & bp) // don't produce a bitmap for an empty string (LaTeX might not like it) // [pending] this should be made dependent on a preference's option new Thread(this).start(); } if (image == null) super.changedUpdate(null); // ie resort to TextLayout (update all) } else { text.updateFrame(); super.changedUpdate(eventType); } }
protected float drawBoxedString(Graphics2D g2, String s, Color c1, Color c2, double x) { // Calculate the width of the string. FontRenderContext frc = g2.getFontRenderContext(); TextLayout subLayout = new TextLayout(s, mFont, frc); float advance = subLayout.getAdvance(); // Fill the background rectangle with a gradient. GradientPaint gradient = new GradientPaint((float) x, 0, c1, (float) (x + advance), 0, c2); g2.setPaint(gradient); Rectangle2D bounds = mLayout.getBounds(); Rectangle2D back = new Rectangle2D.Double(x, 0, advance, bounds.getHeight()); g2.fill(back); // Draw the string over the gradient rectangle. g2.setPaint(Color.white); g2.setFont(mFont); g2.drawString(s, (float) x, (float) -bounds.getY()); return advance; }
@Override int setBounds(int x, int y, int width, int height, boolean move, boolean resize) { int result = super.setBounds(x, y, width, height, move, resize); if ((result & RESIZED) != 0) { layout.setWidth(width > 0 ? width : -1); redraw(); } return result; }
void createWidget() { super.createWidget(); text = ""; if (OS.COMCTL32_MAJOR < 6) { if ((style & SWT.MIRRORED) != 0) { layout.setOrientation(SWT.RIGHT_TO_LEFT); } initAccessible(); } }
LRESULT WM_SIZE(int /*long*/ wParam, int /*long*/ lParam) { LRESULT result = super.WM_SIZE(wParam, lParam); if (OS.COMCTL32_MAJOR < 6) { RECT rect = new RECT(); OS.GetClientRect(handle, rect); layout.setWidth(rect.right > 0 ? rect.right : -1); redraw(); } return result; }
public void render(int w, int h, Graphics2D g2) { int w2 = w / 2; int h2 = h / 2; g2.setPaint(new GradientPaint(0, 0, outerC, w * .35f, h * .35f, innerC)); g2.fillRect(0, 0, w2, h2); g2.setPaint(new GradientPaint(w, 0, outerC, w * .65f, h * .35f, innerC)); g2.fillRect(w2, 0, w2, h2); g2.setPaint(new GradientPaint(0, h, outerC, w * .35f, h * .65f, innerC)); g2.fillRect(0, h2, w2, h2); g2.setPaint(new GradientPaint(w, h, outerC, w * .65f, h * .65f, innerC)); g2.fillRect(w2, h2, w2, h2); g2.setColor(Color.black); TextLayout tl = new TextLayout("GradientPaint", g2.getFont(), g2.getFontRenderContext()); tl.draw( g2, (int) (w / 2 - tl.getBounds().getWidth() / 2), (int) (h / 2 + tl.getBounds().getHeight() / 2)); }
@Override void enableWidget(boolean enabled) { super.enableWidget(enabled); if (isDisposed()) return; TextStyle linkStyle = new TextStyle(null, enabled ? linkColor : disabledColor, null); linkStyle.underline = true; for (int i = 0; i < offsets.length; i++) { Point point = offsets[i]; layout.setStyle(linkStyle, point.x, point.y); } redraw(); }
void releaseWidget() { super.releaseWidget(); if (layout != null) layout.dispose(); layout = null; if (linkColor != null) linkColor.dispose(); linkColor = null; disabledColor = null; offsets = null; ids = null; mnemonics = null; text = null; }
@Override public Point computeSize(int wHint, int hHint, boolean changed) { checkWidget(); if (wHint != SWT.DEFAULT && wHint < 0) wHint = 0; if (hHint != SWT.DEFAULT && hHint < 0) hHint = 0; int width, height; int layoutWidth = layout.getWidth(); // TEMPORARY CODE if (wHint == 0) { layout.setWidth(1); Rectangle rect = layout.getBounds(); width = 0; height = rect.height; } else { layout.setWidth(wHint); Rectangle rect = layout.getBounds(); width = rect.width; height = rect.height; } layout.setWidth(layoutWidth); if (wHint != SWT.DEFAULT) width = wHint; if (hHint != SWT.DEFAULT) height = hHint; int border = getBorderWidth(); width += border * 2; height += border * 2; return new Point(width, height); }
Rectangle[] getRectangles(int linkIndex) { int lineCount = layout.getLineCount(); Rectangle[] rects = new Rectangle[lineCount]; int[] lineOffsets = layout.getLineOffsets(); Point point = offsets[linkIndex]; int lineStart = 1; while (point.x > lineOffsets[lineStart]) lineStart++; int lineEnd = 1; while (point.y > lineOffsets[lineEnd]) lineEnd++; int index = 0; if (lineStart == lineEnd) { rects[index++] = layout.getBounds(point.x, point.y); } else { rects[index++] = layout.getBounds(point.x, lineOffsets[lineStart] - 1); rects[index++] = layout.getBounds(lineOffsets[lineEnd - 1], point.y); if (lineEnd - lineStart > 1) { for (int i = lineStart; i < lineEnd - 1; i++) { rects[index++] = layout.getLineBounds(i); } } } if (rects.length != index) { Rectangle[] tmp = new Rectangle[index]; System.arraycopy(rects, 0, tmp, 0, index); rects = tmp; } return rects; }
/** Gets the drawing area without taking the decorator into account. */ @Override protected Rectangle2D.Double getFigureDrawingArea() { if (getText() == null) { return getBounds(); } else { TextLayout layout = getTextLayout(); Rectangle2D.Double r = new Rectangle2D.Double(origin.x, origin.y, layout.getAdvance(), layout.getAscent()); Rectangle2D lBounds = layout.getBounds(); if (!lBounds.isEmpty() && !Double.isNaN(lBounds.getX())) { r.add( new Rectangle2D.Double( lBounds.getX() + origin.x, (lBounds.getY() + origin.y + layout.getAscent()), lBounds.getWidth(), lBounds.getHeight())); } // grow by two pixels to take antialiasing into account Geom.grow(r, 2d, 2d); return r; } }
@Override long /*int*/ gtk_button_press_event(long /*int*/ widget, long /*int*/ event) { long /*int*/ result = super.gtk_button_press_event(widget, event); if (result != 0) return result; GdkEventButton gdkEvent = new GdkEventButton(); OS.memmove(gdkEvent, event, GdkEventButton.sizeof); if (gdkEvent.button == 1 && gdkEvent.type == OS.GDK_BUTTON_PRESS) { if (focusIndex != -1) setFocus(); int x = (int) gdkEvent.x; int y = (int) gdkEvent.y; if ((style & SWT.MIRRORED) != 0) x = getClientWidth() - x; int offset = layout.getOffset(x, y, null); int oldSelectionX = selection.x; int oldSelectionY = selection.y; selection.x = offset; selection.y = -1; if (oldSelectionX != -1 && oldSelectionY != -1) { if (oldSelectionX > oldSelectionY) { int temp = oldSelectionX; oldSelectionX = oldSelectionY; oldSelectionY = temp; } Rectangle rect = layout.getBounds(oldSelectionX, oldSelectionY); redraw(rect.x, rect.y, rect.width, rect.height, false); } for (int j = 0; j < offsets.length; j++) { Rectangle[] rects = getRectangles(j); for (int i = 0; i < rects.length; i++) { Rectangle rect = rects[i]; if (rect.contains(x, y)) { focusIndex = j; redraw(); return result; } } } } return result; }