/*******************************************************************************
* Copyright (c) 2013, 2015 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.e4.ui.workbench.addons.dndaddon;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
import org.eclipse.e4.ui.services.IStylingEngine;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Region;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class SplitFeedbackOverlay {
final Display display = Display.getCurrent();
private Shell feedbackShell;
private int curSide = 0;
private float ratio;
private List<Rectangle> rects = new ArrayList<Rectangle>();
private Rectangle outerRect;
Boolean isModified = null;
private IStylingEngine stylingEngine;
public SplitFeedbackOverlay(Shell dragShell, Rectangle rect, int side, float pct,
boolean enclosed, boolean modified) {
outerRect = rect;
curSide = side;
ratio = pct;
feedbackShell = new Shell(dragShell, SWT.NO_TRIM | SWT.ON_TOP);
feedbackShell.setBounds(dragShell.getBounds());
feedbackShell.setData(DragAndDropUtil.IGNORE_AS_DROP_TARGET, DragAndDropUtil.IGNORE_AS_DROP_TARGET);
MWindow winModel = (MWindow) dragShell.getData(AbstractPartRenderer.OWNING_ME);
stylingEngine = winModel.getContext().get(IStylingEngine.class);
// Show the appropriate feedback rectangles
setFeedback(enclosed, modified);
defineRegion();
}
public void dispose() {
if (feedbackShell != null && !feedbackShell.isDisposed()) {
Region region = feedbackShell.getRegion();
if (region != null && !region.isDisposed()) {
region.dispose();
}
feedbackShell.dispose();
}
feedbackShell = null;
}
private void showRects(boolean enclosed) {
if (curSide == 0) {
return;
}
Rectangle ca = new Rectangle(outerRect.x, outerRect.y, outerRect.width, outerRect.height);
rects.clear();
if (enclosed) {
addRect(ca);
ca.x += 4;
ca.y += 4;
ca.width -= 8;
ca.height -= 8;
}
int pctWidth = (int) (ca.width * ratio);
int pctHeight = (int) (ca.height * ratio);
Rectangle r1 = null, r2 = null;
if (curSide == SWT.LEFT) {
r1 = new Rectangle(ca.x, ca.y, pctWidth, ca.height);
r2 = new Rectangle(ca.x + r1.width + 2, ca.y, ca.width - (pctWidth + 2), ca.height);
} else if (curSide == SWT.RIGHT) {
r1 = new Rectangle(ca.x, ca.y, ca.width - pctWidth, ca.height);
r2 = new Rectangle(ca.x + r1.width + 2, ca.y, pctWidth - 2, ca.height);
} else if (curSide == SWT.TOP) {
r1 = new Rectangle(ca.x, ca.y, ca.width, pctHeight);
r2 = new Rectangle(ca.x, ca.y + pctHeight + 2, ca.width, ca.height - (pctHeight + 2));
} else if (curSide == SWT.BOTTOM) {
r1 = new Rectangle(ca.x, ca.y, ca.width, ca.height - pctHeight);
r2 = new Rectangle(ca.x, ca.y + r1.height + 2, ca.width, pctHeight - 2);
}
addRect(r1);
addRect(r2);
}
private void defineRegion() {
Region rgn = new Region();
for (Rectangle r : rects) {
rgn.add(r);
rgn.subtract(r.x + 2, r.y + 2, r.width - 4, r.height - 4);
}
// Workaround: Some window managers draw a drop shadow even if the shell
// is set to NO_TRIM. By making the shell contain a component in the
// bottom-right of its parent shell, SWT won't resize it and any extra
// shadows will end up being drawn on top of the shadows for the parent
// shell rather than in the middle of the workbench window.
Composite parent = feedbackShell.getParent();
if (parent instanceof Shell) {
Shell parentShell = (Shell) parent;
Rectangle bounds = parentShell.getBounds();
rgn.add(bounds.width - 1, bounds.height - 1, 1, 1);
}
if (feedbackShell.getRegion() != null && !feedbackShell.getRegion().isDisposed()) {
feedbackShell.getRegion().dispose();
}
feedbackShell.setRegion(rgn);
feedbackShell.redraw();
display.update();
}
private void addRect(Rectangle rect) {
// Map the rect to the feedback shell
rect = display.map(null, feedbackShell, rect);
rects.add(rect);
}
public void setFeedback(boolean enclosed, boolean modified) {
if (isModified == null) {
isModified = !modified;
}
// Update the feedback color if the drag is 'modified'
if (modified != isModified) {
if (!modified) {
stylingEngine.setClassname(feedbackShell, "DragFeedback");
} else {
stylingEngine.setClassname(feedbackShell, "ModifiedDragFeedback");
}
stylingEngine.style(feedbackShell);
isModified = modified;
}
showRects(enclosed);
defineRegion();
feedbackShell.update();
}
/**
* Control this instance's visibility.
*
* @param visible
* make visible if {@code true} or invisible if {@code false}
* @since 0.11
*/
public void setVisible(boolean visible) {
if (feedbackShell != null) {
feedbackShell.setVisible(visible);
}
}
}