• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 com.android.internal.widget.remotecompose.core.operations.layout.modifiers;
17 
18 import android.annotation.NonNull;
19 
20 import com.android.internal.widget.remotecompose.core.CoreDocument;
21 import com.android.internal.widget.remotecompose.core.PaintContext;
22 import com.android.internal.widget.remotecompose.core.PaintOperation;
23 import com.android.internal.widget.remotecompose.core.RemoteContext;
24 import com.android.internal.widget.remotecompose.core.SerializableToString;
25 import com.android.internal.widget.remotecompose.core.VariableSupport;
26 import com.android.internal.widget.remotecompose.core.WireBuffer;
27 import com.android.internal.widget.remotecompose.core.operations.MatrixRestore;
28 import com.android.internal.widget.remotecompose.core.operations.MatrixSave;
29 import com.android.internal.widget.remotecompose.core.operations.layout.ClickHandler;
30 import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation;
31 import com.android.internal.widget.remotecompose.core.operations.layout.Component;
32 import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent;
33 import com.android.internal.widget.remotecompose.core.operations.layout.TouchHandler;
34 import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
35 import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
36 import com.android.internal.widget.remotecompose.core.serialize.Serializable;
37 import com.android.internal.widget.remotecompose.core.serialize.SerializeTags;
38 
39 import java.util.ArrayList;
40 
41 /** Maintain a list of modifiers */
42 public class ComponentModifiers extends PaintOperation
43         implements DecoratorComponent,
44                 ClickHandler,
45                 TouchHandler,
46                 SerializableToString,
47                 Serializable {
48     @NonNull ArrayList<ModifierOperation> mList = new ArrayList<>();
49 
50     @NonNull
getList()51     public ArrayList<ModifierOperation> getList() {
52         return mList;
53     }
54 
55     @Override
apply(@onNull RemoteContext context)56     public void apply(@NonNull RemoteContext context) {
57         super.apply(context);
58         for (ModifierOperation op : mList) {
59             op.apply(context);
60             context.incrementOpCount();
61         }
62     }
63 
64     @NonNull
65     @Override
toString()66     public String toString() {
67         String str = "ComponentModifiers \n";
68         for (ModifierOperation modifierOperation : mList) {
69             str += "    " + modifierOperation.toString() + "\n";
70         }
71         return str;
72     }
73 
74     @Override
write(@onNull WireBuffer buffer)75     public void write(@NonNull WireBuffer buffer) {
76         // nothing
77     }
78 
79     @Override
serializeToString(int indent, @NonNull StringSerializer serializer)80     public void serializeToString(int indent, @NonNull StringSerializer serializer) {
81         serializer.append(indent, "MODIFIERS");
82         for (ModifierOperation m : mList) {
83             m.serializeToString(indent + 1, serializer);
84         }
85     }
86 
87     /**
88      * Add a ModifierOperation
89      *
90      * @param operation a ModifierOperation
91      */
add(@onNull ModifierOperation operation)92     public void add(@NonNull ModifierOperation operation) {
93         mList.add(operation);
94     }
95 
96     /**
97      * Returns the size of the modifier list
98      *
99      * @return number of modifiers
100      */
size()101     public int size() {
102         return mList.size();
103     }
104 
105     @Override
paint(@onNull PaintContext context)106     public void paint(@NonNull PaintContext context) {
107         float tx = 0f;
108         float ty = 0f;
109         for (ModifierOperation op : mList) {
110             if (op.isDirty() && op instanceof VariableSupport) {
111                 ((VariableSupport) op).updateVariables(context.getContext());
112                 op.markNotDirty();
113             }
114             if (op instanceof PaddingModifierOperation) {
115                 PaddingModifierOperation pop = (PaddingModifierOperation) op;
116                 context.translate(pop.getLeft(), pop.getTop());
117                 tx += pop.getLeft();
118                 ty += pop.getTop();
119             }
120             if (op instanceof MatrixSave || op instanceof MatrixRestore) {
121                 continue;
122             }
123             if (op instanceof ClickModifierOperation) {
124                 context.translate(-tx, -ty);
125                 ((ClickModifierOperation) op).paint(context);
126                 context.translate(tx, ty);
127             } else if (op instanceof PaintOperation) {
128                 ((PaintOperation) op).paint(context);
129             }
130         }
131         // Back out the translates created by paddings
132         // TODO: we should be able to get rid of this when drawing the content of a component
133         context.translate(-tx, -ty);
134     }
135 
136     @Override
layout( @onNull RemoteContext context, Component component, float width, float height)137     public void layout(
138             @NonNull RemoteContext context, Component component, float width, float height) {
139         float w = width;
140         float h = height;
141         for (ModifierOperation op : mList) {
142             if (op instanceof PaddingModifierOperation) {
143                 PaddingModifierOperation pop = (PaddingModifierOperation) op;
144                 w -= pop.getLeft() + pop.getRight();
145                 h -= pop.getTop() + pop.getBottom();
146             }
147             if (op instanceof ClickModifierOperation) {
148                 ((DecoratorComponent) op).layout(context, component, width, height);
149             } else if (op instanceof DecoratorComponent) {
150                 ((DecoratorComponent) op).layout(context, component, w, h);
151             }
152         }
153     }
154 
155     /**
156      * Add the operations to this ComponentModifier
157      *
158      * @param operations list of ModifierOperation
159      */
addAll(@onNull ArrayList<ModifierOperation> operations)160     public void addAll(@NonNull ArrayList<ModifierOperation> operations) {
161         mList.addAll(operations);
162     }
163 
164     @Override
onClick( @onNull RemoteContext context, @NonNull CoreDocument document, @NonNull Component component, float x, float y)165     public void onClick(
166             @NonNull RemoteContext context,
167             @NonNull CoreDocument document,
168             @NonNull Component component,
169             float x,
170             float y) {
171         for (ModifierOperation op : mList) {
172             if (op instanceof ClickHandler) {
173                 ((ClickHandler) op).onClick(context, document, component, x, y);
174             }
175         }
176     }
177 
178     @Override
onTouchDown( RemoteContext context, CoreDocument document, Component component, float x, float y)179     public void onTouchDown(
180             RemoteContext context, CoreDocument document, Component component, float x, float y) {
181         for (ModifierOperation op : mList) {
182             if (op instanceof TouchHandler) {
183                 ((TouchHandler) op).onTouchDown(context, document, component, x, y);
184             }
185         }
186     }
187 
188     @Override
onTouchUp( RemoteContext context, CoreDocument document, Component component, float x, float y, float dx, float dy)189     public void onTouchUp(
190             RemoteContext context,
191             CoreDocument document,
192             Component component,
193             float x,
194             float y,
195             float dx,
196             float dy) {
197         for (ModifierOperation op : mList) {
198             if (op instanceof TouchHandler) {
199                 ((TouchHandler) op).onTouchUp(context, document, component, x, y, dx, dy);
200             }
201         }
202     }
203 
204     @Override
onTouchCancel( RemoteContext context, CoreDocument document, Component component, float x, float y)205     public void onTouchCancel(
206             RemoteContext context, CoreDocument document, Component component, float x, float y) {
207         for (ModifierOperation op : mList) {
208             if (op instanceof TouchHandler) {
209                 ((TouchHandler) op).onTouchCancel(context, document, component, x, y);
210             }
211         }
212     }
213 
214     @Override
onTouchDrag( RemoteContext context, CoreDocument document, Component component, float x, float y)215     public void onTouchDrag(
216             RemoteContext context, CoreDocument document, Component component, float x, float y) {
217         for (ModifierOperation op : mList) {
218             if (op instanceof TouchHandler) {
219                 ((TouchHandler) op).onTouchDrag(context, document, component, x, y);
220             }
221         }
222     }
223 
224     /**
225      * Returns true if we have a horizontal scroll modifier
226      *
227      * @return true if we have a horizontal scroll modifier, false otherwise
228      */
hasHorizontalScroll()229     public boolean hasHorizontalScroll() {
230         for (ModifierOperation op : mList) {
231             if (op instanceof ScrollModifierOperation) {
232                 ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
233                 if (scrollModifier.isHorizontalScroll()) {
234                     return true;
235                 }
236             }
237         }
238         return false;
239     }
240 
241     /**
242      * Returns true if we have a vertical scroll modifier
243      *
244      * @return true if we have a vertical scroll modifier, false otherwise
245      */
hasVerticalScroll()246     public boolean hasVerticalScroll() {
247         for (ModifierOperation op : mList) {
248             if (op instanceof ScrollModifierOperation) {
249                 ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
250                 if (scrollModifier.isVerticalScroll()) {
251                     return true;
252                 }
253             }
254         }
255         return false;
256     }
257 
258     /**
259      * Set the horizontal scroll dimension (if we have a scroll modifier)
260      *
261      * @param hostDimension the host component horizontal dimension
262      * @param contentDimension the content horizontal dimension
263      */
setHorizontalScrollDimension(float hostDimension, float contentDimension)264     public void setHorizontalScrollDimension(float hostDimension, float contentDimension) {
265         for (ModifierOperation op : mList) {
266             if (op instanceof ScrollModifierOperation) {
267                 ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
268                 if (scrollModifier.isHorizontalScroll()) {
269                     scrollModifier.setHorizontalScrollDimension(hostDimension, contentDimension);
270                 }
271             }
272         }
273     }
274 
275     /**
276      * Set the vertical scroll dimension (if we have a scroll modifier)
277      *
278      * @param hostDimension the host component vertical dimension
279      * @param contentDimension the content vertical dimension
280      */
setVerticalScrollDimension(float hostDimension, float contentDimension)281     public void setVerticalScrollDimension(float hostDimension, float contentDimension) {
282         for (ModifierOperation op : mList) {
283             if (op instanceof ScrollModifierOperation) {
284                 ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
285                 if (scrollModifier.isVerticalScroll()) {
286                     scrollModifier.setVerticalScrollDimension(hostDimension, contentDimension);
287                 }
288             }
289         }
290     }
291 
292     /**
293      * Returns the horizontal scroll dimension if we have a scroll modifier
294      *
295      * @return the horizontal scroll dimension, or 0 if no scroll modifier
296      */
getHorizontalScrollDimension()297     public float getHorizontalScrollDimension() {
298         for (ModifierOperation op : mList) {
299             if (op instanceof ScrollModifierOperation) {
300                 ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
301                 if (scrollModifier.isHorizontalScroll()) {
302                     return scrollModifier.getContentDimension();
303                 }
304             }
305         }
306         return 0f;
307     }
308 
309     /**
310      * Returns the vertical scroll dimension if we have a scroll modifier
311      *
312      * @return the vertical scroll dimension, or 0 if no scroll modifier
313      */
getVerticalScrollDimension()314     public float getVerticalScrollDimension() {
315         for (ModifierOperation op : mList) {
316             if (op instanceof ScrollModifierOperation) {
317                 ScrollModifierOperation scrollModifier = (ScrollModifierOperation) op;
318                 if (scrollModifier.isVerticalScroll()) {
319                     return scrollModifier.getContentDimension();
320                 }
321             }
322         }
323         return 0f;
324     }
325 
326     @Override
serialize(MapSerializer serializer)327     public void serialize(MapSerializer serializer) {
328         serializer
329                 .addTags(SerializeTags.MODIFIER)
330                 .addType("ComponentModifiers")
331                 .add("modifiers", mList);
332     }
333 }
334