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/swiper/swiper_element.h"
17 
18 #include "core/components/swiper/render_swiper.h"
19 
20 namespace OHOS::Ace {
21 namespace {
22 
23 constexpr int32_t ELEMENT_CHANGE_END_LISTENER_KEY = 1002;
24 constexpr int32_t INDICATOR_FOCUS_INDEX = 1;
25 
26 } // namespace
27 
PerformBuild()28 void SwiperElement::PerformBuild()
29 {
30     auto swiperComponent = AceType::DynamicCast<SwiperComponent>(component_);
31     if (!swiperComponent) {
32         LOGE("get swiper component failed!");
33         return;
34     }
35     axis_ = swiperComponent->GetAxis();
36     auto indicator = swiperComponent->GetIndicator();
37     if (!indicator) {
38         showIndicator_ = false;
39     }
40 
41     if (showIndicator_ && !indicatorFocusNode_) {
42         indicatorFocusNode_ = AceType::MakeRefPtr<FocusNode>();
43         FocusGroup::AddChild(indicatorFocusNode_);
44         registerCallBack();
45     }
46     ComponentGroupElement::PerformBuild();
47 }
48 
registerCallBack()49 void SwiperElement::registerCallBack()
50 {
51     if (!indicatorFocusNode_) {
52         return;
53     }
54     indicatorFocusNode_->SetOnFocusCallback([weak = WeakClaim(this)](void) {
55         auto client = weak.Upgrade();
56         if (!client) {
57             return;
58         }
59         auto weakContext = client->GetContext();
60         auto context = weakContext.Upgrade();
61         if (context) {
62             client->HandleIndicatorFocus(true && context->IsKeyEvent());
63         }
64     });
65 
66     indicatorFocusNode_->SetOnBlurCallback([weak = WeakClaim(this)](void) {
67         auto client = weak.Upgrade();
68         if (client) {
69             client->HandleIndicatorFocus(false);
70         }
71     });
72 }
73 
IsFocusable() const74 bool SwiperElement::IsFocusable() const
75 {
76     auto swiper = DynamicCast<RenderSwiper>(renderNode_);
77     if (!swiper) {
78         LOGE("get render node failed");
79         return false;
80     }
81 
82     if (showIndicator_) {
83         return true;
84     } else {
85         int32_t currentIndex = swiper->GetCurrentIndex();
86         auto currentFocusNode = focusNodes_.begin();
87         std::advance(currentFocusNode, currentIndex);
88         if (currentFocusNode == focusNodes_.end()) {
89             LOGE("target focus node is null");
90             return false;
91         }
92         return (*currentFocusNode)->IsFocusable();
93     }
94 }
95 
OnFocus()96 void SwiperElement::OnFocus()
97 {
98     auto swiper = DynamicCast<RenderSwiper>(renderNode_);
99     if (!swiper) {
100         LOGE("get render node failed");
101         itLastFocusNode_ = focusNodes_.end();
102         return;
103     }
104     swiper->OnStatusChanged(RenderStatus::FOCUS);
105 
106     if (showIndicator_) {
107         auto currentFocusNode = focusNodes_.begin();
108         if ((*currentFocusNode)->RequestFocusImmediately()) {
109             itLastFocusNode_ = currentFocusNode;
110             indicatorFocusNode_ = *itLastFocusNode_;
111         }
112     } else {
113         int32_t currentIndex = swiper->GetCurrentIndex();
114         auto currentFocusNode = focusNodes_.begin();
115         std::advance(currentFocusNode, currentIndex);
116         if (currentFocusNode != focusNodes_.end()) {
117             if ((*currentFocusNode)->RequestFocusImmediately()) {
118                 itLastFocusNode_ = currentFocusNode;
119                 swiper->OnFocus();
120             } else {
121                 // Not found any focusable node, clear focus.
122                 itLastFocusNode_ = focusNodes_.end();
123             }
124         }
125     }
126     swiper->RegisterChangeEndListener(ELEMENT_CHANGE_END_LISTENER_KEY, [weak = WeakClaim(this)](int32_t index) {
127         auto client = weak.Upgrade();
128         if (client) {
129             client->RequestChildFocus(index);
130         }
131     });
132 }
133 
RequestChildFocus(int32_t index)134 void SwiperElement::RequestChildFocus(int32_t index)
135 {
136     auto currentFocusNode = focusNodes_.begin();
137     if (showIndicator_) {
138         std::advance(currentFocusNode, index + INDICATOR_FOCUS_INDEX);
139     } else {
140         std::advance(currentFocusNode, index);
141     }
142     if (currentFocusNode != focusNodes_.end()) {
143         if ((*currentFocusNode)->RequestFocusImmediately()) {
144             itLastFocusNode_ = currentFocusNode;
145         }
146     }
147 }
148 
OnBlur()149 void SwiperElement::OnBlur()
150 {
151     FocusGroup::OnBlur();
152     auto swiper = DynamicCast<RenderSwiper>(renderNode_);
153     if (swiper) {
154         swiper->OnBlur();
155         swiper->UnRegisterChangeEndListener(ELEMENT_CHANGE_END_LISTENER_KEY);
156         swiper->OnStatusChanged(RenderStatus::BLUR);
157     }
158 }
159 
HandleIndicatorFocus(bool isFocus)160 void SwiperElement::HandleIndicatorFocus(bool isFocus)
161 {
162     auto swiper = DynamicCast<RenderSwiper>(renderNode_);
163     if (!swiper) {
164         LOGE("get swiper render node failed");
165         return;
166     }
167     swiper->IndicatorShowFocus(isFocus);
168 }
169 
RequestNextFocus(bool vertical,bool reverse,const Rect & rect)170 bool SwiperElement::RequestNextFocus(bool vertical, bool reverse, const Rect& rect)
171 {
172     auto swiper = DynamicCast<RenderSwiper>(renderNode_);
173     if (!swiper) {
174         return false;
175     }
176     if (showIndicator_ && (*itLastFocusNode_ == indicatorFocusNode_)) {
177         if ((axis_ == Axis::HORIZONTAL && vertical) || (axis_ != Axis::HORIZONTAL && !vertical)) {
178             if (reverse) {
179                 return RequestCurrentItemFocus();
180             }
181         } else {
182             swiper->UpdateIndicatorFocus(true, reverse);
183             return true;
184         }
185     } else {
186         if (showIndicator_) {
187             if ((axis_ == Axis::HORIZONTAL && vertical) || (axis_ != Axis::HORIZONTAL && !vertical)) {
188                 if (!reverse) {
189                     return RequestIndicatorFocus();
190                 }
191             }
192         } else {
193             return false;
194         }
195     }
196     return false;
197 }
198 
RequestIndicatorFocus()199 bool SwiperElement::RequestIndicatorFocus()
200 {
201     auto swiper = DynamicCast<RenderSwiper>(renderNode_);
202     if (!swiper) {
203         return false;
204     }
205     auto currentFocusNode = focusNodes_.begin();
206     if ((*currentFocusNode)->RequestFocusImmediately()) {
207         itLastFocusNode_ = currentFocusNode;
208         indicatorFocusNode_ = *itLastFocusNode_;
209         swiper->IndicatorShowFocus(true);
210         return true;
211     }
212     return false;
213 }
214 
RequestCurrentItemFocus()215 bool SwiperElement::RequestCurrentItemFocus()
216 {
217     auto swiper = DynamicCast<RenderSwiper>(renderNode_);
218     if (!swiper) {
219         LOGE("get swiper render node failed");
220         return false;
221     }
222     int32_t currentIndex = swiper->GetCurrentIndex();
223     auto currentFocusNode = focusNodes_.begin();
224     if (showIndicator_) {
225         std::advance(currentFocusNode, currentIndex + INDICATOR_FOCUS_INDEX);
226     } else {
227         std::advance(currentFocusNode, currentIndex);
228     }
229     if (currentFocusNode != focusNodes_.end()) {
230         if ((*currentFocusNode)->RequestFocusImmediately()) {
231             itLastFocusNode_ = currentFocusNode;
232             swiper->IndicatorShowFocus(false);
233             return true;
234         }
235     }
236     return false;
237 }
238 
OnKeyEvent(const KeyEvent & keyEvent)239 bool SwiperElement::OnKeyEvent(const KeyEvent& keyEvent)
240 {
241     if (!IsCurrentFocus()) {
242         return false;
243     }
244 
245     if (itLastFocusNode_ != focusNodes_.end() && (*itLastFocusNode_)->HandleKeyEvent(keyEvent)) {
246         return true;
247     }
248 
249     if (FocusNode::OnKeyEvent(keyEvent)) {
250         return true;
251     }
252 
253     if (keyEvent.action != KeyAction::UP) {
254         return false;
255     }
256 
257     switch (keyEvent.code) {
258         case KeyCode::TV_CONTROL_UP:
259             return RequestNextFocus(true, true, GetRect());
260         case KeyCode::TV_CONTROL_DOWN:
261             return RequestNextFocus(true, false, GetRect());
262         case KeyCode::TV_CONTROL_LEFT:
263             return RequestNextFocus(false, true, GetRect());
264         case KeyCode::TV_CONTROL_RIGHT:
265             return RequestNextFocus(false, false, GetRect());
266         case KeyCode::KEY_TAB:
267             return RequestNextFocus(false, false, GetRect()) || RequestNextFocus(true, false, GetRect());
268         default:
269             return false;
270     }
271 }
272 
273 } // namespace OHOS::Ace
274