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_v2/indexer/render_indexer.h"
17 
18 #include "base/log/event_report.h"
19 #include "core/components/arc/render_arc.h"
20 #include "core/components/text/render_text.h"
21 
22 namespace OHOS::Ace::V2 {
23 namespace {
24 constexpr Dimension FOCUS_PADDING = 2.0_vp;
25 constexpr int32_t PADDING_SIZE = 2;
26 } // namespace
27 
Create()28 RefPtr<RenderNode> RenderIndexer::Create()
29 {
30     return AceType::MakeRefPtr<RenderIndexer>();
31 }
32 
RenderIndexer()33 RenderIndexer::RenderIndexer()
34 {
35     touchRecognizer_ = AceType::MakeRefPtr<RawRecognizer>();
36     touchRecognizer_->SetOnTouchDown([wp = AceType::WeakClaim(this)](const TouchEventInfo& info) {
37         auto sp = wp.Upgrade();
38         if (sp) {
39             sp->HandleTouchDown(info);
40         }
41     });
42     touchRecognizer_->SetOnTouchUp([wp = AceType::WeakClaim(this)](const TouchEventInfo& info) {
43         auto sp = wp.Upgrade();
44         if (sp) {
45             sp->HandleTouchUp(info);
46         }
47     });
48     touchRecognizer_->SetOnTouchMove([wp = AceType::WeakClaim(this)](const TouchEventInfo& info) {
49         auto sp = wp.Upgrade();
50         if (sp) {
51             sp->HandleTouchMove(info);
52         }
53     });
54 }
55 
Update(const RefPtr<Component> & component)56 void RenderIndexer::Update(const RefPtr<Component>& component)
57 {
58     RefPtr<IndexerComponent> indexerComponent = AceType::DynamicCast<IndexerComponent>(component);
59     if (!indexerComponent) {
60         LOGE("[indexer] Update Get component failed");
61         EventReport::SendRenderException(RenderExcepType::RENDER_COMPONENT_ERR);
62         return;
63     }
64     nonItemCount_ = indexerComponent->GetNonItemCount();
65     bubbleEnabled_ = indexerComponent->IsBubbleEnabled();
66     popupListEnabled_ = indexerComponent->IsPopupListEnabled();
67     bubbleText_ = indexerComponent->GetBubbleTextComponent();
68     focusedItem_ = indexerComponent->GetSelectedIndex();
69     alignStyle_ = indexerComponent->GetAlignStyle();
70     color_ = indexerComponent->GetBubbleBackgroundColor();
71     valueArray_ = indexerComponent->GetLabel();
72 
73     // update item information
74     auto context = GetContext().Upgrade();
75     if (context) {
76         itemSize_ = context->NormalizeToPx(indexerComponent->GetItemSize());
77     }
78     itemSizeRender_ = itemSize_;
79     itemCount_ = indexerComponent->GetItemCount();
80     LOGI("[indexer] Init data, itemSizeRender_:%{public}lf, itemCount_:%{public}d", itemSizeRender_, itemCount_);
81 
82     if (IsValidBubbleBox() && !bubbleBox_->GetChildren().empty()) {
83         auto text = AceType::DynamicCast<RenderText>(bubbleBox_->GetChildren().front());
84         auto item = GetSpecificItem(focusedItem_);
85         if (bubbleText_ && text && item) {
86             bubbleText_->SetData(item->GetSectionText());
87             text->Update(bubbleText_);
88             text->PerformLayout();
89         }
90     }
91     MarkNeedLayout();
92     selectedEventFun_ = AceSyncEvent<void(const std::shared_ptr<IndexerEventInfo>&)>::
93         Create(indexerComponent->GetSelectedEvent(), context_);
94     requestPopupDataEventFun_ = indexerComponent->GetRequestPopupDataFunc();
95 }
96 
PerformLayout()97 void RenderIndexer::PerformLayout()
98 {
99     UpdateItems();
100     if (itemCount_ <= 0) {
101         SetLayoutSize(Size());
102         return;
103     }
104 
105     // calculate self and children size,
106     if (NearZero(itemSize_)) {
107         LOGE("[indexer] Invalid Item size:%{public}lf", itemSize_);
108         return;
109     }
110 
111     // calculate the size of the items
112     const LayoutParam& layoutSetByParent = GetLayoutParam();
113     Size sizeMax = layoutSetByParent.GetMaxSize();
114     if (LessOrEqual(paddingY_ * DOUBLE + itemCount_ * itemSize_, sizeMax.Height())) {
115         itemSizeRender_ = itemSize_;
116     } else {
117         itemSizeRender_ = (sizeMax.Height() - paddingY_ * DOUBLE) / itemCount_;
118     }
119 
120     InitFocusedItem();
121     LayoutParam childrenLayout;
122     childrenLayout.SetMinSize(Size(0.0, 0.0));
123     for (const auto& item : GetChildren()) {
124         item->Layout(childrenLayout);
125     }
126 
127     // then set the position of children
128     Offset position;
129     int32_t count = 0;
130     for (const auto& item : GetChildren()) {
131         if (!AceType::InstanceOf<RenderIndexerItem>(item)) {
132             continue;
133         }
134         position.SetX(paddingX_);
135         position.SetY(paddingY_ + count * itemSizeRender_);
136         item->SetPosition(position);
137         count++;
138     }
139 
140     double indexerWidth = paddingX_ + itemSizeRender_ + paddingX_;
141     double indexerHeight = paddingY_ + count * itemSizeRender_ + paddingY_;
142     SetLayoutSize(Size(indexerWidth, indexerHeight));
143     // layout bubble and popup list.
144     LayoutPopup();
145 }
146 
UpdateItems()147 void RenderIndexer::UpdateItems()
148 {
149     if (nonItemCount_ + static_cast<int32_t>(items_.size()) == static_cast<int32_t>(GetChildren().size())) {
150         LOGI("[indexer] no need update Items");
151         return;
152     }
153     items_.clear();
154     for (auto item : GetChildren()) {
155         if (AceType::InstanceOf<RenderIndexerItem>(item)) {
156             items_.push_back(item);
157         }
158     }
159     LOGI("[indexer] items nums : %{public}d", static_cast<int32_t>(items_.size()));
160 }
161 
InitFocusedItem()162 void RenderIndexer::InitFocusedItem()
163 {
164     for (auto item : items_) {
165         RefPtr<RenderIndexerItem> indexerItem = AceType::DynamicCast<RenderIndexerItem>(item);
166         if (indexerItem) {
167             indexerItem->SetClicked(false);
168         }
169     }
170 
171     if (focusedItem_ >= 0) {
172         auto item = GetSpecificItem(focusedItem_);
173         if (item) {
174             item->SetClicked(true);
175         }
176     }
177 }
178 
LayoutPopup()179 void RenderIndexer::LayoutPopup()
180 {
181     if (IsValidBubbleBox()) {
182         Offset bubblePosition;
183         if (alignStyle_ == AlignStyle::RIGHT) {
184             bubblePosition.SetX(NormalizeToPx(-BUBBLE_POSITION_X) - bubbleDisplay_->GetLayoutSize().Width());
185             bubblePosition.SetY(NormalizeToPx(BUBBLE_POSITION_Y));
186         } else {
187             bubblePosition.SetX(NormalizeToPx(BUBBLE_POSITION_X) + GetLayoutSize().Width());
188             bubblePosition.SetY(NormalizeToPx(BUBBLE_POSITION_Y));
189         }
190 
191         bubbleDisplay_->SetPosition(bubblePosition);
192 #ifdef ENABLE_ROSEN_BACKEND
193         bubbleDisplay_->SetPaintOutOfParent(true);
194 #endif
195     }
196 
197     if (IsValidPopupList()) {
198         Offset popupPosition;
199         popupPosition.SetX(bubbleDisplay_->GetPosition().GetX());
200         popupPosition.SetY(bubbleDisplay_->GetPosition().GetY() + bubbleDisplay_->GetLayoutSize().Height());
201         popupListDisplay_->SetPosition(popupPosition);
202 #ifdef ENABLE_ROSEN_BACKEND
203         popupListDisplay_->SetPaintOutOfParent(true);
204 #endif
205     }
206 }
207 
HandleTouchDown(const TouchEventInfo & info)208 void RenderIndexer::HandleTouchDown(const TouchEventInfo& info)
209 {
210     if (touchBubbleDisplay || touchPopupListDisplay) {
211         LOGI("touch down bubble or popup list.");
212         if (IsValidBubbleBox()) {
213             bubbleDisplay_->UpdateOpacity(DEFAULT_OPACITY);
214         }
215 
216         if (IsValidPopupList()) {
217             popupListDisplay_->UpdateOpacity(DEFAULT_OPACITY);
218         }
219 
220         if (bubbleController_) {
221             bubbleController_->Pause();
222         }
223         return;
224     }
225 
226     if (info.GetTouches().empty()) {
227         return;
228     }
229 
230     touchPostion_ = info.GetTouches().front().GetLocalLocation();
231     LOGI("[indexer] item is HandleTouchDown x:%{public}lf, y:%{public}lf", touchPostion_.GetX(), touchPostion_.GetY());
232     HandleTouched(touchPostion_);
233     clicked_ = true;
234 
235     MarkNeedLayout();
236 }
237 
HandleTouchUp(const TouchEventInfo & info)238 void RenderIndexer::HandleTouchUp(const TouchEventInfo& info)
239 {
240     if ((touchBubbleDisplay || touchPopupListDisplay) && bubbleController_) {
241         LOGI("touch up bubble or popup list.");
242         bubbleController_->UpdatePlayedTime(0);
243         bubbleController_->Resume();
244         return;
245     }
246 
247     if (info.GetTouches().empty()) {
248         return;
249     }
250 
251     touchPostion_ = info.GetTouches().front().GetLocalLocation();
252     LOGI("[indexer] item is HandleTouchUp x:%{public}lf, y:%{public}lf", touchPostion_.GetX(), touchPostion_.GetY());
253     HandleTouched(touchPostion_);
254     if (clicked_) {
255         clicked_ = false;
256         MarkNeedLayout();
257     }
258 }
259 
HandleTouchMove(const TouchEventInfo & info)260 void RenderIndexer::HandleTouchMove(const TouchEventInfo& info)
261 {
262     if (touchBubbleDisplay || touchPopupListDisplay) {
263         return;
264     }
265 
266     if (info.GetTouches().empty()) {
267         return;
268     }
269 
270     touchPostion_ = info.GetTouches().front().GetLocalLocation();
271     LOGI("[indexer] item is HandleTouchMove x:%{public}lf, y:%{public}lf", touchPostion_.GetX(), touchPostion_.GetY());
272     HandleTouched(touchPostion_);
273     if (clicked_) {
274         clicked_ = true;
275         MarkNeedLayout();
276     }
277 }
278 
TouchTest(const Point & globalPoint,const Point & parentLocalPoint,const TouchRestrict & touchRestrict,TouchTestResult & result)279 bool RenderIndexer::TouchTest(const Point& globalPoint, const Point& parentLocalPoint,
280     const TouchRestrict& touchRestrict, TouchTestResult& result)
281 {
282     if (GetDisableTouchEvent() || disabled_) {
283         return false;
284     }
285     auto focusedNode = GetSpecificItem(focusedItem_);
286     if (focusedNode) {
287         focusedNode->SetFocused(false);
288     }
289 
290     // reset touch flag
291     touchBubbleDisplay = false;
292     touchPopupListDisplay = false;
293     Rect bubbleRect;
294     Rect popupListRect;
295 
296     auto isBubbleRect = GetBubbleRect(bubbleRect);
297     if (!isBubbleRect) {
298         LOGW("bubble rect wrong.");
299     }
300 
301     auto isPopupListRect = GetPopupListRect(popupListRect);
302     if (!isPopupListRect) {
303         LOGW("popup list rect wrong.");
304     }
305 
306     // Since the paintRect is relative to parent, use parent local point to perform touch test.
307     if (GetPaintRect().IsInRegion(parentLocalPoint)) {
308         LOGI("touch in indexer");
309 
310         // Calculates the local point location and coordinate offset in this node.
311         const auto localPoint = parentLocalPoint - GetPaintRect().GetOffset();
312         const auto coordinateOffset = globalPoint - localPoint;
313         globalPoint_ = globalPoint;
314         OnTouchTestHit(coordinateOffset, touchRestrict, result);
315         return true;
316     } else if (isBubbleRect && bubbleRect.IsInRegion(globalPoint)) {
317         LOGI("touch in bubble display");
318         touchBubbleDisplay = true;
319 
320         // Calculates the local point location and coordinate offset in bubble.
321         const auto localPoint = parentLocalPoint - GetPaintRect().GetOffset();
322         const auto coordinateOffset = globalPoint - localPoint;
323         globalPoint_ = globalPoint;
324         OnTouchTestHit(coordinateOffset, touchRestrict, result);
325         return RenderNode::TouchTest(globalPoint, parentLocalPoint, touchRestrict, result);
326     } else if (isPopupListRect && popupListRect.IsInRegion(globalPoint)) {
327         LOGI("touch in popupList display");
328         touchPopupListDisplay = true;
329 
330         // Calculates the local point location and coordinate offset in bubble.
331         const auto localPoint = parentLocalPoint - GetPaintRect().GetOffset();
332         const auto coordinateOffset = globalPoint - localPoint;
333         globalPoint_ = globalPoint;
334         OnTouchTestHit(coordinateOffset, touchRestrict, result);
335         return RenderNode::TouchTest(globalPoint, parentLocalPoint, touchRestrict, result);
336     } else {
337         LOGI("touch in other display");
338         if (IsValidBubbleBox() && bubbleController_ && bubbleController_->IsRunning()) {
339             bubbleController_->Finish();
340         }
341     }
342     return false;
343 }
344 
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)345 void RenderIndexer::OnTouchTestHit(
346     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
347 {
348     if (touchRecognizer_) {
349         touchRecognizer_->SetCoordinateOffset(coordinateOffset);
350         result.emplace_back(touchRecognizer_);
351     }
352 }
353 
HandleTouched(const Offset & touchPosition)354 void RenderIndexer::HandleTouched(const Offset& touchPosition)
355 {
356     int32_t index = GetTouchedItemIndex(touchPosition);
357     if (index > -1) {
358         MoveSectionWithIndexer(index);
359     }
360 }
361 
GetTouchedItemIndex(const Offset & touchPosition)362 int32_t RenderIndexer::GetTouchedItemIndex(const Offset& touchPosition)
363 {
364     double position = touchPosition.GetY();
365     if (position < paddingY_) {
366         return -1;
367     }
368 
369     if (NearZero(itemSizeRender_)) {
370         LOGE("[indexer] Invalid Item size:%{public}lf", itemSizeRender_);
371         return -1;
372     }
373 
374     int32_t index = static_cast<int32_t>((position - paddingY_) / itemSizeRender_);
375     LOGI("[indexer] GetTouchedItemIndex section index:%{public}d", index);
376     return GetItemIndex(index);
377 }
378 
UpdateBubbleText()379 void RenderIndexer::UpdateBubbleText()
380 {
381     if (IsValidBubbleBox() && !bubbleBox_->GetChildren().empty()) {
382         // update bubble border
383         RefPtr<Decoration> decoration = bubbleBox_->GetBackDecoration();
384         Border border = decoration->GetBorder();
385         Radius radius;
386         if (popupListEnabled_) {
387             radius = Radius(Dimension(ZERO_RADIUS, DimensionUnit::VP));
388         } else {
389             radius = Radius(Dimension(BUBBLE_BOX_RADIUS, DimensionUnit::VP));
390         }
391         border.SetBottomLeftRadius(radius);
392         border.SetBottomRightRadius(radius);
393         decoration->SetBorder(border);
394 
395         auto text = AceType::DynamicCast<RenderText>(bubbleBox_->GetChildren().front());
396         auto item = GetSpecificItem(focusedItem_);
397         if (bubbleText_ && text && item) {
398             bubbleText_->SetData(item->GetSectionText());
399             text->Update(bubbleText_);
400             text->PerformLayout();
401             BeginBubbleAnimation();
402         }
403     }
404 }
405 
BuildBubbleAnimation()406 void RenderIndexer::BuildBubbleAnimation()
407 {
408     if (!IsValidBubbleBox()) {
409         LOGI("bubble box is invalid");
410         return;
411     }
412     if (!bubbleController_) {
413         bubbleController_ = CREATE_ANIMATOR(GetContext());
414     }
415     bubbleController_->ClearInterpolators();
416     bubbleController_->ClearAllListeners();
417     auto weak = AceType::WeakClaim(this);
418     bubbleController_->AddStopListener([weak]() {
419         auto indexer = weak.Upgrade();
420         if (!indexer) {
421             return;
422         }
423 
424         if (indexer->IsValidBubbleBox()) {
425             indexer->bubbleDisplay_->UpdateOpacity(ZERO_OPACITY);
426         }
427 
428         if (indexer->IsValidPopupList()) {
429             indexer->popupListDisplay_->UpdateOpacity(ZERO_OPACITY);
430         }
431     });
432 
433     // build and start animation
434     auto animation = AceType::MakeRefPtr<KeyframeAnimation<uint8_t>>();
435     auto startFrame = AceType::MakeRefPtr<Keyframe<uint8_t>>(KEYFRAME_BEGIN, DEFAULT_OPACITY);
436     auto midFrame = AceType::MakeRefPtr<Keyframe<uint8_t>>(KEYFRAME_HALF, DEFAULT_OPACITY);
437     auto endFrame = AceType::MakeRefPtr<Keyframe<uint8_t>>(KEYFRAME_END, ZERO_OPACITY);
438     midFrame->SetCurve(Curves::DECELE);
439     endFrame->SetCurve(Curves::DECELE);
440     animation->AddKeyframe(startFrame);
441     animation->AddKeyframe(midFrame);
442     animation->AddKeyframe(endFrame);
443     animation->AddListener([weak](uint8_t value) {
444         auto indexer = weak.Upgrade();
445         if (!indexer) {
446             LOGW("indexer error %s", AceType::TypeName(indexer));
447             return;
448         }
449 
450         if (indexer->IsValidBubbleBox()) {
451             indexer->bubbleDisplay_->UpdateOpacity(value);
452         }
453 
454         // add popup list animation
455         if (indexer->IsValidPopupList()) {
456             indexer->popupListDisplay_->UpdateOpacity(value);
457         }
458     });
459 
460     bubbleController_->AddInterpolator(animation);
461     bubbleController_->SetDuration(INDEXER_BUBBLE_ANIMATION_DURATION);
462 }
463 
BeginBubbleAnimation()464 void RenderIndexer::BeginBubbleAnimation()
465 {
466     if (!IsValidBubbleBox()) {
467         LOGI("bubble box is invalid");
468         return;
469     }
470     if (!bubbleController_) {
471         BuildBubbleAnimation();
472     }
473     if (bubbleController_->IsRunning()) {
474         bubbleController_->Finish();
475     }
476     bubbleController_->Play();
477 }
478 
IsValidBubbleBox()479 bool RenderIndexer::IsValidBubbleBox()
480 {
481     if (!bubbleEnabled_ || GetChildren().empty()) {
482         return false;
483     }
484     if (!bubbleDisplay_) {
485         bubbleDisplay_ = AceType::DynamicCast<RenderDisplay>(GetChildren().front());
486         if (!bubbleDisplay_ || bubbleDisplay_->GetChildren().empty()) {
487             return false;
488         }
489         bubbleBox_ = AceType::DynamicCast<RenderBox>(bubbleDisplay_->GetChildren().front());
490         if (!bubbleBox_) {
491             return false;
492         }
493     }
494     return true;
495 }
496 
IsValidPopupList()497 bool RenderIndexer::IsValidPopupList()
498 {
499     if (!bubbleEnabled_ || !popupListEnabled_ || GetChildren().empty()) {
500         return false;
501     }
502     if (!popupListDisplay_) {
503         popupListDisplay_ = AceType::DynamicCast<RenderDisplay>(GetChildren().back());
504         if (!popupListDisplay_ || popupListDisplay_->GetChildren().empty()) {
505             return false;
506         }
507         popupList_ = AceType::DynamicCast<RenderPopupList>(popupListDisplay_->GetChildren().front());
508         if (!popupList_) {
509             return false;
510         }
511     }
512     return true;
513 }
514 
GetItemIndex(int32_t index)515 int32_t RenderIndexer::GetItemIndex(int32_t index)
516 {
517     if (items_.empty()) {
518         return -1;
519     }
520     int32_t itemIndexInList = -1;
521     RefPtr<RenderNode> itemNode;
522     auto iter = items_.begin();
523     std::advance(iter, index);
524     if (iter == items_.end()) {
525         itemNode = items_.back();
526     } else {
527         itemNode = *iter;
528     }
529     RefPtr<RenderIndexerItem> indexerItem = AceType::DynamicCast<RenderIndexerItem>(itemNode);
530     if (indexerItem) {
531         itemIndexInList = indexerItem->GetSectionIndex();
532     }
533     LOGI("[indexer] GetItemIndex index:%{public}d indexInList:%{public}d", index, itemIndexInList);
534     return itemIndexInList;
535 }
536 
HandleFocusAnimation(const Size & size,const Offset & offset)537 void RenderIndexer::HandleFocusAnimation(const Size& size, const Offset& offset)
538 {
539     auto context = context_.Upgrade();
540     if (!context) {
541         LOGE("Pipeline context upgrade fail!");
542         return;
543     }
544     if (!context->GetRenderFocusAnimation()) {
545         LOGE("focusAnimation is null!");
546         return;
547     }
548 
549     double focusPadding = NormalizeToPx(FOCUS_PADDING);
550     context->ShowFocusAnimation(RRect::MakeRRect(Rect(Offset(), size - Size(focusPadding, focusPadding) * PADDING_SIZE),
551         focusPadding, focusPadding),
552         Color::BLUE, offset + Offset(focusPadding, focusPadding));
553 }
554 
MoveSectionWithIndexer(int32_t curSection)555 void RenderIndexer::MoveSectionWithIndexer(int32_t curSection)
556 {
557     if (focusedItem_ == curSection) {
558         LOGI("Current focused item already is:%{public}d", curSection);
559 
560         // click the same letter multiple times.
561         if (bubbleController_ && !bubbleController_->IsRunning()) {
562             bubbleController_->Play();
563         }
564         return;
565     }
566 
567     RefPtr<RenderIndexerItem> curItem = GetSpecificItem(curSection);
568     if (!curItem || !NeedProcess(curItem)) {
569         LOGW("[indexer] invalid indexer item");
570         return;
571     }
572 
573     // change to correct index
574     BeginFocusAnimation(focusedItem_, curSection);
575     curItem->SetClicked(true); // Make cur clicked item focus.
576     UpdateCurrentSectionItem(curSection);
577 
578     // Make pre focused item blur.
579     RefPtr<RenderIndexerItem> preItem = GetSpecificItem(focusedItem_);
580     if (preItem) {
581         preItem->SetClicked(false);
582     }
583     focusedItem_ = curSection;
584     MoveList(curItem->GetSectionIndex());
585     UpdateBubbleText();
586 }
587 
MoveList(int32_t index)588 void RenderIndexer::MoveList(int32_t index)
589 {
590     if (index < 0) {
591         LOGE("[indexer] invalid item indexer");
592         return;
593     }
594 
595     // trigger onSelected Method
596     OnSelected(index);
597 
598     // trigger onRequestPopupData Method
599     OnRequestPopupData(index);
600 }
601 
GetSpecificItem(int32_t index) const602 RefPtr<RenderIndexerItem> RenderIndexer::GetSpecificItem(int32_t index) const
603 {
604     auto iter = items_.begin();
605     std::advance(iter, index);
606     if (iter != items_.end()) {
607         return AceType::DynamicCast<RenderIndexerItem>(*iter);
608     }
609     return nullptr;
610 }
611 
OnSelected(int32_t selected) const612 void RenderIndexer::OnSelected(int32_t selected) const
613 {
614     if (selectedEventFun_) {
615         auto event = std::make_shared<IndexerEventInfo>(selected);
616         if (event) {
617             selectedEventFun_(event);
618         }
619     }
620 }
621 
OnRequestPopupData(int32_t selected)622 void RenderIndexer::OnRequestPopupData(int32_t selected)
623 {
624     if (requestPopupDataEventFun_) {
625         auto event = std::make_shared<IndexerEventInfo>(selected);
626         if (event) {
627             auto popupData = requestPopupDataEventFun_(event);
628             if (popupList_) {
629                 popupList_->OnRequestPopupDataSelected(popupData);
630             }
631 
632             // switch bubble style
633             if (popupData.size() == 0) {
634                 popupListEnabled_ = false;
635             } else {
636                 popupListEnabled_ = true;
637             }
638         }
639     }
640 }
641 
GetBubbleRect(Rect & rect)642 bool RenderIndexer::GetBubbleRect(Rect& rect)
643 {
644     if (!IsValidBubbleBox()) {
645         return false;
646     }
647 
648     Offset bubbleOffset = bubbleDisplay_->GetGlobalOffset();
649     Size bubbleSize = bubbleDisplay_->GetLayoutSize();
650 
651     rect.SetOffset(bubbleOffset);
652     rect.SetSize(bubbleSize);
653     return true;
654 }
655 
GetPopupListRect(Rect & rect)656 bool RenderIndexer::GetPopupListRect(Rect& rect)
657 {
658     if (!IsValidPopupList()) {
659         return false;
660     }
661     Offset popupListOffset = popupListDisplay_->GetGlobalOffset();
662     Size popupListSize = popupListDisplay_->GetLayoutSize();
663 
664     rect.SetOffset(popupListOffset);
665     rect.SetSize(popupListSize);
666     return true;
667 }
668 } // namespace OHOS::Ace::V2
669