1 /*
2  * Copyright (C) 2019 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 androidx.constraintlayout.core.widgets.analyzer.BasicMeasure;
19 
20 import java.util.HashSet;
21 
22 /**
23  * Base class for Virtual layouts
24  */
25 public class VirtualLayout extends HelperWidget {
26 
27     private int mPaddingTop = 0;
28     private int mPaddingBottom = 0;
29     @SuppressWarnings("unused") private int mPaddingLeft = 0;
30     @SuppressWarnings("unused") private int mPaddingRight = 0;
31     @SuppressWarnings("unused") private int mPaddingStart = 0;
32     private int mPaddingEnd = 0;
33     private int mResolvedPaddingLeft = 0;
34     private int mResolvedPaddingRight = 0;
35 
36     private boolean mNeedsCallFromSolver = false;
37     private int mMeasuredWidth = 0;
38     private int mMeasuredHeight = 0;
39 
40     protected BasicMeasure.Measure mMeasure = new BasicMeasure.Measure();
41 
42     /////////////////////////////////////////////////////////////////////////////////////////////
43     // Accessors
44     /////////////////////////////////////////////////////////////////////////////////////////////
45 
46     // @TODO: add description
setPadding(int value)47     public void setPadding(int value) {
48         mPaddingLeft = value;
49         mPaddingTop = value;
50         mPaddingRight = value;
51         mPaddingBottom = value;
52         mPaddingStart = value;
53         mPaddingEnd = value;
54     }
55 
56     // @TODO: add description
setPaddingStart(int value)57     public void setPaddingStart(int value) {
58         mPaddingStart = value;
59         mResolvedPaddingLeft = value;
60         mResolvedPaddingRight = value;
61     }
62 
setPaddingEnd(int value)63     public void setPaddingEnd(int value) {
64         mPaddingEnd = value;
65     }
66 
67     // @TODO: add description
setPaddingLeft(int value)68     public void setPaddingLeft(int value) {
69         mPaddingLeft = value;
70         mResolvedPaddingLeft = value;
71     }
72 
73     // @TODO: add description
applyRtl(boolean isRtl)74     public void applyRtl(boolean isRtl) {
75         if (mPaddingStart > 0 || mPaddingEnd > 0) {
76             if (isRtl) {
77                 mResolvedPaddingLeft = mPaddingEnd;
78                 mResolvedPaddingRight = mPaddingStart;
79             } else {
80                 mResolvedPaddingLeft = mPaddingStart;
81                 mResolvedPaddingRight = mPaddingEnd;
82             }
83         }
84     }
85 
setPaddingTop(int value)86     public void setPaddingTop(int value) {
87         mPaddingTop = value;
88     }
89 
90     // @TODO: add description
setPaddingRight(int value)91     public void setPaddingRight(int value) {
92         mPaddingRight = value;
93         mResolvedPaddingRight = value;
94     }
95 
setPaddingBottom(int value)96     public void setPaddingBottom(int value) {
97         mPaddingBottom = value;
98     }
99 
getPaddingTop()100     public int getPaddingTop() {
101         return mPaddingTop;
102     }
103 
getPaddingBottom()104     public int getPaddingBottom() {
105         return mPaddingBottom;
106     }
107 
getPaddingLeft()108     public int getPaddingLeft() {
109         return mResolvedPaddingLeft;
110     }
111 
getPaddingRight()112     public int getPaddingRight() {
113         return mResolvedPaddingRight;
114     }
115 
116     /////////////////////////////////////////////////////////////////////////////////////////////
117     // Solver callback
118     /////////////////////////////////////////////////////////////////////////////////////////////
119 
needsCallbackFromSolver(boolean value)120     protected void needsCallbackFromSolver(boolean value) {
121         mNeedsCallFromSolver = value;
122     }
123 
124     // @TODO: add description
needSolverPass()125     public boolean needSolverPass() {
126         return mNeedsCallFromSolver;
127     }
128 
129     /////////////////////////////////////////////////////////////////////////////////////////////
130     // Measure
131     /////////////////////////////////////////////////////////////////////////////////////////////
132 
133     // @TODO: add description
measure(int widthMode, int widthSize, int heightMode, int heightSize)134     public void measure(int widthMode, int widthSize, int heightMode, int heightSize) {
135         // nothing
136     }
137 
138     @Override
updateConstraints(ConstraintWidgetContainer container)139     public void updateConstraints(ConstraintWidgetContainer container) {
140         captureWidgets();
141     }
142 
143     // @TODO: add description
captureWidgets()144     public void captureWidgets() {
145         for (int i = 0; i < mWidgetsCount; i++) {
146             ConstraintWidget widget = mWidgets[i];
147             if (widget != null) {
148                 widget.setInVirtualLayout(true);
149             }
150         }
151     }
152 
getMeasuredWidth()153     public int getMeasuredWidth() {
154         return mMeasuredWidth;
155     }
156 
getMeasuredHeight()157     public int getMeasuredHeight() {
158         return mMeasuredHeight;
159     }
160 
161     // @TODO: add description
setMeasure(int width, int height)162     public void setMeasure(int width, int height) {
163         mMeasuredWidth = width;
164         mMeasuredHeight = height;
165     }
166 
measureChildren()167     protected boolean measureChildren() {
168         BasicMeasure.Measurer measurer = null;
169         if (mParent != null) {
170             measurer = ((ConstraintWidgetContainer) mParent).getMeasurer();
171         }
172         if (measurer == null) {
173             return false;
174         }
175 
176         for (int i = 0; i < mWidgetsCount; i++) {
177             ConstraintWidget widget = mWidgets[i];
178             if (widget == null) {
179                 continue;
180             }
181 
182             if (widget instanceof Guideline) {
183                 continue;
184             }
185 
186             DimensionBehaviour widthBehavior = widget.getDimensionBehaviour(HORIZONTAL);
187             DimensionBehaviour heightBehavior = widget.getDimensionBehaviour(VERTICAL);
188 
189             boolean skip = widthBehavior == DimensionBehaviour.MATCH_CONSTRAINT
190                     && widget.mMatchConstraintDefaultWidth != MATCH_CONSTRAINT_WRAP
191                     && heightBehavior == DimensionBehaviour.MATCH_CONSTRAINT
192                     && widget.mMatchConstraintDefaultHeight != MATCH_CONSTRAINT_WRAP;
193 
194             if (skip) {
195                 // we don't need to measure here as the dimension of the widget
196                 // will be completely computed by the solver.
197                 continue;
198             }
199 
200             if (widthBehavior == DimensionBehaviour.MATCH_CONSTRAINT) {
201                 widthBehavior = DimensionBehaviour.WRAP_CONTENT;
202             }
203             if (heightBehavior == DimensionBehaviour.MATCH_CONSTRAINT) {
204                 heightBehavior = DimensionBehaviour.WRAP_CONTENT;
205             }
206             mMeasure.horizontalBehavior = widthBehavior;
207             mMeasure.verticalBehavior = heightBehavior;
208             mMeasure.horizontalDimension = widget.getWidth();
209             mMeasure.verticalDimension = widget.getHeight();
210             measurer.measure(widget, mMeasure);
211             widget.setWidth(mMeasure.measuredWidth);
212             widget.setHeight(mMeasure.measuredHeight);
213             widget.setBaselineDistance(mMeasure.measuredBaseline);
214         }
215         return true;
216     }
217 
218     BasicMeasure.Measurer mMeasurer = null;
219 
measure(ConstraintWidget widget, ConstraintWidget.DimensionBehaviour horizontalBehavior, int horizontalDimension, ConstraintWidget.DimensionBehaviour verticalBehavior, int verticalDimension)220     protected void measure(ConstraintWidget widget,
221             ConstraintWidget.DimensionBehaviour horizontalBehavior,
222             int horizontalDimension,
223             ConstraintWidget.DimensionBehaviour verticalBehavior,
224             int verticalDimension) {
225         while (mMeasurer == null && getParent() != null) {
226             ConstraintWidgetContainer parent = (ConstraintWidgetContainer) getParent();
227             mMeasurer = parent.getMeasurer();
228         }
229         mMeasure.horizontalBehavior = horizontalBehavior;
230         mMeasure.verticalBehavior = verticalBehavior;
231         mMeasure.horizontalDimension = horizontalDimension;
232         mMeasure.verticalDimension = verticalDimension;
233         mMeasurer.measure(widget, mMeasure);
234         widget.setWidth(mMeasure.measuredWidth);
235         widget.setHeight(mMeasure.measuredHeight);
236         widget.setHasBaseline(mMeasure.measuredHasBaseline);
237         widget.setBaselineDistance(mMeasure.measuredBaseline);
238     }
239 
240     // @TODO: add description
contains(HashSet<ConstraintWidget> widgets)241     public boolean contains(HashSet<ConstraintWidget> widgets) {
242         for (int i = 0; i < mWidgetsCount; i++) {
243             ConstraintWidget widget = mWidgets[i];
244             if (widgets.contains(widget)) {
245                 return true;
246             }
247         }
248         return false;
249     }
250 }
251