001/* 002 * $Id: AbstractLayoutPainter.java 4079 2011-11-15 16:05:13Z kschaefe $ 003 * 004 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021package org.jdesktop.swingx.painter; 022 023import java.awt.Insets; 024import java.awt.Rectangle; 025 026/** 027 * An abstract base class for any painter which can be positioned. This means 028 * the painter has some intrinsic size to what it is drawing and 029 * can be stretched or aligned both horizontally and vertically. 030 * 031 * 032 * The AbstractLayoutPainter class provides the following configuraable properties: 033 * 034 * <ul> 035 * <li>horizonalAlignment - the horizonal alignment (left, center, and right)</li> 036 * <li>verticalAlignment - the verticalAlignment alignment (top, center, and bottom)</li> 037 * <li>fillHorizontal - indicates if the painter should stretch to fill the available space horizontally</li> 038 * <li>fillVertical - indicates if the painter should stretch to fill the available space vertically</li> 039 * <li>insets - whitespace on the top, bottom, left, and right. 040 * </ul> 041 * 042 * By combining these five properties any AbstractLayoutPainter subclass can position it's content 043 * within the paintable area. For example, an ImagePainter has an intrinsic size based on the image 044 * it is painting. If you wanted to paint the image in the lower right hand corner of the paintable 045 * area, but inset by 5 pixels, you could do the following: 046 * 047 * <pre><code> 048 * ImagePainter p = new ImagePainter(null); 049 * p.setVerticalAlignment(AbstractLayoutPainter.VerticalAlignment.BOTTOM); 050 * p.setHorizontalAlignment(AbstractLayoutPainter.HorizontalAlignment.RIGHT); 051 * p.setInsets(new Insets(0,0,5,5)); 052 * </code></pre> 053 * 054 * 055 * For something which is resizable, like a RectanglePainter, you can use the fill properties 056 * to make it resize along with the paintable area. For example, to make a rectangle with 20 px 057 * rounded corners, and which resizes with the paintable area but is inset 058 * by 10 pixels on all sides, you could do 059 * the following: 060 * 061 * <pre><code> 062 * RectanglePainter p = new RectanglePainter(); 063 * p.setRoundHeight(20); 064 * p.setRoundWidth(20); 065 * p.setInsets(new Insets(10,10,10,10)); 066 * p.setFillHorizontal(true); 067 * p.setFillVertical(true); 068 * </code></pre> 069 * 070 * 071 * @author joshua@marinacci.org 072 */ 073@SuppressWarnings("nls") 074public abstract class AbstractLayoutPainter<T> extends AbstractPainter<T> { 075 076 /** 077 * Specifies how to draw the image, i.e. what kind of Style to use 078 * when drawing 079 */ 080 private VerticalAlignment verticalAlignment = VerticalAlignment.CENTER; 081 private HorizontalAlignment horizontalAlignment = HorizontalAlignment.CENTER; 082 private Insets insets = new Insets(0,0,0,0); 083 private boolean fillVertical = false; 084 private boolean fillHorizontal = false; 085 086 /** 087 * Creates a new instance of AbstractLayoutPainter 088 */ 089 public AbstractLayoutPainter() { 090 } 091 092 /** 093 * An enum which controls horizontalAlignment alignment 094 */ 095 public static enum HorizontalAlignment { LEFT, CENTER, RIGHT } 096 097 /** 098 * An enum which controls verticalAlignment alignment 099 */ 100 public static enum VerticalAlignment { TOP, CENTER, BOTTOM } 101 102 /** 103 * Gets the current horizontalAlignment alignment. 104 * 105 * @return the current horizontalAlignment alignment 106 */ 107 public HorizontalAlignment getHorizontalAlignment() { 108 return horizontalAlignment; 109 } 110 111 /** 112 * Gets the current whitespace insets. 113 * @return the current insets 114 */ 115 public Insets getInsets() { 116 return insets; 117 } 118 119 /** 120 * gets the current verticalAlignment alignment 121 * 122 * @return current verticalAlignment alignment 123 */ 124 public VerticalAlignment getVerticalAlignment() { 125 return verticalAlignment; 126 } 127 128 /** 129 * indicates if the painter content is stretched horizontally 130 * 131 * @return the current horizontalAlignment stretch value 132 */ 133 public boolean isFillHorizontal() { 134 return fillHorizontal; 135 } 136 137 /** 138 * indicates if the painter content is stretched vertically 139 * 140 * @return the current verticalAlignment stretch value 141 */ 142 public boolean isFillVertical() { 143 return fillVertical; 144 } 145 146 /** 147 * Sets a new horizontalAlignment alignment. Used to position the content at the left, right, or center. 148 * 149 * @param horizontal new horizontalAlignment alignment 150 */ 151 public void setHorizontalAlignment(HorizontalAlignment horizontal) { 152 HorizontalAlignment old = this.getHorizontalAlignment(); 153 this.horizontalAlignment = horizontal; 154 setDirty(true); 155 firePropertyChange("horizontalAlignment", old, getHorizontalAlignment()); 156 } 157 158 /** 159 * Sets if the content should be stretched horizontally to fill all available horizontalAlignment 160 * space (minus the left and right insets). 161 * 162 * @param fillHorizontal new horizontal stretch value 163 */ 164 public void setFillHorizontal(boolean fillHorizontal) { 165 boolean old = this.isFillHorizontal(); 166 this.fillHorizontal = fillHorizontal; 167 setDirty(true); 168 firePropertyChange("fillHorizontal", old, isFillHorizontal()); 169 } 170 171 /** 172 * Sets the current whitespace insets. 173 * @param insets new insets 174 */ 175 public void setInsets(Insets insets) { 176 Insets old = this.getInsets(); 177 this.insets = insets; 178 setDirty(true); 179 firePropertyChange("insets", old, getInsets()); 180 } 181 182 /** 183 * Sets a new verticalAlignment alignment. Used to position the content at the top, bottom, or center. 184 * 185 * @param vertical new verticalAlignment alignment 186 */ 187 public void setVerticalAlignment(VerticalAlignment vertical) { 188 VerticalAlignment old = this.getVerticalAlignment(); 189 this.verticalAlignment = vertical; 190 setDirty(true); 191 firePropertyChange("verticalAlignment", old, getVerticalAlignment()); 192 } 193 194 /** 195 * Sets if the content should be stretched vertically to fill all available verticalAlignment 196 * space (minus the top and bottom insets). 197 * 198 * @param verticalStretch new verticalAlignment stretch value 199 */ 200 public void setFillVertical(boolean verticalStretch) { 201 boolean old = this.isFillVertical(); 202 this.fillVertical = verticalStretch; 203 setDirty(true); 204 firePropertyChange("fillVertical", old, isFillVertical()); 205 } 206 207 /** 208 * A protected method used by subclasses to calculate the final position of the 209 * content. This will position the content using the fillHorizontal, fillVertical 210 * horizontalAlignment, and verticalAlignment properties. This method 211 * is typically called by subclasses in their doPaint() methods. 212 * 213 * @param contentWidth The width of the content to be painted 214 * @param contentHeight The height of the content to be painted 215 * @param width the width of the area that the content will be positioned in 216 * @param height the height of the area that the content will be positioned in 217 * @return the rectangle for the content to be painted in 218 */ 219 protected final Rectangle calculateLayout(final int contentWidth, final int contentHeight, 220 final int width, final int height) { 221 222 Rectangle rect = new Rectangle(); 223 rect.width = contentWidth; 224 rect.height = contentHeight; 225 226 if(isFillHorizontal()) { 227 rect.width = width - insets.left - insets.right; 228 } 229 230 if(isFillVertical()) { 231 rect.height = height - insets.top - insets.bottom; 232 } 233 rect.x = calculateX(rect.width, width); 234 rect.y = calculateY(rect.height, height); 235 return rect; 236 } 237 238 private int calculateY(final int imgHeight, final int height) { 239 int y = 0; 240 if(getVerticalAlignment() == VerticalAlignment.TOP) { 241 y = 0; 242 y+= insets.top; 243 } 244 if(getVerticalAlignment() == VerticalAlignment.CENTER) { 245 y = (height-imgHeight)/2; 246 y += insets.top; 247 } 248 if(getVerticalAlignment() == VerticalAlignment.BOTTOM) { 249 y = height-imgHeight; 250 y-= insets.bottom; 251 } 252 return y; 253 } 254 255 private int calculateX(final int imgWidth, final int width) { 256 int x = 0; 257 if(getHorizontalAlignment() == HorizontalAlignment.LEFT) { 258 x = 0; 259 x+= insets.left; 260 } 261 if(getHorizontalAlignment() == HorizontalAlignment.CENTER) { 262 x = (width-imgWidth)/2; 263 x += insets.left; 264 } 265 if(getHorizontalAlignment() == HorizontalAlignment.RIGHT) { 266 x = width-imgWidth; 267 x-= insets.right; 268 } 269 return x; 270 } 271}