/******************************************************************************* * Copyright (c) 2005, 2007 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.ui.internal.dnd; import org.eclipse.jface.util.Geometry; import org.eclipse.swt.SWT; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.themes.ColorUtil; /** * Utility class that wraps a given control with a black 'border'. Moving the * border control will cause the given control to move to stay within its bounds. * * @since 3.2 * */ public class DragBorder { // Controls private Composite clientControl = null; private Control dragControl = null; private Canvas border = null; // Colors private Color baseColor; private Color hilightColor; private boolean isHighlight; /** * Construct a new DragBorder. * * @param client The client window that the border must stay within * @param toDrag The control to be placed 'inside' the border */ public DragBorder(Composite client, Control toDrag, boolean provideFrame) { clientControl = client; dragControl = toDrag; Point dragSize = toDrag.getSize(); // Create a control large enough to 'contain' the dragged control border = new Canvas(dragControl.getParent(), SWT.NONE); border.setSize(dragSize.x+2, dragSize.y+2); // Use the SWT 'title' colors since they should always have a proper contrast // and are 'related' (i.e. should look good together) baseColor = border.getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION); RGB background = border.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB(); RGB blended = ColorUtil.blend(baseColor.getRGB(), background); hilightColor = new Color(border.getDisplay(), blended); // Ensure the border is visible and the control is 'above' it... border.moveAbove(null); dragControl.moveAbove(null); if (provideFrame) { border.addPaintListener(new PaintListener() { public void paintControl(PaintEvent e) { if (isHighlight) { e.gc.setForeground(hilightColor); } else { e.gc.setForeground(baseColor); } // Draw a rectangle as our 'border' Rectangle bb = border.getBounds(); e.gc.drawRectangle(0,0,bb.width-1, bb.height-1); } }); } } /** * Move the border (and its 'contained' control to a new position. The new * position will be adjusted to lie entirely within the client area of the * <code>clientControl</code>. * * @param newPos The new position for the border * @param alignment The location of the cursor relative to the border being dragged. * Current implementation only recognizes SWT.TOP & SWT.BOTTOM (which implies SWT.LEFT) * and SWT.CENTER (which centers teh dragged border on the cursor. */ public void setLocation(Point newPos, int alignment) { // Move the border but ensure that it is still inside the Client area if (alignment == SWT.CENTER) { Point size = border.getSize(); border.setLocation(newPos.x - (size.x/2), newPos.y - (size.y/2)); } else if (alignment == SWT.TOP) { border.setLocation(newPos.x, newPos.y); } else { border.setLocation(newPos.x, newPos.y - border.getSize().y); } // Force the control to remain inside the shell Rectangle bb = border.getBounds(); Rectangle cr = clientControl.getClientArea(); Geometry.moveInside(bb,cr); // Ensure that the controls are the 'topmost' controls border.moveAbove(null); dragControl.moveAbove(null); // OK, now move the drag control and the border to their new locations dragControl.setLocation(bb.x+1, bb.y+1); border.setBounds(bb); } /** * Sets the hilight 'mode' for the control. * @param highlight true if the border should be drawn as 'hilighted' */ public void setHighlight(boolean highlight) { isHighlight = highlight; border.redraw(); } /** * Dispose the controls owned by the border. */ public void dispose() { hilightColor.dispose(); border.dispose(); } /** * @return The bounds of the border's control. */ public Rectangle getBounds() { return border.getBounds(); } }