org.eclipse.ui.internal.TrimDropTarget Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of workbench Show documentation
Show all versions of workbench Show documentation
This plug-in contains the bulk of the Workbench implementation, and depends on JFace, SWT, and Core Runtime. It cannot be used independently from org.eclipse.ui. Workbench client plug-ins should not depend directly on this plug-in.
The newest version!
/*******************************************************************************
* Copyright (c) 2004, 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;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jface.util.Geometry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.internal.dnd.DragBorder;
import org.eclipse.ui.internal.dnd.DragUtil;
import org.eclipse.ui.internal.dnd.IDragOverListener;
import org.eclipse.ui.internal.dnd.IDropTarget;
import org.eclipse.ui.internal.dnd.IDropTarget2;
import org.eclipse.ui.internal.layout.IWindowTrim;
import org.eclipse.ui.internal.layout.LayoutUtil;
import org.eclipse.ui.internal.layout.TrimDescriptor;
import org.eclipse.ui.internal.layout.TrimLayout;
import org.eclipse.ui.internal.layout.TrimToolBarBase;
/**
*/
/*package*/class TrimDropTarget implements IDragOverListener {
private final class ActualTrimDropTarget implements IDropTarget2 {
public IWindowTrim draggedTrim;
// tracking parameters
private DragBorder border = null;
private int dockedArea;
// Holder for the position of trim that is 'floating' with the cursor
private int cursorAreaId;
private int initialAreaId;
private IWindowTrim initialInsertBefore;
private Rectangle initialLocation;
/**
* Constructor
*/
private ActualTrimDropTarget() {
super();
draggedTrim = null;
dockedArea = SWT.NONE;
initialAreaId = SWT.NONE;
initialInsertBefore = null;
}
/**
* This method is used to delineate separate trims dragging events. The -first- drag
* event will set this and then it will remain constant until the drag gesture is done;
* either by dropping or escaping. Once the gesture is finished the trim value is set
* back to 'null'.
*
* @param trim The trim item currently being dragged.
*/
public void startDrag(IWindowTrim trim) {
// Are we starting a new drag?
if (draggedTrim != trim) {
// remember the dragged trim
draggedTrim = trim;
// Remember the location that we were in initially so we
// can go back there on an cancel...
initialAreaId = layout.getTrimAreaId(draggedTrim.getControl());
// Determine who we were placed 'before' in the trim
initialInsertBefore = getInsertBefore(initialAreaId, draggedTrim);
// Remember the location that the control used to be at for animation purposes
initialLocation = DragUtil.getDisplayBounds(draggedTrim.getControl());
// The dragged trim is always initially docked
dockedArea = initialAreaId;
}
}
/**
* Determine the trim area from the point. To avoid clashing at the 'corners' due to extending the trim area's
* rectangles we first ensure that the point is not actually -within- a trim area before we check the extended
* rectangles.
*
* @param pos The current cursor pos
* @return the Trim area that the cursor is in or SWT.NONE if the point is not in an area
*/
private int getTrimArea(Point pos) {
// First, check if we're actually -within- a trim area (i.e. no boundary extensions)
int areaId = getTrimArea(pos, 0);
// If we are not inside a trim area...are we 'close' to one?
if (areaId == SWT.NONE) {
areaId = getTrimArea(pos, TrimDragPreferences.getThreshold());
}
// not inside any trim area
return areaId;
}
/**
* Checks the trims areas against the given position. Each trim area is 'extended' into
* the workbench page by the value of extendedBoundaryWidth
before the checking
* takes place.
*
* @param pos The point to check against
* @param extendedBoundaryWidth The amount to extend the trim area's 'inner' edge by
*
* @return The trim area or SWT.NONE if the point is not within any extended trim area's rect.
*/
private int getTrimArea(Point pos, int extendedBoundaryWidth) {
int[] areaIds = layout.getAreaIds();
for (int i = 0; i < areaIds.length; i++) {
Rectangle trimRect = layout.getTrimRect(windowComposite, areaIds[i]);
trimRect = Geometry.toControl(windowComposite, trimRect);
// Only check 'valid' sides
if ( (areaIds[i] & getValidSides()) != SWT.NONE) {
// TODO: more confusion binding 'areaIds' to SWT 'sides'
switch (areaIds[i]) {
case SWT.LEFT:
trimRect.width += extendedBoundaryWidth;
if (pos.y >= trimRect.y &&
pos.y <= (trimRect.y+trimRect.height) &&
pos.x <= (trimRect.x+trimRect.width)) {
return areaIds[i];
}
break;
case SWT.RIGHT:
trimRect.x -= extendedBoundaryWidth;
trimRect.width += extendedBoundaryWidth;
if (pos.y >= trimRect.y &&
pos.y <= (trimRect.y+trimRect.height) &&
pos.x >= trimRect.x) {
return areaIds[i];
}
break;
case SWT.TOP:
trimRect.height += extendedBoundaryWidth;
if (pos.x >= trimRect.x &&
pos.x <= (trimRect.x+trimRect.width) &&
pos.y <= (trimRect.y+trimRect.height)) {
return areaIds[i];
}
break;
case SWT.BOTTOM:
trimRect.y -= extendedBoundaryWidth;
trimRect.height += extendedBoundaryWidth;
if (pos.x >= trimRect.x &&
pos.x <= (trimRect.x+trimRect.width) &&
pos.y >= trimRect.y) {
return areaIds[i];
}
break;
}
}
}
// not inside any trim area
return SWT.NONE;
}
/**
* Determine the window trim that the currently dragged trim should be inserted
* before.
* @param areaId The area id that is being checked
* @param pos The position used to determine the correct insertion trim
* @return The trim to 'dock' the draggedTrim before
*/
private IWindowTrim getInsertBefore(int areaId, Point pos) {
boolean isHorizontal = (areaId == SWT.TOP) || (areaId == SWT.BOTTOM);
// Walk the trim area and return the first one that the positon
// is 'after'.
List tDescs = layout.getTrimArea(areaId).getDescriptors();
for (Iterator iter = tDescs.iterator(); iter.hasNext();) {
TrimDescriptor desc = (TrimDescriptor) iter.next();
// Skip ourselves
if (desc.getTrim() == draggedTrim) {
continue;
}
// Now, check
Rectangle bb = desc.getCache().getControl().getBounds();
Point center = Geometry.centerPoint(bb);
if (isHorizontal) {
if (pos.x < center.x) {
return desc.getTrim();
}
}
else {
if (pos.y < center.y) {
return desc.getTrim();
}
}
}
return null;
}
/**
* Returns the trim that is 'before' the given trim in the given area
*
* @param areaId The areaId of the trim
* @param trim The trim to find the element after
*
* @return The trim that the given trim is 'before'
*/
private IWindowTrim getInsertBefore(int areaId, IWindowTrim trim) {
List tDescs = layout.getTrimArea(areaId).getDescriptors();
for (Iterator iter = tDescs.iterator(); iter.hasNext();) {
TrimDescriptor desc = (TrimDescriptor) iter.next();
if (desc.getTrim() == trim) {
if (iter.hasNext()) {
desc = (TrimDescriptor) iter.next();
return desc.getTrim();
}
return null;
}
}
return null;
}
/**
* Recalculates the drop information based on the current cursor pos.
*
* @param pos The cursor position
*/
public void track(Point pos) {
// Convert the mouse positon into 'local' coords
Rectangle r = new Rectangle(pos.x, pos.y, 1,1);
r = Geometry.toControl(windowComposite, r);
pos.x = r.x;
pos.y = r.y;
// Are we 'inside' a trim area ?
cursorAreaId = getTrimArea(pos);
// Provide tracking for the appropriate 'mode'
if (cursorAreaId != SWT.NONE) {
trackInsideTrimArea(pos);
} else {
trackOutsideTrimArea(pos);
}
}
/**
* Perform the feedback used when the cursor is 'inside' a particular trim area.
* The current implementation will place the dragged trim into the trim area at
* the location determined by the supplied point.
*
* @param pos The point to use to determine where in the trim area the dragged trim
* should be located.
*/
private void trackInsideTrimArea(Point pos) {
// Where should we be?
int newArea = getTrimArea(pos);
IWindowTrim newInsertBefore = getInsertBefore(newArea, pos);
// if we're currently undocked then we should dock
boolean shouldDock = dockedArea == SWT.NONE;
// If we're already docked then only update if there's a change in area or position
if (dockedArea != SWT.NONE) {
// Where are we now?
IWindowTrim curInsertBefore = getInsertBefore(dockedArea, draggedTrim);
// If we're already docked we should only update if there's a change
shouldDock = dockedArea != newArea || curInsertBefore != newInsertBefore;
}
// Do we have to do anything?
if (shouldDock) {
// (Re)dock the trim in the new location
dock(newArea, newInsertBefore);
}
}
/**
* Provide the dragging feedback when the cursor is -not- explicitly inside
* a particular trim area.
*
*/
private void trackOutsideTrimArea(Point pos) {
// If we -were- docked then undock
if (dockedArea != SWT.NONE) {
undock();
}
border.setLocation(pos, SWT.BOTTOM);
}
/**
* Return the set of valid sides that a piece of trim can be docked on. We
* arbitrarily extend this to include any areas that won't cause a change in orientation
*
* @return The extended drop 'side' set
*/
private int getValidSides() {
int result = draggedTrim.getValidSides();
if (result == SWT.NONE) {
return result;
}
// For now, if we can dock...we can dock -anywhere-
return SWT.TOP | SWT.BOTTOM | SWT.LEFT | SWT.RIGHT;
}
/**
* The user either cancelled the drag or tried to drop the trim in an invalid
* area...put the trim back in the last location it was in
*/
private void redock() {
// Since the control might move 'far' we'll provide an animation
Rectangle startRect = DragUtil.getDisplayBounds(draggedTrim.getControl());
RectangleAnimation animation = new RectangleAnimation(
windowComposite.getShell(), startRect, initialLocation, 300);
animation.schedule();
dock(initialAreaId, initialInsertBefore);
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.dnd.IDropTarget#drop()
*/
public void drop() {
// If we aren't docked then restore the initial location
if (dockedArea == SWT.NONE) {
redock();
}
}
/**
* Remove the trim frmo its current 'docked' location and attach it
* to the cursor...
*/
private void undock() {
// Remove the trim from the layout
layout.removeTrim(draggedTrim);
LayoutUtil.resize(draggedTrim.getControl());
// Re-orient the widget to its -original- side and size
draggedTrim.dock(initialAreaId);
draggedTrim.getControl().setSize(initialLocation.width, initialLocation.height);
// Create a new dragging border onto the dragged trim
// Special check for TrimPart...should be generalized
boolean wantsFrame = !(draggedTrim instanceof TrimToolBarBase);
border = new DragBorder(windowComposite, draggedTrim.getControl(), wantsFrame);
dockedArea = SWT.NONE;
}
/**
* Return the 'undocked' trim to its previous location in the layout
*/
private void dock(int areaId, IWindowTrim insertBefore) {
// remove the drag 'border'
if (border != null) {
border.dispose();
border = null;
}
// Update the trim's orientation if necessary
draggedTrim.dock(areaId);
// Add the trim into the layout
layout.addTrim(areaId, draggedTrim, insertBefore);
LayoutUtil.resize(draggedTrim.getControl());
// Remember the area that we're currently docked in
dockedArea = areaId;
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.dnd.IDropTarget#getCursor()
*/
public Cursor getCursor() {
// If the trim isn't docked then show the 'no smoking' sign
if (cursorAreaId == SWT.NONE) {
return windowComposite.getDisplay().getSystemCursor(SWT.CURSOR_NO);
}
// It's docked; show the four-way arrow cursor
return windowComposite.getDisplay().getSystemCursor(SWT.CURSOR_SIZEALL);
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.dnd.IDropTarget#getSnapRectangle()
*/
public Rectangle getSnapRectangle() {
// TODO: KLUDGE!! We don't want to show -any- snap rect
// but Tracker won't allow that so place it where it won't be visible
return new Rectangle(100000, 0,0,0);
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.dnd.IDropTarget2#dragFinished(boolean)
*/
public void dragFinished(boolean dropPerformed) {
// If we didn't perform a drop then restore the original position
if (!dropPerformed && dockedArea == SWT.NONE) {
// Force the dragged trim back into its original position...
redock();
}
// Set the draggedTrim to null. This indicates that we're no longer
// dragging the trim. The first call to the TrimDropTarget's 'drag' method
// will reset this the next time a drag starts.
draggedTrim = null;
}
}
private ActualTrimDropTarget dropTarget;
private TrimLayout layout;
private Composite windowComposite;
/**
* Create a new drop target capable of accepting IWindowTrim items
*
* @param someComposite The control owning the TrimLayout
* @param theWindow the workbenchWindow
*/
public TrimDropTarget(Composite someComposite, WorkbenchWindow theWindow) {
layout = (TrimLayout) someComposite.getLayout();
windowComposite = someComposite;
// Create an instance of a drop target to use
dropTarget = new ActualTrimDropTarget();
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.dnd.IDragOverListener#drag(org.eclipse.swt.widgets.Control, java.lang.Object, org.eclipse.swt.graphics.Point, org.eclipse.swt.graphics.Rectangle)
*/
public IDropTarget drag(Control currentControl, Object draggedObject,
Point position, final Rectangle dragRectangle) {
// Have to be dragging trim
if (!(draggedObject instanceof IWindowTrim)) {
return null;
}
// OK, we're dragging trim. is it from -this- shell?
IWindowTrim trim = (IWindowTrim) draggedObject;
if (trim.getControl().getShell() != windowComposite.getShell()) {
return null;
}
// If this is the -first- drag then inform the drop target
if (dropTarget.draggedTrim == null) {
dropTarget.startDrag(trim);
}
// Forward on to the 'actual' drop target for feedback
dropTarget.track(position);
// Spin the paint loop after every track
windowComposite.getDisplay().update();
return dropTarget;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy