diff options
author | Markus Keller | 2009-06-11 17:29:54 +0000 |
---|---|---|
committer | Markus Keller | 2009-06-11 17:29:54 +0000 |
commit | cef6230e04a6f55f8bb087bfd0ca0d40e1fdfacd (patch) | |
tree | e5489b0aa3b20458343df82da2491ddccf96a2f3 | |
parent | 40752f4743b0589caeb572ede78b448b19e270e2 (diff) | |
download | eclipse.platform.text-cef6230e04a6f55f8bb087bfd0ca0d40e1fdfacd.tar.gz eclipse.platform.text-cef6230e04a6f55f8bb087bfd0ca0d40e1fdfacd.tar.xz eclipse.platform.text-cef6230e04a6f55f8bb087bfd0ca0d40e1fdfacd.zip |
Bug 62652: [hovering] Unable to resize javadoc popups on linux
workaround for SWT bug 23980.
3 files changed, 321 insertions, 2 deletions
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/ResizableShellSupport.java b/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/ResizableShellSupport.java new file mode 100644 index 00000000000..74cf6e2de68 --- /dev/null +++ b/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/ResizableShellSupport.java @@ -0,0 +1,306 @@ +/******************************************************************************* + * Copyright (c) 2009 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.jface.internal.text; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.events.MouseTrackAdapter; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Shell; + +import org.eclipse.jface.util.Geometry; + +/** + * Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=23980 : Shells without borders are + * not resizable on GTK. + * + * @since 3.6 + */ +public class ResizableShellSupport { + + /** + * Listeners installed on the shell. + */ + private static class MouseListenerMix extends MouseTrackAdapter implements MouseListener, MouseMoveListener { + /** + * The shell. + */ + private final Shell fShell; + /** + * The minimal shell width. + */ + private final int fMinShellWidth; + /** + * The minimal shell height. + */ + private final int fMinShellHeight; + + /** + * The last detected edges. + */ + private int fCurrentEdges; + /** + * The shell's original cursor. + */ + private Cursor fOriginalCursor; + + /** + * The location of the mouseDown event (display coordinates). + */ + private Point fOriginalMouseLoc; + /** + * The bounds of the shell on mouseDown (display coordinates). + */ + private Rectangle fOriginalShellBounds; + + /** + * Creates a mouse listener mix + * @param shell the shell + */ + public MouseListenerMix(Shell shell) { + fShell= shell; + Rectangle trim= shell.computeTrim(0, 0, 0, 0); + fMinShellWidth= trim.width + 2 * TRIM_SIZE; + fMinShellHeight= trim.height + 2 * TRIM_SIZE; + } + + /* + * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse.swt.events.MouseEvent) + */ + public void mouseMove(MouseEvent e) { + if (fOriginalMouseLoc != null) { + Point mouse= fShell.toDisplay(e.x, e.y); + int dx= mouse.x - fOriginalMouseLoc.x; + int dy= mouse.y - fOriginalMouseLoc.y; + + Rectangle sb= Geometry.copy(fOriginalShellBounds); + if ((fCurrentEdges & SWT.LEFT) != 0) { + int w= Math.max(sb.width - dx, fMinShellWidth); + sb.x+= sb.width - w; + sb.width= w; + } + if ((fCurrentEdges & SWT.RIGHT) != 0) { + sb.width= Math.max(sb.width + dx, fMinShellWidth); + } + if ((fCurrentEdges & SWT.TOP) != 0) { + int h= Math.max(sb.height - dy, fMinShellHeight); + sb.y+= sb.height - h; + sb.height= h; + } + if ((fCurrentEdges & SWT.BOTTOM) != 0) { + sb.height= Math.max(sb.height + dy, fMinShellHeight); + } + fShell.setBounds(sb); + + } else { + int edges= computeEdges(e); + setEdgesAndCursor(edges); + } + } + + /* + * @see org.eclipse.swt.events.MouseTrackAdapter#mouseExit(org.eclipse.swt.events.MouseEvent) + */ + public void mouseExit(MouseEvent e) { + setEdgesAndCursor(0); + } + + /* + * @see org.eclipse.swt.events.MouseAdapter#mouseDown(org.eclipse.swt.events.MouseEvent) + */ + public void mouseDown(MouseEvent e) { + if (fCurrentEdges != 0) { + fOriginalMouseLoc= fShell.toDisplay(e.x, e.y); + fOriginalShellBounds= fShell.getBounds(); + } + } + + /* + * @see org.eclipse.swt.events.MouseAdapter#mouseUp(org.eclipse.swt.events.MouseEvent) + */ + public void mouseUp(MouseEvent e) { + fOriginalMouseLoc= null; + fOriginalShellBounds= null; + } + + /* + * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) + */ + public void mouseDoubleClick(MouseEvent e) { + // not interesting + } + + /** + * Returns the edges at which the mouse is pointing. The result is one of + * {@link SWT#TOP}, {@link SWT#BOTTOM}, {@link SWT#LEFT}, or {@link SWT#RIGHT}, or a + * sensible combination thereof. + * + * @param e the mouse event + * @return the edges or 0 if the mouse is not over an edge + */ + private int computeEdges(MouseEvent e) { + Rectangle sb= fShell.getClientArea(); + + int edges= 0; + if (sb.contains(e.x, e.y)) { + int bottom= sb.y + sb.height - e.y; + int top= e.y - sb.y; + int right= sb.x + sb.width - e.x; + int left= e.x - sb.x; + + // prioritize bottom-right: + if (bottom <= TRIM_SIZE) { + edges|= SWT.BOTTOM; + } else if (top <= TRIM_SIZE) { + edges|= SWT.TOP; + } + if (right <= TRIM_SIZE) { + edges|= SWT.RIGHT; + } else if (left <= TRIM_SIZE) { + edges|= SWT.LEFT; + } + + // enlarge corners, prioritizing bottom-right: + if ((edges & SWT.BOTTOM) != 0) { + edges= enlargeCorner(SWT.BOTTOM, right, SWT.RIGHT, left, SWT.LEFT); + } else if ((edges & SWT.RIGHT) != 0) { + edges= enlargeCorner(SWT.RIGHT, bottom, SWT.BOTTOM, top, SWT.TOP); + } else if ((edges & SWT.LEFT) != 0) { + edges= enlargeCorner(SWT.LEFT, bottom, SWT.BOTTOM, top, SWT.TOP); + } else if ((edges & SWT.TOP) != 0) { + edges= enlargeCorner(SWT.TOP, right, SWT.RIGHT, left, SWT.LEFT); + } + } + return edges; + } + + /** + * Adds an adjacent edge if the distance to a corner is small enough. First corner gets + * priority. + * + * @param edge the base edge + * @param distance1 distance to first corner + * @param edge1 adjacent edge of first corner + * @param distance2 distance to second corner + * @param edge2 adjacent edge of second corner + * @return the new edges + */ + private static int enlargeCorner(int edge, int distance1, int edge1, int distance2, int edge2) { + int edges= edge; + if (distance1 <= CORNER_SIZE) { + edges|= edge1; + } else if (distance2 <= CORNER_SIZE) { + edges|= edge2; + } + return edges; + } + + /** + * Sets the cursor for the given edges or resets the original if 0. + * + * @param edges the edges or 0 + */ + private void setEdgesAndCursor(int edges) { + if (edges == fCurrentEdges) + return; + + if (edges == 0) { + fShell.setCursor(fOriginalCursor); + fOriginalCursor= null; + fCurrentEdges= edges; + fOriginalMouseLoc= null; + fOriginalShellBounds= null; + return; + } + + if (fCurrentEdges == 0) { + fOriginalCursor= fShell.getCursor(); + } + fCurrentEdges= edges; + + int style= 0; + if ((edges & SWT.TOP) != 0) { + if ((edges & SWT.LEFT) != 0) { + style= SWT.CURSOR_SIZENW; + } else if ((edges & SWT.RIGHT) != 0) { + style= SWT.CURSOR_SIZENE; + } else { + style= SWT.CURSOR_SIZEN; + } + } else if ((edges & SWT.BOTTOM) != 0) { + if ((edges & SWT.LEFT) != 0) { + style= SWT.CURSOR_SIZESW; + } else if ((edges & SWT.RIGHT) != 0) { + style= SWT.CURSOR_SIZESE; + } else { + style= SWT.CURSOR_SIZES; + } + } else if ((edges & SWT.LEFT) != 0) { + style= SWT.CURSOR_SIZEW; + } else if ((edges & SWT.RIGHT) != 0) { + style= SWT.CURSOR_SIZEE; + } + + Cursor cursor= fShell.getDisplay().getSystemCursor(style); + fShell.setCursor(cursor); + } + } + + + /** + * Width of resize trim. + */ + private static final int TRIM_SIZE= 4; + /** + * Enlarged area around corners in which dual-direction is active when mouse is in border. + */ + private static final int CORNER_SIZE= 22; + + /** + * Makes the given shell resizable on all platforms. The shell must have a {@link GridLayout}. + * If the shell is not resizable, this method enlarges the {@link GridLayout#marginWidth + * marginWidth} and {@link GridLayout#marginHeight marginHeight} and expects that the added area + * is not being shrunken or used in any way by other parties. + * + * @param shell the shell + */ + public static void makeResizable(final Shell shell) { + if ((shell.getStyle() & SWT.RESIZE) != 0) + return; + + GridLayout layout= ((GridLayout) shell.getLayout()); + layout.marginWidth+= TRIM_SIZE; + layout.marginHeight+= TRIM_SIZE; + + MouseListenerMix listenerMix= new MouseListenerMix(shell); + shell.addMouseMoveListener(listenerMix); + shell.addMouseTrackListener(listenerMix); + shell.addMouseListener(listenerMix); + + shell.addPaintListener(new PaintListener() { + public void paintControl(PaintEvent e) { + Rectangle clientArea= shell.getClientArea(); + int gap= - TRIM_SIZE / 2; + Geometry.expand(clientArea, gap, gap - 1, gap, gap - 1); + e.gc.setLineWidth(TRIM_SIZE); + e.gc.setForeground(e.display.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW)); + e.gc.drawRectangle(clientArea); + } + }); + } +} diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/AbstractInformationControl.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/AbstractInformationControl.java index a64b1cbd39a..4a66db2bc74 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/AbstractInformationControl.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/AbstractInformationControl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008 IBM Corporation and others. + * Copyright (c) 2008, 2009 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 @@ -43,6 +43,7 @@ import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.ListenerList; import org.eclipse.jface.action.ToolBarManager; +import org.eclipse.jface.internal.text.ResizableShellSupport; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.util.Geometry; @@ -188,6 +189,10 @@ public abstract class AbstractInformationControl implements IInformationControl, setColor(fContentComposite, foreground, background); createStatusComposite(statusFieldText, toolBarManager, foreground, background); + + if (fResizable) { + ResizableShellSupport.makeResizable(fShell); + } } private void createStatusComposite(final String statusFieldText, final ToolBarManager toolBarManager, Color foreground, Color background) { @@ -555,6 +560,12 @@ public abstract class AbstractInformationControl implements IInformationControl, if (fStatusComposite != null) trim.height+= fStatusComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT).y; + if (fResizable) { + GridLayout shellLayout= (GridLayout) fShell.getLayout(); + int w= shellLayout.marginWidth; + int h= shellLayout.marginHeight; + Geometry.expand(trim, w, w, h, h); + } return trim; } diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java index 9b0f4622285..833f5dbb92b 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java @@ -63,6 +63,7 @@ import org.eclipse.jface.bindings.keys.KeySequence; import org.eclipse.jface.bindings.keys.SWTKeySupport; import org.eclipse.jface.contentassist.IContentAssistSubjectControl; import org.eclipse.jface.internal.text.InformationControlReplacer; +import org.eclipse.jface.internal.text.ResizableShellSupport; import org.eclipse.jface.internal.text.TableOwnerDrawSupport; import org.eclipse.jface.preference.JFacePreferences; import org.eclipse.jface.resource.JFaceResources; @@ -601,6 +602,7 @@ class CompletionProposalPopup implements IContentAssistListener { layout.marginHeight= 0; layout.verticalSpacing= 1; fProposalShell.setLayout(layout); + ResizableShellSupport.makeResizable(fProposalShell); if (fContentAssistant.isStatusLineVisible()) { createMessageText(); @@ -974,7 +976,7 @@ class CompletionProposalPopup implements IContentAssistListener { */ public boolean hasFocus() { if (Helper.okToUse(fProposalShell)) { - if ((fProposalShell.isFocusControl() || fProposalTable.isFocusControl())) + if ((fProposalShell.getDisplay().getActiveShell() == fProposalShell)) return true; /* * We have to delegate this query to the additional info controller |