/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Eclipse Public License, Version 1.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.eclipse.org/org/documents/epl-v10.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ide.common.layout.relative; import static com.android.ide.common.api.SegmentType.BASELINE; import static com.android.ide.common.api.SegmentType.BOTTOM; import static com.android.ide.common.api.SegmentType.CENTER_HORIZONTAL; import static com.android.ide.common.api.SegmentType.CENTER_VERTICAL; import static com.android.ide.common.api.SegmentType.LEFT; import static com.android.ide.common.api.SegmentType.RIGHT; import static com.android.ide.common.api.SegmentType.TOP; import static com.android.ide.common.api.SegmentType.UNKNOWN; import static com.android.SdkConstants.ATTR_LAYOUT_ABOVE; import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_BASELINE; import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_BOTTOM; import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_LEFT; import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_BOTTOM; import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_LEFT; import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_RIGHT; import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_TOP; import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_RIGHT; import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_TOP; import static com.android.SdkConstants.ATTR_LAYOUT_BELOW; import static com.android.SdkConstants.ATTR_LAYOUT_CENTER_HORIZONTAL; import static com.android.SdkConstants.ATTR_LAYOUT_CENTER_IN_PARENT; import static com.android.SdkConstants.ATTR_LAYOUT_CENTER_VERTICAL; import static com.android.SdkConstants.ATTR_LAYOUT_TO_LEFT_OF; import static com.android.SdkConstants.ATTR_LAYOUT_TO_RIGHT_OF; import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.ide.common.api.SegmentType; import java.util.HashMap; import java.util.Map; /** * Each constraint type corresponds to a type of constraint available for the * RelativeLayout; for example, {@link #LAYOUT_ABOVE} corresponds to the layout_above constraint. */ enum ConstraintType { LAYOUT_ABOVE(ATTR_LAYOUT_ABOVE, null /* sourceX */, BOTTOM, null /* targetX */, TOP, false /* targetParent */, true /* horizontalEdge */, false /* verticalEdge */, true /* relativeToMargin */), LAYOUT_BELOW(ATTR_LAYOUT_BELOW, null, TOP, null, BOTTOM, false, true, false, true), ALIGN_TOP(ATTR_LAYOUT_ALIGN_TOP, null, TOP, null, TOP, false, true, false, false), ALIGN_BOTTOM(ATTR_LAYOUT_ALIGN_BOTTOM, null, BOTTOM, null, BOTTOM, false, true, false, false), ALIGN_LEFT(ATTR_LAYOUT_ALIGN_LEFT, LEFT, null, LEFT, null, false, false, true, false), ALIGN_RIGHT(ATTR_LAYOUT_ALIGN_RIGHT, RIGHT, null, RIGHT, null, false, false, true, false), LAYOUT_LEFT_OF(ATTR_LAYOUT_TO_LEFT_OF, RIGHT, null, LEFT, null, false, false, true, true), LAYOUT_RIGHT_OF(ATTR_LAYOUT_TO_RIGHT_OF, LEFT, null, RIGHT, null, false, false, true, true), ALIGN_PARENT_TOP(ATTR_LAYOUT_ALIGN_PARENT_TOP, null, TOP, null, TOP, true, true, false, false), ALIGN_BASELINE(ATTR_LAYOUT_ALIGN_BASELINE, null, BASELINE, null, BASELINE, false, true, false, false), ALIGN_PARENT_LEFT(ATTR_LAYOUT_ALIGN_PARENT_LEFT, LEFT, null, LEFT, null, true, false, true, false), ALIGN_PARENT_RIGHT(ATTR_LAYOUT_ALIGN_PARENT_RIGHT, RIGHT, null, RIGHT, null, true, false, true, false), ALIGN_PARENT_BOTTOM(ATTR_LAYOUT_ALIGN_PARENT_BOTTOM, null, BOTTOM, null, BOTTOM, true, true, false, false), LAYOUT_CENTER_HORIZONTAL(ATTR_LAYOUT_CENTER_HORIZONTAL, CENTER_VERTICAL, null, CENTER_VERTICAL, null, true, true, false, false), LAYOUT_CENTER_VERTICAL(ATTR_LAYOUT_CENTER_VERTICAL, null, CENTER_HORIZONTAL, null, CENTER_HORIZONTAL, true, false, true, false), LAYOUT_CENTER_IN_PARENT(ATTR_LAYOUT_CENTER_IN_PARENT, CENTER_VERTICAL, CENTER_HORIZONTAL, CENTER_VERTICAL, CENTER_HORIZONTAL, true, true, true, false); private ConstraintType(String name, SegmentType sourceSegmentTypeX, SegmentType sourceSegmentTypeY, SegmentType targetSegmentTypeX, SegmentType targetSegmentTypeY, boolean targetParent, boolean horizontalEdge, boolean verticalEdge, boolean relativeToMargin) { assert horizontalEdge || verticalEdge; this.name = name; this.sourceSegmentTypeX = sourceSegmentTypeX != null ? sourceSegmentTypeX : UNKNOWN; this.sourceSegmentTypeY = sourceSegmentTypeY != null ? sourceSegmentTypeY : UNKNOWN; this.targetSegmentTypeX = targetSegmentTypeX != null ? targetSegmentTypeX : UNKNOWN; this.targetSegmentTypeY = targetSegmentTypeY != null ? targetSegmentTypeY : UNKNOWN; this.targetParent = targetParent; this.horizontalEdge = horizontalEdge; this.verticalEdge = verticalEdge; this.relativeToMargin = relativeToMargin; } /** The attribute name of the constraint */ public final String name; /** The horizontal position of the source of the constraint */ public final SegmentType sourceSegmentTypeX; /** The vertical position of the source of the constraint */ public final SegmentType sourceSegmentTypeY; /** The horizontal position of the target of the constraint */ public final SegmentType targetSegmentTypeX; /** The vertical position of the target of the constraint */ public final SegmentType targetSegmentTypeY; /** * If true, the constraint targets the parent layout, otherwise it targets another * view */ public final boolean targetParent; /** If true, this constraint affects the horizontal dimension */ public final boolean horizontalEdge; /** If true, this constraint affects the vertical dimension */ public final boolean verticalEdge; /** * Whether this constraint is relative to the margin bounds of the node rather than * the node's actual bounds */ public final boolean relativeToMargin; /** Map from attribute name to constraint type */ private static Map<String, ConstraintType> sNameToType; /** * Returns the {@link ConstraintType} corresponding to the given attribute name, or * null if not found. * * @param attribute the name of the attribute to look up * @return the corresponding {@link ConstraintType} */ @Nullable public static ConstraintType fromAttribute(@NonNull String attribute) { if (sNameToType == null) { ConstraintType[] types = ConstraintType.values(); Map<String, ConstraintType> map = new HashMap<String, ConstraintType>(types.length); for (ConstraintType type : types) { map.put(type.name, type); } sNameToType = map; } return sNameToType.get(attribute); } /** * Returns true if this constraint type represents a constraint where the target edge * is one of the parent edges (actual edge, not center/baseline segments) * * @return true if the target segment is a parent edge */ public boolean isRelativeToParentEdge() { return this == ALIGN_PARENT_LEFT || this == ALIGN_PARENT_RIGHT || this == ALIGN_PARENT_TOP || this == ALIGN_PARENT_BOTTOM; } /** * Returns a {@link ConstraintType} for a potential match of edges. * * @param withParent if true, the target is the parent * @param from the source edge * @param to the target edge * @return a {@link ConstraintType}, or null */ @Nullable public static ConstraintType forMatch(boolean withParent, SegmentType from, SegmentType to) { // Attached to parent edge? if (withParent) { switch (from) { case TOP: return ALIGN_PARENT_TOP; case BOTTOM: return ALIGN_PARENT_BOTTOM; case LEFT: return ALIGN_PARENT_LEFT; case RIGHT: return ALIGN_PARENT_RIGHT; case CENTER_HORIZONTAL: return LAYOUT_CENTER_VERTICAL; case CENTER_VERTICAL: return LAYOUT_CENTER_HORIZONTAL; } return null; } // Attached to some other node. switch (from) { case TOP: switch (to) { case TOP: return ALIGN_TOP; case BOTTOM: return LAYOUT_BELOW; case BASELINE: return ALIGN_BASELINE; } break; case BOTTOM: switch (to) { case TOP: return LAYOUT_ABOVE; case BOTTOM: return ALIGN_BOTTOM; case BASELINE: return ALIGN_BASELINE; } break; case LEFT: switch (to) { case LEFT: return ALIGN_LEFT; case RIGHT: return LAYOUT_RIGHT_OF; } break; case RIGHT: switch (to) { case LEFT: return LAYOUT_LEFT_OF; case RIGHT: return ALIGN_RIGHT; } break; case BASELINE: return ALIGN_BASELINE; } return null; } }