package org.archstudio.bna.utils; import org.archstudio.bna.CoordinateMapperEvent; import org.archstudio.bna.ICoordinateMapper; import org.archstudio.bna.ICoordinateMapperListener; import org.archstudio.bna.IMutableCoordinateMapper; import org.archstudio.swtutils.SWTWidgetUtils; import org.archstudio.sysutils.SystemUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; public class ZoomUtils { public static final double[] ZOOM_VALUES = new double[] { 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00, 1.25, 1.50, 1.75, 2.00, 4.00, 8.00, 16.00 }; public static double getNextLowestZoomValue(double currentZoomValue) { double lowestValue = ZOOM_VALUES[0]; if (currentZoomValue <= lowestValue) { return currentZoomValue; } else { for (int i = 0; i < ZOOM_VALUES.length; i++) { if (currentZoomValue == ZOOM_VALUES[i]) { int index = i - 1; if (index < 0) { index = 0; } return ZOOM_VALUES[index]; } if (currentZoomValue < ZOOM_VALUES[i]) { int index = i - 1; if (index < 0) { index = 0; } return ZOOM_VALUES[index]; } } } return ZOOM_VALUES[ZOOM_VALUES.length - 1]; } public static double getNextHighestZoomValue(double currentZoomValue) { double highestValue = ZOOM_VALUES[ZOOM_VALUES.length - 1]; if (currentZoomValue >= highestValue) { return currentZoomValue; } else { for (int i = ZOOM_VALUES.length - 1; i >= 0; i--) { if (currentZoomValue == ZOOM_VALUES[i]) { int index = i + 1; if (index >= ZOOM_VALUES.length) { index = ZOOM_VALUES.length - 1; } return ZOOM_VALUES[index]; } if (currentZoomValue > ZOOM_VALUES[i]) { int index = i + 1; if (index >= ZOOM_VALUES.length) { index = ZOOM_VALUES.length - 1; } return ZOOM_VALUES[index]; } } } return ZOOM_VALUES[0]; } public static String zoomLevelToString(double zoom) { return SystemUtils.round(zoom * 100.0d) + "%"; } public static double stringToZoomLevel(String s) throws NumberFormatException { s = s.trim(); if (s.endsWith("%")) { s = s.substring(0, s.length() - 1); s = s.trim(); } int pct = Integer.parseInt(s); double scale = pct / 100.0d; return scale; } public static Control createZoomWidget(Composite parent, final Composite bna, final ICoordinateMapper cm) { boolean cmIsMutable = cm instanceof IMutableCoordinateMapper; final Combo combo = new Combo(parent, cmIsMutable ? SWT.NONE : SWT.READ_ONLY); String[] zoomLevels = new String[ZOOM_VALUES.length]; int z = 0; for (int i = ZOOM_VALUES.length - 1; i >= 0; i--) { zoomLevels[z++] = zoomLevelToString(ZOOM_VALUES[i]); } combo.setItems(zoomLevels); combo.setText(zoomLevelToString(cm.getLocalScale())); final ICoordinateMapperListener cml = new ICoordinateMapperListener() { @Override public void coordinateMappingsChanged(final CoordinateMapperEvent evt) { SWTWidgetUtils.async(combo, new Runnable() { @Override public void run() { try { combo.setText(zoomLevelToString(evt.getNewLocalScale())); } catch (Throwable t) { t.printStackTrace(); } } }); } }; cm.addCoordinateMapperListener(cml); if (cmIsMutable) { combo.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent e) { try { double newScale = stringToZoomLevel(combo.getText()); if (newScale == cm.getLocalScale()) { return; } scaleToCenter(bna, (IMutableCoordinateMapper) cm, newScale); } catch (NumberFormatException nfe) { combo.setText(zoomLevelToString(cm.getLocalScale())); } } @Override public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } }); } combo.addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(DisposeEvent e) { cm.removeCoordinateMapperListener(cml); } }); return combo; } public static void scaleToCenter(Control w, IMutableCoordinateMapper mcm, double newScale) { // TODO: I think this can be replaced with mcm.setLocalScaleAndAlign(localScale, localPoint, worldPoint) // Point size = BNAUtils.toPoint(w.getSize()); // int lcx = size.x / 2; // int lcy = size.y / 2; // int worldCenterX = mcm.localXtoWorldX(lcx); // int worldCenterY = mcm.localYtoWorldY(lcy); // // mcm.rescaleAbsolute(newScale); // // int newWorldCenterX = mcm.localXtoWorldX(lcx); // int newWorldCenterY = mcm.localYtoWorldY(lcy); // int dwcx = newWorldCenterX - worldCenterX; // int dwcy = newWorldCenterY - worldCenterY; // mcm.repositionRelative(-dwcx, -dwcy); } }