1 /*
2  * Copyright (c) 2023 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/grid/grid_item_pattern.h"
17 
18 #include "base/log/dump_log.h"
19 #include "base/utils/utils.h"
20 #include "core/components_ng/pattern/grid/grid_item_layout_property.h"
21 #include "core/components_ng/pattern/grid/grid_item_theme.h"
22 #include "core/pipeline_ng/pipeline_context.h"
23 namespace OHOS::Ace::NG {
24 namespace {
25 const Color ITEM_FILL_COLOR = Color::TRANSPARENT;
26 } // namespace
OnAttachToFrameNode()27 void GridItemPattern::OnAttachToFrameNode()
28 {
29     if (gridItemStyle_ == GridItemStyle::PLAIN) {
30         auto host = GetHost();
31         CHECK_NULL_VOID(host);
32         auto pipeline = PipelineContext::GetCurrentContext();
33         CHECK_NULL_VOID(pipeline);
34         auto theme = pipeline->GetTheme<GridItemTheme>();
35         CHECK_NULL_VOID(theme);
36         auto renderContext = host->GetRenderContext();
37         CHECK_NULL_VOID(renderContext);
38         renderContext->UpdateBorderRadius(theme->GetGridItemBorderRadius());
39     }
40 }
41 
OnModifyDone()42 void GridItemPattern::OnModifyDone()
43 {
44     Pattern::OnModifyDone();
45     SetAccessibilityAction();
46     auto host = GetHost();
47     CHECK_NULL_VOID(host);
48     auto focusHub = host->GetFocusHub();
49     CHECK_NULL_VOID(focusHub);
50     InitFocusPaintRect(focusHub);
51     InitDisableStyle();
52     if (gridItemStyle_ == GridItemStyle::PLAIN) {
53         InitHoverEvent();
54         InitPressEvent();
55     }
56 }
57 
MarkIsSelected(bool isSelected)58 void GridItemPattern::MarkIsSelected(bool isSelected)
59 {
60     if (isSelected_ != isSelected) {
61         isSelected_ = isSelected;
62         auto eventHub = GetEventHub<GridItemEventHub>();
63         CHECK_NULL_VOID(eventHub);
64         eventHub->FireSelectChangeEvent(isSelected);
65         auto host = GetHost();
66         CHECK_NULL_VOID(host);
67         if (isSelected) {
68             eventHub->UpdateCurrentUIState(UI_STATE_SELECTED);
69             host->OnAccessibilityEvent(AccessibilityEventType::SELECTED);
70         } else {
71             eventHub->ResetCurrentUIState(UI_STATE_SELECTED);
72             host->OnAccessibilityEvent(AccessibilityEventType::CHANGE);
73         }
74     }
75 }
76 
SetSelectable(bool selectable)77 void GridItemPattern::SetSelectable(bool selectable)
78 {
79     if (isSelected_ && selectable_ && !selectable) {
80         auto host = GetHost();
81         CHECK_NULL_VOID(host);
82         auto context = host->GetRenderContext();
83         CHECK_NULL_VOID(context);
84         context->OnMouseSelectUpdate(false, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
85         MarkIsSelected(false);
86     }
87     selectable_ = selectable;
88 }
89 
SetAccessibilityAction()90 void GridItemPattern::SetAccessibilityAction()
91 {
92     auto host = GetHost();
93     CHECK_NULL_VOID(host);
94     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
95     CHECK_NULL_VOID(accessibilityProperty);
96     accessibilityProperty->SetActionSelect([weakPtr = WeakClaim(this)]() {
97         const auto& pattern = weakPtr.Upgrade();
98         CHECK_NULL_VOID(pattern);
99         if (!pattern->Selectable()) {
100             return;
101         }
102         auto host = pattern->GetHost();
103         CHECK_NULL_VOID(host);
104         auto context = host->GetRenderContext();
105         CHECK_NULL_VOID(context);
106         pattern->MarkIsSelected(true);
107         context->OnMouseSelectUpdate(true, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
108     });
109 
110     accessibilityProperty->SetActionClearSelection([weakPtr = WeakClaim(this)]() {
111         const auto& pattern = weakPtr.Upgrade();
112         CHECK_NULL_VOID(pattern);
113         if (!pattern->Selectable()) {
114             return;
115         }
116         auto host = pattern->GetHost();
117         CHECK_NULL_VOID(host);
118         auto context = host->GetRenderContext();
119         CHECK_NULL_VOID(context);
120         pattern->MarkIsSelected(false);
121         context->OnMouseSelectUpdate(false, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
122     });
123 }
124 
BeforeCreateLayoutWrapper()125 void GridItemPattern::BeforeCreateLayoutWrapper()
126 {
127     if (shallowBuilder_ && !shallowBuilder_->IsExecuteDeepRenderDone()) {
128         shallowBuilder_->ExecuteDeepRender();
129         shallowBuilder_.Reset();
130     }
131 }
132 
GetBlendGgColor()133 Color GridItemPattern::GetBlendGgColor()
134 {
135     Color color = Color::TRANSPARENT;
136     auto pipeline = PipelineContext::GetCurrentContext();
137     CHECK_NULL_RETURN(pipeline, color);
138     auto theme = pipeline->GetTheme<GridItemTheme>();
139     CHECK_NULL_RETURN(theme, color);
140     if (isPressed_) {
141         color = color.BlendColor(theme->GetGridItemPressColor());
142     } else if (isHover_) {
143         color = color.BlendColor(theme->GetGridItemHoverColor());
144     }
145     return color;
146 }
147 
InitHoverEvent()148 void GridItemPattern::InitHoverEvent()
149 {
150     if (hoverEvent_) {
151         return;
152     }
153     auto host = GetHost();
154     CHECK_NULL_VOID(host);
155     auto eventHub = host->GetEventHub<GridItemEventHub>();
156     CHECK_NULL_VOID(eventHub);
157     auto inputHub = eventHub->GetOrCreateInputEventHub();
158     CHECK_NULL_VOID(inputHub);
159     auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
160         auto pattern = weak.Upgrade();
161         if (pattern) {
162             pattern->HandleHoverEvent(isHover);
163         }
164     };
165     hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
166     inputHub->AddOnHoverEvent(hoverEvent_);
167 }
168 
HandleHoverEvent(bool isHover)169 void GridItemPattern::HandleHoverEvent(bool isHover)
170 {
171     auto host = GetHost();
172     CHECK_NULL_VOID(host);
173     auto renderContext = host->GetRenderContext();
174     CHECK_NULL_VOID(renderContext);
175     auto pipeline = PipelineContext::GetCurrentContext();
176     CHECK_NULL_VOID(pipeline);
177     auto theme = pipeline->GetTheme<GridItemTheme>();
178     CHECK_NULL_VOID(theme);
179 
180     isHover_ = isHover;
181     auto hoverColor = GetBlendGgColor();
182     AnimationUtils::BlendBgColorAnimation(
183         renderContext, hoverColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
184 }
185 
InitPressEvent()186 void GridItemPattern::InitPressEvent()
187 {
188     if (touchListener_) {
189         return;
190     }
191     auto host = GetHost();
192     CHECK_NULL_VOID(host);
193     auto gesture = host->GetOrCreateGestureEventHub();
194     CHECK_NULL_VOID(gesture);
195     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
196         auto pattern = weak.Upgrade();
197         CHECK_NULL_VOID(pattern);
198         auto touchType = info.GetTouches().front().GetTouchType();
199         if (touchType == TouchType::DOWN || touchType == TouchType::UP) {
200             pattern->HandlePressEvent(touchType == TouchType::DOWN);
201         }
202     };
203     auto touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
204     gesture->AddTouchEvent(touchListener_);
205 }
206 
HandlePressEvent(bool isPressed)207 void GridItemPattern::HandlePressEvent(bool isPressed)
208 {
209     auto host = GetHost();
210     CHECK_NULL_VOID(host);
211     auto renderContext = host->GetRenderContext();
212     CHECK_NULL_VOID(renderContext);
213     auto pipeline = PipelineBase::GetCurrentContext();
214     CHECK_NULL_VOID(pipeline);
215     auto theme = pipeline->GetTheme<GridItemTheme>();
216     CHECK_NULL_VOID(theme);
217     auto duration = isHover_ ? theme->GetHoverToPressAnimationDuration() : theme->GetHoverAnimationDuration();
218     isPressed_ = isPressed;
219     Color color = GetBlendGgColor();
220     AnimationUtils::BlendBgColorAnimation(renderContext, color, duration, Curves::SHARP);
221 }
222 
InitDisableStyle()223 void GridItemPattern::InitDisableStyle()
224 {
225     auto host = GetHost();
226     CHECK_NULL_VOID(host);
227     auto eventHub = host->GetEventHub<GridItemEventHub>();
228     CHECK_NULL_VOID(eventHub);
229     auto renderContext = host->GetRenderContext();
230     CHECK_NULL_VOID(renderContext);
231     auto pipeline = PipelineBase::GetCurrentContext();
232     CHECK_NULL_VOID(pipeline);
233     auto theme = pipeline->GetTheme<GridItemTheme>();
234     CHECK_NULL_VOID(theme);
235     float opacity = 1.0f;
236     if (!eventHub->IsDeveloperEnabled()) {
237         opacity = theme->GetGridItemDisabledAlpha();
238     }
239     renderContext->SetOpacityMultiplier(opacity);
240 }
241 
InitFocusPaintRect(const RefPtr<FocusHub> & focusHub)242 void GridItemPattern::InitFocusPaintRect(const RefPtr<FocusHub>& focusHub)
243 {
244     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
245         auto pattern = wp.Upgrade();
246         if (pattern) {
247             pattern->GetInnerFocusPaintRect(paintRect);
248         }
249     };
250     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
251 }
252 
GetInnerFocusPaintRect(RoundRect & paintRect)253 void GridItemPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
254 {
255     auto host = GetHost();
256     CHECK_NULL_VOID(host);
257     auto geometryNode = host->GetGeometryNode();
258     CHECK_NULL_VOID(geometryNode);
259     auto gridItemSize = geometryNode->GetFrameSize();
260     auto pipelineContext = PipelineBase::GetCurrentContext();
261     CHECK_NULL_VOID(pipelineContext);
262     auto theme = pipelineContext->GetTheme<GridItemTheme>();
263     CHECK_NULL_VOID(theme);
264     auto focusPaintPadding = theme->GetFocusPaintPadding().ConvertToPx();
265     float width = gridItemSize.Width() + 2 * focusPaintPadding;
266     float height = gridItemSize.Height() + 2 * focusPaintPadding;
267     paintRect.SetRect({ -focusPaintPadding, -focusPaintPadding, width, height });
268     auto renderContext = host->GetRenderContext();
269     CHECK_NULL_VOID(renderContext);
270     auto radius = renderContext->GetBorderRadius().value_or(BorderRadiusProperty());
271     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS,
272         static_cast<float>(radius.radiusTopLeft->ConvertToPx() + focusPaintPadding),
273         static_cast<float>(radius.radiusTopLeft->ConvertToPx() + focusPaintPadding));
274     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS,
275         static_cast<float>(radius.radiusTopRight->ConvertToPx() + focusPaintPadding),
276         static_cast<float>(radius.radiusTopRight->ConvertToPx() + focusPaintPadding));
277     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS,
278         static_cast<float>(radius.radiusBottomLeft->ConvertToPx() + focusPaintPadding),
279         static_cast<float>(radius.radiusBottomLeft->ConvertToPx() + focusPaintPadding));
280     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS,
281         static_cast<float>(radius.radiusBottomRight->ConvertToPx() + focusPaintPadding),
282         static_cast<float>(radius.radiusBottomRight->ConvertToPx() + focusPaintPadding));
283 }
284 
DumpAdvanceInfo()285 void GridItemPattern::DumpAdvanceInfo()
286 {
287     auto property = GetLayoutProperty<GridItemLayoutProperty>();
288     CHECK_NULL_VOID(property);
289     property->GetMainIndex().has_value()
290         ? DumpLog::GetInstance().AddDesc("MainIndex:" + std::to_string(property->GetMainIndex().value()))
291         : DumpLog::GetInstance().AddDesc("MainIndex:null");
292     property->GetCrossIndex().has_value()
293         ? DumpLog::GetInstance().AddDesc("CrossIndex:" + std::to_string(property->GetCrossIndex().value()))
294         : DumpLog::GetInstance().AddDesc("CrossIndex:null");
295     property->GetRowStart().has_value()
296         ? DumpLog::GetInstance().AddDesc("RowStart:" + std::to_string(property->GetRowStart().value()))
297         : DumpLog::GetInstance().AddDesc("RowStart:null");
298     property->GetRowEnd().has_value()
299         ? DumpLog::GetInstance().AddDesc("RowEnd:" + std::to_string(property->GetRowEnd().value()))
300         : DumpLog::GetInstance().AddDesc("RowEnd:null");
301     property->GetColumnStart().has_value()
302         ? DumpLog::GetInstance().AddDesc("ColumnStart:" + std::to_string(property->GetColumnStart().value()))
303         : DumpLog::GetInstance().AddDesc("ColumnStart:null");
304     property->GetColumnEnd().has_value()
305         ? DumpLog::GetInstance().AddDesc("ColumnEnd:" + std::to_string(property->GetColumnEnd().value()))
306         : DumpLog::GetInstance().AddDesc("ColumnEnd:null");
307     property->GetNeedStretch() ? DumpLog::GetInstance().AddDesc("needStretch:true")
308                                : DumpLog::GetInstance().AddDesc("needStretch:false");
309     selectable_ ? DumpLog::GetInstance().AddDesc("selectable:true")
310                 : DumpLog::GetInstance().AddDesc("selectable:false");
311     isSelected_ ? DumpLog::GetInstance().AddDesc("isSelected:true")
312                 : DumpLog::GetInstance().AddDesc("isSelected:false");
313     isHover_ ? DumpLog::GetInstance().AddDesc("isHover:true") : DumpLog::GetInstance().AddDesc("isHover:false");
314     isPressed_ ? DumpLog::GetInstance().AddDesc("isPressed:true") : DumpLog::GetInstance().AddDesc("isPressed:false");
315     switch (gridItemStyle_) {
316         case GridItemStyle::NONE: {
317             DumpLog::GetInstance().AddDesc("GridItemStyle:NONE");
318             break;
319         }
320         case GridItemStyle::PLAIN: {
321             DumpLog::GetInstance().AddDesc("GridItemStyle:PLAIN");
322             break;
323         }
324         default: {
325             break;
326         }
327     }
328 }
329 
UpdateGridItemStyle(GridItemStyle gridItemStyle)330 void GridItemPattern::UpdateGridItemStyle(GridItemStyle gridItemStyle)
331 {
332     gridItemStyle_ = gridItemStyle;
333     auto host = GetHost();
334     CHECK_NULL_VOID(host);
335     auto pipeline = host->GetContextRefPtr();
336     CHECK_NULL_VOID(pipeline);
337     auto theme = pipeline->GetTheme<GridItemTheme>();
338     CHECK_NULL_VOID(theme);
339     auto renderContext = host->GetRenderContext();
340     CHECK_NULL_VOID(renderContext);
341     if (gridItemStyle_ == GridItemStyle::PLAIN) {
342         renderContext->UpdateBorderRadius(theme->GetGridItemBorderRadius());
343     } else if (gridItemStyle_ == GridItemStyle::NONE) {
344         renderContext->UpdateBorderRadius(BorderRadiusProperty());
345     }
346 }
347 } // namespace OHOS::Ace::NG
348