1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_v2/grid/grid_element.h"
17 
18 #include "base/log/log.h"
19 #include "base/utils/utils.h"
20 #include "core/components/grid_layout/grid_layout_component.h"
21 #include "core/components/grid_layout/grid_layout_item_component.h"
22 #include "core/components/grid_layout/render_grid_layout.h"
23 #include "core/components/proxy/render_item_proxy.h"
24 #include "core/components_v2/grid/render_grid_scroll.h"
25 
26 namespace OHOS::Ace::V2 {
27 
CreateRenderNode()28 RefPtr<RenderNode> GridElement::CreateRenderNode()
29 {
30     auto render = RenderElement::CreateRenderNode();
31     RefPtr<RenderGridScroll> renderGrid = AceType::DynamicCast<RenderGridScroll>(render);
32     if (renderGrid) {
33         renderGrid->SetBuildChildByIndex([weak = WeakClaim(this)](int32_t index) {
34             auto element = weak.Upgrade();
35             if (!element) {
36                 return false;
37             }
38             return element->BuildChildByIndex(index);
39         });
40 
41         renderGrid->SetDeleteChildByIndex([weak = WeakClaim(this)](int32_t index) {
42             auto element = weak.Upgrade();
43             if (!element) {
44                 return;
45             }
46             element->DeleteChildByIndex(index);
47         });
48 
49         renderGrid->SetGetChildSpanByIndex([weak = WeakClaim(this)](int32_t index, bool isHorizontal, int32_t& itemMain,
50                                                int32_t& itemCross, int32_t& itemMainSpan, int32_t& itemCrossSpan) {
51             auto element = weak.Upgrade();
52             if (!element) {
53                 return false;
54             }
55             return element->GetItemSpanByIndex(index, isHorizontal, itemMain, itemCross, itemMainSpan, itemCrossSpan);
56         });
57 
58         renderGrid->SetGetItemTotalCount([weak = WeakClaim(this)]() {
59             auto element = weak.Upgrade();
60             if (!element) {
61                 return 0;
62             }
63             return static_cast<int32_t>(element->TotalCount());
64         });
65     }
66 
67     return render;
68 }
69 
PerformBuild()70 void GridElement::PerformBuild()
71 {
72     auto component = AceType::DynamicCast<GridLayoutComponent>(component_);
73     ACE_DCHECK(component); // MUST be GridComponent
74     V2::ElementProxyHost::UpdateChildren(component->GetChildren());
75     RefPtr<RenderGridScroll> render = AceType::DynamicCast<RenderGridScroll>(renderNode_);
76     CHECK_NULL_VOID(render);
77     render->OnDataSourceUpdated(0);
78 }
79 
BuildChildByIndex(int32_t index)80 bool GridElement::BuildChildByIndex(int32_t index)
81 {
82     if (index < 0) {
83         return false;
84     }
85     auto element = GetElementByIndex(index);
86     if (!element) {
87         LOGE("GetElementByIndex failed index=[%d]", index);
88         return false;
89     }
90     auto renderNode = element->GetRenderNode();
91     if (!renderNode) {
92         LOGE("GetRenderNode failed");
93         return false;
94     }
95     RefPtr<RenderGridScroll> grid = AceType::DynamicCast<RenderGridScroll>(renderNode_);
96     if (!grid) {
97         return false;
98     }
99     grid->AddChildByIndex(index, renderNode);
100     return true;
101 }
102 
GetItemSpanByIndex(int32_t index,bool isHorizontal,int32_t & itemMain,int32_t & itemCross,int32_t & itemMainSpan,int32_t & itemCrossSpan)103 bool GridElement::GetItemSpanByIndex(int32_t index, bool isHorizontal, int32_t& itemMain, int32_t& itemCross,
104     int32_t& itemMainSpan, int32_t& itemCrossSpan)
105 {
106     if (index < 0) {
107         return false;
108     }
109     auto component = GetComponentByIndex(index);
110     auto gridItem = AceType::DynamicCast<GridLayoutItemComponent>(component);
111 
112     if (!gridItem) {
113         return false;
114     }
115     if (isHorizontal) {
116         itemMain = gridItem->GetColumnIndex();
117         itemCross = gridItem->GetRowIndex();
118         itemMainSpan = gridItem->GetColumnSpan();
119         itemCrossSpan = gridItem->GetRowSpan();
120     } else {
121         itemMain = gridItem->GetRowIndex();
122         itemCross = gridItem->GetColumnIndex();
123         itemMainSpan = gridItem->GetRowSpan();
124         itemCrossSpan = gridItem->GetColumnSpan();
125     }
126     return true;
127 }
128 
DeleteChildByIndex(int32_t index)129 void GridElement::DeleteChildByIndex(int32_t index)
130 {
131     ReleaseElementByIndex(index);
132 }
133 
RequestNextFocus(bool vertical,bool reverse,const Rect & rect)134 bool GridElement::RequestNextFocus(bool vertical, bool reverse, const Rect& rect)
135 {
136     RefPtr<RenderGridLayout> grid = AceType::DynamicCast<RenderGridLayout>(renderNode_);
137     if (!grid) {
138         LOGE("Render grid is null.");
139         return false;
140     }
141     LOGI("RequestNextFocus vertical:%{public}d reverse:%{public}d.", vertical, reverse);
142     bool ret = false;
143     while (!ret) {
144         int32_t focusIndex = grid->RequestNextFocus(vertical, reverse);
145         int32_t size = static_cast<int32_t>(GetChildrenList().size());
146         if (focusIndex < 0 || focusIndex >= size) {
147             return false;
148         }
149         auto iter = GetChildrenList().begin();
150         std::advance(iter, focusIndex);
151         auto focusNode = *iter;
152         if (!focusNode) {
153             LOGE("Target focus node is null.");
154             return false;
155         }
156         // If current Node can not obtain focus, move to next.
157         ret = focusNode->RequestFocusImmediately();
158     }
159     return ret;
160 }
161 
ApplyRenderChild(const RefPtr<RenderElement> & renderChild)162 void GridElement::ApplyRenderChild(const RefPtr<RenderElement>& renderChild)
163 {
164     if (!renderChild) {
165         LOGE("Element child is null");
166         return;
167     }
168 
169     if (!renderNode_) {
170         LOGE("RenderElement don't have a render node");
171         return;
172     }
173     renderNode_->AddChild(renderChild->GetRenderNode());
174 }
175 
OnUpdateElement(const RefPtr<Element> & element,const RefPtr<Component> & component)176 RefPtr<Element> GridElement::OnUpdateElement(const RefPtr<Element>& element, const RefPtr<Component>& component)
177 {
178     return UpdateChild(element, component);
179 }
180 
OnMakeEmptyComponent()181 RefPtr<Component> GridElement::OnMakeEmptyComponent()
182 {
183     return AceType::MakeRefPtr<GridLayoutItemComponent>();
184 }
185 
OnDataSourceUpdated(size_t startIndex)186 void GridElement::OnDataSourceUpdated(size_t startIndex)
187 {
188     auto context = context_.Upgrade();
189     if (context) {
190         context->AddPostFlushListener(AceType::Claim(this));
191     }
192     RefPtr<RenderGridScroll> render = AceType::DynamicCast<RenderGridScroll>(renderNode_);
193     if (!render) {
194         return;
195     }
196     render->OnDataSourceUpdated(static_cast<int32_t>(startIndex));
197     render->SetTotalCount(ElementProxyHost::TotalCount());
198     ElementProxyHost::OnDataSourceUpdated(startIndex);
199 }
200 
OnPostFlush()201 void GridElement::OnPostFlush()
202 {
203     ReleaseRedundantComposeIds();
204 }
205 
GetReloadedCheckNum()206 size_t GridElement::GetReloadedCheckNum()
207 {
208     RefPtr<RenderGridScroll> render = AceType::DynamicCast<RenderGridScroll>(renderNode_);
209     if (render) {
210         size_t cachedNum = render->GetCachedSize();
211         if (cachedNum > 0) {
212             return cachedNum;
213         }
214     }
215     return ElementProxyHost::GetReloadedCheckNum();
216 }
217 
Dump()218 void GridElement::Dump()
219 {
220     DumpProxy();
221 }
222 
223 } // namespace OHOS::Ace::V2
224