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/picker/render_picker_base.h"
17 #include "core/components/picker/picker_date_component.h"
18 
19 #include <numeric>
20 
21 #include "base/log/event_report.h"
22 #include "core/components/picker/picker_time_component.h"
23 
24 namespace OHOS::Ace {
25 
TouchTest(const Point & globalPoint,const Point & parentLocalPoint,const TouchRestrict & touchRestrict,TouchTestResult & result)26 bool RenderPickerBase::TouchTest(const Point& globalPoint, const Point& parentLocalPoint,
27     const TouchRestrict& touchRestrict, TouchTestResult& result)
28 {
29     if (triangle_) {
30         Rect rect(triangle_->GetGlobalOffset(), triangle_->GetLayoutSize());
31         if (rect.IsInRegion(globalPoint) && GetDisableTouchEvent()) {
32             triangle_->OnTouchTestHit(Offset(), touchRestrict, result);
33             return true;
34         }
35     }
36 
37     if (lunarText_) {
38         Rect rect(lunarText_->GetGlobalOffset(), lunarText_->GetLayoutSize());
39         if (rect.IsInRegion(globalPoint) && switch_ && switch_->GetParent().Upgrade()) {
40             return onChildTouchTest(switch_, touchRestrict, result);
41         }
42     }
43 
44     if (data_->GetSubsidiary()) {
45         if (ok_) {
46             Rect rect(ok_->GetGlobalOffset(), ok_->GetLayoutSize());
47             if (rect.IsInRegion(globalPoint) && ok_->GetParent().Upgrade()) {
48                 return onChildTouchTest(ok_, touchRestrict, result);
49             }
50         }
51 
52         if (cancel_) {
53             Rect rect(cancel_->GetGlobalOffset(), cancel_->GetLayoutSize());
54             if (rect.IsInRegion(globalPoint) && cancel_->GetParent().Upgrade()) {
55                 return onChildTouchTest(cancel_, touchRestrict, result);
56             }
57         }
58 
59         if (columnParent_) {
60             Rect rect(columnParent_->GetGlobalOffset(), columnParent_->GetLayoutSize());
61             if (!rect.IsInRegion(globalPoint)) {
62                 return false;
63             }
64         }
65     }
66 
67     return RenderNode::TouchTest(globalPoint, parentLocalPoint, touchRestrict, result);
68 }
69 
onChildTouchTest(const RefPtr<RenderNode> & child,const TouchRestrict & touchRestrict,TouchTestResult & result)70 bool RenderPickerBase::onChildTouchTest(
71     const RefPtr<RenderNode>& child, const TouchRestrict& touchRestrict, TouchTestResult& result)
72 {
73     auto parent = child->GetParent().Upgrade();
74     Point global;
75     Point local;
76     auto size = child->GetLayoutSize();
77     global = global + child->GetGlobalOffset() + Offset(size.Width() / 2.0, size.Height() / 2.0);
78     local = global - parent->GetGlobalOffset();
79     return child->TouchTest(global, local, touchRestrict, result);
80 }
81 
Update(const RefPtr<Component> & component)82 void RenderPickerBase::Update(const RefPtr<Component>& component)
83 {
84     auto picker = AceType::DynamicCast<PickerBaseComponent>(component);
85     if (!picker) {
86         LOGE("input component is incorrect type or null.");
87         EventReport::SendRenderException(RenderExcepType::RENDER_COMPONENT_ERR);
88         return;
89     }
90 
91     auto textPicker = AceType::DynamicCast<PickerTextComponent>(component);
92     if (textPicker) {
93         selectedIndex_ = textPicker->GetSelected();
94         range_ = textPicker->GetRange();
95     }
96 
97     auto time = AceType::DynamicCast<PickerTimeComponent>(component);
98     if (time) {
99         type_ = "DatePickerType.Time";
100     } else {
101         type_ = "DatePickerType.Date";
102     }
103 
104     auto datePicker = AceType::DynamicCast<PickerDateComponent>(component);
105     if (datePicker) {
106         startDateSolar_ = datePicker->GetStartDate();
107         endDateSolar_ = datePicker->GetEndDate();
108         selectedDate_ = datePicker->GetSelectedDate();
109     }
110 
111     columnHeight_ = picker->GetColumnHeight();
112     data_ = picker;
113     SetInterceptTouchEvent(!data_->GetSubsidiary());
114     data_->OnColumnsCreating();
115     onCancelCallback_ = AceAsyncEvent<void()>::Create(data_->GetOnCancel(), context_);
116     onJSChangeCallback_ = AceAsyncEvent<void(const std::string&)>::Create(data_->GetOnChange(), context_);
117     onChangeCallback_ = AceSyncEvent<void(const std::shared_ptr<BaseEventInfo>&)>::
118         Create(data_->GetOnChange(), context_);
119     onColumnChangeCallback_ = AceAsyncEvent<void(const std::string&)>::Create(data_->GetOnColumnChange(), context_);
120     onDialogAccept_ = AceAsyncEvent<void(const std::string&)>::Create(data_->GetDialogAcceptEvent(), context_);
121     onDialogCancel_ = AceAsyncEvent<void()>::Create(data_->GetDialogCancelEvent(), context_);
122     onDialogChange_ = AceAsyncEvent<void(const std::string&)>::Create(data_->GetDialogChangeEvent(), context_);
123 
124     const auto context = context_.Upgrade();
125     if (context && context->GetIsDeclarative()) {
126         if (picker->GetOnTextCancel()) {
127             onTextCancel_ = *picker->GetOnTextCancel();
128         }
129         if (picker->GetOnTextAccept()) {
130             onTextAccept_ = *picker->GetOnTextAccept();
131         }
132         if (picker->GetOnTextChange()) {
133             onTextChange_ = *picker->GetOnTextChange();
134         }
135     }
136 
137     data_->SetFinishCallback([weak = WeakClaim(this)](bool success) {
138         auto refPtr = weak.Upgrade();
139         if (refPtr) {
140             refPtr->HandleFinish(success);
141         }
142     });
143     data_->SetChangeCallback([weak = WeakClaim(this)](const std::string& tag, bool add, uint32_t index, bool notify) {
144         auto refPtr = weak.Upgrade();
145         if (refPtr) {
146             refPtr->HandleColumnChange(tag, add, index, notify);
147         }
148     });
149     if (data_->GetIsDialog() || data_->GetIsCreateDialogComponent()) {
150         SetButtonHandler();
151     }
152     SetTextDirection(data_->GetTextDirection());
153     MarkNeedLayout();
154 
155     const auto& rotationController = picker->GetRotationController();
156     if (rotationController) {
157         auto weak = AceType::WeakClaim(this);
158         rotationController->SetRequestRotationImpl(weak, context_);
159     }
160 }
161 
SetButtonHandler()162 void RenderPickerBase::SetButtonHandler()
163 {
164     // RenderPicker may created for same component(when showing again),
165     // these event id may already bind, so remove first.
166     BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(data_->GetOnCancelClickId());
167     BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(data_->GetOnOkClickId());
168 
169     auto context = context_.Upgrade();
170     if (context->GetIsDeclarative()) {
171         BackEndEventManager<void(const ClickInfo& info)>::GetInstance().BindBackendEvent(
172             data_->GetOnCancelClickId(), [weak = WeakClaim(this)](const ClickInfo& info) {
173                 const auto& picker = weak.Upgrade();
174                 if (picker) {
175                     picker->HandleFinish(false);
176                 } else {
177                     LOGE("GetOnCancelClickId picker weak.Upgrade is null");
178                 }
179             });
180         BackEndEventManager<void(const ClickInfo& info)>::GetInstance().BindBackendEvent(
181             data_->GetOnOkClickId(), [weak = WeakClaim(this)](const ClickInfo& info) {
182                 const auto& picker = weak.Upgrade();
183                 if (picker) {
184                     picker->HandleFinish(true);
185                 } else {
186                     LOGE("GetOnOkClickId picker weak.Upgrade is null");
187                 }
188             });
189     } else {
190         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
191             data_->GetOnCancelClickId(), [weak = WeakClaim(this)]() {
192                 const auto& picker = weak.Upgrade();
193                 if (picker) {
194                     picker->HandleFinish(false);
195                 } else {
196                     LOGE("GetOnCancelClickId picker weak.Upgrade is null");
197                 }
198             });
199         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
200             data_->GetOnOkClickId(), [weak = WeakClaim(this)]() {
201                 const auto& picker = weak.Upgrade();
202                 if (picker) {
203                     picker->HandleFinish(true);
204                 } else {
205                     LOGE("GetOnOkClickId picker weak.Upgrade is null");
206                 }
207             });
208     }
209     auto cancelNode = data_->GetCancelAccessibility();
210     if (cancelNode) {
211         cancelNode->SetActionClickImpl([weakPtr = WeakClaim(this)]() {
212             const auto& picker = weakPtr.Upgrade();
213             if (picker) {
214                 picker->HandleFinish(false);
215             }
216         });
217     }
218     auto okNode = data_->GetOkAccessibility();
219     if (okNode) {
220         okNode->SetActionClickImpl([weakPtr = WeakClaim(this)]() {
221             const auto& picker = weakPtr.Upgrade();
222             if (picker) {
223                 picker->HandleFinish(true);
224             }
225         });
226     }
227 }
228 
HandleTriangleClick(bool value)229 void RenderPickerBase::HandleTriangleClick(bool value)
230 {
231     if (!data_) {
232         LOGE("data is null");
233         return;
234     }
235 
236     data_->OnTriangleCallback(value);
237     MarkNeedRender();
238 }
239 
SetTriangleHandler()240 void RenderPickerBase::SetTriangleHandler()
241 {
242     if (!triangle_ || triangle_->GetOnClick()) {
243         return;
244     }
245 
246     triangle_->SetOnClick([weak = WeakClaim(this)](bool value) {
247         auto refPtr = weak.Upgrade();
248         if (!refPtr) {
249             return;
250         }
251         refPtr->HandleTriangleClick(value);
252     });
253 }
254 
SetSwitchHandler()255 void RenderPickerBase::SetSwitchHandler()
256 {
257     if (switchHandlerSetted_) {
258         return;
259     }
260 
261     if (!switch_) {
262         LOGE("can not get switch button.");
263         return;
264     }
265 
266     auto switchNode = data_->GetSwitchAccessibility();
267     switch_->SetOnChange([weak = WeakClaim(this)](bool value) {
268         auto refPtr = weak.Upgrade();
269         if (!refPtr) {
270             return;
271         }
272         refPtr->HandleSwitch(value);
273         if (!refPtr->data_) {
274             return;
275         }
276         auto node = refPtr->data_->GetSwitchAccessibility();
277         auto pipeline = refPtr->context_.Upgrade();
278         if (node && pipeline && node->GetClicked()) {
279             node->SetClicked(false);
280             AccessibilityEvent clickEvent;
281             clickEvent.nodeId = node->GetNodeId();
282             clickEvent.eventType = "click";
283             pipeline->SendEventToAccessibility(clickEvent);
284         }
285     });
286 
287     if (switchNode && switch_) {
288         switchNode->SetActionClickImpl([weak = WeakClaim(this)]() {
289             auto refPtr = weak.Upgrade();
290             if (refPtr && refPtr->switch_) {
291                 refPtr->switch_->HandleClick();
292             }
293         });
294     }
295     switchHandlerSetted_ = true;
296 }
297 
PerformLayout()298 void RenderPickerBase::PerformLayout()
299 {
300     SetSwitchHandler();
301     SetTriangleHandler();
302 
303     if (!data_ || !outBox_) {
304         LOGE("data or out box is null.");
305         return;
306     }
307 
308     if (data_->GetIsDialog()) {
309         LayoutBoxes();
310         LayoutColumns();
311         SetLayoutSize(GetLayoutParam().GetMaxSize());
312         if (!hasLayout_) {
313             hasLayout_ = true;
314         }
315         return;
316     }
317 
318     double lunarHeight = 16.0; // use 16.0 not 0.0 for default
319     if (data_->GetHasLunar() && data_->GetTheme()) {
320         auto theme = data_->GetTheme();
321         lunarHeight = NormalizeToPx(theme->GetButtonTopPadding()) + NormalizeToPx(theme->GetLunarHeight());
322     }
323     for (const auto& column : columns_) {
324         column->SetAdjustHeight(lunarHeight);
325     }
326     outBox_->Layout(GetLayoutParam());
327     LayoutColumns();
328     SetLayoutSize(outBox_->GetLayoutSize());
329 }
330 
LayoutBoxes()331 void RenderPickerBase::LayoutBoxes()
332 {
333     if (!stack_ || !outBox_ || !box_ || !data_ || !data_->GetTheme()) {
334         LOGE("inner param invalidate.");
335         return;
336     }
337     auto theme = data_->GetTheme();
338     outBox_->Layout(LayoutParam());
339     SetOutBoxBorderRadius();
340     Size innerSize = box_->GetLayoutSize();
341     if (innerSize.Width() < NormalizeToPx(theme->GetButtonWidth()) * 2.0) { // ok width + cancel width
342         innerSize.SetWidth(NormalizeToPx(theme->GetButtonWidth()) * 2.0);   // ok width + cancel width
343     }
344     // the min size of pupup screen interval is 12.0 vp + 12.0 vp = 24.0 vp
345     if (innerSize.Width() + NormalizeToPx(24.0_vp) > stack_->GetLayoutSize().Width()) {
346         innerSize.SetWidth(stack_->GetLayoutSize().Width() - NormalizeToPx(24.0_vp));
347     }
348     LayoutParam layout;
349     layout.SetFixedSize(GetLayoutParam().GetMaxSize());
350     outBox_->Layout(layout);
351     double x = (outBox_->GetLayoutSize().Width() - innerSize.Width()) / 2.0; // place center
352     double y = 0.0;
353     auto deviceType = SystemProperties::GetDeviceType();
354     if (theme->GetShowButtons() && deviceType == DeviceType::PHONE) {
355         y = (outBox_->GetLayoutSize().Height() - innerSize.Height() -
356              NormalizeToPx(theme->GetButtonTopPadding())); // place bottom
357     } else {
358         y = (outBox_->GetLayoutSize().Height() - innerSize.Height()) / 2.0; // place center
359     }
360     box_->SetPosition(Offset(x, y));
361     layout.SetFixedSize(innerSize);
362     box_->Layout(layout);
363     if (data_->GetSubsidiary()) {
364         auto adjustHeight = NormalizeToPx(theme->GetColumnBottomTotalHeight(data_->GetMasterHasLunar()));
365         y -= adjustHeight;
366         auto outerSize = innerSize;
367         outerSize.AddHeight(adjustHeight);
368         layout.SetFixedSize(outerSize);
369         outBox_->SetPosition(Offset(x, y));
370         outBox_->Layout(layout);
371         double boxY = NormalizeToPx(theme->GetButtonHeight() + theme->GetButtonTopPadding());
372         if (data_->GetMasterHasLunar()) {
373             boxY += NormalizeToPx(theme->GetLunarHeight() + theme->GetButtonTopPadding());
374         }
375         box_->SetPosition(Offset(0.0, boxY));
376         layout.SetFixedSize(innerSize);
377         box_->Layout(layout);
378     }
379 }
380 
LayoutColumns()381 void RenderPickerBase::LayoutColumns()
382 {
383     if (!columnParent_ || columns_.empty() || !data_) {
384         LOGE("inner param invalidate.");
385         return;
386     }
387 
388     double totalWidth = columnParent_->GetLayoutSize().Width();
389     double totalHeight = columnParent_->GetLayoutSize().Height();
390     int32_t ratioCount = std::accumulate(columns_.begin(), columns_.end(), 0,
391         [](uint32_t sum, const RefPtr<RenderPickerColumn>& column) { return sum += column->GetWidthRatio(); });
392 
393     bool divideEvenly = SystemProperties::GetDeviceType() != DeviceType::PHONE || ratioCount == 0;
394     double oneWidth = divideEvenly ? totalWidth / columns_.size() : totalWidth / ratioCount;
395     double left = 0;
396     LayoutParam layout;
397     for (uint32_t index = 0; index < columns_.size(); ++index) {
398         uint32_t realIndex = 0;
399         if (data_->NeedRtlColumnOrder()) {
400             if (data_->GetTextDirection() == TextDirection::RTL) {
401                 realIndex = columns_.size() - 1 - index; // the last index is columns_.size() - 1
402             } else {
403                 realIndex = index;
404             }
405         } else {
406             realIndex = index;
407         }
408         columns_[realIndex]->SetPosition(Offset(left + columns_[realIndex]->GetXOffset(), 0.0));
409         double columnWidth = divideEvenly ? oneWidth : oneWidth * columns_[realIndex]->GetWidthRatio();
410         layout.SetFixedSize(Size(columnWidth, totalHeight));
411         columns_[realIndex]->Layout(layout);
412         left += columnWidth;
413     }
414 }
415 
SetOutBoxBorderRadius()416 void RenderPickerBase::SetOutBoxBorderRadius()
417 {
418     auto context = context_.Upgrade();
419     if (context && context->GetIsDeclarative()) {
420         auto decoration = outBox_->GetBackDecoration();
421         auto parent = outBox_->GetParent().Upgrade();
422         auto borderRadius = Radius();
423         while (parent) {
424             if (AceType::InstanceOf<RenderBox>(parent)) {
425                 auto boxParent = DynamicCast<RenderBox>(parent);
426                 borderRadius = boxParent->GetBackDecoration()->GetBorder().TopLeftRadius();
427                 break;
428             }
429             parent = parent->GetParent().Upgrade();
430         }
431         decoration->SetBorderRadius(borderRadius);
432         outBox_->SetBackDecoration(decoration);
433     }
434 }
435 
UpdateAccessibility()436 void RenderPickerBase::UpdateAccessibility()
437 {
438     if (!data_) {
439         LOGE("inner params of render picker base has error.");
440         return;
441     }
442 
443     auto titleNode = data_->GetTitleAccessibility();
444     if (titleNode && title_) {
445         UpdateTextAccessibility(titleNode, title_);
446     }
447 
448     auto lunarNode = data_->GetLunarAccessibility();
449     if (lunarNode && lunarText_) {
450         UpdateTextAccessibility(lunarNode, lunarText_);
451     }
452 
453     auto switchNode = data_->GetSwitchAccessibility();
454     if (switchNode && switch_) {
455         UpdateSwitchAccessibility(switchNode, switch_);
456     }
457 
458     auto cancelNode = data_->GetCancelAccessibility();
459     if (cancelNode && cancel_) {
460         UpdateButtonAccessibility(cancelNode, cancel_);
461     }
462 
463     auto okNode = data_->GetOkAccessibility();
464     if (okNode && ok_) {
465         UpdateButtonAccessibility(okNode, ok_);
466     }
467 
468 #if defined(PREVIEW)
469     auto pickerDialogNode = data_->GetPickerDialogAccessibility();
470     if (pickerDialogNode && box_) {
471         UpdatePickerDialogAccessibility(pickerDialogNode, box_);
472     }
473 #endif
474 }
475 
UpdateSwitchAccessibility(const RefPtr<AccessibilityNode> & node,const RefPtr<RenderCheckbox> & renderSwitch)476 void RenderPickerBase::UpdateSwitchAccessibility(
477     const RefPtr<AccessibilityNode>& node, const RefPtr<RenderCheckbox>& renderSwitch)
478 {
479     if (!node || !renderSwitch) {
480         return;
481     }
482     auto pipeline = context_.Upgrade();
483     if (!pipeline) {
484         return;
485     }
486     auto viewScale = pipeline->GetViewScale();
487     auto leftTop = renderSwitch->GetGlobalOffset();
488     node->SetLeft(leftTop.GetX() * viewScale);
489     node->SetTop(leftTop.GetY() * viewScale);
490     auto size = renderSwitch->GetLayoutSize();
491     node->SetWidth(size.Width() * viewScale);
492     node->SetHeight(size.Height() * viewScale);
493     node->SetCheckedState(renderSwitch->GetChecked());
494     if (lunarText_) {
495         node->SetText(lunarText_->GetTextData());
496     }
497     node->SetEnabledState(true);
498     node->SetCheckableState(true);
499     node->SetClickableState(true);
500     node->SetFocusableState(true);
501     node->AddSupportAction(AceAction::ACTION_CLICK);
502 }
503 
UpdatePickerDialogAccessibility(const RefPtr<AccessibilityNode> & node,const RefPtr<RenderBox> & box)504 void RenderPickerBase::UpdatePickerDialogAccessibility(
505     const RefPtr<AccessibilityNode>& node, const RefPtr<RenderBox>& box)
506 {
507     if (!node || !box) {
508         return;
509     }
510     auto pipeline = context_.Upgrade();
511     if (!pipeline) {
512         return;
513     }
514     auto viewScale = pipeline->GetViewScale();
515     auto leftTop = box->GetGlobalOffset();
516     node->SetLeft(leftTop.GetX() * viewScale);
517     node->SetTop(leftTop.GetY() * viewScale);
518     auto size = box->GetLayoutSize();
519     node->SetWidth(size.Width() * viewScale);
520     node->SetHeight(size.Height() * viewScale);
521 }
522 
UpdateTextAccessibility(const RefPtr<AccessibilityNode> & node,const RefPtr<RenderText> & text)523 void RenderPickerBase::UpdateTextAccessibility(const RefPtr<AccessibilityNode>& node, const RefPtr<RenderText>& text)
524 {
525     if (!node || !text) {
526         return;
527     }
528     auto pipeline = context_.Upgrade();
529     if (!pipeline) {
530         return;
531     }
532     auto viewScale = pipeline->GetViewScale();
533     auto leftTop = text->GetGlobalOffset();
534     node->SetLeft(leftTop.GetX() * viewScale);
535     node->SetTop(leftTop.GetY() * viewScale);
536     auto size = text->GetLayoutSize();
537     node->SetWidth(size.Width() * viewScale);
538     node->SetHeight(size.Height() * viewScale);
539     node->SetText(text->GetTextData());
540 }
541 
UpdateButtonAccessibility(const RefPtr<AccessibilityNode> & node,const RefPtr<RenderButton> & button)542 void RenderPickerBase::UpdateButtonAccessibility(
543     const RefPtr<AccessibilityNode>& node, const RefPtr<RenderButton>& button)
544 {
545     if (!node || !button) {
546         return;
547     }
548     auto pipeline = context_.Upgrade();
549     if (!pipeline) {
550         return;
551     }
552     auto viewScale = pipeline->GetViewScale();
553     auto leftTop = button->GetGlobalOffset();
554     node->SetLeft(leftTop.GetX() * viewScale);
555     node->SetTop(leftTop.GetY() * viewScale);
556     auto size = button->GetLayoutSize();
557     node->SetWidth(size.Width() * viewScale);
558     node->SetHeight(size.Height() * viewScale);
559     node->SetEnabledState(true);
560     node->SetClickableState(true);
561     node->SetFocusableState(true);
562     node->AddSupportAction(AceAction::ACTION_CLICK);
563     node->AddSupportAction(AceAction::ACTION_LONG_CLICK);
564 }
565 
HandleFinish(bool success)566 void RenderPickerBase::HandleFinish(bool success)
567 {
568     if (!data_) {
569         LOGE("data is null.");
570         return;
571     }
572 
573     if (data_->GetSubsidiary() && data_->GetAnimationController()) {
574         auto controller = data_->GetAnimationController();
575         controller->Play(false);
576         return;
577     }
578 
579     if (success) {
580         data_->OnSelectedSaving();
581     }
582 
583     if (success && onChangeCallback_) {
584         auto str = data_->GetSelectedObject(false, "");
585         onChangeCallback_(std::make_shared<DatePickerChangeEvent>(str));
586     }
587 
588     if (success && onJSChangeCallback_) {
589         onJSChangeCallback_(std::string("\"change\",") + data_->GetSelectedObject(false, "") + ",null");
590     }
591 
592     if (!success && onCancelCallback_) {
593         onCancelCallback_();
594     }
595 
596     if (onTextCancel_) {
597         onTextCancel_();
598     }
599 
600     if (data_->GetIsCreateDialogComponent()) {
601         if (success && onDialogAccept_) {
602             onDialogAccept_(std::string("\"change\",") + data_->GetSelectedObject(false, "") + ",null");
603         } else if (!success && onDialogCancel_) {
604             onDialogCancel_();
605         }
606     }
607     data_->HideDialog();
608 }
609 
HandleSwitch(bool checked)610 void RenderPickerBase::HandleSwitch(bool checked)
611 {
612     if (!data_) {
613         LOGE("data is null.");
614         return;
615     }
616 
617     std::vector<std::string> tags;
618     data_->OnLunarCallback(checked, tags);
619     for (const auto& tag : tags) {
620         auto iter = std::find_if(columns_.begin(), columns_.end(),
621             [&tag](const RefPtr<RenderPickerColumn>& column) { return column->GetColumnTag() == tag; });
622         if (iter != columns_.end()) {
623             (*iter)->FlushCurrentOptions();
624         }
625     }
626 }
627 
HandleColumnChange(const std::string & tag,bool isAdd,uint32_t index,bool needNotify)628 void RenderPickerBase::HandleColumnChange(const std::string& tag, bool isAdd, uint32_t index, bool needNotify)
629 {
630     if (!data_) {
631         LOGE("data is null.");
632         return;
633     }
634 
635     if (onColumnChangeCallback_ && needNotify) {
636         onColumnChangeCallback_(std::string("\"columnchange\",") + data_->GetSelectedObject(true, tag) + ",null");
637     }
638 
639     if (onTextAccept_) {
640         onTextAccept_(tag, index);
641     }
642 
643     std::vector<std::string> tags;
644     data_->OnDataLinking(tag, isAdd, index, tags);
645     for (const auto& tag : tags) {
646         auto iter = std::find_if(columns_.begin(), columns_.end(),
647             [&tag](const RefPtr<RenderPickerColumn>& column) { return column->GetColumnTag() == tag; });
648         if (iter != columns_.end()) {
649             (*iter)->FlushCurrentOptions();
650         }
651     }
652 
653     if (!data_->GetIsDialog() && !data_->GetIsCreateDialogComponent()) {
654         HandleFinish(true);
655         RefPtr<PickerColumnComponent> pickerColumn = data_->GetColumn(tag);
656         if (!pickerColumn) {
657             LOGE("pickerColumn Component is null");
658             return;
659         }
660         if (onTextChange_) {
661             onTextChange_(pickerColumn->GetCurrentText(), pickerColumn->GetCurrentIndex());
662         }
663         return;
664     }
665 
666     if (data_->GetIsCreateDialogComponent() && onDialogChange_) {
667         onDialogChange_(std::string("\"columnchange\",") + data_->GetSelectedObject(true, "") + ",null");
668     }
669 
670     data_->OnTitleBuilding();
671     auto titleComponent = data_->GetTitle();
672     if (data_->GetHasTitle()) {
673         if (title_ && titleComponent) {
674             title_->Update(titleComponent);
675         } else {
676             LOGE("render title or title component is null.");
677         }
678     }
679 }
680 
UpdateRenders()681 void RenderPickerBase::UpdateRenders()
682 {
683     ClearRenders();
684     GetRenders();
685     InitPickerAnimation();
686     switchHandlerSetted_ = false;
687 }
688 
GetRenders()689 void RenderPickerBase::GetRenders()
690 {
691     auto render = GetParent().Upgrade();
692     while (render && !AceType::InstanceOf<RenderStack>(render)) {
693         render = render->GetParent().Upgrade();
694     }
695     if (render) {
696         stack_ = AceType::DynamicCast<RenderStack>(render);
697     }
698     GetRenders(AceType::Claim(this));
699 }
700 
InitPickerAnimation()701 void RenderPickerBase::InitPickerAnimation()
702 {
703     if (!data_) {
704         LOGE("data is null for picker animation");
705         return;
706     }
707 
708     auto controller = data_->GetAnimationController();
709     if (!controller) {
710         LOGE("controller is null for picker animation.");
711         return;
712     }
713 
714     controller->SetPipeline(GetContext());
715     if (lunarDisplay_) {
716         controller->SetLunar(lunarDisplay_);
717     }
718     if (buttonsDisplay_) {
719         controller->SetButtons(buttonsDisplay_);
720     }
721     if (triangle_) {
722         controller->SetTriangle(triangle_);
723     }
724 
725     for (const auto& column : columns_) {
726         if (!column) {
727             continue;
728         }
729 
730         if (column->GetColumnTag() == PickerBaseComponent::PICKER_YEAR_COLUMN) {
731             controller->SetYear(column);
732         }
733         if (column->GetColumnTag() == PickerBaseComponent::PICKER_MONTH_COLUMN) {
734             controller->SetMonth(column);
735         }
736         if (column->GetColumnTag() == PickerBaseComponent::PICKER_DAY_COLUMN) {
737             controller->SetDay(column);
738         }
739         if (column->GetColumnTag() == PickerBaseComponent::PICKER_MONTHDAY_COLUMN) {
740             controller->SetMonthDay(column);
741         }
742         if (column->GetColumnTag() == PickerBaseComponent::PICKER_AMPM_COLUMN) {
743             controller->SetAmPm(column);
744         }
745         if (column->GetColumnTag() == PickerBaseComponent::PICKER_HOUR_COLUMN) {
746             controller->SetHour(column);
747         }
748         if (column->GetColumnTag() == PickerBaseComponent::PICKER_MINUTE_COLUMN) {
749             controller->SetMinute(column);
750         }
751         if (column->GetColumnTag() == PickerBaseComponent::PICKER_SECOND_COLUMN) {
752             controller->SetSecond(column);
753         }
754     }
755 }
756 
DealRenders(const RefPtr<RenderNode> & render)757 void RenderPickerBase::DealRenders(const RefPtr<RenderNode>& render)
758 {
759     if (AceType::InstanceOf<RenderDisplay>(render)) {
760         if (!buttonsDisplay_) {
761             buttonsDisplay_ = AceType::DynamicCast<RenderDisplay>(render);
762         } else {
763             auto temp = buttonsDisplay_;
764             buttonsDisplay_ = AceType::DynamicCast<RenderDisplay>(render);
765             lunarDisplay_ = temp;
766         }
767     }
768 
769     if (AceType::InstanceOf<RenderBox>(render)) {
770         auto parent = render->GetParent().Upgrade();
771         if (parent && AceType::InstanceOf<RenderPickerBase>(parent)) {
772             outBox_ = AceType::DynamicCast<RenderBox>(render);
773         }
774         if (parent && AceType::InstanceOf<RenderBox>(parent)) {
775             auto grand = parent->GetParent().Upgrade();
776             if (grand && AceType::InstanceOf<RenderPickerBase>(grand)) {
777                 box_ = AceType::DynamicCast<RenderBox>(render);
778             }
779         }
780     }
781 }
782 
GetRenders(const RefPtr<RenderNode> & render)783 void RenderPickerBase::GetRenders(const RefPtr<RenderNode>& render)
784 {
785     if (!render) {
786         return;
787     }
788 
789     if (AceType::InstanceOf<RenderTriangle>(render)) {
790         triangle_ = AceType::DynamicCast<RenderTriangle>(render);
791         return;
792     }
793 
794     if (AceType::InstanceOf<RenderCheckbox>(render)) {
795         switch_ = AceType::DynamicCast<RenderCheckbox>(render);
796         return;
797     }
798 
799     if (AceType::InstanceOf<RenderButton>(render)) {
800         auto gesture = AceType::DynamicCast<RenderButton>(render);
801         if (!cancel_ && !ok_) {
802             cancel_ = gesture;
803             return;
804         }
805         ok_ = gesture;
806         return;
807     }
808 
809     if (AceType::InstanceOf<RenderPickerColumn>(render)) {
810         auto column = AceType::DynamicCast<RenderPickerColumn>(render);
811         columns_.push_back(column);
812         if (!columnParent_ && column->GetParent().Upgrade()) {
813             columnParent_ = column->GetParent().Upgrade();
814         }
815         return;
816     }
817 
818     if (AceType::InstanceOf<RenderText>(render)) {
819         auto parent = render->GetParent().Upgrade();
820         if (parent && AceType::InstanceOf<RenderBox>(parent)) {
821             title_ = AceType::DynamicCast<RenderText>(render);
822             return;
823         }
824         if (parent && AceType::InstanceOf<RenderFlex>(parent)) {
825             lunarText_ = AceType::DynamicCast<RenderText>(render);
826             return;
827         }
828     }
829 
830     DealRenders(render);
831     for (const auto& child : render->GetChildren()) {
832 #if defined(PREVIEW)
833         child->SetAccessibilityNode(nullptr);
834 #endif
835         GetRenders(child);
836     }
837 }
838 
ClearRenders()839 void RenderPickerBase::ClearRenders()
840 {
841     title_ = nullptr;
842     triangle_ = nullptr;
843     lunarDisplay_ = nullptr;
844     buttonsDisplay_ = nullptr;
845     stack_ = nullptr;
846     box_ = nullptr;
847     outBox_ = nullptr;
848     cancel_ = nullptr;
849     ok_ = nullptr;
850     columns_.clear();
851     columnParent_ = nullptr;
852     switch_ = nullptr;
853     lunarText_ = nullptr;
854 }
855 
InitializeSelectedOption(const RefPtr<RenderPickerColumn> & pickerColumn)856 void RenderPickerBase::InitializeSelectedOption(const RefPtr<RenderPickerColumn>& pickerColumn)
857 {
858     for (const auto& option : pickerColumn->GetOptions()) {
859         if (!option->GetSelected()) {
860             continue;
861         }
862 
863         auto focusRenderBox = option->GetRenderBox();
864         if (!focusRenderBox) {
865             break;
866         }
867 
868         focusBoxSize_ = focusRenderBox->GetLayoutSize();
869         focusBoxOffset_ = focusRenderBox->GetGlobalOffset() - GetGlobalOffset();
870         break;
871     }
872 }
873 
GetBgColorBox() const874 const RefPtr<RenderBox> RenderPickerBase::GetBgColorBox() const
875 {
876     auto parent = GetParent().Upgrade();
877     while (parent && !parent->IsHeadRenderNode()) {
878         if (AceType::InstanceOf<RenderBox>(parent)) {
879             return AceType::DynamicCast<RenderBox>(parent);
880         }
881 
882         parent = parent->GetParent().Upgrade();
883     }
884 
885     if (AceType::InstanceOf<RenderBox>(parent)) {
886         return AceType::DynamicCast<RenderBox>(parent);
887     }
888 
889     return nullptr;
890 }
891 
892 } // namespace OHOS::Ace
893