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