/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * 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.intellij.android.designer.model.layout.relative; import com.android.tools.idea.designer.Segment; import com.intellij.android.designer.designSurface.feedbacks.TextFeedback; import com.intellij.ui.SimpleTextAttributes; import org.jetbrains.annotations.Nullable; import java.awt.*; import static com.android.SdkConstants.*; /** * A match is a potential pairing of two segments with a given {@link ConstraintType}. */ class Match { /** * the edge of the dragged node that is matched */ public final Segment with; /** * the "other" edge that the dragged edge is matched with */ public final Segment edge; /** * the signed distance between the matched edges */ public final int delta; /** * the type of constraint this is a match for */ public final ConstraintType type; /** * whether this {@link Match} results in a cycle */ public boolean cycle; /** * Create a new match. * * @param edge the "other" edge that the dragged edge is matched with * @param with the edge of the dragged node that is matched * @param type the type of constraint this is a match for * @param delta the signed distance between the matched edges */ public Match(Segment edge, Segment with, ConstraintType type, int delta) { this.edge = edge; this.with = with; this.type = type; this.delta = delta; } /** * Returns the XML constraint attribute value for this match * * @param generateId whether an id should be generated if one is missing * @return the XML constraint attribute value for this match */ public String getConstraint(boolean generateId) { if (type.targetParent) { return type.name + '=' + VALUE_TRUE; } else { String id = edge.id; if (id == null || id.length() == -1) { if (!generateId) { // Placeholder to display for the user during dragging id = "<generated>"; } else { // Must generate an id on the fly! // See if it's been set by a different constraint we've already applied // to this same node if (edge.node != null) { id = edge.node.ensureId(); } } } return type.name + '=' + id; } } @Override public String toString() { return "Match [type=" + type + ", delta=" + delta + ", edge=" + edge + "]"; } /** Style to use when describing component names */ @SuppressWarnings("UseJBColor") // The designer canvas is not using light/dark themes; colors match Android theme rendering private static final SimpleTextAttributes SNAP_ATTRIBUTES = new SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, new Color(60, 139, 186)); /** * Describes this match in the given {@link TextFeedback} * * @param feedback the feedback to write the description into * @param margin the number of pixels to use as a margin * @param marginAttribute the name of the applicable margin attribute */ public void describe(TextFeedback feedback, int margin, String marginAttribute) { // Display the constraint. Remove the @id/ and @+id/ prefixes to make the text // shorter and easier to read. This doesn't use stripPrefix() because the id is // usually not a prefix of the value (for example, 'layout_alignBottom=@+id/foo'). feedback.clear(); String constraint = getConstraint(false /* generateId */); String description = constraint.replace(NEW_ID_PREFIX, "").replace(ID_PREFIX, ""); if (description.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)) { description = description.substring(ATTR_LAYOUT_RESOURCE_PREFIX.length()); } // Instead of "alignParentLeft=true", just display "alignParentLeft" if (description.endsWith("=true")) { description = description.substring(0, description.length() - "=true".length()); } feedback.append(description, SNAP_ATTRIBUTES); if (margin > 0) { feedback.append(String.format(", margin=%1$d dp", margin)); } } @Nullable public String getRtlConstraint(boolean generateId) { switch (type) { case ALIGN_LEFT: return replaceAttribute(getConstraint(generateId), ATTR_LAYOUT_ALIGN_LEFT, ATTR_LAYOUT_ALIGN_START); case LAYOUT_LEFT_OF: return replaceAttribute(getConstraint(generateId), ATTR_LAYOUT_TO_LEFT_OF, ATTR_LAYOUT_TO_START_OF); case ALIGN_RIGHT: return replaceAttribute(getConstraint(generateId), ATTR_LAYOUT_ALIGN_RIGHT, ATTR_LAYOUT_ALIGN_END); case LAYOUT_RIGHT_OF: return replaceAttribute(getConstraint(generateId), ATTR_LAYOUT_TO_RIGHT_OF, ATTR_LAYOUT_TO_END_OF); case ALIGN_PARENT_LEFT: return replaceAttribute(getConstraint(generateId), ATTR_LAYOUT_ALIGN_PARENT_LEFT, ATTR_LAYOUT_ALIGN_PARENT_START); case ALIGN_PARENT_RIGHT: return replaceAttribute(getConstraint(generateId), ATTR_LAYOUT_ALIGN_PARENT_RIGHT, ATTR_LAYOUT_ALIGN_PARENT_END); } return null; } private static String replaceAttribute(String s, String oldName, String newName) { assert s.startsWith(oldName) : s; return newName + s.substring(oldName.length()); } }