1 /*
2 * Copyright (c) 2022-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_event_hub.h"
17
18 #include "core/animation/spring_curve.h"
19 #include "core/components_ng/base/frame_node.h"
20 #include "core/components_ng/pattern/grid/grid_item_layout_property.h"
21 #include "core/components_ng/pattern/grid/grid_item_pattern.h"
22 #include "core/components_ng/pattern/grid/grid_layout_property.h"
23 #include "core/components_ng/pattern/grid/grid_pattern.h"
24 #include "core/components_ng/render/adapter/component_snapshot.h"
25 #include "core/pipeline_ng/pipeline_context.h"
26 #include "core/pipeline_ng/ui_task_scheduler.h"
27
28 namespace OHOS::Ace::NG {
29 #if defined(PIXEL_MAP_SUPPORTED) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
30 constexpr int32_t CREATE_PIXELMAP_TIME = 80;
31 #endif
32
InitItemDragEvent(const RefPtr<GestureEventHub> & gestureHub)33 void GridEventHub::InitItemDragEvent(const RefPtr<GestureEventHub>& gestureHub)
34 {
35 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
36 auto eventHub = weak.Upgrade();
37 if (eventHub) {
38 eventHub->HandleOnItemDragStart(info);
39 }
40 };
41
42 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
43 auto eventHub = weak.Upgrade();
44 if (eventHub) {
45 eventHub->HandleOnItemDragUpdate(info);
46 }
47 };
48
49 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
50 auto eventHub = weak.Upgrade();
51 if (eventHub) {
52 eventHub->HandleOnItemDragEnd(info);
53 }
54 };
55
56 auto actionCancelTask = [weak = WeakClaim(this)]() {
57 auto eventHub = weak.Upgrade();
58 if (eventHub) {
59 eventHub->HandleOnItemDragCancel();
60 }
61 };
62
63 auto dragEvent = MakeRefPtr<DragEvent>(
64 std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
65 gestureHub->SetDragEvent(dragEvent, { PanDirection::ALL }, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE);
66 }
67
CheckPostionInGrid(float x,float y)68 bool GridEventHub::CheckPostionInGrid(float x, float y)
69 {
70 auto host = GetFrameNode();
71 CHECK_NULL_RETURN(host, false);
72 auto size = host->GetRenderContext()->GetPaintRectWithTransform();
73 size.SetOffset(host->GetTransformRelativeOffset());
74 return size.IsInRegion(PointF(x, y));
75 }
76
GetInsertPosition(float x,float y)77 int32_t GridEventHub::GetInsertPosition(float x, float y)
78 {
79 if (!CheckPostionInGrid(x, y)) {
80 return -1;
81 }
82
83 auto host = GetFrameNode();
84 CHECK_NULL_RETURN(host, -1);
85 auto pattern = AceType::DynamicCast<GridPattern>(host->GetPattern());
86 CHECK_NULL_RETURN(pattern, -1);
87 auto itemFrameNode = host->FindChildByPosition(x, y);
88 if (itemFrameNode) {
89 RefPtr<GridItemLayoutProperty> itemLayoutProperty = itemFrameNode->GetLayoutProperty<GridItemLayoutProperty>();
90 CHECK_NULL_RETURN(itemLayoutProperty, 0);
91 auto mainIndex = itemLayoutProperty->GetMainIndex().value_or(-1);
92 auto crossIndex = itemLayoutProperty->GetCrossIndex().value_or(-1);
93 return mainIndex * pattern->GetCrossCount() + crossIndex;
94 }
95
96 // on virtual grid item dragged in this grid
97 if (pattern->GetGridLayoutInfo().currentRect_.IsInRegion(PointF(x, y))) {
98 return pattern->GetOriginalIndex();
99 }
100
101 // in grid, but not on any grid item
102 return pattern->GetChildrenCount();
103 }
104
GetFrameNodeChildSize()105 int GridEventHub::GetFrameNodeChildSize()
106 {
107 auto host = GetFrameNode();
108 CHECK_NULL_RETURN(host, 0);
109 auto pattern = host->GetPattern<GridPattern>();
110 CHECK_NULL_RETURN(pattern, 0);
111 return pattern->GetChildrenCount();
112 }
113
GetGridItemIndex(const RefPtr<FrameNode> & frameNode)114 int32_t GridEventHub::GetGridItemIndex(const RefPtr<FrameNode>& frameNode)
115 {
116 CHECK_NULL_RETURN(frameNode, 0);
117 auto gridFrameNode = GetFrameNode();
118 CHECK_NULL_RETURN(gridFrameNode, 0);
119 auto gridPattern = gridFrameNode->GetPattern<GridPattern>();
120 CHECK_NULL_RETURN(gridPattern, 0);
121 RefPtr<GridItemPattern> itemPattern = frameNode->GetPattern<GridItemPattern>();
122 CHECK_NULL_RETURN(itemPattern, 0);
123 auto itemProperty = frameNode->GetLayoutProperty<GridItemLayoutProperty>();
124 CHECK_NULL_RETURN(itemProperty, 0);
125
126 auto gridLayoutInfo = gridPattern->GetGridLayoutInfo();
127 auto mainIndex = itemProperty->GetMainIndex().value_or(-1);
128 auto crossIndex = itemProperty->GetCrossIndex().value_or(-1);
129 auto crossIndexIterator = gridLayoutInfo.gridMatrix_.find(mainIndex);
130 if (crossIndexIterator != gridLayoutInfo.gridMatrix_.end()) {
131 auto crossIndexMap = crossIndexIterator->second;
132
133 auto indexIterator = crossIndexMap.find(crossIndex);
134 if (indexIterator != crossIndexMap.end()) {
135 return indexIterator->second;
136 }
137 }
138
139 return 0;
140 }
141
GetEditable() const142 bool GridEventHub::GetEditable() const
143 {
144 auto host = GetFrameNode();
145 CHECK_NULL_RETURN(host, false);
146 auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
147 CHECK_NULL_RETURN(layoutProperty, false);
148 return layoutProperty->GetEditable().value_or(false);
149 }
150
HandleOnItemDragStart(const GestureEvent & info)151 void GridEventHub::HandleOnItemDragStart(const GestureEvent& info)
152 {
153 if (!GetEditable()) {
154 return;
155 }
156
157 auto pipeline = PipelineContext::GetCurrentContext();
158 CHECK_NULL_VOID(pipeline);
159
160 auto globalX = static_cast<float>(info.GetGlobalPoint().GetX());
161 auto globalY = static_cast<float>(info.GetGlobalPoint().GetY());
162
163 auto host = GetFrameNode();
164 CHECK_NULL_VOID(host);
165 auto gridItem = host->FindChildByPosition(globalX, globalY);
166 CHECK_NULL_VOID(gridItem);
167 draggedIndex_ = GetGridItemIndex(gridItem);
168
169 OHOS::Ace::ItemDragInfo itemDragInfo;
170 itemDragInfo.SetX(pipeline->ConvertPxToVp(Dimension(globalX, DimensionUnit::PX)));
171 itemDragInfo.SetY(pipeline->ConvertPxToVp(Dimension(globalY, DimensionUnit::PX)));
172 auto customNode = FireOnItemDragStart(itemDragInfo, draggedIndex_);
173 CHECK_NULL_VOID(customNode);
174 #if defined(PIXEL_MAP_SUPPORTED) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
175 auto callback = [id = Container::CurrentId(), pipeline, info, host, gridItem, weak = WeakClaim(this)](
176 std::shared_ptr<Media::PixelMap> mediaPixelMap, int32_t /*arg*/,
177 const std::function<void()>& /*unused*/) {
178 ContainerScope scope(id);
179 if (!mediaPixelMap) {
180 TAG_LOGE(AceLogTag::ACE_DRAG, "gridItem drag start failed, custom component screenshot is empty.");
181 return;
182 }
183 auto pixelMap = PixelMap::CreatePixelMap(reinterpret_cast<void*>(&mediaPixelMap));
184 CHECK_NULL_VOID(pixelMap);
185 auto taskScheduler = pipeline->GetTaskExecutor();
186 CHECK_NULL_VOID(taskScheduler);
187 taskScheduler->PostTask(
188 [weak, pipeline, info, pixelMap, host, gridItem]() {
189 auto eventHub = weak.Upgrade();
190 CHECK_NULL_VOID(eventHub);
191 auto manager = pipeline->GetDragDropManager();
192 CHECK_NULL_VOID(manager);
193 eventHub->dragDropProxy_ = manager->CreateAndShowDragWindow(pixelMap, info);
194 CHECK_NULL_VOID(eventHub->dragDropProxy_);
195 eventHub->dragDropProxy_->OnItemDragStart(info, host);
196 gridItem->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
197 eventHub->draggingItem_ = gridItem;
198 },
199 TaskExecutor::TaskType::UI);
200 };
201 NG::ComponentSnapshot::Create(customNode, std::move(callback), false, CREATE_PIXELMAP_TIME);
202 #else
203 auto manager = pipeline->GetDragDropManager();
204 CHECK_NULL_VOID(manager);
205 dragDropProxy_ = manager->CreateAndShowDragWindow(customNode, info);
206 CHECK_NULL_VOID(dragDropProxy_);
207 dragDropProxy_->OnItemDragStart(info, host);
208 gridItem->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
209 draggingItem_ = gridItem;
210 #endif
211 }
212
HandleOnItemDragUpdate(const GestureEvent & info)213 void GridEventHub::HandleOnItemDragUpdate(const GestureEvent& info)
214 {
215 if (!GetEditable()) {
216 return;
217 }
218
219 CHECK_NULL_VOID(dragDropProxy_);
220 dragDropProxy_->OnItemDragMove(info, draggedIndex_, DragType::GRID);
221 }
222
HandleOnItemDragEnd(const GestureEvent & info)223 void GridEventHub::HandleOnItemDragEnd(const GestureEvent& info)
224 {
225 CHECK_NULL_VOID(dragDropProxy_);
226 if (GetEditable()) {
227 dragDropProxy_->OnItemDragEnd(info, draggedIndex_, DragType::GRID);
228 } else {
229 dragDropProxy_->onItemDragCancel();
230 }
231 dragDropProxy_->DestroyDragWindow();
232 dragDropProxy_ = nullptr;
233 draggedIndex_ = 0;
234 if (draggingItem_) {
235 draggingItem_->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
236 draggingItem_ = nullptr;
237 }
238
239 auto host = GetFrameNode();
240 CHECK_NULL_VOID(host);
241 auto pattern = AceType::DynamicCast<GridPattern>(host->GetPattern());
242 CHECK_NULL_VOID(pattern);
243 pattern->ClearDragState();
244 }
245
HandleOnItemDragCancel()246 void GridEventHub::HandleOnItemDragCancel()
247 {
248 if (!GetEditable()) {
249 return;
250 }
251
252 CHECK_NULL_VOID(dragDropProxy_);
253 dragDropProxy_->onItemDragCancel();
254 dragDropProxy_->DestroyDragWindow();
255 dragDropProxy_ = nullptr;
256 draggedIndex_ = 0;
257 if (draggingItem_) {
258 draggingItem_->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
259 draggingItem_ = nullptr;
260 }
261
262 auto host = GetFrameNode();
263 CHECK_NULL_VOID(host);
264 auto pattern = AceType::DynamicCast<GridPattern>(host->GetPattern());
265 CHECK_NULL_VOID(pattern);
266 pattern->ClearDragState();
267 }
268
FireOnItemDragEnter(const ItemDragInfo & dragInfo)269 void GridEventHub::FireOnItemDragEnter(const ItemDragInfo& dragInfo)
270 {
271 if (onItemDragEnter_) {
272 onItemDragEnter_(dragInfo);
273 }
274 }
275
FireOnItemDragLeave(const ItemDragInfo & dragInfo,int32_t itemIndex)276 void GridEventHub::FireOnItemDragLeave(const ItemDragInfo& dragInfo, int32_t itemIndex)
277 {
278 if (itemIndex == -1) {
279 auto host = GetFrameNode();
280 CHECK_NULL_VOID(host);
281 auto pattern = AceType::DynamicCast<GridPattern>(host->GetPattern());
282 CHECK_NULL_VOID(pattern);
283 auto insertIndex = pattern->GetChildrenCount();
284 MoveItems(itemIndex, insertIndex);
285 }
286
287 if (onItemDragLeave_) {
288 onItemDragLeave_(dragInfo, itemIndex);
289 }
290 }
291
FireOnItemDrop(const ItemDragInfo & dragInfo,int32_t itemIndex,int32_t insertIndex,bool isSuccess)292 bool GridEventHub::FireOnItemDrop(const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex, bool isSuccess)
293 {
294 TAG_LOGI(AceLogTag::ACE_GRID, "itemIndex:%{public}d, insertIndex:%{public}d", itemIndex, insertIndex);
295 auto host = GetFrameNode();
296 CHECK_NULL_RETURN(host, false);
297 auto pattern = AceType::DynamicCast<GridPattern>(host->GetPattern());
298 CHECK_NULL_RETURN(pattern, false);
299 if (pattern->SupportAnimation()) {
300 insertIndex = (itemIndex == -1 || insertIndex == -1) ? insertIndex : pattern->GetOriginalIndex();
301 pattern->ClearDragState();
302 }
303
304 if (draggingItem_) {
305 draggingItem_->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
306 }
307 if (onItemDrop_) {
308 onItemDrop_(dragInfo, itemIndex, insertIndex, isSuccess);
309 host->ChildrenUpdatedFrom(0);
310 return true;
311 }
312 host->ChildrenUpdatedFrom(0);
313 return false;
314 }
315
FireOnItemDragMove(const ItemDragInfo & dragInfo,int32_t itemIndex,int32_t insertIndex) const316 void GridEventHub::FireOnItemDragMove(const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex) const
317 {
318 MoveItems(itemIndex, insertIndex);
319
320 if (onItemDragMove_) {
321 onItemDragMove_(dragInfo, itemIndex, insertIndex);
322 }
323 }
324
MoveItems(int32_t itemIndex,int32_t insertIndex) const325 void GridEventHub::MoveItems(int32_t itemIndex, int32_t insertIndex) const
326 {
327 auto host = GetFrameNode();
328 CHECK_NULL_VOID(host);
329 auto pattern = AceType::DynamicCast<GridPattern>(host->GetPattern());
330 CHECK_NULL_VOID(pattern);
331 if (!pattern->SupportAnimation()) {
332 return;
333 }
334 constexpr float ANIMATION_CURVE_VELOCITY = 0.0f; // The move animation spring curve velocity is 0.0
335 constexpr float ANIMATION_CURVE_MASS = 1.0f; // The move animation spring curve mass is 1.0
336 constexpr float ANIMATION_CURVE_STIFFNESS = 400.0f; // The move animation spring curve stiffness is 110.0
337 constexpr float ANIMATION_CURVE_DAMPING = 38.0f; // The move animation spring curve damping is 17.0
338 AnimationOption option;
339 constexpr int32_t duration = 400;
340 option.SetDuration(duration);
341 auto curve = MakeRefPtr<SpringCurve>(
342 ANIMATION_CURVE_VELOCITY, ANIMATION_CURVE_MASS, ANIMATION_CURVE_STIFFNESS, ANIMATION_CURVE_DAMPING);
343 option.SetCurve(curve);
344 AnimationUtils::Animate(
345 option, [pattern, itemIndex, insertIndex]() { pattern->MoveItems(itemIndex, insertIndex); }, nullptr);
346 }
347 } // namespace OHOS::Ace::NG