1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.view; 18 import android.graphics.Rect; 19 20 /** 21 * Standard constants and tools for placing an object within a potentially 22 * larger container. 23 */ 24 public class Gravity 25 { 26 /** Constant indicating that no gravity has been set **/ 27 public static final int NO_GRAVITY = 0x0000; 28 29 /** Raw bit indicating the gravity for an axis has been specified. */ 30 public static final int AXIS_SPECIFIED = 0x0001; 31 32 /** Raw bit controlling how the left/top edge is placed. */ 33 public static final int AXIS_PULL_BEFORE = 0x0002; 34 /** Raw bit controlling how the right/bottom edge is placed. */ 35 public static final int AXIS_PULL_AFTER = 0x0004; 36 /** Raw bit controlling whether the right/bottom edge is clipped to its 37 * container, based on the gravity direction being applied. */ 38 public static final int AXIS_CLIP = 0x0008; 39 40 /** Bits defining the horizontal axis. */ 41 public static final int AXIS_X_SHIFT = 0; 42 /** Bits defining the vertical axis. */ 43 public static final int AXIS_Y_SHIFT = 4; 44 45 /** Push object to the top of its container, not changing its size. */ 46 public static final int TOP = (AXIS_PULL_BEFORE|AXIS_SPECIFIED)<<AXIS_Y_SHIFT; 47 /** Push object to the bottom of its container, not changing its size. */ 48 public static final int BOTTOM = (AXIS_PULL_AFTER|AXIS_SPECIFIED)<<AXIS_Y_SHIFT; 49 /** Push object to the left of its container, not changing its size. */ 50 public static final int LEFT = (AXIS_PULL_BEFORE|AXIS_SPECIFIED)<<AXIS_X_SHIFT; 51 /** Push object to the right of its container, not changing its size. */ 52 public static final int RIGHT = (AXIS_PULL_AFTER|AXIS_SPECIFIED)<<AXIS_X_SHIFT; 53 54 /** Place object in the vertical center of its container, not changing its 55 * size. */ 56 public static final int CENTER_VERTICAL = AXIS_SPECIFIED<<AXIS_Y_SHIFT; 57 /** Grow the vertical size of the object if needed so it completely fills 58 * its container. */ 59 public static final int FILL_VERTICAL = TOP|BOTTOM; 60 61 /** Place object in the horizontal center of its container, not changing its 62 * size. */ 63 public static final int CENTER_HORIZONTAL = AXIS_SPECIFIED<<AXIS_X_SHIFT; 64 /** Grow the horizontal size of the object if needed so it completely fills 65 * its container. */ 66 public static final int FILL_HORIZONTAL = LEFT|RIGHT; 67 68 /** Place the object in the center of its container in both the vertical 69 * and horizontal axis, not changing its size. */ 70 public static final int CENTER = CENTER_VERTICAL|CENTER_HORIZONTAL; 71 72 /** Grow the horizontal and vertical size of the object if needed so it 73 * completely fills its container. */ 74 public static final int FILL = FILL_VERTICAL|FILL_HORIZONTAL; 75 76 /** Flag to clip the edges of the object to its container along the 77 * vertical axis. */ 78 public static final int CLIP_VERTICAL = AXIS_CLIP<<AXIS_Y_SHIFT; 79 80 /** Flag to clip the edges of the object to its container along the 81 * horizontal axis. */ 82 public static final int CLIP_HORIZONTAL = AXIS_CLIP<<AXIS_X_SHIFT; 83 84 /** 85 * Binary mask to get the horizontal gravity of a gravity. 86 */ 87 public static final int HORIZONTAL_GRAVITY_MASK = (AXIS_SPECIFIED | 88 AXIS_PULL_BEFORE | AXIS_PULL_AFTER) << AXIS_X_SHIFT; 89 /** 90 * Binary mask to get the vertical gravity of a gravity. 91 */ 92 public static final int VERTICAL_GRAVITY_MASK = (AXIS_SPECIFIED | 93 AXIS_PULL_BEFORE | AXIS_PULL_AFTER) << AXIS_Y_SHIFT; 94 95 /** Special constant to enable clipping to an overall display along the 96 * vertical dimension. This is not applied by default by 97 * {@link #apply(int, int, int, Rect, int, int, Rect)}; you must do so 98 * yourself by calling {@link #applyDisplay}. 99 */ 100 public static final int DISPLAY_CLIP_VERTICAL = 0x10000000; 101 102 /** Special constant to enable clipping to an overall display along the 103 * horizontal dimension. This is not applied by default by 104 * {@link #apply(int, int, int, Rect, int, int, Rect)}; you must do so 105 * yourself by calling {@link #applyDisplay}. 106 */ 107 public static final int DISPLAY_CLIP_HORIZONTAL = 0x01000000; 108 109 /** 110 * Apply a gravity constant to an object. 111 * 112 * @param gravity The desired placement of the object, as defined by the 113 * constants in this class. 114 * @param w The horizontal size of the object. 115 * @param h The vertical size of the object. 116 * @param container The frame of the containing space, in which the object 117 * will be placed. Should be large enough to contain the 118 * width and height of the object. 119 * @param outRect Receives the computed frame of the object in its 120 * container. 121 */ apply(int gravity, int w, int h, Rect container, Rect outRect)122 public static void apply(int gravity, int w, int h, Rect container, 123 Rect outRect) { 124 apply(gravity, w, h, container, 0, 0, outRect); 125 } 126 127 /** 128 * Apply a gravity constant to an object. 129 * 130 * @param gravity The desired placement of the object, as defined by the 131 * constants in this class. 132 * @param w The horizontal size of the object. 133 * @param h The vertical size of the object. 134 * @param container The frame of the containing space, in which the object 135 * will be placed. Should be large enough to contain the 136 * width and height of the object. 137 * @param xAdj Offset to apply to the X axis. If gravity is LEFT this 138 * pushes it to the right; if gravity is RIGHT it pushes it to 139 * the left; if gravity is CENTER_HORIZONTAL it pushes it to the 140 * right or left; otherwise it is ignored. 141 * @param yAdj Offset to apply to the Y axis. If gravity is TOP this pushes 142 * it down; if gravity is BOTTOM it pushes it up; if gravity is 143 * CENTER_VERTICAL it pushes it down or up; otherwise it is 144 * ignored. 145 * @param outRect Receives the computed frame of the object in its 146 * container. 147 */ apply(int gravity, int w, int h, Rect container, int xAdj, int yAdj, Rect outRect)148 public static void apply(int gravity, int w, int h, Rect container, 149 int xAdj, int yAdj, Rect outRect) { 150 switch (gravity&((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_X_SHIFT)) { 151 case 0: 152 outRect.left = container.left 153 + ((container.right - container.left - w)/2) + xAdj; 154 outRect.right = outRect.left + w; 155 if ((gravity&(AXIS_CLIP<<AXIS_X_SHIFT)) 156 == (AXIS_CLIP<<AXIS_X_SHIFT)) { 157 if (outRect.left < container.left) { 158 outRect.left = container.left; 159 } 160 if (outRect.right > container.right) { 161 outRect.right = container.right; 162 } 163 } 164 break; 165 case AXIS_PULL_BEFORE<<AXIS_X_SHIFT: 166 outRect.left = container.left + xAdj; 167 outRect.right = outRect.left + w; 168 if ((gravity&(AXIS_CLIP<<AXIS_X_SHIFT)) 169 == (AXIS_CLIP<<AXIS_X_SHIFT)) { 170 if (outRect.right > container.right) { 171 outRect.right = container.right; 172 } 173 } 174 break; 175 case AXIS_PULL_AFTER<<AXIS_X_SHIFT: 176 outRect.right = container.right - xAdj; 177 outRect.left = outRect.right - w; 178 if ((gravity&(AXIS_CLIP<<AXIS_X_SHIFT)) 179 == (AXIS_CLIP<<AXIS_X_SHIFT)) { 180 if (outRect.left < container.left) { 181 outRect.left = container.left; 182 } 183 } 184 break; 185 default: 186 outRect.left = container.left + xAdj; 187 outRect.right = container.right + xAdj; 188 break; 189 } 190 191 switch (gravity&((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_Y_SHIFT)) { 192 case 0: 193 outRect.top = container.top 194 + ((container.bottom - container.top - h)/2) + yAdj; 195 outRect.bottom = outRect.top + h; 196 if ((gravity&(AXIS_CLIP<<AXIS_Y_SHIFT)) 197 == (AXIS_CLIP<<AXIS_Y_SHIFT)) { 198 if (outRect.top < container.top) { 199 outRect.top = container.top; 200 } 201 if (outRect.bottom > container.bottom) { 202 outRect.bottom = container.bottom; 203 } 204 } 205 break; 206 case AXIS_PULL_BEFORE<<AXIS_Y_SHIFT: 207 outRect.top = container.top + yAdj; 208 outRect.bottom = outRect.top + h; 209 if ((gravity&(AXIS_CLIP<<AXIS_Y_SHIFT)) 210 == (AXIS_CLIP<<AXIS_Y_SHIFT)) { 211 if (outRect.bottom > container.bottom) { 212 outRect.bottom = container.bottom; 213 } 214 } 215 break; 216 case AXIS_PULL_AFTER<<AXIS_Y_SHIFT: 217 outRect.bottom = container.bottom - yAdj; 218 outRect.top = outRect.bottom - h; 219 if ((gravity&(AXIS_CLIP<<AXIS_Y_SHIFT)) 220 == (AXIS_CLIP<<AXIS_Y_SHIFT)) { 221 if (outRect.top < container.top) { 222 outRect.top = container.top; 223 } 224 } 225 break; 226 default: 227 outRect.top = container.top + yAdj; 228 outRect.bottom = container.bottom + yAdj; 229 break; 230 } 231 } 232 233 /** 234 * Apply additional gravity behavior based on the overall "display" that an 235 * object exists in. This can be used after 236 * {@link #apply(int, int, int, Rect, int, int, Rect)} to place the object 237 * within a visible display. By default this moves or clips the object 238 * to be visible in the display; the gravity flags 239 * {@link #DISPLAY_CLIP_HORIZONTAL} and {@link #DISPLAY_CLIP_VERTICAL} 240 * can be used to change this behavior. 241 * 242 * @param gravity Gravity constants to modify the placement within the 243 * display. 244 * @param display The rectangle of the display in which the object is 245 * being placed. 246 * @param inoutObj Supplies the current object position; returns with it 247 * modified if needed to fit in the display. 248 */ applyDisplay(int gravity, Rect display, Rect inoutObj)249 public static void applyDisplay(int gravity, Rect display, Rect inoutObj) { 250 if ((gravity&DISPLAY_CLIP_VERTICAL) != 0) { 251 if (inoutObj.top < display.top) inoutObj.top = display.top; 252 if (inoutObj.bottom > display.bottom) inoutObj.bottom = display.bottom; 253 } else { 254 int off = 0; 255 if (inoutObj.top < display.top) off = display.top-inoutObj.top; 256 else if (inoutObj.bottom > display.bottom) off = display.bottom-inoutObj.bottom; 257 if (off != 0) { 258 if (inoutObj.height() > (display.bottom-display.top)) { 259 inoutObj.top = display.top; 260 inoutObj.bottom = display.bottom; 261 } else { 262 inoutObj.top += off; 263 inoutObj.bottom += off; 264 } 265 } 266 } 267 268 if ((gravity&DISPLAY_CLIP_HORIZONTAL) != 0) { 269 if (inoutObj.left < display.left) inoutObj.left = display.left; 270 if (inoutObj.right > display.right) inoutObj.right = display.right; 271 } else { 272 int off = 0; 273 if (inoutObj.left < display.left) off = display.left-inoutObj.left; 274 else if (inoutObj.right > display.right) off = display.right-inoutObj.right; 275 if (off != 0) { 276 if (inoutObj.width() > (display.right-display.left)) { 277 inoutObj.left = display.left; 278 inoutObj.right = display.right; 279 } else { 280 inoutObj.left += off; 281 inoutObj.right += off; 282 } 283 } 284 } 285 } 286 287 /** 288 * <p>Indicate whether the supplied gravity has a vertical pull.</p> 289 * 290 * @param gravity the gravity to check for vertical pull 291 * @return true if the supplied gravity has a vertical pull 292 */ isVertical(int gravity)293 public static boolean isVertical(int gravity) { 294 return gravity > 0 && (gravity & VERTICAL_GRAVITY_MASK) != 0; 295 } 296 297 /** 298 * <p>Indicate whether the supplied gravity has an horizontal pull.</p> 299 * 300 * @param gravity the gravity to check for horizontal pull 301 * @return true if the supplied gravity has an horizontal pull 302 */ isHorizontal(int gravity)303 public static boolean isHorizontal(int gravity) { 304 return gravity > 0 && (gravity & HORIZONTAL_GRAVITY_MASK) != 0; 305 } 306 } 307