Merge "9patch: Set default zoom level based on image size."
diff --git a/draw9patch/src/main/java/com/android/draw9patch/ui/ImageEditorPanel.java b/draw9patch/src/main/java/com/android/draw9patch/ui/ImageEditorPanel.java
index 3b4cdcb..3529542 100644
--- a/draw9patch/src/main/java/com/android/draw9patch/ui/ImageEditorPanel.java
+++ b/draw9patch/src/main/java/com/android/draw9patch/ui/ImageEditorPanel.java
@@ -43,6 +43,8 @@
 import javax.swing.JScrollPane;
 import javax.swing.JSlider;
 import javax.swing.JSplitPane;
+import javax.swing.event.AncestorEvent;
+import javax.swing.event.AncestorListener;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
@@ -59,6 +61,7 @@
     private JLabel yLabel;
 
     private TexturePaint texture;
+    private JSlider zoomSlider;
 
     public ImageEditorPanel(MainFrame mainFrame, BufferedImage image, String name) {
         this.image = image;
@@ -76,6 +79,32 @@
         buildStatusPanel();
 
         checkImage();
+
+        addAncestorListener(new AncestorListener() {
+            @Override
+            public void ancestorAdded(AncestorEvent event) {
+            }
+
+            @Override
+            public void ancestorRemoved(AncestorEvent event) {
+            }
+
+            @Override
+            public void ancestorMoved(AncestorEvent event) {
+                // allow the image viewer to set the optimal zoom level and ensure that the
+                // zoom slider's setting is in sync with the image viewer's zoom
+                removeAncestorListener(this);
+                synchronizeImageViewerZoomLevel();
+            }
+        });
+    }
+
+    private void synchronizeImageViewerZoomLevel() {
+        zoomSlider.setValue(viewer.getZoom());
+    }
+
+    public ImageViewer getViewer() {
+        return viewer;
     }
 
     private void loadSupport() {
@@ -145,7 +174,7 @@
                 GridBagConstraints.LINE_END, GridBagConstraints.NONE,
                 new Insets(0, 0, 0, 0), 0, 0));
 
-        JSlider zoomSlider = new JSlider(ImageViewer.MIN_ZOOM, ImageViewer.MAX_ZOOM,
+        zoomSlider = new JSlider(ImageViewer.MIN_ZOOM, ImageViewer.MAX_ZOOM,
                 ImageViewer.DEFAULT_ZOOM);
         zoomSlider.setSnapToTicks(true);
         zoomSlider.putClientProperty("JComponent.sizeVariant", "small");
@@ -182,15 +211,15 @@
                 GridBagConstraints.LINE_END, GridBagConstraints.NONE,
                 new Insets(0, 0, 0, 0), 0, 0));
 
-        zoomSlider = new JSlider(200, 600, (int) (StretchesViewer.DEFAULT_SCALE * 100.0f));
-        zoomSlider.setSnapToTicks(true);
-        zoomSlider.putClientProperty("JComponent.sizeVariant", "small");
-        zoomSlider.addChangeListener(new ChangeListener() {
+        JSlider jSlider = new JSlider(200, 600, (int) (StretchesViewer.DEFAULT_SCALE * 100.0f));
+        jSlider.setSnapToTicks(true);
+        jSlider.putClientProperty("JComponent.sizeVariant", "small");
+        jSlider.addChangeListener(new ChangeListener() {
             public void stateChanged(ChangeEvent evt) {
                 stretchesViewer.setScale(((JSlider) evt.getSource()).getValue() / 100.0f);
             }
         });
-        status.add(zoomSlider, new GridBagConstraints(2, 1, 1, 1, 0.0f, 0.0f,
+        status.add(jSlider, new GridBagConstraints(2, 1, 1, 1, 0.0f, 0.0f,
                 GridBagConstraints.LINE_START, GridBagConstraints.NONE,
                 new Insets(0, 0, 0, 0), 0, 0));
 
diff --git a/draw9patch/src/main/java/com/android/draw9patch/ui/ImageViewer.java b/draw9patch/src/main/java/com/android/draw9patch/ui/ImageViewer.java
index fca896f..58b20b7 100644
--- a/draw9patch/src/main/java/com/android/draw9patch/ui/ImageViewer.java
+++ b/draw9patch/src/main/java/com/android/draw9patch/ui/ImageViewer.java
@@ -76,6 +76,9 @@
     private static final double STRIPES_SPACING = 6.0;
     private static final int STRIPES_ANGLE = 45;
 
+    /** The fraction of the window size that the 9patch should occupy. */
+    private static final float IDEAL_IMAGE_FRACTION_OF_WINDOW = 0.7f;
+
     /** Default zoom level for the 9patch image. */
     public static final int DEFAULT_ZOOM = 8;
 
@@ -193,9 +196,8 @@
             }
             @Override
             public void ancestorMoved(AncestorEvent event) {
-                // Set exactly size.
-                setZoom(DEFAULT_ZOOM);
                 removeAncestorListener(this);
+                setDefaultZoom();
             }
             @Override
             public void ancestorAdded(AncestorEvent event) {
@@ -474,7 +476,6 @@
         patchesChanged();
         repaint();
 
-
         isEditMode = false;
         editRegion = null;
     }
@@ -1100,6 +1101,21 @@
         return size;
     }
 
+    private void setDefaultZoom() {
+        int frameWidth = getWidth(), frameHeight = getHeight();
+        int z = DEFAULT_ZOOM;
+        if (frameWidth > 0 && frameHeight > 0) {
+            float w = (float) image.getWidth() / frameWidth;
+            float h = (float) image.getHeight() / frameHeight;
+
+            float current = Math.max(w, h);
+            float ideal = IDEAL_IMAGE_FRACTION_OF_WINDOW;
+
+            z = clamp(Math.round(ideal / current), 1, MAX_ZOOM);
+        }
+        setZoom(z);
+    }
+
     void setZoom(int value) {
         zoom = value;
         updateSize();
@@ -1110,6 +1126,10 @@
         }
     }
 
+    int getZoom() {
+        return zoom;
+    }
+
     private void updateSize() {
         int width = image.getWidth();
         int height = image.getHeight();
@@ -1158,6 +1178,10 @@
         listeners.add(p);
     }
 
+    public void removePatchUpdateListener(PatchUpdateListener p) {
+        listeners.remove(p);
+    }
+
     private void notifyPatchesUpdated() {
         for (PatchUpdateListener p: listeners) {
             p.patchesUpdated();