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  */
16 package com.android.ide.common.layout.relative;
17 
18 import static com.android.ide.common.api.SegmentType.BASELINE;
19 import static com.android.ide.common.api.SegmentType.BOTTOM;
20 import static com.android.ide.common.api.SegmentType.CENTER_HORIZONTAL;
21 import static com.android.ide.common.api.SegmentType.CENTER_VERTICAL;
22 import static com.android.ide.common.api.SegmentType.LEFT;
23 import static com.android.ide.common.api.SegmentType.RIGHT;
24 import static com.android.ide.common.api.SegmentType.TOP;
25 import static com.android.ide.common.api.SegmentType.UNKNOWN;
26 import static com.android.SdkConstants.ATTR_LAYOUT_ABOVE;
27 import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_BASELINE;
28 import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_BOTTOM;
29 import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_LEFT;
30 import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_BOTTOM;
31 import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_LEFT;
32 import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_RIGHT;
33 import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_TOP;
34 import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_RIGHT;
35 import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_TOP;
36 import static com.android.SdkConstants.ATTR_LAYOUT_BELOW;
37 import static com.android.SdkConstants.ATTR_LAYOUT_CENTER_HORIZONTAL;
38 import static com.android.SdkConstants.ATTR_LAYOUT_CENTER_IN_PARENT;
39 import static com.android.SdkConstants.ATTR_LAYOUT_CENTER_VERTICAL;
40 import static com.android.SdkConstants.ATTR_LAYOUT_TO_LEFT_OF;
41 import static com.android.SdkConstants.ATTR_LAYOUT_TO_RIGHT_OF;
42 
43 import com.android.annotations.NonNull;
44 import com.android.annotations.Nullable;
45 import com.android.ide.common.api.SegmentType;
46 
47 import java.util.HashMap;
48 import java.util.Map;
49 
50 /**
51  * Each constraint type corresponds to a type of constraint available for the
52  * RelativeLayout; for example, {@link #LAYOUT_ABOVE} corresponds to the layout_above constraint.
53  */
54 enum ConstraintType {
55     LAYOUT_ABOVE(ATTR_LAYOUT_ABOVE,
56             null /* sourceX */, BOTTOM, null /* targetX */, TOP,
57             false /* targetParent */, true /* horizontalEdge */, false /* verticalEdge */,
58             true /* relativeToMargin */),
59 
60     LAYOUT_BELOW(ATTR_LAYOUT_BELOW, null, TOP, null, BOTTOM, false, true, false, true),
61     ALIGN_TOP(ATTR_LAYOUT_ALIGN_TOP, null, TOP, null, TOP, false, true, false, false),
62     ALIGN_BOTTOM(ATTR_LAYOUT_ALIGN_BOTTOM, null, BOTTOM, null, BOTTOM, false, true, false, false),
63     ALIGN_LEFT(ATTR_LAYOUT_ALIGN_LEFT, LEFT, null, LEFT, null, false, false, true, false),
64     ALIGN_RIGHT(ATTR_LAYOUT_ALIGN_RIGHT, RIGHT, null, RIGHT, null, false, false, true, false),
65     LAYOUT_LEFT_OF(ATTR_LAYOUT_TO_LEFT_OF, RIGHT, null, LEFT, null, false, false, true, true),
66     LAYOUT_RIGHT_OF(ATTR_LAYOUT_TO_RIGHT_OF, LEFT, null, RIGHT, null, false, false, true, true),
67     ALIGN_PARENT_TOP(ATTR_LAYOUT_ALIGN_PARENT_TOP, null, TOP, null, TOP, true, true, false, false),
68     ALIGN_BASELINE(ATTR_LAYOUT_ALIGN_BASELINE, null, BASELINE, null, BASELINE, false, true, false,
69             false),
70     ALIGN_PARENT_LEFT(ATTR_LAYOUT_ALIGN_PARENT_LEFT, LEFT, null, LEFT, null, true, false, true,
71             false),
72     ALIGN_PARENT_RIGHT(ATTR_LAYOUT_ALIGN_PARENT_RIGHT, RIGHT, null, RIGHT, null, true, false, true,
73             false),
74     ALIGN_PARENT_BOTTOM(ATTR_LAYOUT_ALIGN_PARENT_BOTTOM, null, BOTTOM, null, BOTTOM, true, true,
75             false, false),
76     LAYOUT_CENTER_HORIZONTAL(ATTR_LAYOUT_CENTER_HORIZONTAL, CENTER_VERTICAL, null, CENTER_VERTICAL,
77             null, true, true, false, false),
78     LAYOUT_CENTER_VERTICAL(ATTR_LAYOUT_CENTER_VERTICAL, null, CENTER_HORIZONTAL, null,
79             CENTER_HORIZONTAL, true, false, true, false),
80     LAYOUT_CENTER_IN_PARENT(ATTR_LAYOUT_CENTER_IN_PARENT, CENTER_VERTICAL, CENTER_HORIZONTAL,
81             CENTER_VERTICAL, CENTER_HORIZONTAL, true, true, true, false);
82 
ConstraintType(String name, SegmentType sourceSegmentTypeX, SegmentType sourceSegmentTypeY, SegmentType targetSegmentTypeX, SegmentType targetSegmentTypeY, boolean targetParent, boolean horizontalEdge, boolean verticalEdge, boolean relativeToMargin)83     private ConstraintType(String name, SegmentType sourceSegmentTypeX,
84             SegmentType sourceSegmentTypeY, SegmentType targetSegmentTypeX,
85             SegmentType targetSegmentTypeY, boolean targetParent, boolean horizontalEdge,
86             boolean verticalEdge, boolean relativeToMargin) {
87         assert horizontalEdge || verticalEdge;
88 
89         this.name = name;
90         this.sourceSegmentTypeX = sourceSegmentTypeX != null ? sourceSegmentTypeX : UNKNOWN;
91         this.sourceSegmentTypeY = sourceSegmentTypeY != null ? sourceSegmentTypeY : UNKNOWN;
92         this.targetSegmentTypeX = targetSegmentTypeX != null ? targetSegmentTypeX : UNKNOWN;
93         this.targetSegmentTypeY = targetSegmentTypeY != null ? targetSegmentTypeY : UNKNOWN;
94         this.targetParent = targetParent;
95         this.horizontalEdge = horizontalEdge;
96         this.verticalEdge = verticalEdge;
97         this.relativeToMargin = relativeToMargin;
98     }
99 
100     /** The attribute name of the constraint */
101     public final String name;
102 
103     /** The horizontal position of the source of the constraint */
104     public final SegmentType sourceSegmentTypeX;
105 
106     /** The vertical position of the source of the constraint */
107     public final SegmentType sourceSegmentTypeY;
108 
109     /** The horizontal position of the target of the constraint */
110     public final SegmentType targetSegmentTypeX;
111 
112     /** The vertical position of the target of the constraint */
113     public final SegmentType targetSegmentTypeY;
114 
115     /**
116      * If true, the constraint targets the parent layout, otherwise it targets another
117      * view
118      */
119     public final boolean targetParent;
120 
121     /** If true, this constraint affects the horizontal dimension */
122     public final boolean horizontalEdge;
123 
124     /** If true, this constraint affects the vertical dimension */
125     public final boolean verticalEdge;
126 
127     /**
128      * Whether this constraint is relative to the margin bounds of the node rather than
129      * the node's actual bounds
130      */
131     public final boolean relativeToMargin;
132 
133     /** Map from attribute name to constraint type */
134     private static Map<String, ConstraintType> sNameToType;
135 
136     /**
137      * Returns the {@link ConstraintType} corresponding to the given attribute name, or
138      * null if not found.
139      *
140      * @param attribute the name of the attribute to look up
141      * @return the corresponding {@link ConstraintType}
142      */
143     @Nullable
fromAttribute(@onNull String attribute)144     public static ConstraintType fromAttribute(@NonNull String attribute) {
145         if (sNameToType == null) {
146             ConstraintType[] types = ConstraintType.values();
147             Map<String, ConstraintType> map = new HashMap<String, ConstraintType>(types.length);
148             for (ConstraintType type : types) {
149                 map.put(type.name, type);
150             }
151             sNameToType = map;
152         }
153         return sNameToType.get(attribute);
154     }
155 
156     /**
157      * Returns true if this constraint type represents a constraint where the target edge
158      * is one of the parent edges (actual edge, not center/baseline segments)
159      *
160      * @return true if the target segment is a parent edge
161      */
isRelativeToParentEdge()162     public boolean isRelativeToParentEdge() {
163         return this == ALIGN_PARENT_LEFT || this == ALIGN_PARENT_RIGHT || this == ALIGN_PARENT_TOP
164                 || this == ALIGN_PARENT_BOTTOM;
165     }
166 
167     /**
168      * Returns a {@link ConstraintType} for a potential match of edges.
169      *
170      * @param withParent if true, the target is the parent
171      * @param from the source edge
172      * @param to the target edge
173      * @return a {@link ConstraintType}, or null
174      */
175     @Nullable
forMatch(boolean withParent, SegmentType from, SegmentType to)176     public static ConstraintType forMatch(boolean withParent, SegmentType from, SegmentType to) {
177         // Attached to parent edge?
178         if (withParent) {
179             switch (from) {
180                 case TOP:
181                     return ALIGN_PARENT_TOP;
182                 case BOTTOM:
183                     return ALIGN_PARENT_BOTTOM;
184                 case LEFT:
185                     return ALIGN_PARENT_LEFT;
186                 case RIGHT:
187                     return ALIGN_PARENT_RIGHT;
188                 case CENTER_HORIZONTAL:
189                     return LAYOUT_CENTER_VERTICAL;
190                 case CENTER_VERTICAL:
191                     return LAYOUT_CENTER_HORIZONTAL;
192             }
193 
194             return null;
195         }
196 
197         // Attached to some other node.
198         switch (from) {
199             case TOP:
200                 switch (to) {
201                     case TOP:
202                         return ALIGN_TOP;
203                     case BOTTOM:
204                         return LAYOUT_BELOW;
205                     case BASELINE:
206                         return ALIGN_BASELINE;
207                 }
208                 break;
209             case BOTTOM:
210                 switch (to) {
211                     case TOP:
212                         return LAYOUT_ABOVE;
213                     case BOTTOM:
214                         return ALIGN_BOTTOM;
215                     case BASELINE:
216                         return ALIGN_BASELINE;
217                 }
218                 break;
219             case LEFT:
220                 switch (to) {
221                     case LEFT:
222                         return ALIGN_LEFT;
223                     case RIGHT:
224                         return LAYOUT_RIGHT_OF;
225                 }
226                 break;
227             case RIGHT:
228                 switch (to) {
229                     case LEFT:
230                         return LAYOUT_LEFT_OF;
231                     case RIGHT:
232                         return ALIGN_RIGHT;
233                 }
234                 break;
235             case BASELINE:
236                 return ALIGN_BASELINE;
237         }
238 
239         return null;
240     }
241 }
242