1 /*
2 * Copyright (c) 2023 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_ng/pattern/swiper_indicator/indicator_common/swiper_arrow_pattern.h"
17
18 #include "base/log/dump_log.h"
19 #include "base/utils/utils.h"
20 #include "core/components/theme/icon_theme.h"
21 #include "core/components_ng/base/frame_node.h"
22 #include "core/components_ng/event/gesture_event_hub.h"
23 #include "core/components_ng/pattern/swiper/swiper_pattern.h"
24 #include "core/components_ng/pattern/text/text_pattern.h"
25 #include "core/components_v2/inspector/inspector_constants.h"
26 #include "core/pipeline_ng/pipeline_context.h"
27
28 namespace OHOS::Ace::NG {
OnModifyDone()29 void SwiperArrowPattern::OnModifyDone()
30 {
31 Pattern::OnModifyDone();
32 if (isFirstCreate_) {
33 InitNavigationArrow();
34 auto swiperNode = GetSwiperNode();
35 CHECK_NULL_VOID(swiperNode);
36 auto swiperEventHub = swiperNode->GetEventHub<SwiperEventHub>();
37 CHECK_NULL_VOID(swiperEventHub);
38 InitSwiperChangeEvent(swiperEventHub);
39 index_ = GetSwiperArrowLayoutProperty()->GetIndex().value_or(0);
40 isFirstCreate_ = false;
41 InitEvent();
42 InitOnKeyEvent();
43 } else {
44 UpdateArrowContent();
45 }
46 UpdateButtonNode(index_);
47 }
48
InitOnKeyEvent()49 void SwiperArrowPattern::InitOnKeyEvent()
50 {
51 auto host = GetHost();
52 CHECK_NULL_VOID(host);
53 auto focusHub = host->GetFocusHub();
54 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
55 auto pattern = wp.Upgrade();
56 if (pattern) {
57 return pattern->OnKeyEvent(event);
58 }
59 return false;
60 };
61 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
62 }
63
OnKeyEvent(const KeyEvent & event)64 bool SwiperArrowPattern::OnKeyEvent(const KeyEvent& event)
65 {
66 if (event.action != KeyAction::DOWN) {
67 return false;
68 }
69
70 if (event.code == KeyCode::KEY_ENTER || event.code == KeyCode::KEY_SPACE) {
71 OnClick();
72 return true;
73 }
74 return false;
75 }
76
OnClick() const77 void SwiperArrowPattern::OnClick() const
78 {
79 auto swiperNode = GetSwiperNode();
80 CHECK_NULL_VOID(swiperNode);
81 auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
82 CHECK_NULL_VOID(swiperPattern);
83 auto swiperController = swiperPattern->GetSwiperController();
84 CHECK_NULL_VOID(swiperController);
85 auto host = GetHost();
86 CHECK_NULL_VOID(host);
87 if (host->GetTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG) {
88 if (swiperPattern->IsHorizontalAndRightToLeft()) {
89 swiperController->ShowNext();
90 } else {
91 swiperController->ShowPrevious();
92 }
93 return;
94 }
95 if (host->GetTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG) {
96 if (swiperPattern->IsHorizontalAndRightToLeft()) {
97 swiperController->ShowPrevious();
98 } else {
99 swiperController->ShowNext();
100 }
101 }
102 }
103
InitSwiperChangeEvent(const RefPtr<SwiperEventHub> & swiperEventHub)104 void SwiperArrowPattern::InitSwiperChangeEvent(const RefPtr<SwiperEventHub>& swiperEventHub)
105 {
106 ChangeEvent changeEvent = [weak = WeakClaim(this)](int32_t index) {
107 auto pattern = weak.Upgrade();
108 CHECK_NULL_VOID(pattern);
109 pattern->UpdateButtonNode(index);
110 };
111 if (swiperChangeEvent_) {
112 (*swiperChangeEvent_).swap(changeEvent);
113 } else {
114 swiperChangeEvent_ = std::make_shared<ChangeEvent>(std::move(changeEvent));
115 swiperEventHub->AddOnChangeEvent(swiperChangeEvent_);
116 }
117 }
118
UpdateButtonNode(int32_t index)119 void SwiperArrowPattern::UpdateButtonNode(int32_t index)
120 {
121 index_ = index;
122 auto host = GetHost();
123 CHECK_NULL_VOID(host);
124 auto buttonNode = DynamicCast<FrameNode>(host->GetFirstChild());
125 CHECK_NULL_VOID(buttonNode);
126 auto symbolNode = DynamicCast<FrameNode>(buttonNode->GetFirstChild());
127 CHECK_NULL_VOID(symbolNode);
128 SetButtonVisible(isVisible_);
129 symbolNode->MarkModifyDone();
130 }
131
InitEvent()132 void SwiperArrowPattern::InitEvent()
133 {
134 auto host = GetHost();
135 CHECK_NULL_VOID(host);
136 auto arrowGestureHub = host->GetOrCreateGestureEventHub();
137 CHECK_NULL_VOID(arrowGestureHub);
138 // Set hit test mode transparent to avoid blocking the touch event of child nodes and sibling nodes.
139 arrowGestureHub->SetHitTestMode(HitTestMode::HTMTRANSPARENT);
140 auto buttonNode = DynamicCast<FrameNode>(host->GetFirstChild());
141 CHECK_NULL_VOID(buttonNode);
142
143 auto buttonGestureHub = buttonNode->GetOrCreateGestureEventHub();
144
145 auto touchCallback = [weak = WeakClaim(this), buttonNode](const TouchEventInfo& info) {
146 auto pattern = weak.Upgrade();
147 CHECK_NULL_VOID(pattern);
148 pattern->ButtonTouchEvent(buttonNode, info.GetTouches().front().GetTouchType());
149 };
150 buttonTouchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
151 buttonGestureHub->AddTouchEvent(buttonTouchListener_);
152
153 auto hoverCallback = [weak = WeakClaim(this), buttonNode](bool isHovered) {
154 auto pattern = weak.Upgrade();
155 CHECK_NULL_VOID(pattern);
156 pattern->ButtonOnHover(buttonNode, isHovered);
157 };
158 buttonOnHoverListener_ = MakeRefPtr<InputEvent>(std::move(hoverCallback));
159 auto buttonInputHub = buttonNode->GetOrCreateInputEventHub();
160 buttonInputHub->AddOnHoverEvent(buttonOnHoverListener_);
161
162 auto clickCallback = [weak = WeakClaim(this)](const GestureEvent& info) {
163 auto pattern = weak.Upgrade();
164 CHECK_NULL_VOID(pattern);
165 pattern->ButtonClickEvent();
166 };
167 if (buttonClickListener_) {
168 buttonGestureHub->RemoveClickEvent(buttonClickListener_);
169 }
170 buttonClickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
171 buttonGestureHub->AddClickEvent(buttonClickListener_);
172 }
173
ButtonClickEvent()174 void SwiperArrowPattern::ButtonClickEvent()
175 {
176 auto swiperArrowLayoutProperty = GetSwiperArrowLayoutProperty();
177 CHECK_NULL_VOID(swiperArrowLayoutProperty);
178 if (!hoverOnClickFlag_ && swiperArrowLayoutProperty->GetHoverShowValue(false)) {
179 return;
180 }
181
182 OnClick();
183 }
184
InitNavigationArrow()185 void SwiperArrowPattern::InitNavigationArrow()
186 {
187 auto buttonNode = FrameNode::GetOrCreateFrameNode(V2::BUTTON_ETS_TAG,
188 ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<ButtonPattern>(); });
189 auto buttonNodeFocusHub = buttonNode->GetFocusHub();
190 CHECK_NULL_VOID(buttonNodeFocusHub);
191 buttonNodeFocusHub->SetParentFocusable(false);
192 auto swiperArrowLayoutProperty = GetSwiperArrowLayoutProperty();
193 CHECK_NULL_VOID(swiperArrowLayoutProperty);
194 auto symbolNode = FrameNode::GetOrCreateFrameNode(V2::SYMBOL_ETS_TAG,
195 ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<TextPattern>(); });
196 auto host = GetHost();
197 CHECK_NULL_VOID(host);
198 auto renderContext = host->GetRenderContext();
199 CHECK_NULL_VOID(renderContext);
200 BorderRadiusProperty radius;
201 radius.SetRadius(swiperArrowLayoutProperty->GetBackgroundSizeValue());
202 renderContext->UpdateBorderRadius(radius);
203 host->AddChild(buttonNode);
204 buttonNode->AddChild(symbolNode);
205 UpdateArrowContent();
206 }
207
TotalCount() const208 int32_t SwiperArrowPattern::TotalCount() const
209 {
210 auto swiperNode = GetSwiperNode();
211 CHECK_NULL_RETURN(swiperNode, 0);
212 auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
213 CHECK_NULL_RETURN(swiperPattern, 0);
214 return swiperPattern->RealTotalCount() - 1;
215 }
216
ButtonTouchEvent(RefPtr<FrameNode> buttonNode,TouchType touchType)217 void SwiperArrowPattern::ButtonTouchEvent(RefPtr<FrameNode> buttonNode, TouchType touchType)
218 {
219 auto swiperArrowLayoutProperty = GetSwiperArrowLayoutProperty();
220 CHECK_NULL_VOID(swiperArrowLayoutProperty);
221 const auto& renderContext = buttonNode->GetRenderContext();
222 CHECK_NULL_VOID(renderContext);
223 auto pipelineContext = PipelineBase::GetCurrentContext();
224 CHECK_NULL_VOID(pipelineContext);
225 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
226 CHECK_NULL_VOID(swiperIndicatorTheme);
227 Color backgroundColor;
228 RefPtr<FrameNode> symbolNode = DynamicCast<FrameNode>(buttonNode->GetFirstChild());
229 CHECK_NULL_VOID(symbolNode);
230 auto symbolLayoutProperty = symbolNode->GetLayoutProperty<TextLayoutProperty>();
231 CHECK_NULL_VOID(symbolLayoutProperty);
232 if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
233 isTouch_ = false;
234 if (isHover_) {
235 backgroundColor = swiperIndicatorTheme->GetHoverArrowBackgroundColor();
236 renderContext->ResetBlendBgColor();
237 renderContext->BlendBgColor(backgroundColor);
238 } else {
239 renderContext->ResetBlendBgColor();
240 }
241 }
242 if (!hoverOnClickFlag_ && swiperArrowLayoutProperty->GetHoverShowValue(false)) {
243 return;
244 }
245 if (touchType == TouchType::DOWN) {
246 isTouch_ = true;
247 if (isHover_) {
248 backgroundColor = swiperIndicatorTheme->GetHoverArrowBackgroundColor().BlendColor(
249 swiperIndicatorTheme->GetClickArrowBackgroundColor());
250 } else {
251 backgroundColor = swiperIndicatorTheme->GetClickArrowBackgroundColor();
252 }
253 renderContext->ResetBlendBgColor();
254 renderContext->BlendBgColor(backgroundColor);
255 auto symbolEffectOptions = symbolLayoutProperty->GetSymbolEffectOptionsValue(SymbolEffectOptions());
256 symbolEffectOptions.SetEffectType(SymbolEffectType::BOUNCE);
257 symbolEffectOptions.SetIsTxtActive(true);
258 symbolEffectOptions.SetIsTxtActiveSource(1);
259 symbolLayoutProperty->UpdateSymbolEffectOptions(symbolEffectOptions);
260 symbolNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
261 }
262 }
263
ButtonOnHover(RefPtr<FrameNode> buttonNode,bool isHovered)264 void SwiperArrowPattern::ButtonOnHover(RefPtr<FrameNode> buttonNode, bool isHovered)
265 {
266 hoverOnClickFlag_ = isHovered;
267 isHover_ = isHovered;
268 const auto& renderContext = buttonNode->GetRenderContext();
269 CHECK_NULL_VOID(renderContext);
270 auto pipelineContext = PipelineBase::GetCurrentContext();
271 CHECK_NULL_VOID(pipelineContext);
272 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
273 CHECK_NULL_VOID(swiperIndicatorTheme);
274 Color backgroundColor;
275
276 auto swiperNode = GetSwiperNode();
277 CHECK_NULL_VOID(swiperNode);
278 auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
279 CHECK_NULL_VOID(swiperPattern);
280 auto swiperLayoutProperty = swiperPattern->GetLayoutProperty<SwiperLayoutProperty>();
281 CHECK_NULL_VOID(swiperLayoutProperty);
282 if (swiperLayoutProperty->GetHoverShowValue(false)) {
283 swiperPattern->ArrowHover(isHover_);
284 }
285 if (isHovered) {
286 if (isTouch_) {
287 backgroundColor = swiperIndicatorTheme->GetHoverArrowBackgroundColor().BlendColor(
288 swiperIndicatorTheme->GetClickArrowBackgroundColor());
289 } else {
290 backgroundColor = swiperIndicatorTheme->GetHoverArrowBackgroundColor();
291 }
292 renderContext->ResetBlendBgColor();
293 renderContext->BlendBgColor(backgroundColor);
294 } else {
295 if (isTouch_) {
296 backgroundColor = swiperIndicatorTheme->GetClickArrowBackgroundColor();
297 renderContext->ResetBlendBgColor();
298 renderContext->BlendBgColor(backgroundColor);
299 } else {
300 renderContext->ResetBlendBgColor();
301 }
302 }
303 }
304
SetButtonVisible(bool visible)305 void SwiperArrowPattern::SetButtonVisible(bool visible)
306 {
307 isVisible_ = visible;
308 auto host = GetHost();
309 CHECK_NULL_VOID(host);
310 auto buttonNode = DynamicCast<FrameNode>(host->GetFirstChild());
311 CHECK_NULL_VOID(buttonNode);
312 auto buttonNodeGestureHub = buttonNode->GetOrCreateGestureEventHub();
313 CHECK_NULL_VOID(buttonNodeGestureHub);
314 const auto& renderContext = buttonNode->GetRenderContext();
315 CHECK_NULL_VOID(renderContext);
316 auto swiperArrowLayoutProperty = GetSwiperArrowLayoutProperty();
317 CHECK_NULL_VOID(swiperArrowLayoutProperty);
318 auto isHoverShow = swiperArrowLayoutProperty->GetHoverShowValue(false);
319 auto hostFocusHub = host->GetFocusHub();
320 CHECK_NULL_VOID(hostFocusHub);
321 auto swiperNode = GetSwiperNode();
322 CHECK_NULL_VOID(swiperNode);
323 auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
324 CHECK_NULL_VOID(swiperPattern);
325 auto leftIndex = 0;
326 auto rightIndex = swiperPattern->TotalCount() - swiperPattern->GetDisplayCount();
327 if (swiperPattern->IsHorizontalAndRightToLeft()) {
328 leftIndex = swiperPattern->TotalCount() - swiperPattern->GetDisplayCount();
329 rightIndex = 0;
330 }
331 if ((host->GetTag() == V2::SWIPER_LEFT_ARROW_ETS_TAG && index_ == leftIndex) ||
332 (host->GetTag() == V2::SWIPER_RIGHT_ARROW_ETS_TAG && index_ == rightIndex)) {
333 if (!swiperArrowLayoutProperty->GetLoopValue(true)) {
334 renderContext->SetVisible(false);
335 // Set hit test mode NONE to make sure button not respond to the touch events when invisible.
336 buttonNodeGestureHub->SetHitTestMode(HitTestMode::HTMNONE);
337 hostFocusHub->SetParentFocusable(false);
338 hostFocusHub->LostSelfFocus();
339 return;
340 }
341 }
342 if (isHoverShow) {
343 hostFocusHub->SetParentFocusable(false);
344 hostFocusHub->LostSelfFocus();
345 } else {
346 hostFocusHub->SetParentFocusable(true);
347 visible = true;
348 }
349 renderContext->SetVisible(visible);
350 // Set hit test mode BLOCK to make sure button respond to the touch events when visible.
351 buttonNodeGestureHub->SetHitTestMode(visible ? HitTestMode::HTMBLOCK : HitTestMode::HTMNONE);
352 }
353
UpdateArrowContent()354 void SwiperArrowPattern::UpdateArrowContent()
355 {
356 auto swiperArrowLayoutProperty = GetSwiperArrowLayoutProperty();
357 CHECK_NULL_VOID(swiperArrowLayoutProperty);
358 auto host = GetHost();
359 CHECK_NULL_VOID(host);
360 auto buttonNode = DynamicCast<FrameNode>(host->GetFirstChild());
361 CHECK_NULL_VOID(buttonNode);
362 buttonNode->GetRenderContext()->UpdateBackgroundColor(
363 swiperArrowLayoutProperty->GetIsShowBackgroundValue(false)
364 ? swiperArrowLayoutProperty->GetBackgroundColorValue(backgroundColor_)
365 : Color::TRANSPARENT);
366 auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
367 CHECK_NULL_VOID(buttonLayoutProperty);
368 buttonLayoutProperty->UpdateUserDefinedIdealSize(
369 CalcSize(CalcLength(swiperArrowLayoutProperty->GetBackgroundSizeValue()),
370 CalcLength(swiperArrowLayoutProperty->GetBackgroundSizeValue())));
371 backgroundColor_ = buttonNode->GetRenderContext()->GetBackgroundColorValue(Color::TRANSPARENT);
372 RefPtr<FrameNode> symbolNode = DynamicCast<FrameNode>(buttonNode->GetFirstChild());
373 CHECK_NULL_VOID(symbolNode);
374 auto symbolLayoutProperty = symbolNode->GetLayoutProperty<TextLayoutProperty>();
375 CHECK_NULL_VOID(symbolLayoutProperty);
376 auto swiperLayoutProperty = GetSwiperArrowLayoutProperty();
377 CHECK_NULL_VOID(swiperLayoutProperty);
378 auto pipelineContext = PipelineBase::GetCurrentContext();
379 CHECK_NULL_VOID(pipelineContext);
380 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
381 CHECK_NULL_VOID(swiperIndicatorTheme);
382 bool isRtl = swiperLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
383 if (V2::SWIPER_LEFT_ARROW_ETS_TAG == GetHost()->GetTag()) {
384 if (swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
385 symbolLayoutProperty->UpdateSymbolSourceInfo(SymbolSourceInfo(
386 isRtl ? swiperIndicatorTheme->GetRightSymbolId() : swiperIndicatorTheme->GetLeftSymbolId()));
387 } else {
388 symbolLayoutProperty->UpdateSymbolSourceInfo(SymbolSourceInfo(swiperIndicatorTheme->GetUpSymbolId()));
389 }
390 } else if (V2::SWIPER_RIGHT_ARROW_ETS_TAG == GetHost()->GetTag()) {
391 if (swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
392 symbolLayoutProperty->UpdateSymbolSourceInfo(SymbolSourceInfo(
393 isRtl ? swiperIndicatorTheme->GetLeftSymbolId() : swiperIndicatorTheme->GetRightSymbolId()));
394 } else {
395 symbolLayoutProperty->UpdateSymbolSourceInfo(SymbolSourceInfo(swiperIndicatorTheme->GetDownSymbolId()));
396 }
397 }
398 symbolLayoutProperty->UpdateFontSize(swiperArrowLayoutProperty->GetArrowSizeValue());
399 symbolLayoutProperty->UpdateSymbolColorList({ swiperArrowLayoutProperty->GetArrowColorValue() });
400 if (!swiperArrowLayoutProperty->GetEnabledValue(true)) {
401 buttonNode->GetRenderContext()->UpdateBackgroundColor(
402 backgroundColor_.BlendOpacity(swiperIndicatorTheme->GetArrowDisabledAlpha()));
403 symbolLayoutProperty->UpdateSymbolColorList({ swiperArrowLayoutProperty->GetArrowColorValue().BlendOpacity(
404 swiperIndicatorTheme->GetArrowDisabledAlpha()) });
405 }
406 symbolNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
407 symbolNode->MarkModifyDone();
408 }
409
DumpAdvanceInfo()410 void SwiperArrowPattern::DumpAdvanceInfo()
411 {
412 DumpLog::GetInstance().AddDesc("index:" + std::to_string(index_));
413 isTouch_ ? DumpLog::GetInstance().AddDesc("isTouch:true") : DumpLog::GetInstance().AddDesc("isTouch:false");
414 isHover_ ? DumpLog::GetInstance().AddDesc("isHover:true") : DumpLog::GetInstance().AddDesc("isHover:false");
415 hoverOnClickFlag_ ? DumpLog::GetInstance().AddDesc("hoverOnClickFlag:true")
416 : DumpLog::GetInstance().AddDesc("hoverOnClickFlag:false");
417 }
418 } // namespace OHOS::Ace::NG
419