View Javadoc
1   package fr.ifremer.reefdb.ui.swing.util.image;
2   
3   /*
4    * #%L
5    * Reef DB :: UI
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2014 - 2015 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   *
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   *
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  import fr.ifremer.reefdb.config.ReefDbConfiguration;
27  import org.jdesktop.swingx.JXPanel;
28  import org.jdesktop.swingx.painter.MattePainter;
29  import org.jdesktop.swingx.util.PaintUtils;
30  
31  import javax.swing.BorderFactory;
32  import javax.swing.JComponent;
33  import javax.swing.border.Border;
34  import java.awt.*;
35  import java.awt.image.BufferedImage;
36  
37  /*
38   *  Support custom painting on a panel in the form of
39   *
40   *  a) images - that can be scaled, tiled or painted at original size
41   *  b) non solid painting - that can be done by using a Paint object
42   *
43   *  Also, any component added directly to this panel will be made
44   *  non-opaque so that the custom painting can show through.
45   */
46  
47  /**
48   * <p>BackgroundPanel class.</p>
49   */
50  public class BackgroundPanel extends JXPanel {
51  
52      private Image image;
53      private BufferedImage scaledImage;
54      private boolean selected = false;
55  
56      private static final Border outsideBorder = BorderFactory.createEmptyBorder(10, 10, 10, 10);
57      private float alignmentX = 0.5f;
58      private float alignmentY = 0.5f;
59      public static final double NO_SCALE = 1d;
60      private boolean scaled = false;
61      private double ratio = NO_SCALE;
62  
63      /**
64       * <p>Constructor for BackgroundPanel.</p>
65       */
66      public BackgroundPanel() {
67          this(null, false);
68      }
69  
70      /*
71       *  Set image as the background
72       */
73  
74      /**
75       * <p>Constructor for BackgroundPanel.</p>
76       *
77       * @param image          a {@link java.awt.Image} object.
78       * @param withBackground a boolean.
79       */
80      public BackgroundPanel(Image image, boolean withBackground) {
81          setLayout(new BorderLayout());
82          if (withBackground) {
83              setBackgroundPainter(new MattePainter(PaintUtils.getCheckerPaint(Color.white, new Color(250, 250, 250), 50)));
84          }
85          setImage(image);
86          setSelected(false);
87      }
88  
89      /*
90       *	Set the image used as the background
91       */
92  
93      /**
94       * <p>Setter for the field <code>image</code>.</p>
95       *
96       * @param image a {@link java.awt.Image} object.
97       */
98      public void setImage(Image image) {
99          this.image = image;
100         repaint();
101     }
102 
103     /**
104      * <p>isSelected.</p>
105      *
106      * @return a boolean.
107      */
108     public boolean isSelected() {
109         return selected;
110     }
111 
112     /**
113      * <p>Setter for the field <code>selected</code>.</p>
114      *
115      * @param selected a boolean.
116      */
117     public void setSelected(boolean selected) {
118         this.selected = selected;
119         setBorder(BorderFactory.createCompoundBorder(outsideBorder,
120                 selected ? BorderFactory.createMatteBorder(2, 2, 2, 2, ReefDbConfiguration.getInstance().getColorSelectedRow()) : null));
121     }
122 
123     /*
124      *  Specify the horizontal alignment of the image when using ACTUAL style
125      */
126 
127     /**
128      * <p>setImageAlignmentX.</p>
129      *
130      * @param alignmentX a float.
131      */
132     public void setImageAlignmentX(float alignmentX) {
133         this.alignmentX = alignmentX > 1.0f ? 1.0f : alignmentX < 0.0f ? 0.0f : alignmentX;
134         repaint();
135     }
136 
137     /*
138      *  Specify the horizontal alignment of the image when using ACTUAL style
139      */
140 
141     /**
142      * <p>setImageAlignmentY.</p>
143      *
144      * @param alignmentY a float.
145      */
146     public void setImageAlignmentY(float alignmentY) {
147         this.alignmentY = alignmentY > 1.0f ? 1.0f : alignmentY < 0.0f ? 0.0f : alignmentY;
148         repaint();
149     }
150 
151     /**
152      * <p>Setter for the field <code>scaled</code>.</p>
153      *
154      * @param scaled a boolean.
155      */
156     public void setScaled(boolean scaled) {
157         this.scaled = scaled;
158         scaleImage();
159         repaint();
160     }
161 
162     public void setRatio(double ratio) {
163         this.ratio = ratio;
164         setScaled(ratio != NO_SCALE);
165     }
166 
167     /**
168      * <p>scaleImage.</p>
169      */
170     private void scaleImage() {
171         if (scaled && image != null) {
172 
173             int imageWidth = image.getWidth(this);
174             int imageHeight = image.getHeight(this);
175 
176             if (ratio == NO_SCALE) {
177                 int pw = super.getPreferredSize().width;   //panel width
178                 int ph = super.getPreferredSize().height;  //panel height
179 
180                 // use doubles so division below won't round
181                 if (pw < imageWidth || ph < imageHeight) {
182 
183                     double rw = (double) pw / (double) imageWidth;
184                     double rh = (double) ph / (double) imageHeight;
185 
186                     ratio = Math.min(rw, rh);
187 
188                 }
189             }
190             int newWidth = Math.max((int) (imageWidth * ratio), 1);
191             int newHeight = Math.max((int) (imageHeight * ratio), 1);
192 
193             scaledImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
194             Graphics2D g = scaledImage.createGraphics();
195             g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
196             g.drawImage(image, 0, 0, newWidth, newHeight, 0, 0, imageWidth, imageHeight, null);
197             g.dispose();
198 
199         } else {
200             scaledImage = null;
201         }
202     }
203     /*
204      *  Override method so we can make the component transparent
205      */
206 
207     /**
208      * <p>add.</p>
209      *
210      * @param component a {@link javax.swing.JComponent} object.
211      */
212     public void add(JComponent component) {
213         add(component, null);
214     }
215 
216     /*
217      *  Override to provide a preferred size equal to the image size
218      */
219 
220     /**
221      * {@inheritDoc}
222      */
223     @Override
224     public Dimension getPreferredSize() {
225         Image imageToRender = scaled ? scaledImage : image;
226         if (imageToRender != null) {
227             Insets insets = getInsets();
228             return new Dimension(imageToRender.getWidth(this) + insets.left + insets.right, imageToRender.getHeight(this) + insets.top + insets.bottom);
229         } else {
230             return super.getPreferredSize();
231         }
232     }
233 
234     /*
235      *  Add custom painting
236      */
237 
238     /**
239      * {@inheritDoc}
240      */
241     @Override
242     protected void paintComponent(Graphics g) {
243         super.paintComponent(g);
244 
245         //  Draw the image
246         Image imageToDraw = scaled ? scaledImage : image;
247         if (imageToDraw != null) {
248             Dimension d = getSize();
249             Insets insets = getInsets();
250             int width = d.width - insets.left - insets.right;
251             int height = d.height - insets.top - insets.left;
252             float x = (width - imageToDraw.getWidth(null)) * alignmentX;
253             float y = (height - imageToDraw.getHeight(null)) * alignmentY;
254             g.drawImage(imageToDraw, (int) x + insets.left, (int) y + insets.top, this);
255         }
256     }
257 
258 }