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