• 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 = GetEventHub<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 
368 void CalendarMonthPattern::OnLanguageConfigurationUpdate()
369 {
370     auto host = GetHost();
371     CHECK_NULL_VOID(host);
372     auto pipelineContext = host->GetContext();
373     CHECK_NULL_VOID(pipelineContext);
374     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
375     CHECK_NULL_VOID(theme);
376     auto swiperNode = host->GetParent();
377     CHECK_NULL_VOID(swiperNode);
378     auto calendarNode = swiperNode->GetParent();
379     CHECK_NULL_VOID(calendarNode);
380     auto scrollNode = calendarNode->GetParent();
381     CHECK_NULL_VOID(scrollNode);
382     auto columnNode = scrollNode->GetParent();
383     CHECK_NULL_VOID(columnNode);
384     auto rowNode = columnNode->GetChildAtIndex(WEEK_ROW_INDEX);
385     CHECK_NULL_VOID(rowNode);
386     auto textNodes = rowNode->GetChildren();
387     std::vector<std::string> weekNumbers = Localization::GetInstance()->GetWeekdays(true);
388     int32_t column = 0;
389     for (auto textNode : textNodes) {
390         std::string weekContent { weekNumbers[column % CALENDAR_WEEK_DAYS] };
391         auto textFrameNode = AceType::DynamicCast<NG::FrameNode>(textNode);
392         CHECK_NULL_VOID(textFrameNode);
393         auto calendarPaintProperty = host->GetPaintProperty<CalendarPaintProperty>();
394         CHECK_NULL_VOID(calendarPaintProperty);
395         auto fontSize = calendarPaintProperty->GetWeekFontSize().value_or(theme->GetCalendarTheme().weekFontSize);
396         auto textLayoutProperty = textFrameNode->GetLayoutProperty<TextLayoutProperty>();
397         CHECK_NULL_VOID(textLayoutProperty);
398         textLayoutProperty->UpdateContent(weekContent);
399         textLayoutProperty->UpdateFontSize(fontSize);
400         ++column;
401     }
402 }
403 
404 void CalendarMonthPattern::BeforeSyncGeometryProperties(const DirtySwapConfig& config)
405 {
406     auto host = GetHost();
407     CHECK_NULL_VOID(host);
408     auto width = GetWidth(host);
409     auto pipelineContext = host->GetContext();
410     CHECK_NULL_VOID(pipelineContext);
411     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
412     CHECK_NULL_VOID(theme);
413     auto calendarDaySize = GetDaySize(theme);
414     auto space = (width - calendarDaySize.ConvertToPx() * CALENDAR_WEEK_DAYS) / (CALENDAR_WEEK_DAYS - 1);
415     Dimension colSpace = 0.0_px;
416     if (Positive(space)) {
417         colSpace.SetValue(space);
418     }
419     auto swiperNode = host->GetParent();
420     CHECK_NULL_VOID(swiperNode);
421     auto calendarNode = swiperNode->GetParent();
422     CHECK_NULL_VOID(calendarNode);
423     auto scrollNode = calendarNode->GetParent();
424     CHECK_NULL_VOID(scrollNode);
425     auto columnNode = scrollNode->GetParent();
426     CHECK_NULL_VOID(columnNode);
427     auto rowNode = columnNode->GetChildAtIndex(WEEK_ROW_INDEX);
428     CHECK_NULL_VOID(rowNode);
429     auto textNodes = rowNode->GetChildren();
430     for (auto textNode : textNodes) {
431         auto textFrameNode = AceType::DynamicCast<NG::FrameNode>(textNode);
432         CHECK_NULL_VOID(textFrameNode);
433         auto calendarPaintProperty = host->GetPaintProperty<CalendarPaintProperty>();
434         CHECK_NULL_VOID(calendarPaintProperty);
435         auto fontSize = calendarPaintProperty->GetWeekFontSize().value_or(theme->GetCalendarTheme().weekFontSize);
436         auto textLayoutProperty = textFrameNode->GetLayoutProperty<TextLayoutProperty>();
437         CHECK_NULL_VOID(textLayoutProperty);
438         textLayoutProperty->UpdateFontSize(fontSize);
439         textLayoutProperty->UpdateTextColor(theme->GetCalendarTheme().weekColor);
440         textLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(calendarDaySize), std::nullopt));
441     }
442 
443     auto rowFrameNode = AceType::DynamicCast<NG::FrameNode>(rowNode);
444     CHECK_NULL_VOID(rowFrameNode);
445     auto weekLayoutProperty = rowFrameNode->GetLayoutProperty<LinearLayoutProperty>();
446     CHECK_NULL_VOID(weekLayoutProperty);
447     weekLayoutProperty->UpdateSpace(colSpace);
448     rowFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
449 }
450 
451 void CalendarMonthPattern::InitTouchEvent()
452 {
453     if (touchListener_) {
454         return;
455     }
456 
457     auto host = GetHost();
458     CHECK_NULL_VOID(host);
459     auto gesture = host->GetOrCreateGestureEventHub();
460     CHECK_NULL_VOID(gesture);
461     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
462         auto calendarPattern = weak.Upgrade();
463         CHECK_NULL_VOID(calendarPattern);
464         if (info.GetTouches().empty()) {
465             return;
466         }
467         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
468             calendarPattern->OnTouchEvent(info.GetTouches().front().GetLocalLocation(), true);
469         }
470         if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
471             info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
472             calendarPattern->OnTouchEvent(info.GetTouches().front().GetLocalLocation(), false);
473         }
474     };
475     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
476     gesture->AddTouchEvent(touchListener_);
477 }
478 
479 void CalendarMonthPattern::InitHoverEvent()
480 {
481     if (hoverListener_) {
482         return;
483     }
484 
485     auto host = GetHost();
486     CHECK_NULL_VOID(host);
487     auto eventHub = GetEventHub<CalendarEventHub>();
488     CHECK_NULL_VOID(eventHub);
489     auto inputHub = eventHub->GetOrCreateInputEventHub();
490     CHECK_NULL_VOID(inputHub);
491     auto hoverCallback = [weak = WeakClaim(this)](bool state) {
492         auto calendarPattern = weak.Upgrade();
493         CHECK_NULL_VOID(calendarPattern);
494         calendarPattern->SetHoverState(state);
495         if (!state) {
496             Offset localLocation;
497             calendarPattern->OnHoverEvent(localLocation, false);
498         }
499     };
500     hoverListener_ = MakeRefPtr<InputEvent>(std::move(hoverCallback));
501     inputHub->AddOnHoverEvent(hoverListener_);
502     auto mouseCallback = [weak = WeakClaim(this)](MouseInfo& info) {
503         auto calendarPattern = weak.Upgrade();
504         CHECK_NULL_VOID(calendarPattern);
505         calendarPattern->OnHoverEvent(info.GetLocalLocation(), calendarPattern->GetHoverState());
506     };
507     inputHub->SetMouseEvent(std::move(mouseCallback));
508 }
509 
510 bool CalendarMonthPattern::IsDateInRange(const CalendarDay& day)
511 {
512     PickerDate date;
513     date.SetYear(day.month.year);
514     date.SetMonth(day.month.month);
515     date.SetDay(day.day);
516     for (const auto& range : disabledDateRange_) {
517         if (PickerDate::IsDateInRange(date, range.first, range.second)) {
518             return false;
519         }
520     }
521     return PickerDate::IsDateInRange(date, startDate_, endDate_);
522 }
523 
524 void CalendarMonthPattern::OnClick(Offset& localLocation, const ObtainedMonth& obtainedMonth)
525 {
526     auto host = GetHost();
527     CHECK_NULL_VOID(host);
528     auto pattern = host->GetPattern<CalendarMonthPattern>();
529     CHECK_NULL_VOID(pattern);
530     auto index = JudgeArea(localLocation);
531     pattern->obtainedMonth_ = obtainedMonth;
532     if (!obtainedMonth_.days.empty()) {
533         if (!IsDateInRange(obtainedMonth_.days[index])) {
534             return;
535         }
536         for (auto& day : pattern->obtainedMonth_.days) {
537             day.focused = false;
538         }
539         auto calendarEventHub = GetEventHub<CalendarEventHub>();
540         CHECK_NULL_VOID(calendarEventHub);
541         if (index >= 0 && index < static_cast<int32_t>(obtainedMonth.days.size())) {
542             pattern->obtainedMonth_.days[index].focused = true;
543             auto json = JsonUtil::Create(true);
544             json->Put("day", obtainedMonth.days[index].day);
545             json->Put("month", obtainedMonth.days[index].month.month);
546             json->Put("year", obtainedMonth.days[index].month.year);
547             calendarEventHub->UpdateSelectedChangeEvent(json->ToString());
548         }
549         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
550     }
551 }
552 
553 void CalendarMonthPattern::OnTouchEvent(const Offset& localLocation, bool isPressed)
554 {
555     if (!isCalendarDialog_ || obtainedMonth_.days.empty()) {
556         return;
557     }
558     auto index = JudgeArea(localLocation);
559     if (!(index < 0 || index >= static_cast<int32_t>(obtainedMonth_.days.size())) && isPressed &&
560         IsDateInRange(obtainedMonth_.days[index])) {
561         obtainedMonth_.days[index].isPressing = true;
562     } else {
563         for (auto& day : obtainedMonth_.days) {
564             day.isPressing = false;
565         }
566     }
567 
568     auto host = GetHost();
569     CHECK_NULL_VOID(host);
570     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
571 }
572 
573 void CalendarMonthPattern::OnHoverEvent(const Offset& localLocation, bool state)
574 {
575     if (!isCalendarDialog_ || obtainedMonth_.days.empty()) {
576         return;
577     }
578     int32_t index = JudgeArea(localLocation);
579     if (index < 0 || index >= static_cast<int32_t>(obtainedMonth_.days.size())) {
580         return;
581     }
582     for (auto& day : obtainedMonth_.days) {
583         day.isHovering = false;
584     }
585     if (state && IsDateInRange(obtainedMonth_.days[index])) {
586         obtainedMonth_.days[index].isHovering = true;
587     }
588 
589     auto host = GetHost();
590     CHECK_NULL_VOID(host);
591     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
592 }
593 
594 int32_t CalendarMonthPattern::JudgeArea(const Offset& offset)
595 {
596     auto host = GetHost();
597     CHECK_NULL_RETURN(host, false);
598     auto paintProperty = host->GetPaintProperty<CalendarPaintProperty>();
599     CHECK_NULL_RETURN(paintProperty, false);
600     auto pipelineContext = host->GetContext();
601     CHECK_NULL_RETURN(pipelineContext, false);
602     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
603     CHECK_NULL_RETURN(theme, false);
604     auto gregorianDayHeight = paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx() <= 0
605                                 ? theme->GetCalendarTheme().gregorianCalendarHeight.ConvertToPx()
606                                 : paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx();
607     auto weekHeight = paintProperty->GetWeekHeight().value_or(theme->GetCalendarTheme().weekHeight).ConvertToPx();
608     auto weekAndDayRowSpace =
609         paintProperty->GetWeekAndDayRowSpace().value_or(theme->GetCalendarTheme().weekAndDayRowSpace).ConvertToPx();
610     auto dayHeight = paintProperty->GetDayHeight().value_or(theme->GetCalendarTheme().dayHeight).ConvertToPx();
611     auto dayWidth = paintProperty->GetDayWidth().value_or(theme->GetCalendarTheme().dayWidth).ConvertToPx();
612     const static int32_t columnsOfData = 7;
613     auto colSpace = paintProperty->GetColSpaceValue({}).ConvertToPx() <= 0
614                         ? theme->GetCalendarTheme().colSpace.ConvertToPx()
615                         : paintProperty->GetColSpaceValue({}).ConvertToPx();
616     auto dailyFourRowSpace = NonPositive(paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx())
617                                  ? theme->GetCalendarTheme().dailySixRowSpace.ConvertToPx()
618                                  : paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx();
619     auto dailyFiveRowSpace = paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx() <= 0
620                                  ? theme->GetCalendarTheme().dailyFiveRowSpace.ConvertToPx()
621                                  : paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx();
622     auto dailySixRowSpace = paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx() <= 0
623                                 ? theme->GetCalendarTheme().dailySixRowSpace.ConvertToPx()
624                                 : paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx();
625     auto rows = (static_cast<int32_t>(obtainedMonth_.days.size()) / columnsOfData);
626     auto rowSpace = dailySixRowSpace;
627     switch (rows) {
628         case 4: {
629             rowSpace = dailyFourRowSpace;
630             break;
631         }
632         case 5: {
633             rowSpace = dailyFiveRowSpace;
634             break;
635         }
636         default:
637             break;
638     }
639     if (IsLargeSize(theme)) {
640         gregorianDayHeight = GetDaySize(theme).ConvertToPx();
641     }
642     auto browHeight = weekHeight + weekAndDayRowSpace - gregorianDayHeight;
643     auto maxHeight = host->GetGeometryNode()->GetFrameSize().Height();
644     auto maxWidth = host->GetGeometryNode()->GetFrameSize().Width();
645     if ((offset.GetX() < 0) || (offset.GetX() > maxWidth) || (offset.GetY() < browHeight) ||
646         (offset.GetY() > maxHeight) || LessOrEqual(dayHeight, 0.0) || LessOrEqual(dayWidth, 0.0)) {
647         return -1;
648     }
649     auto height = offset.GetY() - browHeight;
650     int32_t y =
651         height < (dayHeight + rowSpace / 2) ? 0 : (height - dayHeight - rowSpace / 2) / (dayHeight + rowSpace) + 1;
652     int32_t x = offset.GetX() < (dayWidth + colSpace / 2)
653                     ? 0
654                     : (offset.GetX() - dayWidth - colSpace / 2) / (dayWidth + colSpace) + 1;
655     auto textDirection = host->GetLayoutProperty()->GetNonAutoLayoutDirection();
656     if (textDirection == TextDirection::RTL) {
657         x = columnsOfData - x - 1;
658     }
659     return (y * columnsOfData + x);
660 }
661 
662 class CalendarAccessibilitySAObserverCallback : public AccessibilitySAObserverCallback {
663 public:
664     CalendarAccessibilitySAObserverCallback(
665         const WeakPtr<CalendarMonthPattern> &weakCalendarPattern, int64_t accessibilityId)
666         : AccessibilitySAObserverCallback(accessibilityId), weakCalendarPattern_(weakCalendarPattern)
667     {}
668 
669     ~CalendarAccessibilitySAObserverCallback() override = default;
670 
671     bool OnState(bool state) override
672     {
673         auto calendarPattern = weakCalendarPattern_.Upgrade();
674         CHECK_NULL_RETURN(calendarPattern, false);
675         if (state) {
676             calendarPattern->InitCurrentVirtualNode();
677         } else {
678             calendarPattern->ClearCalendarVirtualNode();
679         }
680         return true;
681     }
682 private:
683     WeakPtr<CalendarMonthPattern> weakCalendarPattern_;
684 };
685 
686 void CalendarMonthPattern::InitializeCalendarAccessibility()
687 {
688     auto host = GetHost();
689     CHECK_NULL_VOID(host);
690     auto pipeline = host->GetContext();
691     CHECK_NULL_VOID(pipeline);
692     auto accessibilityManager = pipeline->GetAccessibilityManager();
693     CHECK_NULL_VOID(accessibilityManager);
694     accessibilitySAObserverCallback_ = std::make_shared<CalendarAccessibilitySAObserverCallback>(
695         WeakClaim(this), host->GetAccessibilityId());
696     accessibilityManager->RegisterAccessibilitySAObserverCallback(host->GetAccessibilityId(),
697         accessibilitySAObserverCallback_);
698     if (margin_ == 0) {
699         auto paintProperty = host->GetPaintProperty<CalendarPaintProperty>();
700         CHECK_NULL_VOID(paintProperty);
701         dayHeight_ = paintProperty->GetDayHeight().value_or(Dimension(0.0f)).ConvertToPx();
702         dayWidth_ = paintProperty->GetDayWidth().value_or(Dimension(0.0f)).ConvertToPx();
703         RefPtr<CalendarTheme> theme = pipeline->GetTheme<CalendarTheme>();
704         CHECK_NULL_VOID(theme);
705         auto sliderTheme = pipeline->GetTheme<SliderTheme>();
706         CHECK_NULL_VOID(sliderTheme);
707         margin_ = theme->GetDialogMargin().ConvertToPx();
708         selectedTxt_ = sliderTheme->GetSelectedTxt();
709         disabledDesc_ = sliderTheme->GetDisabelDesc();
710         deviceOrientation_ = SystemProperties::GetDeviceOrientation();
711     }
712 }
713 
714 void CalendarMonthPattern::InitCurrentVirtualNode()
715 {
716     auto deviceOrientation = SystemProperties::GetDeviceOrientation();
717     if ((!isInitVirtualNode_ || buttonAccessibilityNodeVec_.size() != obtainedMonth_.days.size() ||
718         deviceOrientation_ != deviceOrientation) &&
719         monthState_ == MonthState::CUR_MONTH) {
720         isInitVirtualNode_ = InitCalendarVirtualNode();
721     } else {
722         FireModifyAccessibilityVirtualNode(obtainedMonth_);
723     }
724 }
725 
726 void CalendarMonthPattern::ClearFocusCalendarDay()
727 {
728     focusedCalendarDay_.index = 0;
729     deviceOrientation_ = SystemProperties::GetDeviceOrientation();
730     CHECK_NULL_VOID(lineNode_);
731     auto lineNodeProp = lineNode_->GetLayoutProperty();
732     CHECK_NULL_VOID(lineNodeProp);
733     if (monthState_ == MonthState::CUR_MONTH) {
734         lineNodeProp->UpdateVisibility(VisibleType::VISIBLE);
735     } else {
736         lineNodeProp->UpdateVisibility(VisibleType::GONE);
737     }
738 }
739 
740 void CalendarMonthPattern::ClearCalendarVirtualNode()
741 {
742     auto host = GetHost();
743     CHECK_NULL_VOID(host);
744     buttonAccessibilityNodeVec_.clear();
745     accessibilityPropertyVec_.clear();
746     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
747     CHECK_NULL_VOID(accessibilityProperty);
748     accessibilityProperty->SaveAccessibilityVirtualNode(nullptr);
749 }
750 
751 void CalendarMonthPattern::SetLineNodeSize(RefPtr<FrameNode> lineNode)
752 {
753     auto host = GetHost();
754     CHECK_NULL_VOID(host);
755     auto hostLayoutProperty = host->GetLayoutProperty();
756     CHECK_NULL_VOID(hostLayoutProperty);
757     auto width = hostLayoutProperty->GetLayoutConstraint()->selfIdealSize.Width().value_or(Infinity<float>());
758     auto height = hostLayoutProperty->GetLayoutConstraint()->selfIdealSize.Height().value_or(Infinity<float>());
759     CHECK_NULL_VOID(lineNode);
760     auto layoutProperty = lineNode->GetLayoutProperty<LayoutProperty>();
761     CHECK_NULL_VOID(layoutProperty);
762     layoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(width), CalcLength(height)));
763 }
764 
765 void CalendarMonthPattern::SetFocusNode(int32_t index, bool isDeviceOrientation)
766 {
767     auto host = GetHost();
768     CHECK_NULL_VOID(host);
769     auto layoutProperty = host->GetLayoutProperty();
770     CHECK_NULL_VOID(layoutProperty);
771     auto textDirection = layoutProperty->GetNonAutoLayoutDirection();
772     auto remainderWeek = index % CALENDAR_WEEK_DAYS;
773     int32_t selectedIndex = (textDirection == TextDirection::RTL ?
774         CALENDAR_WEEK_DAYS - remainderWeek * 2 + index - 1 : index);
775     if (isDeviceOrientation) {
776         selectedIndex = index;
777     }
778     if (selectedIndex >= static_cast<int32_t>(buttonAccessibilityNodeVec_.size()) || selectedIndex < 0) {
779         return;
780     }
781     buttonAccessibilityNodeVec_[selectedIndex]->OnAccessibilityEvent(AccessibilityEventType::REQUEST_FOCUS);
782     selectedIndex_ = selectedIndex;
783 }
784 
785 bool CalendarMonthPattern::InitCalendarVirtualNode()
786 {
787     auto host = GetHost();
788     CHECK_NULL_RETURN(host, false);
789     buttonAccessibilityNodeVec_.clear();
790     accessibilityPropertyVec_.clear();
791     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
792     CHECK_NULL_RETURN(accessibilityProperty, false);
793     accessibilityProperty->SaveAccessibilityVirtualNode(nullptr);
794     auto lineNode = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
795         AceType::MakeRefPtr<LinearLayoutPattern>(true));
796     for (auto& day : obtainedMonth_.days) {
797         auto buttonNode = AddButtonNodeIntoVirtual(day);
798         lineNode->AddChild(buttonNode);
799         buttonAccessibilityNodeVec_.emplace_back(buttonNode);
800         ChangeVirtualNodeContent(day);
801     }
802     SetLineNodeSize(lineNode);
803     SetCalendarAccessibilityLevel(AccessibilityProperty::Level::NO_STR);
804     accessibilityProperty->SetAccessibilityText(" ");
805     auto virtualFrameNode = AceType::DynamicCast<NG::FrameNode>(lineNode);
806     CHECK_NULL_RETURN(virtualFrameNode, false);
807     virtualFrameNode->SetAccessibilityNodeVirtual();
808     virtualFrameNode->SetAccessibilityVirtualNodeParent(AceType::DynamicCast<NG::UINode>(host));
809     virtualFrameNode->SetFirstAccessibilityVirtualNode();
810     FrameNode::ProcessOffscreenNode(virtualFrameNode);
811     accessibilityProperty->SaveAccessibilityVirtualNode(lineNode);
812     lineNode_ = lineNode;
813     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
814     auto deviceOrientation = SystemProperties::GetDeviceOrientation();
815     if (deviceOrientation_ != deviceOrientation && !isFirstEnter_) {
816         SetFocusNode(focusedCalendarDay_.index, true);
817         deviceOrientation_ = deviceOrientation;
818     }
819     if (!isFirstEnter_) {
820         return true;
821     }
822     for (auto &day : obtainedMonth_.days) {
823         if (day.isSelected) {
824             SetFocusNode(day.index);
825             isFirstEnter_ = false;
826             focusedCalendarDay_ = day;
827             break;
828         }
829     }
830     return true;
831 }
832 
833 std::pair<int32_t, int32_t> GetXYByIndex(const int32_t index)
834 {
835     if (index < CALENDAR_WEEK_DAYS - 1) {
836         return {index, 0};
837     } else {
838         return {(index % CALENDAR_WEEK_DAYS), (index / CALENDAR_WEEK_DAYS)};
839     }
840 }
841 
842 void CalendarMonthPattern::ChangeVirtualNodeState(const CalendarDay& calendarDay)
843 {
844     if (selectedIndex_ >= static_cast<int32_t>(accessibilityPropertyVec_.size()) || selectedIndex_ < 0) {
845         return;
846     }
847     if (calendarDay.index != selectedIndex_ &&
848         calendarDay.month.month == obtainedMonth_.month && calendarDay.month.month == obtainedMonth_.month) {
849         accessibilityPropertyVec_[selectedIndex_]->SetUserSelected(true);
850     }
851 }
852 
853 RefPtr<FrameNode> CalendarMonthPattern::AddButtonNodeIntoVirtual(const CalendarDay& calendarDay)
854 {
855     auto buttonNode = FrameNode::CreateFrameNode(
856         V2::BUTTON_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ButtonPattern>());
857     auto buttonAccessibilityProperty = buttonNode->GetAccessibilityProperty<AccessibilityProperty>();
858     CHECK_NULL_RETURN(buttonAccessibilityProperty, nullptr);
859     auto host = GetHost();
860     CHECK_NULL_RETURN(host, nullptr);
861     auto pipeline = host->GetContext();
862     if (pipeline) {
863         UpdateAccessibilityButtonNode(buttonNode, calendarDay.index);
864     } else {
865         UpdateButtonNodeWithoutTheme(buttonNode, calendarDay.index);
866     }
867     accessibilityPropertyVec_.emplace_back(buttonAccessibilityProperty);
868     InitVirtualButtonClickEvent(buttonNode, calendarDay.index);
869     buttonAccessibilityProperty->SetOnAccessibilityFocusCallback([weak = WeakClaim(this), calendarDay](bool focus) {
870         if (focus) {
871             auto calendar = weak.Upgrade();
872             CHECK_NULL_VOID(calendar);
873             calendar->focusedCalendarDay_ = calendarDay;
874             calendar->ChangeVirtualNodeState(calendarDay);
875         }
876     });
877     return buttonNode;
878 }
879 
880 float GetRowSpace(RefPtr<CalendarPaintProperty> paintProperty, RefPtr<CalendarTheme> theme, size_t daySize)
881 {
882     auto dailyFourRowSpace = NonPositive(paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx())
883                                  ? theme->GetCalendarTheme().dailySixRowSpace.ConvertToPx()
884                                  : paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx();
885     auto dailyFiveRowSpace = paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx() <= 0
886                                  ? theme->GetCalendarTheme().dailyFiveRowSpace.ConvertToPx()
887                                  : paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx();
888     auto dailySixRowSpace = paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx() <= 0
889                                 ? theme->GetCalendarTheme().dailySixRowSpace.ConvertToPx()
890                                 : paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx();
891     auto rows = (static_cast<int32_t>(daySize) / CALENDAR_WEEK_DAYS);
892     auto rowSpace = dailySixRowSpace;
893     switch (rows) {
894         case DAILY_FOUR_ROWSPACE: {
895             rowSpace = dailyFourRowSpace;
896             break;
897         }
898         case DAILY_FIVE_ROWSPACE: {
899             rowSpace = dailyFiveRowSpace;
900             break;
901         }
902         default:
903             break;
904     }
905     return rowSpace;
906 }
907 
908 void CalendarMonthPattern::SetCalendarAccessibilityLevel(const std::string& level)
909 {
910     auto host = GetHost();
911     CHECK_NULL_VOID(host);
912     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
913     CHECK_NULL_VOID(accessibilityProperty);
914     accessibilityProperty->SetAccessibilityLevel(level);
915     auto parent = host->GetParent();
916     while (parent && parent->GetTag() != V2::DIALOG_ETS_TAG) {
917         auto parentNode = AceType::DynamicCast<NG::FrameNode>(parent);
918         CHECK_NULL_VOID(parentNode);
919         auto parentAccessibilityProperty = parentNode->GetAccessibilityProperty<AccessibilityProperty>();
920         CHECK_NULL_VOID(parentAccessibilityProperty);
921         parentAccessibilityProperty->SetAccessibilityLevel(level);
922         parent = parent->GetParent();
923     }
924 }
925 
926 void CalendarMonthPattern::InitAccessibilityHoverEvent()
927 {
928     auto host = GetHost();
929     CHECK_NULL_VOID(host);
930     auto eventHub = host->GetOrCreateInputEventHub();
931     CHECK_NULL_VOID(eventHub);
932     eventHub->SetAccessibilityHoverEvent([weak = WeakClaim(this)](bool isHover, AccessibilityHoverInfo& info) {
933         auto calendar = weak.Upgrade();
934         CHECK_NULL_VOID(calendar);
935         calendar->HandleAccessibilityHoverEvent(isHover, info);
936     });
937 }
938 
939 void CalendarMonthPattern::HandleAccessibilityHoverEvent(bool isHover, AccessibilityHoverInfo& info)
940 {
941     if (isHover) {
942         isOnHover_ = true;
943     } else if (!isHover) {
944         isOnHover_ = false;
945     }
946 }
947 
948 float GetRowSpaceWithoutTheme(RefPtr<CalendarPaintProperty> paintProperty, size_t daySize)
949 {
950     auto dailyFourRowSpace = NonPositive(paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx())
951                                  ? 0.0f
952                                  : paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx();
953     auto dailyFiveRowSpace = paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx() <= 0
954                                  ? 0.0f
955                                  : paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx();
956     auto dailySixRowSpace = paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx() <= 0
957                                 ? 0.0f
958                                 : paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx();
959     auto rows = (static_cast<int32_t>(daySize) / CALENDAR_WEEK_DAYS);
960     auto rowSpace = dailySixRowSpace;
961     switch (rows) {
962         case DAILY_FOUR_ROWSPACE: {
963             rowSpace = dailyFourRowSpace;
964             break;
965         }
966         case DAILY_FIVE_ROWSPACE: {
967             rowSpace = dailyFiveRowSpace;
968             break;
969         }
970         default:
971             break;
972     }
973     return rowSpace;
974 }
975 
976 void CalendarMonthPattern::UpdateButtonNodeWithoutTheme(RefPtr<FrameNode> frameNode, int32_t index)
977 {
978     auto host = GetHost();
979     CHECK_NULL_VOID(host);
980     auto paintProperty = host->GetPaintProperty<CalendarPaintProperty>();
981     CHECK_NULL_VOID(paintProperty);
982     auto dayHeight = paintProperty->GetDayHeight().value_or(Dimension(0.0f)).ConvertToPx();
983     auto dayWidth = paintProperty->GetDayWidth().value_or(Dimension(0.0f)).ConvertToPx();
984     CHECK_NULL_VOID(frameNode);
985     auto buttonLayoutProperty = frameNode->GetLayoutProperty<ButtonLayoutProperty>();
986     CHECK_NULL_VOID(buttonLayoutProperty);
987     buttonLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(dayWidth), CalcLength(dayHeight)));
988     auto pos = GetXYByIndex(index);
989     auto colSpace = paintProperty->GetColSpaceValue({}).ConvertToPx() <= 0
990                     ? 0.0f
991                     : paintProperty->GetColSpaceValue({}).ConvertToPx();
992     Dimension buttonOffsetX = Dimension(margin_ / 2 + (colSpace + dayWidth) * pos.first);
993     auto weekHeight = paintProperty->GetWeekHeight().value_or(Dimension(0.0f)).ConvertToPx();
994     auto rowSpace = GetRowSpaceWithoutTheme(paintProperty, obtainedMonth_.days.size());
995     auto weekAndDayRowSpace =
996         paintProperty->GetWeekAndDayRowSpace().value_or(Dimension(0.0f)).ConvertToPx();
997     auto gregorianDayHeight = paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx();
998     auto browHeight = weekHeight + weekAndDayRowSpace - gregorianDayHeight;
999     Dimension buttonOffsetY = Dimension(browHeight + (dayHeight + rowSpace) * pos.second);
1000     auto renderContext = frameNode->GetRenderContext();
1001     CHECK_NULL_VOID(renderContext);
1002     renderContext->UpdatePosition(OffsetT(buttonOffsetX, buttonOffsetY));
1003     frameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1004 }
1005 
1006 void CalendarMonthPattern::UpdateAccessibilityButtonNode(RefPtr<FrameNode> frameNode, int32_t index)
1007 {
1008     auto host = GetHost();
1009     CHECK_NULL_VOID(host);
1010     auto paintProperty = host->GetPaintProperty<CalendarPaintProperty>();
1011     CHECK_NULL_VOID(paintProperty);
1012     auto pipelineContext = host->GetContext();
1013     CHECK_NULL_VOID(pipelineContext);
1014     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
1015     CHECK_NULL_VOID(theme);
1016     auto dayHeight = paintProperty->GetDayHeight().value_or(theme->GetCalendarTheme().dayHeight).ConvertToPx();
1017     auto dayWidth = paintProperty->GetDayWidth().value_or(theme->GetCalendarTheme().dayWidth).ConvertToPx();
1018     CHECK_NULL_VOID(frameNode);
1019     auto buttonLayoutProperty = frameNode->GetLayoutProperty<ButtonLayoutProperty>();
1020     CHECK_NULL_VOID(buttonLayoutProperty);
1021     buttonLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(dayWidth), CalcLength(dayHeight)));
1022     auto renderContext = frameNode->GetRenderContext();
1023     CHECK_NULL_VOID(renderContext);
1024     auto pos = GetXYByIndex(index);
1025     auto colSpace = paintProperty->GetColSpaceValue({}).ConvertToPx() <= 0
1026                     ? theme->GetCalendarTheme().colSpace.ConvertToPx()
1027                     : paintProperty->GetColSpaceValue({}).ConvertToPx();
1028     colSpace_ = colSpace;
1029     Dimension buttonOffsetX = Dimension(margin_ / 2 + (colSpace + dayWidth) * pos.first);
1030     auto gregorianDayHeight = paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx() <= 0
1031                             ? theme->GetCalendarTheme().gregorianCalendarHeight.ConvertToPx()
1032                             : paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx();
1033     auto weekHeight = paintProperty->GetWeekHeight().value_or(theme->GetCalendarTheme().weekHeight).ConvertToPx();
1034     auto rowSpace = GetRowSpace(paintProperty, theme, obtainedMonth_.days.size());
1035     auto weekAndDayRowSpace =
1036         paintProperty->GetWeekAndDayRowSpace().value_or(theme->GetCalendarTheme().weekAndDayRowSpace).ConvertToPx();
1037     if (IsLargeSize(theme)) {
1038         gregorianDayHeight = GetDaySize(theme).ConvertToPx();
1039     }
1040     auto browHeight = weekHeight + weekAndDayRowSpace - gregorianDayHeight;
1041     Dimension buttonOffsetY = Dimension(browHeight + (dayHeight + rowSpace) * pos.second);
1042     renderContext->UpdatePosition(OffsetT(buttonOffsetX, buttonOffsetY));
1043     frameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1044 }
1045 
1046 std::string CalendarMonthPattern::GetDayStr(int32_t index)
1047 {
1048     auto host = GetHost();
1049     CHECK_NULL_RETURN(host, "");
1050     auto pipelineContext = host->GetContext();
1051     CHECK_NULL_RETURN(pipelineContext, "");
1052     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
1053     CHECK_NULL_RETURN(theme, "");
1054     switch (index) {
1055         case MONDAY_INDEX:
1056             return theme->GetCalendarTheme().monday;
1057         case TUESDAY_INDEX:
1058             return theme->GetCalendarTheme().tuesday;
1059         case WEDNESDAY_INDEX:
1060             return theme->GetCalendarTheme().wednesday;
1061         case THURSDAY_INDEX:
1062             return theme->GetCalendarTheme().thursday;
1063         case FRIDAY_INDEX:
1064             return theme->GetCalendarTheme().friday;
1065         case SATURDAY_INDEX:
1066             return theme->GetCalendarTheme().saturday;
1067         default:
1068             return theme->GetCalendarTheme().sunday;
1069     }
1070 }
1071 
1072 void CalendarMonthPattern::ChangeVirtualNodeContent(const CalendarDay& calendarDay)
1073 {
1074     auto host = GetHost();
1075     CHECK_NULL_VOID(host);
1076     auto layoutProperty = host->GetLayoutProperty();
1077     CHECK_NULL_VOID(layoutProperty);
1078     auto textDirection = layoutProperty->GetNonAutoLayoutDirection();
1079     auto remainderWeek = calendarDay.index % CALENDAR_WEEK_DAYS;
1080     int32_t index = (textDirection == TextDirection::RTL ?
1081         CALENDAR_WEEK_DAYS - remainderWeek * 2 + calendarDay.index - 1 : calendarDay.index);
1082     if (index >= static_cast<int32_t>(buttonAccessibilityNodeVec_.size()) || index < 0) {
1083         return;
1084     }
1085     std::string message;
1086     if (calendarDay.month.year == calendarDay_.month.year && calendarDay.month.month == calendarDay_.month.month &&
1087                       calendarDay.day == calendarDay_.day) {
1088         message += Localization::GetInstance()->GetEntryLetters("calendar.today");
1089     }
1090     message += std::to_string(calendarDay.month.year) + "/";
1091     message += std::to_string(calendarDay.month.month) + "/";
1092     message += std::to_string(calendarDay.day);
1093     message += GetDayStr(remainderWeek);
1094     auto node = buttonAccessibilityNodeVec_[index];
1095     auto buttonAccessibilityProperty = node->GetAccessibilityProperty<AccessibilityProperty>();
1096     CHECK_NULL_VOID(buttonAccessibilityProperty);
1097     if (calendarDay.month.month != obtainedMonth_.month) {
1098         buttonAccessibilityProperty->SetAccessibilityDescription(disabledDesc_);
1099     } else if (index == selectedIndex_) {
1100         // Delete the description of the selected node
1101         buttonAccessibilityProperty->SetAccessibilityDescription(" ");
1102     } else {
1103         // Set the default description to other nodes
1104         buttonAccessibilityProperty->SetAccessibilityDescription("");
1105     }
1106     buttonAccessibilityProperty->SetUserDisabled(calendarDay.month.month != obtainedMonth_.month ? true : false);
1107     buttonAccessibilityProperty->SetUserSelected(false);
1108     buttonAccessibilityProperty->SetAccessibilityText(message);
1109 }
1110 
1111 void CalendarMonthPattern::FireModifyAccessibilityVirtualNode(const ObtainedMonth& currentData)
1112 {
1113     if (isInitVirtualNode_) {
1114         auto host = GetHost();
1115         CHECK_NULL_VOID(host);
1116         auto pipeline = host->GetContext();
1117         CHECK_NULL_VOID(pipeline);
1118         pipeline->AddAfterRenderTask([weak = WeakClaim(this), currentData]() {
1119             auto calendarMonthPattern = weak.Upgrade();
1120             CHECK_NULL_VOID(calendarMonthPattern);
1121             calendarMonthPattern->ModifyAccessibilityVirtualNode(currentData);
1122         });
1123     }
1124 }
1125 
1126 void CalendarMonthPattern::ModifyAccessibilityVirtualNode(const ObtainedMonth& currentData)
1127 {
1128     if (buttonAccessibilityNodeVec_.size() < 1) {
1129         return;
1130     }
1131     for (auto& day : currentData.days) {
1132         ChangeVirtualNodeContent(day);
1133     }
1134 }
1135 } // namespace OHOS::Ace::NG
1136