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