• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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/calendar/calendar_month_pattern.h"
17 
18 #include "base/geometry/offset.h"
19 #include "base/i18n/localization.h"
20 #include "base/utils/utils.h"
21 #include "core/common/ace_application_info.h"
22 #include "core/components_ng/base/frame_node.h"
23 #include "core/components_ng/pattern/button/button_layout_property.h"
24 #include "core/components_ng/pattern/button/button_pattern.h"
25 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
26 #include "core/components_ng/pattern/calendar/calendar_paint_method.h"
27 #include "core/components_ng/pattern/calendar_picker/calendar_dialog_view.h"
28 #include "core/components/slider/slider_theme.h"
29 #include "core/pipeline_ng/pipeline_context.h"
30 
31 namespace OHOS::Ace::NG {
32 namespace {
33 constexpr int32_t CALENDAR_WEEK_DAYS = 7;
34 constexpr int32_t DAILY_FOUR_ROWSPACE = 4;
35 constexpr int32_t DAILY_FIVE_ROWSPACE = 5;
36 constexpr int32_t CALENDAR_DISTANCE_ADJUST_FOCUSED_SIZE = 2;
37 constexpr Dimension CALENDAR_DISTANCE_ADJUST_FOCUSED_EVENT = 4.0_vp;
38 constexpr int32_t MONDAY_INDEX = 1;
39 constexpr int32_t TUESDAY_INDEX = 2;
40 constexpr int32_t WEDNESDAY_INDEX = 3;
41 constexpr int32_t THURSDAY_INDEX = 4;
42 constexpr int32_t FRIDAY_INDEX = 5;
43 constexpr int32_t SATURDAY_INDEX = 6;
44 constexpr int32_t WEEK_ROW_INDEX = 1;
45 } // namespace
46 
CreateNodePaintMethod()47 RefPtr<NodePaintMethod> CalendarMonthPattern::CreateNodePaintMethod()
48 {
49     if (AceApplicationInfo::GetInstance().IsAccessibilityEnabled()) {
50         InitCurrentVirtualNode();
51     }
52     CalendarPaintParams params;
53     params.startDate = startDate_;
54     params.endDate = endDate_;
55     params.markToday = markToday_;
56     params.disabledDateRange = disabledDateRange_;
57     return MakeRefPtr<CalendarPaintMethod>(obtainedMonth_, calendarDay_, params, isCalendarDialog_);
58 }
59 
SetCalendarDay(const CalendarDay & calendarDay)60 void CalendarMonthPattern::SetCalendarDay(const CalendarDay& calendarDay)
61 {
62     calendarDay_ = calendarDay;
63     if (monthState_ == MonthState::CUR_MONTH && !obtainedMonth_.days.empty()) {
64         for (auto& day : obtainedMonth_.days) {
65             if (day.month.year == calendarDay.month.year && day.month.month == calendarDay.month.month &&
66                 day.day == calendarDay.day) {
67                 day.focused = true;
68             }
69         }
70     }
71 }
72 
InitFoldState()73 void CalendarMonthPattern::InitFoldState()
74 {
75     auto container = Container::Current();
76     CHECK_NULL_VOID(container);
77     container->InitIsFoldable();
78     if (container->IsFoldable()) {
79         currentFoldStatus_ = container->GetCurrentFoldStatus();
80     }
81 }
82 
FireIsFoldStatusChanged()83 void CalendarMonthPattern::FireIsFoldStatusChanged()
84 {
85     auto container = Container::Current();
86     CHECK_NULL_VOID(container);
87     if (!container->IsFoldable()) {
88         return;
89     }
90     auto foldStatus = container->GetCurrentFoldStatus();
91     auto host = GetHost();
92     CHECK_NULL_VOID(host);
93     auto paintProperty = host->GetPaintProperty<CalendarPaintProperty>();
94     CHECK_NULL_VOID(paintProperty);
95     auto colSpace = paintProperty->GetColSpaceValue({}).ConvertToPx();
96     if (foldStatus != currentFoldStatus_ && colSpace_ != colSpace && monthState_ == MonthState::CUR_MONTH) {
97         currentFoldStatus_ = foldStatus;
98         InitCalendarVirtualNode();
99         SetFocusNode(focusedCalendarDay_.index, true);
100     }
101 }
102 
OnAttachToFrameNode()103 void CalendarMonthPattern::OnAttachToFrameNode()
104 {
105     auto host = GetHost();
106     CHECK_NULL_VOID(host);
107     host->GetRenderContext()->SetClipToFrame(true);
108     InitFoldState();
109 }
110 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)111 bool CalendarMonthPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
112 {
113     if (IsCalendarDialog()) {
114         SetColRowSpace();
115     }
116 
117     return !(config.skipMeasure || dirty->SkipMeasureContent());
118 }
119 
~CalendarMonthPattern()120 CalendarMonthPattern::~CalendarMonthPattern()
121 {
122     auto host = GetHost();
123     CHECK_NULL_VOID(host);
124     auto pipeline = host->GetContext();
125     CHECK_NULL_VOID(pipeline);
126     auto accessibilityManager = pipeline->GetAccessibilityManager();
127     CHECK_NULL_VOID(accessibilityManager);
128     accessibilityManager->DeregisterAccessibilitySAObserverCallback(host->GetAccessibilityId());
129 }
130 
GetDaySize(const RefPtr<CalendarTheme> & theme)131 Dimension CalendarMonthPattern::GetDaySize(const RefPtr<CalendarTheme>& theme)
132 {
133     auto pipeline = GetHost()->GetContext();
134     CHECK_NULL_RETURN(pipeline, theme->GetCalendarPickerDayWidthOrHeight());
135     auto fontSizeScale = pipeline->GetFontScale();
136 #ifndef ARKUI_WEARABLE
137     if (fontSizeScale < theme->GetCalendarPickerLargeScale() || CalendarDialogView::CheckOrientationChange()) {
138 #else
139     if (fontSizeScale < theme->GetCalendarPickerLargeScale()) {
140 #endif
141         return theme->GetCalendarPickerDayWidthOrHeight();
142     } else {
143         return theme->GetCalendarPickerDayLargeWidthOrHeight();
144     }
145 }
146 
147 bool CalendarMonthPattern::IsLargeSize(const RefPtr<CalendarTheme>& theme)
148 {
149     auto pipeline = GetHost()->GetContext();
150     CHECK_NULL_RETURN(pipeline, false);
151     auto fontSizeScale = pipeline->GetFontScale();
152 #ifndef ARKUI_WEARABLE
153     if ((fontSizeScale < theme->GetCalendarPickerLargeScale() || CalendarDialogView::CheckOrientationChange())
154         && theme->GetCalendarPickerDayLargeWidthOrHeight() > theme->GetCalendarPickerDayWidthOrHeight()) {
155 #else
156     if (fontSizeScale < theme->GetCalendarPickerLargeScale()
157         && theme->GetCalendarPickerDayLargeWidthOrHeight() > theme->GetCalendarPickerDayWidthOrHeight()) {
158 #endif
159         return false;
160     } else {
161         return true;
162     }
163 }
164 
165 void CalendarMonthPattern::SetColRowSpace()
166 {
167     auto host = GetHost();
168     CHECK_NULL_VOID(host);
169     auto contentConstraint = host->GetLayoutProperty()->GetLayoutConstraint();
170     if (!contentConstraint.has_value()) {
171         return;
172     }
173     auto constraint = contentConstraint.value();
174 
175     auto dataSize = GetMonthData().days.size();
176     if (dataSize <= 0) {
177         return;
178     }
179 
180     auto pipelineContext = host->GetContext();
181     CHECK_NULL_VOID(pipelineContext);
182     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
183     CHECK_NULL_VOID(theme);
184     auto selfWidth = constraint.selfIdealSize.Width();
185     if (!selfWidth.has_value()) {
186         return;
187     }
188     auto width = selfWidth.value() - CALENDAR_DISTANCE_ADJUST_FOCUSED_EVENT.ConvertToPx() * 2;
189     auto paintProperty = GetPaintProperty<CalendarPaintProperty>();
190     CHECK_NULL_VOID(paintProperty);
191     auto gregorianDayHeight = paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx() <= 0
192                     ? theme->GetCalendarTheme().gregorianCalendarHeight.ConvertToPx()
193                     : paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx();
194     if (IsLargeSize(theme)) {
195         gregorianDayHeight = GetDaySize(theme).ConvertToPx();
196     }
197     auto selfHeight = constraint.selfIdealSize.Height();
198     if (!selfHeight.has_value()) {
199         return;
200     }
201     auto height = selfHeight.value()
202         - CALENDAR_DISTANCE_ADJUST_FOCUSED_EVENT.ConvertToPx() + gregorianDayHeight;
203     auto calendarDaySize = GetDaySize(theme);
204     auto space = (width - calendarDaySize.ConvertToPx() * CALENDAR_WEEK_DAYS) / (CALENDAR_WEEK_DAYS - 1);
205     if (Positive(space)) {
206         Dimension colSpace = 0.0_px;
207         colSpace.SetValue(space);
208         paintProperty->UpdateColSpace(colSpace);
209     }
210 
211     auto rowCount = dataSize / CALENDAR_WEEK_DAYS;
212     space = (height - calendarDaySize.ConvertToPx() * (rowCount + 1)) / rowCount;
213     if (!Positive(space)) {
214         return;
215     }
216     Dimension rowSpace = 0.0_px;
217     rowSpace.SetValue(space);
218     paintProperty->UpdateWeekAndDayRowSpace(rowSpace);
219     switch (rowCount) {
220         case 4:
221             paintProperty->UpdateDailyFourRowSpace(rowSpace);
222             break;
223         case 6:
224             paintProperty->UpdateDailySixRowSpace(rowSpace);
225             break;
226         case 5:
227         default:
228             paintProperty->UpdateDailyFiveRowSpace(rowSpace);
229             break;
230     }
231 }
232 
233 void CalendarMonthPattern::OnModifyDone()
234 {
235     Pattern::OnModifyDone();
236     InitClickEvent();
237     InitTouchEvent();
238     InitHoverEvent();
239     InitAccessibilityHoverEvent();
240     InitializeCalendarAccessibility();
241 }
242 
243 void CalendarMonthPattern::SetVirtualNodeUserSelected(int32_t index)
244 {
245     if (accessibilityPropertyVec_.size() < 1) {
246         return;
247     }
248     auto host = GetHost();
249     CHECK_NULL_VOID(host);
250     auto layoutProperty = host->GetLayoutProperty();
251     CHECK_NULL_VOID(layoutProperty);
252     auto textDirection = layoutProperty->GetNonAutoLayoutDirection();
253     auto remainderWeek = index % CALENDAR_WEEK_DAYS;
254     int32_t selectedIndex = (textDirection == TextDirection::RTL ?
255         CALENDAR_WEEK_DAYS - remainderWeek * 2 + index - 1 : index);
256     std::string selectMessage;
257     for (int i = 0; i < static_cast<int32_t>(accessibilityPropertyVec_.size()); i++) {
258         if (i == selectedIndex &&
259             obtainedMonth_.days[i].month.month == obtainedMonth_.month &&
260             obtainedMonth_.days[i].month.year == obtainedMonth_.year) {
261             selectMessage += accessibilityPropertyVec_[index]->GetAccessibilityText();
262             continue;
263         }
264         accessibilityPropertyVec_[i]->SetUserSelected(false);
265     }
266     if (!obtainedMonth_.days.empty()) {
267         for (auto& day : obtainedMonth_.days) {
268             day.focused = false;
269         }
270         auto calendarEventHub = GetOrCreateEventHub<CalendarEventHub>();
271         CHECK_NULL_VOID(calendarEventHub);
272         if (selectedIndex >= 0 && selectedIndex < static_cast<int32_t>(obtainedMonth_.days.size())) {
273             obtainedMonth_.days[selectedIndex].focused = true;
274             auto json = JsonUtil::Create(true);
275             json->Put("day", obtainedMonth_.days[selectedIndex].day);
276             json->Put("month", obtainedMonth_.days[selectedIndex].month.month);
277             json->Put("year", obtainedMonth_.days[selectedIndex].month.year);
278             calendarEventHub->UpdateSelectedChangeEvent(json->ToString());
279         }
280     }
281     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
282     if (!selectMessage.empty()) {
283         host->OnAccessibilityEvent(AccessibilityEventType::ANNOUNCE_FOR_ACCESSIBILITY, selectedTxt_ + selectMessage);
284         selectedIndex_ = index;
285     }
286 }
287 
288 void CalendarMonthPattern::InitVirtualButtonClickEvent(RefPtr<FrameNode> frameNode, int32_t index)
289 {
290     CHECK_NULL_VOID(frameNode);
291     auto gesture = frameNode->GetOrCreateGestureEventHub();
292     CHECK_NULL_VOID(gesture);
293     auto clickCallback = [weak = WeakClaim(this), index](GestureEvent& info) {
294         auto calendarPattern = weak.Upgrade();
295         CHECK_NULL_VOID(calendarPattern);
296         calendarPattern->SetVirtualNodeUserSelected(index);
297     };
298     auto clickListener = MakeRefPtr<ClickEvent>(std::move(clickCallback));
299     gesture->AddClickAfterEvent(clickListener);
300 }
301 
302 void CalendarMonthPattern::InitClickEvent()
303 {
304     if (clickListener_) {
305         return;
306     }
307 
308     auto host = GetHost();
309     CHECK_NULL_VOID(host);
310     auto gesture = host->GetOrCreateGestureEventHub();
311     CHECK_NULL_VOID(gesture);
312     auto obtainedMonth = obtainedMonth_;
313     auto clickCallback = [weak = WeakClaim(this), obtainedMonth](GestureEvent& info) {
314         auto calendarPattern = weak.Upgrade();
315         CHECK_NULL_VOID(calendarPattern);
316         auto localLocation = info.GetFingerList().begin()->localLocation_;
317         calendarPattern->OnClick(localLocation, calendarPattern->obtainedMonth_);
318     };
319     clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
320     gesture->AddClickEvent(clickListener_);
321 }
322 
323 float CalendarMonthPattern::GetWidth(const RefPtr<FrameNode>& host)
324 {
325     auto width = 0.0f;
326     auto contentConstraint = host->GetLayoutProperty()->GetLayoutConstraint();
327     if (!contentConstraint.has_value()) {
328         return width;
329     }
330     auto constraint = contentConstraint.value();
331     auto selfWidth = constraint.selfIdealSize.Width();
332     if (!selfWidth.has_value()) {
333         return width;
334     }
335     width = selfWidth.value()
336         - CALENDAR_DISTANCE_ADJUST_FOCUSED_EVENT.ConvertToPx() * CALENDAR_DISTANCE_ADJUST_FOCUSED_SIZE;
337     return width;
338 }
339 
340 void CalendarMonthPattern::OnColorConfigurationUpdate()
341 {
342     auto host = GetHost();
343     CHECK_NULL_VOID(host);
344     auto pipelineContext = host->GetContext();
345     CHECK_NULL_VOID(pipelineContext);
346     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
347     CHECK_NULL_VOID(theme);
348     auto swiperNode = host->GetParent();
349     CHECK_NULL_VOID(swiperNode);
350     auto calendarNode = swiperNode->GetParent();
351     CHECK_NULL_VOID(calendarNode);
352     auto scrollNode = calendarNode->GetParent();
353     CHECK_NULL_VOID(scrollNode);
354     auto columnNode = scrollNode->GetParent();
355     CHECK_NULL_VOID(columnNode);
356     auto rowNode = columnNode->GetChildAtIndex(WEEK_ROW_INDEX);
357     CHECK_NULL_VOID(rowNode);
358     auto textNodes = rowNode->GetChildren();
359     for (auto textNode : textNodes) {
360         auto textFrameNode = AceType::DynamicCast<NG::FrameNode>(textNode);
361         CHECK_NULL_VOID(textFrameNode);
362         auto textLayoutProperty = textFrameNode->GetLayoutProperty<TextLayoutProperty>();
363         CHECK_NULL_VOID(textLayoutProperty);
364         textLayoutProperty->UpdateTextColor(theme->GetCalendarTheme().weekColor);
365     }
366 
367     if (SystemProperties::ConfigChangePerform()) {
368         rowNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
369         swiperNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
370     }
371 }
372 
373 void CalendarMonthPattern::OnLanguageConfigurationUpdate()
374 {
375     auto host = GetHost();
376     CHECK_NULL_VOID(host);
377     auto pipelineContext = host->GetContext();
378     CHECK_NULL_VOID(pipelineContext);
379     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
380     CHECK_NULL_VOID(theme);
381     auto swiperNode = host->GetParent();
382     CHECK_NULL_VOID(swiperNode);
383     auto calendarNode = swiperNode->GetParent();
384     CHECK_NULL_VOID(calendarNode);
385     auto scrollNode = calendarNode->GetParent();
386     CHECK_NULL_VOID(scrollNode);
387     auto columnNode = scrollNode->GetParent();
388     CHECK_NULL_VOID(columnNode);
389     auto rowNode = columnNode->GetChildAtIndex(WEEK_ROW_INDEX);
390     CHECK_NULL_VOID(rowNode);
391     auto textNodes = rowNode->GetChildren();
392     std::vector<std::string> weekNumbers = Localization::GetInstance()->GetWeekdays(true);
393     int32_t column = 0;
394     for (auto textNode : textNodes) {
395         std::string weekContent { weekNumbers[column % CALENDAR_WEEK_DAYS] };
396         auto textFrameNode = AceType::DynamicCast<NG::FrameNode>(textNode);
397         CHECK_NULL_VOID(textFrameNode);
398         auto calendarPaintProperty = host->GetPaintProperty<CalendarPaintProperty>();
399         CHECK_NULL_VOID(calendarPaintProperty);
400         auto fontSize = calendarPaintProperty->GetWeekFontSize().value_or(theme->GetCalendarTheme().weekFontSize);
401         auto textLayoutProperty = textFrameNode->GetLayoutProperty<TextLayoutProperty>();
402         CHECK_NULL_VOID(textLayoutProperty);
403         textLayoutProperty->UpdateContent(weekContent);
404         textLayoutProperty->UpdateFontSize(fontSize);
405         ++column;
406     }
407 }
408 
409 void CalendarMonthPattern::BeforeSyncGeometryProperties(const DirtySwapConfig& config)
410 {
411     auto host = GetHost();
412     CHECK_NULL_VOID(host);
413     auto width = GetWidth(host);
414     auto pipelineContext = host->GetContext();
415     CHECK_NULL_VOID(pipelineContext);
416     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
417     CHECK_NULL_VOID(theme);
418     auto calendarDaySize = GetDaySize(theme);
419     auto space = (width - calendarDaySize.ConvertToPx() * CALENDAR_WEEK_DAYS) / (CALENDAR_WEEK_DAYS - 1);
420     Dimension colSpace = 0.0_px;
421     if (Positive(space)) {
422         colSpace.SetValue(space);
423     }
424     auto swiperNode = host->GetParent();
425     CHECK_NULL_VOID(swiperNode);
426     auto calendarNode = swiperNode->GetParent();
427     CHECK_NULL_VOID(calendarNode);
428     auto scrollNode = calendarNode->GetParent();
429     CHECK_NULL_VOID(scrollNode);
430     auto columnNode = scrollNode->GetParent();
431     CHECK_NULL_VOID(columnNode);
432     auto rowNode = columnNode->GetChildAtIndex(WEEK_ROW_INDEX);
433     CHECK_NULL_VOID(rowNode);
434     auto textNodes = rowNode->GetChildren();
435     for (auto textNode : textNodes) {
436         auto textFrameNode = AceType::DynamicCast<NG::FrameNode>(textNode);
437         CHECK_NULL_VOID(textFrameNode);
438         auto calendarPaintProperty = host->GetPaintProperty<CalendarPaintProperty>();
439         CHECK_NULL_VOID(calendarPaintProperty);
440         auto fontSize = calendarPaintProperty->GetWeekFontSize().value_or(theme->GetCalendarTheme().weekFontSize);
441         auto textLayoutProperty = textFrameNode->GetLayoutProperty<TextLayoutProperty>();
442         CHECK_NULL_VOID(textLayoutProperty);
443         textLayoutProperty->UpdateFontSize(fontSize);
444         textLayoutProperty->UpdateTextColor(theme->GetCalendarTheme().weekColor);
445         textLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(calendarDaySize), std::nullopt));
446     }
447 
448     auto rowFrameNode = AceType::DynamicCast<NG::FrameNode>(rowNode);
449     CHECK_NULL_VOID(rowFrameNode);
450     auto weekLayoutProperty = rowFrameNode->GetLayoutProperty<LinearLayoutProperty>();
451     CHECK_NULL_VOID(weekLayoutProperty);
452     weekLayoutProperty->UpdateSpace(colSpace);
453     rowFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
454 }
455 
456 void CalendarMonthPattern::InitTouchEvent()
457 {
458     if (touchListener_) {
459         return;
460     }
461 
462     auto host = GetHost();
463     CHECK_NULL_VOID(host);
464     auto gesture = host->GetOrCreateGestureEventHub();
465     CHECK_NULL_VOID(gesture);
466     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
467         auto calendarPattern = weak.Upgrade();
468         CHECK_NULL_VOID(calendarPattern);
469         if (info.GetTouches().empty()) {
470             return;
471         }
472         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
473             calendarPattern->OnTouchEvent(info.GetTouches().front().GetLocalLocation(), true);
474         }
475         if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
476             info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
477             calendarPattern->OnTouchEvent(info.GetTouches().front().GetLocalLocation(), false);
478         }
479     };
480     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
481     gesture->AddTouchEvent(touchListener_);
482 }
483 
484 void CalendarMonthPattern::InitHoverEvent()
485 {
486     if (hoverListener_) {
487         return;
488     }
489 
490     auto host = GetHost();
491     CHECK_NULL_VOID(host);
492     auto eventHub = GetOrCreateEventHub<CalendarEventHub>();
493     CHECK_NULL_VOID(eventHub);
494     auto inputHub = eventHub->GetOrCreateInputEventHub();
495     CHECK_NULL_VOID(inputHub);
496     auto hoverCallback = [weak = WeakClaim(this)](bool state) {
497         auto calendarPattern = weak.Upgrade();
498         CHECK_NULL_VOID(calendarPattern);
499         calendarPattern->SetHoverState(state);
500         if (!state) {
501             Offset localLocation;
502             calendarPattern->OnHoverEvent(localLocation, false);
503         }
504     };
505     hoverListener_ = MakeRefPtr<InputEvent>(std::move(hoverCallback));
506     inputHub->AddOnHoverEvent(hoverListener_);
507     auto mouseCallback = [weak = WeakClaim(this)](MouseInfo& info) {
508         auto calendarPattern = weak.Upgrade();
509         CHECK_NULL_VOID(calendarPattern);
510         calendarPattern->OnHoverEvent(info.GetLocalLocation(), calendarPattern->GetHoverState());
511     };
512     inputHub->SetMouseEvent(std::move(mouseCallback));
513 }
514 
515 bool CalendarMonthPattern::IsDateInRange(const CalendarDay& day)
516 {
517     PickerDate date;
518     date.SetYear(day.month.year);
519     date.SetMonth(day.month.month);
520     date.SetDay(day.day);
521     for (const auto& range : disabledDateRange_) {
522         if (PickerDate::IsDateInRange(date, range.first, range.second)) {
523             return false;
524         }
525     }
526     return PickerDate::IsDateInRange(date, startDate_, endDate_);
527 }
528 
529 void CalendarMonthPattern::OnClick(Offset& localLocation, const ObtainedMonth& obtainedMonth)
530 {
531     auto host = GetHost();
532     CHECK_NULL_VOID(host);
533     auto pattern = host->GetPattern<CalendarMonthPattern>();
534     CHECK_NULL_VOID(pattern);
535     auto index = JudgeArea(localLocation);
536     pattern->obtainedMonth_ = obtainedMonth;
537     if (!obtainedMonth_.days.empty()) {
538         if (!IsDateInRange(obtainedMonth_.days[index])) {
539             return;
540         }
541         for (auto& day : pattern->obtainedMonth_.days) {
542             day.focused = false;
543         }
544         auto calendarEventHub = GetOrCreateEventHub<CalendarEventHub>();
545         CHECK_NULL_VOID(calendarEventHub);
546         if (index >= 0 && index < static_cast<int32_t>(obtainedMonth.days.size())) {
547             pattern->obtainedMonth_.days[index].focused = true;
548             auto json = JsonUtil::Create(true);
549             json->Put("day", obtainedMonth.days[index].day);
550             json->Put("month", obtainedMonth.days[index].month.month);
551             json->Put("year", obtainedMonth.days[index].month.year);
552             calendarEventHub->UpdateSelectedChangeEvent(json->ToString());
553         }
554         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
555     }
556 }
557 
558 void CalendarMonthPattern::OnTouchEvent(const Offset& localLocation, bool isPressed)
559 {
560     if (!isCalendarDialog_ || obtainedMonth_.days.empty()) {
561         return;
562     }
563     auto index = JudgeArea(localLocation);
564     if (!(index < 0 || index >= static_cast<int32_t>(obtainedMonth_.days.size())) && isPressed &&
565         IsDateInRange(obtainedMonth_.days[index])) {
566         obtainedMonth_.days[index].isPressing = true;
567     } else {
568         for (auto& day : obtainedMonth_.days) {
569             day.isPressing = false;
570         }
571     }
572 
573     auto host = GetHost();
574     CHECK_NULL_VOID(host);
575     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
576 }
577 
578 void CalendarMonthPattern::OnHoverEvent(const Offset& localLocation, bool state)
579 {
580     if (!isCalendarDialog_ || obtainedMonth_.days.empty()) {
581         return;
582     }
583     int32_t index = JudgeArea(localLocation);
584     if (index < 0 || index >= static_cast<int32_t>(obtainedMonth_.days.size())) {
585         return;
586     }
587     for (auto& day : obtainedMonth_.days) {
588         day.isHovering = false;
589     }
590     if (state && IsDateInRange(obtainedMonth_.days[index])) {
591         obtainedMonth_.days[index].isHovering = true;
592     }
593 
594     auto host = GetHost();
595     CHECK_NULL_VOID(host);
596     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
597 }
598 
599 int32_t CalendarMonthPattern::JudgeArea(const Offset& offset)
600 {
601     auto host = GetHost();
602     CHECK_NULL_RETURN(host, false);
603     auto paintProperty = host->GetPaintProperty<CalendarPaintProperty>();
604     CHECK_NULL_RETURN(paintProperty, false);
605     auto pipelineContext = host->GetContext();
606     CHECK_NULL_RETURN(pipelineContext, false);
607     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
608     CHECK_NULL_RETURN(theme, false);
609     auto gregorianDayHeight = paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx() <= 0
610                                 ? theme->GetCalendarTheme().gregorianCalendarHeight.ConvertToPx()
611                                 : paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx();
612     auto weekHeight = paintProperty->GetWeekHeight().value_or(theme->GetCalendarTheme().weekHeight).ConvertToPx();
613     auto weekAndDayRowSpace =
614         paintProperty->GetWeekAndDayRowSpace().value_or(theme->GetCalendarTheme().weekAndDayRowSpace).ConvertToPx();
615     auto dayHeight = paintProperty->GetDayHeight().value_or(theme->GetCalendarTheme().dayHeight).ConvertToPx();
616     auto dayWidth = paintProperty->GetDayWidth().value_or(theme->GetCalendarTheme().dayWidth).ConvertToPx();
617     const static int32_t columnsOfData = 7;
618     auto colSpace = paintProperty->GetColSpaceValue({}).ConvertToPx() <= 0
619                         ? theme->GetCalendarTheme().colSpace.ConvertToPx()
620                         : paintProperty->GetColSpaceValue({}).ConvertToPx();
621     auto dailyFourRowSpace = NonPositive(paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx())
622                                  ? theme->GetCalendarTheme().dailySixRowSpace.ConvertToPx()
623                                  : paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx();
624     auto dailyFiveRowSpace = paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx() <= 0
625                                  ? theme->GetCalendarTheme().dailyFiveRowSpace.ConvertToPx()
626                                  : paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx();
627     auto dailySixRowSpace = paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx() <= 0
628                                 ? theme->GetCalendarTheme().dailySixRowSpace.ConvertToPx()
629                                 : paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx();
630     auto rows = (static_cast<int32_t>(obtainedMonth_.days.size()) / columnsOfData);
631     auto rowSpace = dailySixRowSpace;
632     switch (rows) {
633         case 4: {
634             rowSpace = dailyFourRowSpace;
635             break;
636         }
637         case 5: {
638             rowSpace = dailyFiveRowSpace;
639             break;
640         }
641         default:
642             break;
643     }
644     if (IsLargeSize(theme)) {
645         gregorianDayHeight = GetDaySize(theme).ConvertToPx();
646     }
647     auto browHeight = weekHeight + weekAndDayRowSpace - gregorianDayHeight;
648     auto maxHeight = host->GetGeometryNode()->GetFrameSize().Height();
649     auto maxWidth = host->GetGeometryNode()->GetFrameSize().Width();
650     if ((offset.GetX() < 0) || (offset.GetX() > maxWidth) || (offset.GetY() < browHeight) ||
651         (offset.GetY() > maxHeight) || LessOrEqual(dayHeight, 0.0) || LessOrEqual(dayWidth, 0.0)) {
652         return -1;
653     }
654     auto height = offset.GetY() - browHeight;
655     int32_t y =
656         height < (dayHeight + rowSpace / 2) ? 0 : (height - dayHeight - rowSpace / 2) / (dayHeight + rowSpace) + 1;
657     int32_t x = offset.GetX() < (dayWidth + colSpace / 2)
658                     ? 0
659                     : (offset.GetX() - dayWidth - colSpace / 2) / (dayWidth + colSpace) + 1;
660     auto textDirection = host->GetLayoutProperty()->GetNonAutoLayoutDirection();
661     if (textDirection == TextDirection::RTL) {
662         x = columnsOfData - x - 1;
663     }
664     return (y * columnsOfData + x);
665 }
666 
667 class CalendarAccessibilitySAObserverCallback : public AccessibilitySAObserverCallback {
668 public:
669     CalendarAccessibilitySAObserverCallback(
670         const WeakPtr<CalendarMonthPattern> &weakCalendarPattern, int64_t accessibilityId)
671         : AccessibilitySAObserverCallback(accessibilityId), weakCalendarPattern_(weakCalendarPattern)
672     {}
673 
674     ~CalendarAccessibilitySAObserverCallback() override = default;
675 
676     bool OnState(bool state) override
677     {
678         auto calendarPattern = weakCalendarPattern_.Upgrade();
679         CHECK_NULL_RETURN(calendarPattern, false);
680         if (state) {
681             calendarPattern->InitCurrentVirtualNode();
682         } else {
683             calendarPattern->ClearCalendarVirtualNode();
684         }
685         return true;
686     }
687 private:
688     WeakPtr<CalendarMonthPattern> weakCalendarPattern_;
689 };
690 
691 void CalendarMonthPattern::InitializeCalendarAccessibility()
692 {
693     auto host = GetHost();
694     CHECK_NULL_VOID(host);
695     auto pipeline = host->GetContext();
696     CHECK_NULL_VOID(pipeline);
697     auto accessibilityManager = pipeline->GetAccessibilityManager();
698     CHECK_NULL_VOID(accessibilityManager);
699     accessibilitySAObserverCallback_ = std::make_shared<CalendarAccessibilitySAObserverCallback>(
700         WeakClaim(this), host->GetAccessibilityId());
701     accessibilityManager->RegisterAccessibilitySAObserverCallback(host->GetAccessibilityId(),
702         accessibilitySAObserverCallback_);
703     if (margin_ == 0) {
704         auto paintProperty = host->GetPaintProperty<CalendarPaintProperty>();
705         CHECK_NULL_VOID(paintProperty);
706         dayHeight_ = paintProperty->GetDayHeight().value_or(Dimension(0.0f)).ConvertToPx();
707         dayWidth_ = paintProperty->GetDayWidth().value_or(Dimension(0.0f)).ConvertToPx();
708         RefPtr<CalendarTheme> theme = pipeline->GetTheme<CalendarTheme>();
709         CHECK_NULL_VOID(theme);
710         auto sliderTheme = pipeline->GetTheme<SliderTheme>();
711         CHECK_NULL_VOID(sliderTheme);
712         margin_ = theme->GetDialogMargin().ConvertToPx();
713         selectedTxt_ = sliderTheme->GetSelectedTxt();
714         disabledDesc_ = sliderTheme->GetDisabelDesc();
715         deviceOrientation_ = SystemProperties::GetDeviceOrientation();
716     }
717 }
718 
719 void CalendarMonthPattern::InitCurrentVirtualNode()
720 {
721     auto deviceOrientation = SystemProperties::GetDeviceOrientation();
722     if ((!isInitVirtualNode_ || buttonAccessibilityNodeVec_.size() != obtainedMonth_.days.size() ||
723         deviceOrientation_ != deviceOrientation) &&
724         monthState_ == MonthState::CUR_MONTH) {
725         isInitVirtualNode_ = InitCalendarVirtualNode();
726     } else {
727         FireModifyAccessibilityVirtualNode(obtainedMonth_);
728     }
729 }
730 
731 void CalendarMonthPattern::ClearFocusCalendarDay()
732 {
733     focusedCalendarDay_.index = 0;
734     deviceOrientation_ = SystemProperties::GetDeviceOrientation();
735     CHECK_NULL_VOID(lineNode_);
736     auto lineNodeProp = lineNode_->GetLayoutProperty();
737     CHECK_NULL_VOID(lineNodeProp);
738     if (monthState_ == MonthState::CUR_MONTH) {
739         lineNodeProp->UpdateVisibility(VisibleType::VISIBLE);
740     } else {
741         lineNodeProp->UpdateVisibility(VisibleType::GONE);
742     }
743 }
744 
745 void CalendarMonthPattern::ClearCalendarVirtualNode()
746 {
747     auto host = GetHost();
748     CHECK_NULL_VOID(host);
749     buttonAccessibilityNodeVec_.clear();
750     accessibilityPropertyVec_.clear();
751     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
752     CHECK_NULL_VOID(accessibilityProperty);
753     accessibilityProperty->SaveAccessibilityVirtualNode(nullptr);
754 }
755 
756 void CalendarMonthPattern::SetLineNodeSize(RefPtr<FrameNode> lineNode)
757 {
758     auto host = GetHost();
759     CHECK_NULL_VOID(host);
760     auto hostLayoutProperty = host->GetLayoutProperty();
761     CHECK_NULL_VOID(hostLayoutProperty);
762     auto width = hostLayoutProperty->GetLayoutConstraint()->selfIdealSize.Width().value_or(Infinity<float>());
763     auto height = hostLayoutProperty->GetLayoutConstraint()->selfIdealSize.Height().value_or(Infinity<float>());
764     CHECK_NULL_VOID(lineNode);
765     auto layoutProperty = lineNode->GetLayoutProperty<LayoutProperty>();
766     CHECK_NULL_VOID(layoutProperty);
767     layoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(width), CalcLength(height)));
768 }
769 
770 void CalendarMonthPattern::SetFocusNode(int32_t index, bool isDeviceOrientation)
771 {
772     auto host = GetHost();
773     CHECK_NULL_VOID(host);
774     auto layoutProperty = host->GetLayoutProperty();
775     CHECK_NULL_VOID(layoutProperty);
776     auto textDirection = layoutProperty->GetNonAutoLayoutDirection();
777     auto remainderWeek = index % CALENDAR_WEEK_DAYS;
778     int32_t selectedIndex = (textDirection == TextDirection::RTL ?
779         CALENDAR_WEEK_DAYS - remainderWeek * 2 + index - 1 : index);
780     if (isDeviceOrientation) {
781         selectedIndex = index;
782     }
783     if (selectedIndex >= static_cast<int32_t>(buttonAccessibilityNodeVec_.size()) || selectedIndex < 0) {
784         return;
785     }
786     buttonAccessibilityNodeVec_[selectedIndex]->OnAccessibilityEvent(AccessibilityEventType::REQUEST_FOCUS);
787     selectedIndex_ = selectedIndex;
788 }
789 
790 bool CalendarMonthPattern::InitCalendarVirtualNode()
791 {
792     auto host = GetHost();
793     CHECK_NULL_RETURN(host, false);
794     buttonAccessibilityNodeVec_.clear();
795     accessibilityPropertyVec_.clear();
796     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
797     CHECK_NULL_RETURN(accessibilityProperty, false);
798     accessibilityProperty->SaveAccessibilityVirtualNode(nullptr);
799     auto lineNode = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
800         AceType::MakeRefPtr<LinearLayoutPattern>(true));
801     for (auto& day : obtainedMonth_.days) {
802         auto buttonNode = AddButtonNodeIntoVirtual(day);
803         lineNode->AddChild(buttonNode);
804         buttonAccessibilityNodeVec_.emplace_back(buttonNode);
805         ChangeVirtualNodeContent(day);
806     }
807     SetLineNodeSize(lineNode);
808     SetCalendarAccessibilityLevel(AccessibilityProperty::Level::NO_STR);
809     accessibilityProperty->SetAccessibilityText(" ");
810     auto virtualFrameNode = AceType::DynamicCast<NG::FrameNode>(lineNode);
811     CHECK_NULL_RETURN(virtualFrameNode, false);
812     virtualFrameNode->SetAccessibilityNodeVirtual();
813     virtualFrameNode->SetAccessibilityVirtualNodeParent(AceType::DynamicCast<NG::UINode>(host));
814     virtualFrameNode->SetFirstAccessibilityVirtualNode();
815     FrameNode::ProcessOffscreenNode(virtualFrameNode);
816     accessibilityProperty->SaveAccessibilityVirtualNode(lineNode);
817     lineNode_ = lineNode;
818     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
819     auto deviceOrientation = SystemProperties::GetDeviceOrientation();
820     if (deviceOrientation_ != deviceOrientation && !isFirstEnter_) {
821         SetFocusNode(focusedCalendarDay_.index, true);
822         deviceOrientation_ = deviceOrientation;
823     }
824     if (!isFirstEnter_) {
825         return true;
826     }
827     for (auto &day : obtainedMonth_.days) {
828         if (day.isSelected) {
829             SetFocusNode(day.index);
830             isFirstEnter_ = false;
831             focusedCalendarDay_ = day;
832             break;
833         }
834     }
835     return true;
836 }
837 
838 std::pair<int32_t, int32_t> GetXYByIndex(const int32_t index)
839 {
840     if (index < CALENDAR_WEEK_DAYS - 1) {
841         return {index, 0};
842     } else {
843         return {(index % CALENDAR_WEEK_DAYS), (index / CALENDAR_WEEK_DAYS)};
844     }
845 }
846 
847 void CalendarMonthPattern::ChangeVirtualNodeState(const CalendarDay& calendarDay)
848 {
849     if (selectedIndex_ >= static_cast<int32_t>(accessibilityPropertyVec_.size()) || selectedIndex_ < 0) {
850         return;
851     }
852     if (calendarDay.index != selectedIndex_ &&
853         calendarDay.month.month == obtainedMonth_.month && calendarDay.month.month == obtainedMonth_.month) {
854         accessibilityPropertyVec_[selectedIndex_]->SetUserSelected(true);
855     }
856 }
857 
858 RefPtr<FrameNode> CalendarMonthPattern::AddButtonNodeIntoVirtual(const CalendarDay& calendarDay)
859 {
860     auto buttonNode = FrameNode::CreateFrameNode(
861         V2::BUTTON_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ButtonPattern>());
862     auto buttonAccessibilityProperty = buttonNode->GetAccessibilityProperty<AccessibilityProperty>();
863     CHECK_NULL_RETURN(buttonAccessibilityProperty, nullptr);
864     auto host = GetHost();
865     CHECK_NULL_RETURN(host, nullptr);
866     auto pipeline = host->GetContext();
867     if (pipeline) {
868         UpdateAccessibilityButtonNode(buttonNode, calendarDay.index);
869     } else {
870         UpdateButtonNodeWithoutTheme(buttonNode, calendarDay.index);
871     }
872     accessibilityPropertyVec_.emplace_back(buttonAccessibilityProperty);
873     InitVirtualButtonClickEvent(buttonNode, calendarDay.index);
874     buttonAccessibilityProperty->SetOnAccessibilityFocusCallback([weak = WeakClaim(this), calendarDay](bool focus) {
875         if (focus) {
876             auto calendar = weak.Upgrade();
877             CHECK_NULL_VOID(calendar);
878             calendar->focusedCalendarDay_ = calendarDay;
879             calendar->ChangeVirtualNodeState(calendarDay);
880         }
881     });
882     return buttonNode;
883 }
884 
885 float GetRowSpace(RefPtr<CalendarPaintProperty> paintProperty, RefPtr<CalendarTheme> theme, size_t daySize)
886 {
887     auto dailyFourRowSpace = NonPositive(paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx())
888                                  ? theme->GetCalendarTheme().dailySixRowSpace.ConvertToPx()
889                                  : paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx();
890     auto dailyFiveRowSpace = paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx() <= 0
891                                  ? theme->GetCalendarTheme().dailyFiveRowSpace.ConvertToPx()
892                                  : paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx();
893     auto dailySixRowSpace = paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx() <= 0
894                                 ? theme->GetCalendarTheme().dailySixRowSpace.ConvertToPx()
895                                 : paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx();
896     auto rows = (static_cast<int32_t>(daySize) / CALENDAR_WEEK_DAYS);
897     auto rowSpace = dailySixRowSpace;
898     switch (rows) {
899         case DAILY_FOUR_ROWSPACE: {
900             rowSpace = dailyFourRowSpace;
901             break;
902         }
903         case DAILY_FIVE_ROWSPACE: {
904             rowSpace = dailyFiveRowSpace;
905             break;
906         }
907         default:
908             break;
909     }
910     return rowSpace;
911 }
912 
913 void CalendarMonthPattern::SetCalendarAccessibilityLevel(const std::string& level)
914 {
915     auto host = GetHost();
916     CHECK_NULL_VOID(host);
917     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
918     CHECK_NULL_VOID(accessibilityProperty);
919     accessibilityProperty->SetAccessibilityLevel(level);
920     auto parent = host->GetParent();
921     while (parent && parent->GetTag() != V2::DIALOG_ETS_TAG) {
922         auto parentNode = AceType::DynamicCast<NG::FrameNode>(parent);
923         CHECK_NULL_VOID(parentNode);
924         auto parentAccessibilityProperty = parentNode->GetAccessibilityProperty<AccessibilityProperty>();
925         CHECK_NULL_VOID(parentAccessibilityProperty);
926         parentAccessibilityProperty->SetAccessibilityLevel(level);
927         parent = parent->GetParent();
928     }
929 }
930 
931 void CalendarMonthPattern::InitAccessibilityHoverEvent()
932 {
933     auto host = GetHost();
934     CHECK_NULL_VOID(host);
935     auto eventHub = host->GetOrCreateInputEventHub();
936     CHECK_NULL_VOID(eventHub);
937     eventHub->SetAccessibilityHoverEvent([weak = WeakClaim(this)](bool isHover, AccessibilityHoverInfo& info) {
938         auto calendar = weak.Upgrade();
939         CHECK_NULL_VOID(calendar);
940         calendar->HandleAccessibilityHoverEvent(isHover, info);
941     });
942 }
943 
944 void CalendarMonthPattern::HandleAccessibilityHoverEvent(bool isHover, AccessibilityHoverInfo& info)
945 {
946     if (isHover) {
947         isOnHover_ = true;
948     } else if (!isHover) {
949         isOnHover_ = false;
950     }
951 }
952 
953 float GetRowSpaceWithoutTheme(RefPtr<CalendarPaintProperty> paintProperty, size_t daySize)
954 {
955     auto dailyFourRowSpace = NonPositive(paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx())
956                                  ? 0.0f
957                                  : paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx();
958     auto dailyFiveRowSpace = paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx() <= 0
959                                  ? 0.0f
960                                  : paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx();
961     auto dailySixRowSpace = paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx() <= 0
962                                 ? 0.0f
963                                 : paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx();
964     auto rows = (static_cast<int32_t>(daySize) / CALENDAR_WEEK_DAYS);
965     auto rowSpace = dailySixRowSpace;
966     switch (rows) {
967         case DAILY_FOUR_ROWSPACE: {
968             rowSpace = dailyFourRowSpace;
969             break;
970         }
971         case DAILY_FIVE_ROWSPACE: {
972             rowSpace = dailyFiveRowSpace;
973             break;
974         }
975         default:
976             break;
977     }
978     return rowSpace;
979 }
980 
981 void CalendarMonthPattern::UpdateButtonNodeWithoutTheme(RefPtr<FrameNode> frameNode, int32_t index)
982 {
983     auto host = GetHost();
984     CHECK_NULL_VOID(host);
985     auto paintProperty = host->GetPaintProperty<CalendarPaintProperty>();
986     CHECK_NULL_VOID(paintProperty);
987     auto dayHeight = paintProperty->GetDayHeight().value_or(Dimension(0.0f)).ConvertToPx();
988     auto dayWidth = paintProperty->GetDayWidth().value_or(Dimension(0.0f)).ConvertToPx();
989     CHECK_NULL_VOID(frameNode);
990     auto buttonLayoutProperty = frameNode->GetLayoutProperty<ButtonLayoutProperty>();
991     CHECK_NULL_VOID(buttonLayoutProperty);
992     buttonLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(dayWidth), CalcLength(dayHeight)));
993     auto pos = GetXYByIndex(index);
994     auto colSpace = paintProperty->GetColSpaceValue({}).ConvertToPx() <= 0
995                     ? 0.0f
996                     : paintProperty->GetColSpaceValue({}).ConvertToPx();
997     Dimension buttonOffsetX = Dimension(margin_ / 2 + (colSpace + dayWidth) * pos.first);
998     auto weekHeight = paintProperty->GetWeekHeight().value_or(Dimension(0.0f)).ConvertToPx();
999     auto rowSpace = GetRowSpaceWithoutTheme(paintProperty, obtainedMonth_.days.size());
1000     auto weekAndDayRowSpace =
1001         paintProperty->GetWeekAndDayRowSpace().value_or(Dimension(0.0f)).ConvertToPx();
1002     auto gregorianDayHeight = paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx();
1003     auto browHeight = weekHeight + weekAndDayRowSpace - gregorianDayHeight;
1004     Dimension buttonOffsetY = Dimension(browHeight + (dayHeight + rowSpace) * pos.second);
1005     auto renderContext = frameNode->GetRenderContext();
1006     CHECK_NULL_VOID(renderContext);
1007     renderContext->UpdatePosition(OffsetT(buttonOffsetX, buttonOffsetY));
1008     frameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1009 }
1010 
1011 void CalendarMonthPattern::UpdateAccessibilityButtonNode(RefPtr<FrameNode> frameNode, int32_t index)
1012 {
1013     auto host = GetHost();
1014     CHECK_NULL_VOID(host);
1015     auto paintProperty = host->GetPaintProperty<CalendarPaintProperty>();
1016     CHECK_NULL_VOID(paintProperty);
1017     auto pipelineContext = host->GetContext();
1018     CHECK_NULL_VOID(pipelineContext);
1019     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
1020     CHECK_NULL_VOID(theme);
1021     auto dayHeight = paintProperty->GetDayHeight().value_or(theme->GetCalendarTheme().dayHeight).ConvertToPx();
1022     auto dayWidth = paintProperty->GetDayWidth().value_or(theme->GetCalendarTheme().dayWidth).ConvertToPx();
1023     CHECK_NULL_VOID(frameNode);
1024     auto buttonLayoutProperty = frameNode->GetLayoutProperty<ButtonLayoutProperty>();
1025     CHECK_NULL_VOID(buttonLayoutProperty);
1026     buttonLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(dayWidth), CalcLength(dayHeight)));
1027     auto renderContext = frameNode->GetRenderContext();
1028     CHECK_NULL_VOID(renderContext);
1029     auto pos = GetXYByIndex(index);
1030     auto colSpace = paintProperty->GetColSpaceValue({}).ConvertToPx() <= 0
1031                     ? theme->GetCalendarTheme().colSpace.ConvertToPx()
1032                     : paintProperty->GetColSpaceValue({}).ConvertToPx();
1033     colSpace_ = colSpace;
1034     Dimension buttonOffsetX = Dimension(margin_ / 2 + (colSpace + dayWidth) * pos.first);
1035     auto gregorianDayHeight = paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx() <= 0
1036                             ? theme->GetCalendarTheme().gregorianCalendarHeight.ConvertToPx()
1037                             : paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx();
1038     auto weekHeight = paintProperty->GetWeekHeight().value_or(theme->GetCalendarTheme().weekHeight).ConvertToPx();
1039     auto rowSpace = GetRowSpace(paintProperty, theme, obtainedMonth_.days.size());
1040     auto weekAndDayRowSpace =
1041         paintProperty->GetWeekAndDayRowSpace().value_or(theme->GetCalendarTheme().weekAndDayRowSpace).ConvertToPx();
1042     if (IsLargeSize(theme)) {
1043         gregorianDayHeight = GetDaySize(theme).ConvertToPx();
1044     }
1045     auto browHeight = weekHeight + weekAndDayRowSpace - gregorianDayHeight;
1046     Dimension buttonOffsetY = Dimension(browHeight + (dayHeight + rowSpace) * pos.second);
1047     renderContext->UpdatePosition(OffsetT(buttonOffsetX, buttonOffsetY));
1048     frameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1049 }
1050 
1051 std::string CalendarMonthPattern::GetDayStr(int32_t index)
1052 {
1053     auto host = GetHost();
1054     CHECK_NULL_RETURN(host, "");
1055     auto pipelineContext = host->GetContext();
1056     CHECK_NULL_RETURN(pipelineContext, "");
1057     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
1058     CHECK_NULL_RETURN(theme, "");
1059     switch (index) {
1060         case MONDAY_INDEX:
1061             return theme->GetCalendarTheme().monday;
1062         case TUESDAY_INDEX:
1063             return theme->GetCalendarTheme().tuesday;
1064         case WEDNESDAY_INDEX:
1065             return theme->GetCalendarTheme().wednesday;
1066         case THURSDAY_INDEX:
1067             return theme->GetCalendarTheme().thursday;
1068         case FRIDAY_INDEX:
1069             return theme->GetCalendarTheme().friday;
1070         case SATURDAY_INDEX:
1071             return theme->GetCalendarTheme().saturday;
1072         default:
1073             return theme->GetCalendarTheme().sunday;
1074     }
1075 }
1076 
1077 std::string CalendarMonthPattern::GetTodayStr()
1078 {
1079     auto host = GetHost();
1080     CHECK_NULL_RETURN(host, "");
1081     auto pipelineContext = host->GetContext();
1082     CHECK_NULL_RETURN(pipelineContext, "");
1083     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
1084     CHECK_NULL_RETURN(theme, "");
1085     return theme->GetCalendarTheme().today;
1086 }
1087 
1088 void CalendarMonthPattern::ChangeVirtualNodeContent(const CalendarDay& calendarDay)
1089 {
1090     auto host = GetHost();
1091     CHECK_NULL_VOID(host);
1092     auto layoutProperty = host->GetLayoutProperty();
1093     CHECK_NULL_VOID(layoutProperty);
1094     auto textDirection = layoutProperty->GetNonAutoLayoutDirection();
1095     auto remainderWeek = calendarDay.index % CALENDAR_WEEK_DAYS;
1096     int32_t index = (textDirection == TextDirection::RTL ?
1097         CALENDAR_WEEK_DAYS - remainderWeek * 2 + calendarDay.index - 1 : calendarDay.index);
1098     if (index >= static_cast<int32_t>(buttonAccessibilityNodeVec_.size()) || index < 0) {
1099         return;
1100     }
1101     std::string message;
1102     if (calendarDay.month.year == calendarDay_.month.year && calendarDay.month.month == calendarDay_.month.month &&
1103                       calendarDay.day == calendarDay_.day) {
1104         message += GetTodayStr();
1105     }
1106     message += std::to_string(calendarDay.month.year) + "/";
1107     message += std::to_string(calendarDay.month.month) + "/";
1108     message += std::to_string(calendarDay.day);
1109     message += GetDayStr(remainderWeek);
1110     auto node = buttonAccessibilityNodeVec_[index];
1111     auto buttonAccessibilityProperty = node->GetAccessibilityProperty<AccessibilityProperty>();
1112     CHECK_NULL_VOID(buttonAccessibilityProperty);
1113     if (calendarDay.month.month != obtainedMonth_.month) {
1114         buttonAccessibilityProperty->SetAccessibilityDescription(disabledDesc_);
1115     } else if (index == selectedIndex_) {
1116         // Delete the description of the selected node
1117         buttonAccessibilityProperty->SetAccessibilityDescription(" ");
1118     } else {
1119         // Set the default description to other nodes
1120         buttonAccessibilityProperty->SetAccessibilityDescription("");
1121     }
1122     buttonAccessibilityProperty->SetUserDisabled(calendarDay.month.month != obtainedMonth_.month ? true : false);
1123     buttonAccessibilityProperty->SetUserSelected(false);
1124     buttonAccessibilityProperty->SetAccessibilityText(message);
1125 }
1126 
1127 void CalendarMonthPattern::FireModifyAccessibilityVirtualNode(const ObtainedMonth& currentData)
1128 {
1129     if (isInitVirtualNode_) {
1130         auto host = GetHost();
1131         CHECK_NULL_VOID(host);
1132         auto pipeline = host->GetContext();
1133         CHECK_NULL_VOID(pipeline);
1134         pipeline->AddAfterRenderTask([weak = WeakClaim(this), currentData]() {
1135             auto calendarMonthPattern = weak.Upgrade();
1136             CHECK_NULL_VOID(calendarMonthPattern);
1137             calendarMonthPattern->ModifyAccessibilityVirtualNode(currentData);
1138         });
1139     }
1140 }
1141 
1142 void CalendarMonthPattern::ModifyAccessibilityVirtualNode(const ObtainedMonth& currentData)
1143 {
1144     if (buttonAccessibilityNodeVec_.size() < 1) {
1145         return;
1146     }
1147     for (auto& day : currentData.days) {
1148         ChangeVirtualNodeContent(day);
1149     }
1150 }
1151 
1152 void CalendarMonthPattern::UpdateDayRadius(const CalcDimension& dayRadius)
1153 {
1154     auto host = GetHost();
1155     CHECK_NULL_VOID(host);
1156     auto paintProperty = host->GetPaintProperty<CalendarPaintProperty>();
1157     CHECK_NULL_VOID(paintProperty);
1158 
1159     auto pipelineContext = host->GetContext();
1160     CHECK_NULL_VOID(pipelineContext);
1161 
1162     if (pipelineContext->IsSystmColorChange()) {
1163         paintProperty->UpdateDayRadius(dayRadius);
1164     }
1165 
1166     if (host->GetRerenderable()) {
1167         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1168     }
1169 }
1170 } // namespace OHOS::Ace::NG
1171