• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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