1/*
2 * Copyright (c) 2020-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 "components/ui_view_group.h"
17
18#include <cstring>
19
20#include "components/root_view.h"
21#include "components/ui_tree_manager.h"
22#include "gfx_utils/graphic_log.h"
23
24namespace OHOS {
25UIViewGroup::UIViewGroup()
26    : childrenHead_(nullptr),
27      childrenRenderHead_(nullptr),
28      childrenTail_(nullptr),
29      childrenNum_(0),
30      isDragging_(false),
31      disallowIntercept_(false),
32      isAutoSize_(false)
33{
34    isViewGroup_ = true;
35#if ENABLE_FOCUS_MANAGER
36    isInterceptFocus_ = false;
37#endif
38}
39
40UIViewGroup::~UIViewGroup() {}
41
42void UIViewGroup::Add(UIView* view)
43{
44    if ((view == this) || (view == nullptr)) {
45        GRAPHIC_LOGE("view can not be nullptr and added to self");
46        return;
47    }
48    if (view->GetParent() != nullptr) {
49        GRAPHIC_LOGE("can not add view multi times");
50        return;
51    }
52
53    if (childrenHead_ == nullptr) {
54        childrenHead_ = view;
55    } else {
56        if (childrenTail_ == nullptr) {
57            return;
58        }
59        childrenTail_->SetNextSibling(view);
60    }
61    view->SetParent(this);
62    view->SetNextSibling(nullptr);
63    childrenTail_ = view;
64    childrenNum_++;
65    if (isAutoSize_) {
66        AutoResize();
67    }
68    UpdateRenderView(view);
69    OnChildChanged();
70}
71
72void UIViewGroup::Insert(UIView* prevView, UIView* insertView)
73{
74    if ((insertView == nullptr) || (insertView == this)) {
75        GRAPHIC_LOGE("insertView can not be nullptr and insert to self");
76        return;
77    }
78
79    if (insertView->GetParent() != nullptr) {
80        GRAPHIC_LOGE("can not insert view multi times");
81        return;
82    }
83
84    if (childrenHead_ == nullptr) {
85        Add(insertView);
86        UpdateRenderView(insertView);
87        return;
88    }
89
90    if (prevView == nullptr) {
91        insertView->SetNextSibling(childrenHead_);
92        insertView->SetParent(this);
93        childrenHead_ = insertView;
94    } else {
95        UIView* nextView = prevView->GetNextSibling();
96        prevView->SetNextSibling(insertView);
97        insertView->SetNextSibling(nextView);
98        insertView->SetParent(this);
99    }
100    if (childrenTail_ == prevView) {
101        childrenTail_ = insertView;
102    }
103    childrenNum_++;
104    if (isAutoSize_) {
105        AutoResize();
106    }
107    UpdateRenderView(insertView);
108    OnChildChanged();
109}
110
111void UIViewGroup::Remove(UIView* view)
112{
113    if ((childrenHead_ == nullptr) || (view == nullptr)) {
114        return;
115    }
116    UITreeManager::GetInstance().OnLifeEvent(view, UITreeManager::REMOVE);
117
118#if LOCAL_RENDER
119    RootView::GetInstance()->RemoveViewFromInvalidMap(view);
120    InvalidateRect(view->GetRect());
121#endif
122    if (childrenHead_ == view) {
123        RemoveRenderView(view);
124        childrenHead_ = childrenHead_->GetNextSibling();
125        view->SetParent(nullptr);
126        view->SetNextSibling(nullptr);
127        if (childrenTail_ == view) {
128            childrenTail_ = nullptr;
129        }
130        childrenNum_--;
131        OnChildChanged();
132        return;
133    }
134    UIView* node = childrenHead_;
135    while (node->GetNextSibling() != nullptr) {
136        if (node->GetNextSibling() == view) {
137            RemoveRenderView(view);
138            node->SetNextSibling(view->GetNextSibling());
139            view->SetParent(nullptr);
140            view->SetNextSibling(nullptr);
141            if (childrenTail_ == view) {
142                childrenTail_ = node;
143            }
144            childrenNum_--;
145            OnChildChanged();
146            return;
147        }
148        node = node->GetNextSibling();
149    }
150}
151
152void UIViewGroup::RemoveAll()
153{
154    UIView* node = childrenHead_;
155    childrenHead_ = nullptr;
156    childrenTail_ = nullptr;
157    childrenRenderHead_ = nullptr;
158    childrenNum_ = 0;
159    UIView* tmp = nullptr;
160    while (node != nullptr) {
161        tmp = node;
162        UITreeManager::GetInstance().OnLifeEvent(node, UITreeManager::REMOVE);
163        node = node->GetNextSibling();
164        tmp->SetParent(nullptr);
165        tmp->SetNextSibling(nullptr);
166        tmp->SetNextRenderSibling(nullptr);
167    }
168    OnChildChanged();
169}
170
171void UIViewGroup::GetTargetView(const Point& point, UIView** last)
172{
173    if (last == nullptr) {
174        return;
175    }
176
177    Rect rect = GetRect();
178    if (disallowIntercept_) {
179        *last = nullptr;
180        return;
181    }
182    if (!rect.IsContains(point)) {
183        return;
184    }
185    if (!visible_) {
186        return;
187    }
188    if (touchable_) {
189        *last = this;
190    }
191    if (isDragging_) {
192        return;
193    }
194    UIView* view = GetChildrenRenderHead();
195    while (view != nullptr) {
196        if (!view->IsViewGroup()) {
197            rect = view->GetRect();
198            if (rect.IsContains(point)) {
199                view->GetTargetView(point, last);
200            }
201        } else {
202            UIViewGroup* viewGroup = static_cast<UIViewGroup*>(view);
203            viewGroup->GetTargetView(point, last);
204        }
205        view = view->GetNextRenderSibling();
206    }
207}
208
209void UIViewGroup::GetTargetView(const Point& point, UIView** current, UIView** target)
210{
211    if ((current == nullptr) || (target == nullptr)) {
212        return;
213    }
214
215    Rect rect = GetRect();
216    if (disallowIntercept_) {
217        *current = nullptr;
218        *target = nullptr;
219        return;
220    }
221    if (!rect.IsContains(point)) {
222        return;
223    }
224    if (!visible_) {
225        return;
226    }
227    *target = this;
228    if (touchable_) {
229        *current = this;
230    }
231    if (isDragging_) {
232        return;
233    }
234    Point pointTran = point;
235    if (transMap_ != nullptr && !GetTransformMap().IsInvalid()) {
236        Rect relativeRect = GetOrigRect();
237        pointTran = GetTransformMap().GetOrigPoint(point, relativeRect);
238    }
239    UIView* view = GetChildrenRenderHead();
240    while (view != nullptr) {
241        if (!view->IsViewGroup()) {
242            rect = view->GetRect();
243            if (rect.IsContains(pointTran)) {
244                view->GetTargetView(pointTran, current, target);
245            }
246        } else {
247            UIViewGroup* viewGroup = static_cast<UIViewGroup*>(view);
248            viewGroup->GetTargetView(pointTran, current, target);
249        }
250        view = view->GetNextRenderSibling();
251    }
252}
253
254Rect UIViewGroup::GetAllChildRelativeRect() const
255{
256    Rect rect = {0, 0, 0, 0};
257    UIView* view = childrenHead_;
258    bool isRectValid = false;
259    while (view != nullptr) {
260        if (!view->IsVisible()) {
261            view = view->GetNextSibling();
262            continue;
263        }
264        Rect rectChild = view->GetRelativeRect();
265        if (!isRectValid) {
266            rect = rectChild;
267            isRectValid = true;
268        } else {
269            rect.Join(rect, rectChild);
270        }
271        view = view->GetNextSibling();
272    }
273    return rect;
274}
275
276UIView* UIViewGroup::GetChildrenRenderHead() const
277{
278    return childrenRenderHead_;
279}
280
281void UIViewGroup::SetChildrenRenderHead(UIView* renderHead)
282{
283    if ((renderHead != nullptr) && (renderHead->GetParent() != this)) {
284        GRAPHIC_LOGE("can not set as render head if it is not a child view");
285        return;
286    }
287    childrenRenderHead_ = renderHead;
288}
289
290UIView* UIViewGroup::GetChildById(const char* id) const
291{
292    if (id == nullptr || childrenHead_ == nullptr) {
293        return nullptr;
294    }
295    UIView* child = childrenHead_;
296    while (child != nullptr) {
297        if ((child->GetViewId() != nullptr) && !strcmp(child->GetViewId(), id)) {
298            return child;
299        } else if (child->IsViewGroup() && static_cast<UIViewGroup*>(child)->GetChildrenHead() != nullptr) {
300            child = static_cast<UIViewGroup*>(child)->GetChildrenHead();
301            continue;
302        } else if (child->GetNextSibling() != nullptr) {
303            child = child->GetNextSibling();
304            continue;
305        }
306        while (child->GetParent() != this && child->GetParent()->GetNextSibling() == nullptr) {
307            child = child->GetParent();
308        }
309        if (child->GetParent() != this) {
310            child = child->GetParent()->GetNextSibling();
311            continue;
312        }
313        break;
314    }
315    return nullptr;
316}
317
318void UIViewGroup::MoveChildByOffset(int16_t xOffset, int16_t yOffset)
319{
320    UIView* view = childrenHead_;
321    while (view != nullptr) {
322        int16_t x = view->GetX() + xOffset;
323        int16_t y = view->GetY() + yOffset;
324        view->SetPosition(x, y);
325        view = view->GetNextSibling();
326    }
327}
328
329void UIViewGroup::AutoResize()
330{
331    Rect rect = GetAllChildRelativeRect();
332    SetWidth(rect.GetWidth() + rect.GetLeft());
333    SetHeight(rect.GetHeight() + rect.GetTop());
334}
335
336void UIViewGroup::RemoveRenderView(UIView* targetView)
337{
338    if (targetView == nullptr) {
339        return;
340    }
341
342    if (targetView->GetParent() == nullptr) {
343        return;
344    }
345
346    UIViewGroup* viewGroup = reinterpret_cast<UIViewGroup*>(targetView->GetParent());
347    UIView* node = viewGroup->GetChildrenRenderHead();
348    if (node == nullptr) {
349        return;
350    }
351    if (node == targetView) {
352        viewGroup->SetChildrenRenderHead(node->GetNextRenderSibling());
353        targetView->SetNextRenderSibling(nullptr);
354    } else {
355        while (node->GetNextRenderSibling() != nullptr) {
356            if (node->GetNextRenderSibling() == targetView) {
357                node->SetNextRenderSibling(targetView->GetNextRenderSibling());
358                targetView->SetNextRenderSibling(nullptr);
359                break;
360            }
361            node = node->GetNextRenderSibling();
362        }
363    }
364}
365
366void UIViewGroup::UpdateRenderView(UIView* targetView)
367{
368    if (targetView == nullptr) {
369        return;
370    }
371
372    if (targetView->GetParent() == nullptr) {
373        return;
374    }
375    RemoveRenderView(targetView);
376
377    UIViewGroup* viewGroup = reinterpret_cast<UIViewGroup*>(targetView->GetParent());
378    UIView* curView = viewGroup->GetChildrenRenderHead();
379    if (curView == nullptr) {
380        viewGroup->SetChildrenRenderHead(targetView);
381        targetView->SetNextRenderSibling(nullptr);
382        return;
383    }
384
385    int16_t curZIndex = curView->GetZIndex();
386    int16_t targetZIndex = targetView->GetZIndex();
387    UIView* nextView = curView->GetNextRenderSibling();
388    UIView* preView = nullptr;
389
390    if (curZIndex > targetZIndex) {
391        targetView->SetNextRenderSibling(curView);
392        viewGroup->SetChildrenRenderHead(targetView);
393        return;
394    }
395
396    while (nextView != nullptr) {
397        int16_t nextZIndex = nextView->GetZIndex();
398        if (curZIndex == targetZIndex) {
399            InsertRenderView(curView, preView, targetView);
400            return;
401        }
402        if ((curZIndex < targetZIndex) && (targetZIndex < nextZIndex)) {
403            curView->SetNextRenderSibling(targetView);
404            targetView->SetNextRenderSibling(nextView);
405            return;
406        }
407        preView = curView;
408        curView = nextView;
409        nextView = nextView->GetNextRenderSibling();
410        curZIndex = curView->GetZIndex();
411    }
412
413    if (curZIndex == targetZIndex) {
414        InsertRenderView(curView, preView, targetView);
415    } else {
416        curView->SetNextRenderSibling(targetView);
417        targetView->SetNextRenderSibling(nullptr);
418    }
419}
420
421namespace {
422    bool AheadOfTargetView(UIView* currentView, UIView* targetView)
423    {
424        if ((targetView == nullptr) || (currentView == nullptr)) {
425            return  false;
426        }
427        while (currentView != nullptr) {
428            UIView* nextView = currentView->GetNextSibling();
429            if (nextView == targetView) {
430                return  true;
431            }
432            currentView = nextView;
433        }
434        return false;
435    }
436}
437
438void UIViewGroup::InsertRenderView(UIView* anchorView, UIView* anchorPreView, UIView* targetView)
439{
440    if ((targetView == nullptr) || (anchorView == nullptr)) {
441        return;
442    }
443
444    if (anchorView->GetParent() == nullptr) {
445        return;
446    }
447    int16_t targetZIndex = targetView->GetZIndex();
448    int16_t curZIndex;
449    UIView* node = anchorView;
450    UIView* lastView = anchorPreView;
451    while (node != nullptr) {
452        curZIndex = node->GetZIndex();
453        if (curZIndex == targetZIndex) {
454            if (AheadOfTargetView(node, targetView)) {
455                lastView = node;
456            } else if (lastView == nullptr) {
457                UIViewGroup* viewGroup = reinterpret_cast<UIViewGroup*>(anchorView->GetParent());
458                targetView->SetNextRenderSibling(viewGroup->GetChildrenRenderHead());
459                viewGroup->SetChildrenRenderHead(targetView);
460                return;
461            } else {
462                lastView->SetNextRenderSibling(targetView);
463                targetView->SetNextRenderSibling(node);
464                return;
465            }
466        } else if (curZIndex > targetZIndex) {
467            lastView->SetNextRenderSibling(targetView);
468            targetView->SetNextRenderSibling(node);
469            return;
470        }
471        node = node->GetNextRenderSibling();
472    }
473    lastView->SetNextRenderSibling(targetView);
474    targetView->SetNextRenderSibling(nullptr);
475}
476} // namespace OHOS
477