package org.archstudio.bna.things.utility;
import org.archstudio.bna.IBNAView;
import org.archstudio.bna.IBNAWorld;
import org.archstudio.bna.ICoordinate;
import org.archstudio.bna.ICoordinateMapper;
import org.archstudio.bna.IMutableCoordinateMapper;
import org.archstudio.bna.facets.peers.IHasInnerViewPeer;
import org.archstudio.bna.logics.tracking.ModelBoundsTrackingLogic;
import org.archstudio.bna.things.AbstractThingPeer;
import org.archstudio.bna.ui.IUIResources;
import org.archstudio.bna.utils.DefaultBNAView;
import org.archstudio.bna.utils.LinearCoordinateMapper;
import org.archstudio.sysutils.SystemUtils;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
public class WorldThingPeer<T extends WorldThing> extends AbstractThingPeer<T> implements IHasInnerViewPeer<T> {
private IBNAView iView = null;
public WorldThingPeer(T thing, IBNAView view, ICoordinateMapper cm) {
super(thing, view, cm);
}
@Override
public void dispose() {
if (iView != null) {
iView.dispose();
}
super.dispose();
}
@Override
public IBNAView getInnerView() {
IBNAView iView = null;
Rectangle lbb = cm.worldToLocal(t.getBoundingBox());
if (lbb.height >= 5 && lbb.width >= 5) {
IBNAWorld iWorld = t.getWorld();
if (iWorld != null) {
// determine the offset and scale for the inner view
ModelBoundsTrackingLogic iBoundsLogic = iWorld.getThingLogicManager().addThingLogic(
ModelBoundsTrackingLogic.class);
ICoordinateMapper iCM = this.iView != null ? this.iView.getCoordinateMapper()
: new LinearCoordinateMapper();
Rectangle iBounds = iBoundsLogic.getModelBounds();
if (iBounds.width == 0 || iBounds.height == 0) {
iBounds = iCM.getWorldBounds();
}
if (iCM instanceof IMutableCoordinateMapper) {
IMutableCoordinateMapper iMCM = (IMutableCoordinateMapper) iCM;
double xScale = (double) lbb.width / iBounds.width;
double yScale = (double) lbb.height / iBounds.height;
double parentScale = cm.getLocalScale();
double iScale = Math.min(parentScale, Math.min(xScale, yScale));
int dx = SystemUtils.round((lbb.width - iBounds.width * iScale) / 2);
int dy = SystemUtils.round((lbb.height - iBounds.height * iScale) / 2);
iMCM.setLocalScaleAndAlign(iScale, new Point(lbb.x + dx, lbb.y + dy), new Point(iBounds.x,
iBounds.y));
}
// check for infinite recursion
Rectangle outerLBB = cm.worldToLocal(iBounds);
Rectangle innerLBB = iCM.worldToLocal(iBounds);
if (!outerLBB.equals(innerLBB)) {
if (this.iView != null && this.iView.getBNAWorld() == iWorld) {
iView = this.iView;
}
else {
iView = new DefaultBNAView(view, iWorld, iCM);
iView.setBNAUI(view.getBNAUI());
}
}
}
}
if (this.iView != iView) {
if (this.iView != null) {
this.iView.dispose();
this.iView = null;
}
this.iView = iView;
}
return this.iView;
}
@Override
public boolean draw(Rectangle localBounds, IUIResources r) {
Rectangle lbb = cm.worldToLocal(t.getBoundingBox());
if (!localBounds.intersects(lbb)) {
return false;
}
IBNAView iView = getInnerView();
if (iView != null) {
r.renderThings(iView, localBounds);
}
return true;
}
@Override
public boolean isInThing(ICoordinate location) {
Point worldPoint = location.getWorldPoint();
Rectangle wbb = t.getBoundingBox();
if (!wbb.contains(worldPoint)) {
return false;
}
return true;
}
}