From: Frederick W. <fre...@us...> - 2012-01-10 11:22:28
|
rails/ui/swing/ImageLoader.java | 22 +++++++++- rails/ui/swing/MapPanel.java | 81 ++++++++++++++++++++++++++++++++++++-- rails/ui/swing/hexmap/HexMap.java | 44 ++------------------ 3 files changed, 105 insertions(+), 42 deletions(-) New commits: commit 38e4a6e05fae1349af459ed47c438271dc7373da Author: Frederick Weld <fre...@gm...> Date: Tue Jan 10 12:16:54 2012 +0100 Added round-off to the fit-to-xyz zoom (continuous zoom, scroll bar) The current logic of discrete zoom steps is still valid - but it is complemented by a continuous adjustment factor ("last mile adjustment"). In addition, the appearance and width of the scroll bar is now considered. diff --git a/rails/ui/swing/ImageLoader.java b/rails/ui/swing/ImageLoader.java index b22bcbf..f663639 100644 --- a/rails/ui/swing/ImageLoader.java +++ b/rails/ui/swing/ImageLoader.java @@ -27,6 +27,9 @@ public class ImageLoader { private static Map<Integer, Document> svgMap; private static double[] zoomFactors = new double[21]; + //defines adjustment of zoom factor (should be close to 1) + //(used for perfect-fit sizing that requires arbitrary zoom) + private static double zoomAdjustmentFactor = 1; private static double svgWidth = 75; private static double svgHeight = svgWidth * 0.5 * Math.sqrt(3.0); @@ -129,11 +132,28 @@ public class ImageLoader { if (zoomStep < 0) zoomStep = 0; else if (zoomStep > 20) zoomStep = 20; if (zoomFactors[zoomStep] == 0.0) { - zoomFactors[zoomStep] = 1.0 * Math.pow(2.0, 0.25*(zoomStep-10)); + zoomFactors[zoomStep] = zoomAdjustmentFactor * Math.pow(2.0, 0.25*(zoomStep-10)); } return zoomFactors[zoomStep]; } + + /** + * @param zoomAdjustmentFactor Additional factor applied to zoom factor. Used + * for precisely adjusting zoom-step based zoom factors for perfect fit requirements. + */ + public void setZoomAdjustmentFactor (double zoomAdjustmentFactor) { + ImageLoader.zoomAdjustmentFactor = zoomAdjustmentFactor; + + //invalidate buffered zoom step zoom factors + for (int i = 0 ; i < zoomFactors.length ; i++) { + zoomFactors[i] = 0; + } + } + + public void resetAdjustmentFactor() { + setZoomAdjustmentFactor(1); + } public ImageLoader() { directories.add(tileRootDir + svgTileDir); diff --git a/rails/ui/swing/MapPanel.java b/rails/ui/swing/MapPanel.java index e1be54b..6175b9b 100644 --- a/rails/ui/swing/MapPanel.java +++ b/rails/ui/swing/MapPanel.java @@ -20,11 +20,14 @@ import rails.ui.swing.hexmap.*; public class MapPanel extends JPanel { private static final long serialVersionUID = 1L; + //defines how many pixels should be left as safety margin when calculating fit zooms + private static final int zoomFitSafetyMargin = 4; + private MapManager mmgr; private HexMap map; private HexMapImage mapImage; private JScrollPane scrollPane; - + private GameUIManager gameUIManager; private JLayeredPane layeredPane; @@ -132,8 +135,80 @@ public class MapPanel extends JPanel { adjustToNewMapZoom(); } - private void zoomFit (boolean fitWidth, boolean fitHeight) { - map.zoomFit (getSize(), fitWidth, fitHeight); + /** + * Zoom-to-fit functionality is based on the discrete zoom steps. + * In order to achieve correctly fitting zoom, continuous adjustment factors are + * determined on top of that. + */ + private void zoomFit (boolean fitToWidth, boolean fitToHeight) { + ImageLoader imageLoader = GameUIManager.getImageLoader(); + int zoomStep = map.getZoomStep(); + + //reset adjustment factor + imageLoader.resetAdjustmentFactor(); + + //determine the available size to fit to + //(double needed for subsequent calculations) + double width = getSize().width - zoomFitSafetyMargin; + double height = getSize().height - zoomFitSafetyMargin; + + double idealFactorWidth = width / originalMapSize.width; + double idealFactorHeight = height / originalMapSize.height; + + //determine which dimension will be the critical one for the resize + boolean isWidthCritical = ( !fitToHeight + || (fitToWidth && idealFactorWidth < idealFactorHeight)); + + //check whether scrollbar will appear in the fit-to dimension and + //reduce available size accordingly (not relevant for fit-to-window) + if (isWidthCritical && idealFactorWidth > idealFactorHeight) { + width -= scrollPane.getVerticalScrollBar().getPreferredSize().width; + idealFactorWidth = width / originalMapSize.width; + } + if (!isWidthCritical && idealFactorWidth < idealFactorHeight) { + height -= scrollPane.getHorizontalScrollBar().getPreferredSize().height; + idealFactorHeight = height / originalMapSize.height; + } + + //abort resize if no space available + if (width < 0 || height < 0) return; + + //increase zoomFactor until constraints do not hold + //OR zoom cannot be increased any more + while + ( + ( + (!fitToWidth || idealFactorWidth > imageLoader.getZoomFactor(zoomStep)) + && + (!fitToHeight || idealFactorHeight > imageLoader.getZoomFactor(zoomStep)) + ) + && + imageLoader.getZoomFactor(zoomStep+1) != imageLoader.getZoomFactor(zoomStep) + ) + zoomStep++; + + //decrease zoomFactor until constraints do hold + //OR zoom cannot be decreased any more + while + ( + ( + (fitToWidth && idealFactorWidth < imageLoader.getZoomFactor(zoomStep)) + || + (fitToHeight && idealFactorHeight < imageLoader.getZoomFactor(zoomStep)) + ) + && + imageLoader.getZoomFactor(zoomStep-1) != imageLoader.getZoomFactor(zoomStep) + ) + zoomStep--; + + //Determine and apply adjustment factor for precise fit + double idealFactor = isWidthCritical ? idealFactorWidth : idealFactorHeight; + imageLoader.setZoomAdjustmentFactor ( + idealFactor / imageLoader.getZoomFactor(zoomStep)); + + //trigger zoom execution + map.setZoomStep(zoomStep); + adjustToNewMapZoom(); } diff --git a/rails/ui/swing/hexmap/HexMap.java b/rails/ui/swing/hexmap/HexMap.java index 0dc3c1a..e862f6d 100644 --- a/rails/ui/swing/hexmap/HexMap.java +++ b/rails/ui/swing/hexmap/HexMap.java @@ -562,43 +562,15 @@ public abstract class HexMap implements MouseListener, zoom(); } -/** - * Zoom-to-fit functionality is based on the discrete zoom steps. - * This means that no pixel precision is to be expected - */ - public void zoomFit (Dimension availableSize, boolean fitToWidth, boolean fitToHeight) { - double idealFactorWidth = availableSize.getWidth() / originalSize.width; - double idealFactorHeight = availableSize.getHeight() / originalSize.height; - //increase zoomFactor until constraints do not hold - //OR zoom cannot be increased any more - while - ( - ( - (!fitToWidth || idealFactorWidth > GameUIManager.getImageLoader().getZoomFactor(zoomStep)) - && - (!fitToHeight || idealFactorHeight > GameUIManager.getImageLoader().getZoomFactor(zoomStep)) - ) - && - GameUIManager.getImageLoader().getZoomFactor(zoomStep+1) != GameUIManager.getImageLoader().getZoomFactor(zoomStep) - ) - zoomStep++; - //decrease zoomFactor until constraints do hold - //OR zoom cannot be decreased any more - while - ( - ( - (fitToWidth && idealFactorWidth < GameUIManager.getImageLoader().getZoomFactor(zoomStep)) - || - (fitToHeight && idealFactorHeight < GameUIManager.getImageLoader().getZoomFactor(zoomStep)) - ) - && - GameUIManager.getImageLoader().getZoomFactor(zoomStep-1) != GameUIManager.getImageLoader().getZoomFactor(zoomStep) - ) - zoomStep--; - //trigger zoom execution + public void setZoomStep (int zoomStep) { + this.zoomStep = zoomStep; zoom(); } + public int getZoomStep () { + return zoomStep; + } + private void zoom() { zoomFactor = GameUIManager.getImageLoader().getZoomFactor(zoomStep); log.debug("HexMap: zoomStep = "+ zoomStep); @@ -614,10 +586,6 @@ public abstract class HexMap implements MouseListener, scale = (Scale.get() * zoomFactor); } - public int getZoomStep () { - return zoomStep; - } - public Dimension getOriginalSize() { return originalSize; } |