1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
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 */
16package com.android.ide.common.layout;
17
18import static com.android.SdkConstants.ANDROID_URI;
19import static com.android.SdkConstants.ATTR_LAYOUT_GRAVITY;
20import static com.android.SdkConstants.GRAVITY_VALUE_BOTTOM;
21import static com.android.SdkConstants.GRAVITY_VALUE_CENTER;
22import static com.android.SdkConstants.GRAVITY_VALUE_CENTER_HORIZONTAL;
23import static com.android.SdkConstants.GRAVITY_VALUE_CENTER_VERTICAL;
24import static com.android.SdkConstants.GRAVITY_VALUE_FILL;
25import static com.android.SdkConstants.GRAVITY_VALUE_FILL_HORIZONTAL;
26import static com.android.SdkConstants.GRAVITY_VALUE_FILL_VERTICAL;
27import static com.android.SdkConstants.GRAVITY_VALUE_LEFT;
28import static com.android.SdkConstants.GRAVITY_VALUE_RIGHT;
29import static com.android.SdkConstants.GRAVITY_VALUE_TOP;
30
31import org.w3c.dom.Element;
32
33/** Helper class for looking up the gravity masks of gravity attributes */
34public class GravityHelper {
35    /** Bitmask for a gravity which includes left */
36    public static final int GRAVITY_LEFT         = 1 << 0;
37
38    /** Bitmask for a gravity which includes right */
39    public static final int GRAVITY_RIGHT        = 1 << 1;
40
41    /** Bitmask for a gravity which includes center horizontal */
42    public static final int GRAVITY_CENTER_HORIZ = 1 << 2;
43
44    /** Bitmask for a gravity which includes fill horizontal */
45    public static final int GRAVITY_FILL_HORIZ   = 1 << 3;
46
47    /** Bitmask for a gravity which includes center vertical */
48    public static final int GRAVITY_CENTER_VERT  = 1 << 4;
49
50    /** Bitmask for a gravity which includes fill vertical */
51    public static final int GRAVITY_FILL_VERT    = 1 << 5;
52
53    /** Bitmask for a gravity which includes top */
54    public static final int GRAVITY_TOP          = 1 << 6;
55
56    /** Bitmask for a gravity which includes bottom */
57    public static final int GRAVITY_BOTTOM       = 1 << 7;
58
59    /** Bitmask for a gravity which includes any horizontal constraint */
60    public static final int GRAVITY_HORIZ_MASK = GRAVITY_CENTER_HORIZ | GRAVITY_FILL_HORIZ
61            | GRAVITY_LEFT | GRAVITY_RIGHT;
62
63    /** Bitmask for a gravity which any vertical constraint */
64    public static final int GRAVITY_VERT_MASK = GRAVITY_CENTER_VERT | GRAVITY_FILL_VERT
65            | GRAVITY_TOP | GRAVITY_BOTTOM;
66
67    /**
68     * Returns the gravity of the given element
69     *
70     * @param element the element to look up the gravity for
71     * @return a bit mask corresponding to the selected gravities
72     */
73    public static int getGravity(Element element) {
74        String gravityString = element.getAttributeNS(ANDROID_URI, ATTR_LAYOUT_GRAVITY);
75        return getGravity(gravityString, GRAVITY_LEFT | GRAVITY_TOP);
76    }
77
78    /**
79     * Returns the gravity bitmask for the given gravity string description
80     *
81     * @param gravityString the gravity string description
82     * @param defaultMask the default/initial bitmask to start with
83     * @return a bitmask corresponding to the gravity description
84     */
85    public static int getGravity(String gravityString, int defaultMask) {
86        int gravity = defaultMask;
87        if (gravityString != null && gravityString.length() > 0) {
88            String[] anchors = gravityString.split("\\|"); //$NON-NLS-1$
89            for (String anchor : anchors) {
90                if (GRAVITY_VALUE_CENTER.equals(anchor)) {
91                    gravity = GRAVITY_CENTER_HORIZ | GRAVITY_CENTER_VERT;
92                } else if (GRAVITY_VALUE_FILL.equals(anchor)) {
93                    gravity = GRAVITY_FILL_HORIZ | GRAVITY_FILL_VERT;
94                } else if (GRAVITY_VALUE_CENTER_VERTICAL.equals(anchor)) {
95                    gravity = (gravity & GRAVITY_HORIZ_MASK) | GRAVITY_CENTER_VERT;
96                } else if (GRAVITY_VALUE_CENTER_HORIZONTAL.equals(anchor)) {
97                    gravity = (gravity & GRAVITY_VERT_MASK) | GRAVITY_CENTER_HORIZ;
98                } else if (GRAVITY_VALUE_FILL_VERTICAL.equals(anchor)) {
99                    gravity = (gravity & GRAVITY_HORIZ_MASK) | GRAVITY_FILL_VERT;
100                } else if (GRAVITY_VALUE_FILL_HORIZONTAL.equals(anchor)) {
101                    gravity = (gravity & GRAVITY_VERT_MASK) | GRAVITY_FILL_HORIZ;
102                } else if (GRAVITY_VALUE_TOP.equals(anchor)) {
103                    gravity = (gravity & GRAVITY_HORIZ_MASK) | GRAVITY_TOP;
104                } else if (GRAVITY_VALUE_BOTTOM.equals(anchor)) {
105                    gravity = (gravity & GRAVITY_HORIZ_MASK) | GRAVITY_BOTTOM;
106                } else if (GRAVITY_VALUE_LEFT.equals(anchor)) {
107                    gravity = (gravity & GRAVITY_VERT_MASK) | GRAVITY_LEFT;
108                } else if (GRAVITY_VALUE_RIGHT.equals(anchor)) {
109                    gravity = (gravity & GRAVITY_VERT_MASK) | GRAVITY_RIGHT;
110                } else {
111                    // "clip" not supported
112                }
113            }
114        }
115
116        return gravity;
117    }
118
119    /**
120     * Returns true if the given gravity bitmask is constrained horizontally
121     *
122     * @param gravity the gravity bitmask
123     * @return true if the given gravity bitmask is constrained horizontally
124     */
125    public static boolean isConstrainedHorizontally(int gravity) {
126        return (gravity & GRAVITY_HORIZ_MASK) != 0;
127    }
128
129    /**
130     * Returns true if the given gravity bitmask is constrained vertically
131     *
132     * @param gravity the gravity bitmask
133     * @return true if the given gravity bitmask is constrained vertically
134     */
135    public static boolean isConstrainedVertically(int gravity) {
136        return (gravity & GRAVITY_VERT_MASK) != 0;
137    }
138
139    /**
140     * Returns true if the given gravity bitmask is left aligned
141     *
142     * @param gravity the gravity bitmask
143     * @return true if the given gravity bitmask is left aligned
144     */
145    public static boolean isLeftAligned(int gravity) {
146        return (gravity & GRAVITY_LEFT) != 0;
147    }
148
149    /**
150     * Returns true if the given gravity bitmask is top aligned
151     *
152     * @param gravity the gravity bitmask
153     * @return true if the given gravity bitmask is aligned
154     */
155    public static boolean isTopAligned(int gravity) {
156        return (gravity & GRAVITY_TOP) != 0;
157    }
158
159    /** Returns a gravity value string from the given gravity bitmask
160     *
161     * @param gravity the gravity bitmask
162     * @return the corresponding gravity string suitable as an XML attribute value
163     */
164    public static String getGravity(int gravity) {
165        if (gravity == 0) {
166            return "";
167        }
168
169        if ((gravity & (GRAVITY_CENTER_HORIZ | GRAVITY_CENTER_VERT)) ==
170                (GRAVITY_CENTER_HORIZ | GRAVITY_CENTER_VERT)) {
171            return GRAVITY_VALUE_CENTER;
172        }
173
174        StringBuilder sb = new StringBuilder(30);
175        int horizontal = gravity & GRAVITY_HORIZ_MASK;
176        int vertical = gravity & GRAVITY_VERT_MASK;
177
178        if ((horizontal & GRAVITY_LEFT) != 0) {
179            sb.append(GRAVITY_VALUE_LEFT);
180        } else if ((horizontal & GRAVITY_RIGHT) != 0) {
181            sb.append(GRAVITY_VALUE_RIGHT);
182        } else if ((horizontal & GRAVITY_CENTER_HORIZ) != 0) {
183            sb.append(GRAVITY_VALUE_CENTER_HORIZONTAL);
184        } else if ((horizontal & GRAVITY_FILL_HORIZ) != 0) {
185            sb.append(GRAVITY_VALUE_FILL_HORIZONTAL);
186        }
187
188        if (sb.length() > 0 && vertical != 0) {
189            sb.append('|');
190        }
191
192        if ((vertical & GRAVITY_TOP) != 0) {
193            sb.append(GRAVITY_VALUE_TOP);
194        } else if ((vertical & GRAVITY_BOTTOM) != 0) {
195            sb.append(GRAVITY_VALUE_BOTTOM);
196        } else if ((vertical & GRAVITY_CENTER_VERT) != 0) {
197            sb.append(GRAVITY_VALUE_CENTER_VERTICAL);
198        } else if ((vertical & GRAVITY_FILL_VERT) != 0) {
199            sb.append(GRAVITY_VALUE_FILL_VERTICAL);
200        }
201
202        return sb.toString();
203    }
204}
205