1 /* 2 * Copyright (C) 2015 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 package androidx.constraintlayout.core.widgets; 17 18 import static androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour.WRAP_CONTENT; 19 20 import androidx.constraintlayout.core.LinearSystem; 21 import androidx.constraintlayout.core.SolverVariable; 22 23 import java.util.HashMap; 24 25 /** 26 * Guideline 27 */ 28 public class Guideline extends ConstraintWidget { 29 public static final int HORIZONTAL = 0; 30 public static final int VERTICAL = 1; 31 32 public static final int RELATIVE_PERCENT = 0; 33 public static final int RELATIVE_BEGIN = 1; 34 public static final int RELATIVE_END = 2; 35 public static final int RELATIVE_UNKNOWN = -1; 36 37 protected float mRelativePercent = -1; 38 protected int mRelativeBegin = -1; 39 protected int mRelativeEnd = -1; 40 protected boolean mGuidelineUseRtl = true; 41 42 private ConstraintAnchor mAnchor = mTop; 43 private int mOrientation = HORIZONTAL; 44 private int mMinimumPosition = 0; 45 private boolean mResolved; 46 Guideline()47 public Guideline() { 48 mAnchors.clear(); 49 mAnchors.add(mAnchor); 50 final int count = mListAnchors.length; 51 for (int i = 0; i < count; i++) { 52 mListAnchors[i] = mAnchor; 53 } 54 } 55 56 @Override copy(ConstraintWidget src, HashMap<ConstraintWidget, ConstraintWidget> map)57 public void copy(ConstraintWidget src, HashMap<ConstraintWidget, ConstraintWidget> map) { 58 super.copy(src, map); 59 Guideline srcGuideline = (Guideline) src; 60 mRelativePercent = srcGuideline.mRelativePercent; 61 mRelativeBegin = srcGuideline.mRelativeBegin; 62 mRelativeEnd = srcGuideline.mRelativeEnd; 63 mGuidelineUseRtl = srcGuideline.mGuidelineUseRtl; 64 setOrientation(srcGuideline.mOrientation); 65 } 66 67 @Override allowedInBarrier()68 public boolean allowedInBarrier() { 69 return true; 70 } 71 72 // @TODO: add description getRelativeBehaviour()73 public int getRelativeBehaviour() { 74 if (mRelativePercent != -1) { 75 return RELATIVE_PERCENT; 76 } 77 if (mRelativeBegin != -1) { 78 return RELATIVE_BEGIN; 79 } 80 if (mRelativeEnd != -1) { 81 return RELATIVE_END; 82 } 83 return RELATIVE_UNKNOWN; 84 } 85 86 // @TODO: add description setOrientation(int orientation)87 public void setOrientation(int orientation) { 88 if (mOrientation == orientation) { 89 return; 90 } 91 mOrientation = orientation; 92 mAnchors.clear(); 93 if (mOrientation == VERTICAL) { 94 mAnchor = mLeft; 95 } else { 96 mAnchor = mTop; 97 } 98 mAnchors.add(mAnchor); 99 final int count = mListAnchors.length; 100 for (int i = 0; i < count; i++) { 101 mListAnchors[i] = mAnchor; 102 } 103 } 104 getAnchor()105 public ConstraintAnchor getAnchor() { 106 return mAnchor; 107 } 108 109 /** 110 * Specify the xml type for the container 111 */ 112 @Override getType()113 public String getType() { 114 return "Guideline"; 115 } 116 117 /** 118 * get the orientation VERTICAL or HORIZONTAL 119 * @return orientation 120 */ getOrientation()121 public int getOrientation() { 122 return mOrientation; 123 } 124 125 /** 126 * set the minimum position 127 * @param minimum 128 */ setMinimumPosition(int minimum)129 public void setMinimumPosition(int minimum) { 130 mMinimumPosition = minimum; 131 } 132 133 /** 134 * Get the Minimum Position 135 * @return the Minimum Position 136 */ getMinimumPosition()137 public int getMinimumPosition() { 138 return mMinimumPosition; 139 } 140 141 @Override getAnchor(ConstraintAnchor.Type anchorType)142 public ConstraintAnchor getAnchor(ConstraintAnchor.Type anchorType) { 143 switch (anchorType) { 144 case LEFT: 145 case RIGHT: { 146 if (mOrientation == VERTICAL) { 147 return mAnchor; 148 } 149 } 150 break; 151 case TOP: 152 case BOTTOM: { 153 if (mOrientation == HORIZONTAL) { 154 return mAnchor; 155 } 156 } 157 break; 158 case BASELINE: 159 case CENTER: 160 case CENTER_X: 161 case CENTER_Y: 162 case NONE: 163 return null; 164 } 165 return null; 166 } 167 168 // @TODO: add description setGuidePercent(int value)169 public void setGuidePercent(int value) { 170 setGuidePercent(value / 100f); 171 } 172 173 // @TODO: add description setGuidePercent(float value)174 public void setGuidePercent(float value) { 175 if (value > -1) { 176 mRelativePercent = value; 177 mRelativeBegin = -1; 178 mRelativeEnd = -1; 179 } 180 } 181 182 // @TODO: add description setGuideBegin(int value)183 public void setGuideBegin(int value) { 184 if (value > -1) { 185 mRelativePercent = -1; 186 mRelativeBegin = value; 187 mRelativeEnd = -1; 188 } 189 } 190 191 // @TODO: add description setGuideEnd(int value)192 public void setGuideEnd(int value) { 193 if (value > -1) { 194 mRelativePercent = -1; 195 mRelativeBegin = -1; 196 mRelativeEnd = value; 197 } 198 } 199 getRelativePercent()200 public float getRelativePercent() { 201 return mRelativePercent; 202 } 203 getRelativeBegin()204 public int getRelativeBegin() { 205 return mRelativeBegin; 206 } 207 getRelativeEnd()208 public int getRelativeEnd() { 209 return mRelativeEnd; 210 } 211 212 // @TODO: add description setFinalValue(int position)213 public void setFinalValue(int position) { 214 if (LinearSystem.FULL_DEBUG) { 215 System.out.println("*** SET FINAL GUIDELINE VALUE " 216 + position + " FOR " + getDebugName()); 217 } 218 mAnchor.setFinalValue(position); 219 mResolved = true; 220 } 221 222 @Override isResolvedHorizontally()223 public boolean isResolvedHorizontally() { 224 return mResolved; 225 } 226 227 @Override isResolvedVertically()228 public boolean isResolvedVertically() { 229 return mResolved; 230 } 231 232 @Override addToSolver(LinearSystem system, boolean optimize)233 public void addToSolver(LinearSystem system, boolean optimize) { 234 if (LinearSystem.FULL_DEBUG) { 235 System.out.println("\n----------------------------------------------"); 236 System.out.println("-- adding " + getDebugName() + " to the solver"); 237 System.out.println("----------------------------------------------\n"); 238 } 239 240 ConstraintWidgetContainer parent = (ConstraintWidgetContainer) getParent(); 241 if (parent == null) { 242 return; 243 } 244 ConstraintAnchor begin = parent.getAnchor(ConstraintAnchor.Type.LEFT); 245 ConstraintAnchor end = parent.getAnchor(ConstraintAnchor.Type.RIGHT); 246 boolean parentWrapContent = mParent != null 247 ? mParent.mListDimensionBehaviors[DIMENSION_HORIZONTAL] == WRAP_CONTENT : false; 248 if (mOrientation == HORIZONTAL) { 249 begin = parent.getAnchor(ConstraintAnchor.Type.TOP); 250 end = parent.getAnchor(ConstraintAnchor.Type.BOTTOM); 251 parentWrapContent = mParent != null 252 ? mParent.mListDimensionBehaviors[DIMENSION_VERTICAL] == WRAP_CONTENT : false; 253 } 254 if (mResolved && mAnchor.hasFinalValue()) { 255 SolverVariable guide = system.createObjectVariable(mAnchor); 256 if (LinearSystem.FULL_DEBUG) { 257 System.out.println("*** SET FINAL POSITION FOR GUIDELINE " 258 + getDebugName() + " TO " + mAnchor.getFinalValue()); 259 } 260 system.addEquality(guide, mAnchor.getFinalValue()); 261 if (mRelativeBegin != -1) { 262 if (parentWrapContent) { 263 system.addGreaterThan(system.createObjectVariable(end), guide, 264 0, SolverVariable.STRENGTH_EQUALITY); 265 } 266 } else if (mRelativeEnd != -1) { 267 if (parentWrapContent) { 268 SolverVariable parentRight = system.createObjectVariable(end); 269 system.addGreaterThan(guide, system.createObjectVariable(begin), 270 0, SolverVariable.STRENGTH_EQUALITY); 271 system.addGreaterThan(parentRight, guide, 0, SolverVariable.STRENGTH_EQUALITY); 272 } 273 } 274 mResolved = false; 275 return; 276 } 277 if (mRelativeBegin != -1) { 278 SolverVariable guide = system.createObjectVariable(mAnchor); 279 SolverVariable parentLeft = system.createObjectVariable(begin); 280 system.addEquality(guide, parentLeft, mRelativeBegin, SolverVariable.STRENGTH_FIXED); 281 if (parentWrapContent) { 282 system.addGreaterThan(system.createObjectVariable(end), 283 guide, 0, SolverVariable.STRENGTH_EQUALITY); 284 } 285 } else if (mRelativeEnd != -1) { 286 SolverVariable guide = system.createObjectVariable(mAnchor); 287 SolverVariable parentRight = system.createObjectVariable(end); 288 system.addEquality(guide, parentRight, -mRelativeEnd, SolverVariable.STRENGTH_FIXED); 289 if (parentWrapContent) { 290 system.addGreaterThan(guide, system.createObjectVariable(begin), 291 0, SolverVariable.STRENGTH_EQUALITY); 292 system.addGreaterThan(parentRight, guide, 0, SolverVariable.STRENGTH_EQUALITY); 293 } 294 } else if (mRelativePercent != -1) { 295 SolverVariable guide = system.createObjectVariable(mAnchor); 296 SolverVariable parentRight = system.createObjectVariable(end); 297 system.addConstraint(LinearSystem 298 .createRowDimensionPercent(system, guide, parentRight, 299 mRelativePercent)); 300 } 301 } 302 303 @Override updateFromSolver(LinearSystem system, boolean optimize)304 public void updateFromSolver(LinearSystem system, boolean optimize) { 305 if (getParent() == null) { 306 return; 307 } 308 int value = system.getObjectVariableValue(mAnchor); 309 if (mOrientation == VERTICAL) { 310 setX(value); 311 setY(0); 312 setHeight(getParent().getHeight()); 313 setWidth(0); 314 } else { 315 setX(0); 316 setY(value); 317 setWidth(getParent().getWidth()); 318 setHeight(0); 319 } 320 } 321 inferRelativePercentPosition()322 void inferRelativePercentPosition() { 323 float percent = (getX() / (float) getParent().getWidth()); 324 if (mOrientation == HORIZONTAL) { 325 percent = (getY() / (float) getParent().getHeight()); 326 } 327 setGuidePercent(percent); 328 } 329 inferRelativeBeginPosition()330 void inferRelativeBeginPosition() { 331 int position = getX(); 332 if (mOrientation == HORIZONTAL) { 333 position = getY(); 334 } 335 setGuideBegin(position); 336 } 337 inferRelativeEndPosition()338 void inferRelativeEndPosition() { 339 int position = getParent().getWidth() - getX(); 340 if (mOrientation == HORIZONTAL) { 341 position = getParent().getHeight() - getY(); 342 } 343 setGuideEnd(position); 344 } 345 346 // @TODO: add description cyclePosition()347 public void cyclePosition() { 348 if (mRelativeBegin != -1) { 349 // cycle to percent-based position 350 inferRelativePercentPosition(); 351 } else if (mRelativePercent != -1) { 352 // cycle to end-based position 353 inferRelativeEndPosition(); 354 } else if (mRelativeEnd != -1) { 355 // cycle to begin-based position 356 inferRelativeBeginPosition(); 357 } 358 } 359 isPercent()360 public boolean isPercent() { 361 return mRelativePercent != -1 && mRelativeBegin == -1 && mRelativeEnd == -1; 362 } 363 } 364