/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.ui.figures;
import java.util.List;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.LayeredPane;
import org.eclipse.draw2d.ScalableFigure;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.ViewportUtilities;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.LayerConstants;
import org.whole.lang.ui.layout.ViewportTracking;
import org.whole.lang.util.CompositeUtils;
/**
* @author Enrico Persiani
*/
public class ViewportTrackingStrategy implements IViewportTrackingStrategy {
protected IEntityFigure hostFigure;
protected ViewportTracking viewportTracking;
protected int ascent;
protected int indent;
public ViewportTrackingStrategy(IEntityFigure hostFigure) {
this(hostFigure, ViewportTracking.BOTH);
}
public ViewportTrackingStrategy(IEntityFigure hostFigure, ViewportTracking viewportTracking) {
this.hostFigure = hostFigure;
this.viewportTracking = viewportTracking;
}
public int getIndent() {
return indent;
}
public void setIndent(int indent) {
this.indent = indent;
}
public int getAscent() {
return ascent;
}
public void setAscent(int ascent) {
this.ascent = ascent;
}
protected Viewport viewport;
protected Viewport getViewport() {
if (viewport == null)
viewport = ViewportUtilities.getNearestEnclosingViewport(hostFigure);
return viewport;
}
protected Rectangle[] childrenBounds;
protected Rectangle compositeBounds = null;
@Override
public void onInvalidate() {
if (childrenBounds == null)
childrenBounds = new Rectangle[0];
else if (compositeBounds != null) {
@SuppressWarnings("unchecked")
List<IFigure> children = hostFigure.getChildren();
for (int i = 0; i < childrenBounds.length; i++) {
Rectangle.SINGLETON.setBounds(childrenBounds[i]);
Rectangle.SINGLETON.translate(hostFigure.getBounds().x, hostFigure.getBounds().y);
children.get(i).setBounds(Rectangle.SINGLETON);
}
}
int size = hostFigure.getChildren().size();
if (childrenBounds.length != size)
childrenBounds = CompositeUtils.resize(childrenBounds, size, () -> new Rectangle());
compositeBounds = null;
}
@Override
public void onPaintChildren(Graphics graphics) {
if (hostFigure.getChildren().isEmpty())
return;
Point amount = calculateTranslateAmount();
@SuppressWarnings("unchecked")
List<IFigure> children = hostFigure.getChildren();
for (int i = 0; i < childrenBounds.length; i++) {
Rectangle.SINGLETON.setBounds(childrenBounds[i]);
Rectangle.SINGLETON.translate(amount);
Rectangle.SINGLETON.translate(hostFigure.getBounds().x, hostFigure.getBounds().y);
children.get(i).setBounds(Rectangle.SINGLETON);
}
getViewport().validate();
}
protected Point translateAmount = new Point();
@SuppressWarnings("unchecked")
protected Point calculateTranslateAmount() {
translateAmount.setLocation(0, 0);
if (childrenBounds.length == 0)
return translateAmount;
Viewport viewport = getViewport();
LayeredPane layeredPane = (LayeredPane) viewport.getContents();
ScalableFigure scalableLayeredPane = (ScalableFigure) layeredPane.getLayer(LayerConstants.SCALABLE_LAYERS);
Rectangle clientArea = viewport.getClientArea().scale(1/scalableLayeredPane.getScale());
Rectangle bounds = hostFigure.getBounds();
if (!bounds.intersects(clientArea))
return translateAmount;
if (compositeBounds == null) {
List<IFigure> children = hostFigure.getChildren();
compositeBounds = new Rectangle(children.get(0).getBounds());
compositeBounds.translate(-bounds.x, -bounds.y);
for (int i = 0; i < childrenBounds.length; i++) {
childrenBounds[i].setBounds(children.get(i).getBounds());
childrenBounds[i].translate(-bounds.x, -bounds.y);
compositeBounds.union(childrenBounds[i]);
}
}
Rectangle compositeBounds = Rectangle.SINGLETON.setBounds(this.compositeBounds);
compositeBounds.translate(hostFigure.getBounds().x, hostFigure.getBounds().y);
int minDX = bounds.x - compositeBounds.x;
int minDY = bounds.y - compositeBounds.y;
int maxDX = bounds.right() - compositeBounds.right();
int maxDY = bounds.bottom() - compositeBounds.bottom();
if (clientArea.height < compositeBounds.height &&
clientArea.width < compositeBounds.width)
return translateAmount;
if (viewportTracking.isHorizontal())
translateAmount.setX(Math.max(minDX, Math.min(maxDX, clientArea.x > compositeBounds.x ?
clientArea.x - compositeBounds.x : (compositeBounds.right() > clientArea.right() ?
clientArea.right() - compositeBounds.right() : 0))));
if (viewportTracking.isVertical())
translateAmount.setY(Math.max(minDY, Math.min(maxDY, clientArea.y > compositeBounds.y ?
clientArea.y - compositeBounds.y : (compositeBounds.bottom() > clientArea.bottom() ?
clientArea.bottom() - compositeBounds.bottom() : 0))));
return translateAmount;
}
}