1 /*
2 * Copyright (c) 2021-2022 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/tab_bar/tab_bar_element.h"
17
18 #include "core/components/tab_bar/render_tab_bar.h"
19
20 namespace OHOS::Ace {
21
CreateRenderNode()22 RefPtr<RenderNode> TabBarElement::CreateRenderNode()
23 {
24 RefPtr<RenderNode> node = ComponentGroupElement::CreateRenderNode();
25
26 RefPtr<RenderTabBar> tabBar = AceType::DynamicCast<RenderTabBar>(node);
27 if (tabBar) {
28 tabBar->RegisterCallback([weakTabBarElement = AceType::WeakClaim(this)](int32_t index) {
29 auto tabBar = weakTabBarElement.Upgrade();
30 if (tabBar) {
31 tabBar->UpdateElement(index);
32 }
33 });
34 }
35 return node;
36 }
37
UpdateElement(int32_t index)38 void TabBarElement::UpdateElement(int32_t index)
39 {
40 if (controller_) {
41 int32_t preIndex = controller_->GetIndex();
42 controller_->SetIndex(index);
43 int32_t curIndex = controller_->GetIndex();
44 if (preIndex != curIndex) {
45 controller_->ChangeDispatch(curIndex);
46 }
47 controller_->OnTabBarChanged(index);
48 UpdateIndex(curIndex);
49 }
50 }
51
Update()52 void TabBarElement::Update()
53 {
54 if (component_) {
55 RefPtr<TabBarComponent> tabBar = AceType::DynamicCast<TabBarComponent>(component_);
56 tabBar_ = tabBar;
57
58 if (!tabBar) {
59 LOGE("TabBarElement::Update: get TabBarComponent failed!");
60 return;
61 }
62 indicatorStyle_ = tabBar->GetIndicator();
63 focusIndicatorStyle_ = tabBar->GetFocusIndicator();
64 tabs_.clear();
65 tabBar->BuildItems(tabs_);
66 vertical_ = tabBar->IsVertical();
67 auto controller = tabBar->GetController();
68 if (controller && (controller_ != controller)) {
69 // Get index from old controller before replace.
70 if (!controller->IsIndexDefined() && controller_) {
71 controller->SetIndexWithoutChangeContent(controller_->GetIndex());
72 }
73 controller_ = controller;
74 }
75 if (!controller_) {
76 LOGE("fail to get controller");
77 return;
78 }
79 controller_->SetBarElement(AceType::Claim(this));
80 auto domChangeEvent = AceAsyncEvent<void(uint32_t)>::Create(tabBar->GetDomChangeEventId(), GetContext());
81 if (domChangeEvent) {
82 domChangeEvent(controller_->GetIndex());
83 }
84 }
85 ComponentGroupElement::Update();
86 }
87
RequestNextFocus(bool vertical,bool reverse,const Rect & rect)88 bool TabBarElement::RequestNextFocus(bool vertical, bool reverse, const Rect& rect)
89 {
90 if (vertical_ == vertical) {
91 if (GoToNextFocus(reverse)) {
92 int32_t index = std::distance(focusNodes_.begin(), itLastFocusNode_);
93 UpdateElement(index);
94 return true;
95 }
96 }
97 return false;
98 }
99
UpdateScrollIndicator(double percent,int32_t newIndex,bool needChange)100 void TabBarElement::UpdateScrollIndicator(double percent, int32_t newIndex, bool needChange)
101 {
102 RefPtr<RenderTabBar> tabBar = AceType::DynamicCast<RenderTabBar>(renderNode_);
103 if (tabBar) {
104 tabBar->SetScrollIndicator(percent, newIndex, needChange);
105 }
106 }
107
UpdateIndex(int32_t index)108 void TabBarElement::UpdateIndex(int32_t index)
109 {
110 RefPtr<RenderTabBar> tabBar = AceType::DynamicCast<RenderTabBar>(renderNode_);
111 if (tabBar) {
112 tabBar->SetIndex(index);
113 }
114 }
115
PerformBuild()116 void TabBarElement::PerformBuild()
117 {
118 if (tabs_.empty()) {
119 ComponentGroupElement::PerformBuild();
120 return;
121 }
122 auto itChild = children_.begin();
123 auto itChildEnd = children_.end();
124 auto itComponent = tabs_.begin();
125 auto itComponentEnd = tabs_.end();
126
127 while (itChild != itChildEnd && itComponent != itComponentEnd) {
128 UpdateChild(*(itChild++), *(itComponent++));
129 }
130 // delete useless element.
131 while (itChild != itChildEnd) {
132 UpdateChild(*(itChild++), nullptr);
133 }
134 // update component.
135 while (itComponent != itComponentEnd) {
136 UpdateChild(nullptr, *(itComponent++));
137 }
138 GetRenderNode()->MarkNeedLayout();
139 }
140
OnFocus()141 void TabBarElement::OnFocus()
142 {
143 RefPtr<RenderTabBar> tabBar = AceType::DynamicCast<RenderTabBar>(renderNode_);
144 if (tabBar) {
145 tabBar->HandleFocusEvent(true);
146 if (focusIndicatorStyle_) {
147 tabBar->UpdateIndicatorStyle(focusIndicatorStyle_);
148 }
149 }
150 if (controller_) {
151 int32_t index = controller_->GetIndex();
152 int32_t size = static_cast<int32_t>(focusNodes_.size());
153 if (size > 0) {
154 size--;
155 }
156 index = std::clamp(index, 0, size);
157 itLastFocusNode_ = focusNodes_.begin();
158 std::advance(itLastFocusNode_, index);
159 }
160
161 return FocusGroup::OnFocus();
162 }
163
OnBlur()164 void TabBarElement::OnBlur()
165 {
166 RefPtr<RenderTabBar> tabBar = AceType::DynamicCast<RenderTabBar>(renderNode_);
167 if (tabBar) {
168 tabBar->HandleFocusEvent(false);
169 if (indicatorStyle_) {
170 tabBar->UpdateIndicatorStyle(indicatorStyle_);
171 }
172 }
173 return FocusGroup::OnBlur();
174 }
175
176 } // namespace OHOS::Ace