Home | History | Annotate | Download | only in view
      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      */
    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      */
    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      */
    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      */
    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      */
    303     public static boolean isHorizontal(int gravity) {
    304         return gravity > 0 && (gravity & HORIZONTAL_GRAVITY_MASK) != 0;
    305     }
    306 }
    307