/* * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "components/ui_view_group.h" #include #include "components/root_view.h" #include "components/ui_tree_manager.h" #include "gfx_utils/graphic_log.h" namespace OHOS { UIViewGroup::UIViewGroup() : childrenHead_(nullptr), childrenRenderHead_(nullptr), childrenTail_(nullptr), childrenNum_(0), isDragging_(false), disallowIntercept_(false), isAutoSize_(false) { isViewGroup_ = true; #if ENABLE_FOCUS_MANAGER isInterceptFocus_ = false; #endif } UIViewGroup::~UIViewGroup() {} void UIViewGroup::Add(UIView* view) { if ((view == this) || (view == nullptr)) { GRAPHIC_LOGE("view can not be nullptr and added to self"); return; } if (view->GetParent() != nullptr) { GRAPHIC_LOGE("can not add view multi times"); return; } if (childrenHead_ == nullptr) { childrenHead_ = view; } else { if (childrenTail_ == nullptr) { return; } childrenTail_->SetNextSibling(view); } view->SetParent(this); view->SetNextSibling(nullptr); childrenTail_ = view; childrenNum_++; if (isAutoSize_) { AutoResize(); } UpdateRenderView(view); OnChildChanged(); } void UIViewGroup::Insert(UIView* prevView, UIView* insertView) { if ((insertView == nullptr) || (insertView == this)) { GRAPHIC_LOGE("insertView can not be nullptr and insert to self"); return; } if (insertView->GetParent() != nullptr) { GRAPHIC_LOGE("can not insert view multi times"); return; } if (childrenHead_ == nullptr) { Add(insertView); UpdateRenderView(insertView); return; } if (prevView == nullptr) { insertView->SetNextSibling(childrenHead_); insertView->SetParent(this); childrenHead_ = insertView; } else { UIView* nextView = prevView->GetNextSibling(); prevView->SetNextSibling(insertView); insertView->SetNextSibling(nextView); insertView->SetParent(this); } if (childrenTail_ == prevView) { childrenTail_ = insertView; } childrenNum_++; if (isAutoSize_) { AutoResize(); } UpdateRenderView(insertView); OnChildChanged(); } void UIViewGroup::Remove(UIView* view) { if ((childrenHead_ == nullptr) || (view == nullptr)) { return; } UITreeManager::GetInstance().OnLifeEvent(view, UITreeManager::REMOVE); #if LOCAL_RENDER RootView::GetInstance()->RemoveViewFromInvalidMap(view); InvalidateRect(view->GetRect()); #endif if (childrenHead_ == view) { RemoveRenderView(view); childrenHead_ = childrenHead_->GetNextSibling(); view->SetParent(nullptr); view->SetNextSibling(nullptr); if (childrenTail_ == view) { childrenTail_ = nullptr; } childrenNum_--; OnChildChanged(); return; } UIView* node = childrenHead_; while (node->GetNextSibling() != nullptr) { if (node->GetNextSibling() == view) { RemoveRenderView(view); node->SetNextSibling(view->GetNextSibling()); view->SetParent(nullptr); view->SetNextSibling(nullptr); if (childrenTail_ == view) { childrenTail_ = node; } childrenNum_--; OnChildChanged(); return; } node = node->GetNextSibling(); } } void UIViewGroup::RemoveAll() { UIView* node = childrenHead_; childrenHead_ = nullptr; childrenTail_ = nullptr; childrenRenderHead_ = nullptr; childrenNum_ = 0; UIView* tmp = nullptr; while (node != nullptr) { tmp = node; UITreeManager::GetInstance().OnLifeEvent(node, UITreeManager::REMOVE); node = node->GetNextSibling(); tmp->SetParent(nullptr); tmp->SetNextSibling(nullptr); tmp->SetNextRenderSibling(nullptr); } OnChildChanged(); } void UIViewGroup::GetTargetView(const Point& point, UIView** last) { if (last == nullptr) { return; } Rect rect = GetRect(); if (disallowIntercept_) { *last = nullptr; return; } if (!rect.IsContains(point)) { return; } if (!visible_) { return; } if (touchable_) { *last = this; } if (isDragging_) { return; } UIView* view = GetChildrenRenderHead(); while (view != nullptr) { if (!view->IsViewGroup()) { rect = view->GetRect(); if (rect.IsContains(point)) { view->GetTargetView(point, last); } } else { UIViewGroup* viewGroup = static_cast(view); viewGroup->GetTargetView(point, last); } view = view->GetNextRenderSibling(); } } void UIViewGroup::GetTargetView(const Point& point, UIView** current, UIView** target) { if ((current == nullptr) || (target == nullptr)) { return; } Rect rect = GetRect(); if (disallowIntercept_) { *current = nullptr; *target = nullptr; return; } if (!rect.IsContains(point)) { return; } if (!visible_) { return; } *target = this; if (touchable_) { *current = this; } if (isDragging_) { return; } Point pointTran = point; if (transMap_ != nullptr && !GetTransformMap().IsInvalid()) { Rect relativeRect = GetOrigRect(); pointTran = GetTransformMap().GetOrigPoint(point, relativeRect); } UIView* view = GetChildrenRenderHead(); while (view != nullptr) { if (!view->IsViewGroup()) { rect = view->GetRect(); if (rect.IsContains(pointTran)) { view->GetTargetView(pointTran, current, target); } } else { UIViewGroup* viewGroup = static_cast(view); viewGroup->GetTargetView(pointTran, current, target); } view = view->GetNextRenderSibling(); } } Rect UIViewGroup::GetAllChildRelativeRect() const { Rect rect = {0, 0, 0, 0}; UIView* view = childrenHead_; bool isRectValid = false; while (view != nullptr) { if (!view->IsVisible()) { view = view->GetNextSibling(); continue; } Rect rectChild = view->GetRelativeRect(); if (!isRectValid) { rect = rectChild; isRectValid = true; } else { rect.Join(rect, rectChild); } view = view->GetNextSibling(); } return rect; } UIView* UIViewGroup::GetChildrenRenderHead() const { return childrenRenderHead_; } void UIViewGroup::SetChildrenRenderHead(UIView* renderHead) { if ((renderHead != nullptr) && (renderHead->GetParent() != this)) { GRAPHIC_LOGE("can not set as render head if it is not a child view"); return; } childrenRenderHead_ = renderHead; } UIView* UIViewGroup::GetChildById(const char* id) const { if (id == nullptr || childrenHead_ == nullptr) { return nullptr; } UIView* child = childrenHead_; while (child != nullptr) { if ((child->GetViewId() != nullptr) && !strcmp(child->GetViewId(), id)) { return child; } else if (child->IsViewGroup() && static_cast(child)->GetChildrenHead() != nullptr) { child = static_cast(child)->GetChildrenHead(); continue; } else if (child->GetNextSibling() != nullptr) { child = child->GetNextSibling(); continue; } while (child->GetParent() != this && child->GetParent()->GetNextSibling() == nullptr) { child = child->GetParent(); } if (child->GetParent() != this) { child = child->GetParent()->GetNextSibling(); continue; } break; } return nullptr; } void UIViewGroup::MoveChildByOffset(int16_t xOffset, int16_t yOffset) { UIView* view = childrenHead_; while (view != nullptr) { int16_t x = view->GetX() + xOffset; int16_t y = view->GetY() + yOffset; view->SetPosition(x, y); view = view->GetNextSibling(); } } void UIViewGroup::AutoResize() { Rect rect = GetAllChildRelativeRect(); SetWidth(rect.GetWidth() + rect.GetLeft()); SetHeight(rect.GetHeight() + rect.GetTop()); } void UIViewGroup::RemoveRenderView(UIView* targetView) { if (targetView == nullptr) { return; } if (targetView->GetParent() == nullptr) { return; } UIViewGroup* viewGroup = reinterpret_cast(targetView->GetParent()); UIView* node = viewGroup->GetChildrenRenderHead(); if (node == nullptr) { return; } if (node == targetView) { viewGroup->SetChildrenRenderHead(node->GetNextRenderSibling()); targetView->SetNextRenderSibling(nullptr); } else { while (node->GetNextRenderSibling() != nullptr) { if (node->GetNextRenderSibling() == targetView) { node->SetNextRenderSibling(targetView->GetNextRenderSibling()); targetView->SetNextRenderSibling(nullptr); break; } node = node->GetNextRenderSibling(); } } } void UIViewGroup::UpdateRenderView(UIView* targetView) { if (targetView == nullptr) { return; } if (targetView->GetParent() == nullptr) { return; } RemoveRenderView(targetView); UIViewGroup* viewGroup = reinterpret_cast(targetView->GetParent()); UIView* curView = viewGroup->GetChildrenRenderHead(); if (curView == nullptr) { viewGroup->SetChildrenRenderHead(targetView); targetView->SetNextRenderSibling(nullptr); return; } int16_t curZIndex = curView->GetZIndex(); int16_t targetZIndex = targetView->GetZIndex(); UIView* nextView = curView->GetNextRenderSibling(); UIView* preView = nullptr; if (curZIndex > targetZIndex) { targetView->SetNextRenderSibling(curView); viewGroup->SetChildrenRenderHead(targetView); return; } while (nextView != nullptr) { int16_t nextZIndex = nextView->GetZIndex(); if (curZIndex == targetZIndex) { InsertRenderView(curView, preView, targetView); return; } if ((curZIndex < targetZIndex) && (targetZIndex < nextZIndex)) { curView->SetNextRenderSibling(targetView); targetView->SetNextRenderSibling(nextView); return; } preView = curView; curView = nextView; nextView = nextView->GetNextRenderSibling(); curZIndex = curView->GetZIndex(); } if (curZIndex == targetZIndex) { InsertRenderView(curView, preView, targetView); } else { curView->SetNextRenderSibling(targetView); targetView->SetNextRenderSibling(nullptr); } } namespace { bool AheadOfTargetView(UIView* currentView, UIView* targetView) { if ((targetView == nullptr) || (currentView == nullptr)) { return false; } while (currentView != nullptr) { UIView* nextView = currentView->GetNextSibling(); if (nextView == targetView) { return true; } currentView = nextView; } return false; } } void UIViewGroup::InsertRenderView(UIView* anchorView, UIView* anchorPreView, UIView* targetView) { if ((targetView == nullptr) || (anchorView == nullptr)) { return; } if (anchorView->GetParent() == nullptr) { return; } int16_t targetZIndex = targetView->GetZIndex(); int16_t curZIndex; UIView* node = anchorView; UIView* lastView = anchorPreView; while (node != nullptr) { curZIndex = node->GetZIndex(); if (curZIndex == targetZIndex) { if (AheadOfTargetView(node, targetView)) { lastView = node; } else if (lastView == nullptr) { UIViewGroup* viewGroup = reinterpret_cast(anchorView->GetParent()); targetView->SetNextRenderSibling(viewGroup->GetChildrenRenderHead()); viewGroup->SetChildrenRenderHead(targetView); return; } else { lastView->SetNextRenderSibling(targetView); targetView->SetNextRenderSibling(node); return; } } else if (curZIndex > targetZIndex) { lastView->SetNextRenderSibling(targetView); targetView->SetNextRenderSibling(node); return; } node = node->GetNextRenderSibling(); } lastView->SetNextRenderSibling(targetView); targetView->SetNextRenderSibling(nullptr); } } // namespace OHOS