* 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 <cstring>
#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<UIViewGroup*>(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<UIViewGroup*>(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<UIViewGroup*>(child)->GetChildrenHead() != nullptr) {
child = static_cast<UIViewGroup*>(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<UIViewGroup*>(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<UIViewGroup*>(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<UIViewGroup*>(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);
}
}