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 #if defined(PIXEL_MAP_SUPPORTED)
172 auto callback = [id = Container::CurrentId(), pipeline, info, host, gridItem, weak = WeakClaim(this)](
173 std::shared_ptr<Media::PixelMap> mediaPixelMap, int32_t /*arg*/,
174 const std::function<void()>& finishCallback) {
175 ContainerScope scope(id);
176 if (!mediaPixelMap) {
177 TAG_LOGE(AceLogTag::ACE_DRAG, "gridItem drag start failed, custom component screenshot is empty.");
178 return;
179 }
180 CHECK_NULL_VOID(pipeline);
181 auto taskScheduler = pipeline->GetTaskExecutor();
182 CHECK_NULL_VOID(taskScheduler);
183 taskScheduler->PostTask(
184 [finishCallback]() {
185 if (finishCallback) {
186 finishCallback();
187 }
188 },
189 TaskExecutor::TaskType::UI, "ArkUIGridItemDragRemoveCustomNode");
190 auto pixelMap = PixelMap::CreatePixelMap(reinterpret_cast<void*>(&mediaPixelMap));
191 CHECK_NULL_VOID(pixelMap);
192 taskScheduler->PostTask(
193 [weak, pipeline, info, pixelMap, host, gridItem]() {
194 auto eventHub = weak.Upgrade();
195 CHECK_NULL_VOID(eventHub);
196 auto manager = pipeline->GetDragDropManager();
197 CHECK_NULL_VOID(manager);
198 eventHub->dragDropProxy_ = manager->CreateAndShowItemDragOverlay(pixelMap, info, eventHub);
199 CHECK_NULL_VOID(eventHub->dragDropProxy_);
200 eventHub->dragDropProxy_->OnItemDragStart(info, host);
201 gridItem->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
202 eventHub->draggingItem_ = gridItem;
203 if (!manager->IsDraggingPressed(info.GetPointerId())) {
204 eventHub->HandleOnItemDragEnd(info);
205 }
206 },
207 TaskExecutor::TaskType::UI, "ArkUIGridItemDragStart");
208 };
209 SnapshotParam param;
210 if (auto pixmap = ComponentSnapshot::CreateSync(customNode, param); pixmap) {
211 callback(pixmap, 0, nullptr);
212 return;
213 }
214 param.delay = CREATE_PIXELMAP_TIME;
215 NG::ComponentSnapshot::Create(customNode, std::move(callback), true, param);
216 #else
217 auto manager = pipeline->GetDragDropManager();
218 CHECK_NULL_VOID(manager);
219 dragDropProxy_ = manager->CreateAndShowItemDragOverlay(customNode, info, AceType::Claim(this));
220 CHECK_NULL_VOID(dragDropProxy_);
221 dragDropProxy_->OnItemDragStart(info, host);
222 gridItem->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
223 draggingItem_ = gridItem;
224 if (!manager->IsDraggingPressed(info.GetPointerId())) {
225 HandleOnItemDragEnd(info);
226 }
227 #endif
228 }
229
HandleOnItemDragUpdate(const GestureEvent & info)230 void GridEventHub::HandleOnItemDragUpdate(const GestureEvent& info)
231 {
232 if (!GetEditable()) {
233 return;
234 }
235
236 CHECK_NULL_VOID(dragDropProxy_);
237 dragDropProxy_->OnItemDragMove(info, draggedIndex_, DragType::GRID);
238 }
239
HandleOnItemDragEnd(const GestureEvent & info)240 void GridEventHub::HandleOnItemDragEnd(const GestureEvent& info)
241 {
242 CHECK_NULL_VOID(dragDropProxy_);
243 if (GetEditable()) {
244 dragDropProxy_->OnItemDragEnd(info, draggedIndex_, DragType::GRID);
245 } else {
246 dragDropProxy_->onItemDragCancel();
247 }
248 dragDropProxy_->DestroyDragWindow();
249 dragDropProxy_ = nullptr;
250 draggedIndex_ = 0;
251 if (draggingItem_) {
252 draggingItem_->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
253 draggingItem_ = nullptr;
254 }
255
256 auto host = GetFrameNode();
257 CHECK_NULL_VOID(host);
258 auto pattern = AceType::DynamicCast<GridPattern>(host->GetPattern());
259 CHECK_NULL_VOID(pattern);
260 pattern->ClearDragState();
261 }
262
HandleOnItemDragCancel()263 void GridEventHub::HandleOnItemDragCancel()
264 {
265 CHECK_NULL_VOID(dragDropProxy_);
266 dragDropProxy_->onItemDragCancel();
267 dragDropProxy_->DestroyDragWindow();
268 dragDropProxy_ = nullptr;
269 draggedIndex_ = 0;
270 if (draggingItem_) {
271 draggingItem_->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
272 draggingItem_ = nullptr;
273 }
274
275 auto host = GetFrameNode();
276 CHECK_NULL_VOID(host);
277 auto pattern = AceType::DynamicCast<GridPattern>(host->GetPattern());
278 CHECK_NULL_VOID(pattern);
279 pattern->ClearDragState();
280 }
281
FireOnItemDragEnter(const ItemDragInfo & dragInfo)282 void GridEventHub::FireOnItemDragEnter(const ItemDragInfo& dragInfo)
283 {
284 if (onItemDragEnter_) {
285 onItemDragEnter_(dragInfo);
286 }
287 }
288
FireOnItemDragLeave(const ItemDragInfo & dragInfo,int32_t itemIndex)289 void GridEventHub::FireOnItemDragLeave(const ItemDragInfo& dragInfo, int32_t itemIndex)
290 {
291 if (itemIndex == -1) {
292 auto host = GetFrameNode();
293 CHECK_NULL_VOID(host);
294 auto pattern = AceType::DynamicCast<GridPattern>(host->GetPattern());
295 CHECK_NULL_VOID(pattern);
296 auto insertIndex = pattern->GetChildrenCount();
297 MoveItems(itemIndex, insertIndex);
298 pattern->ClearDragState();
299 }
300
301 if (onItemDragLeave_) {
302 onItemDragLeave_(dragInfo, itemIndex);
303 }
304 }
305
FireOnItemDrop(const ItemDragInfo & dragInfo,int32_t itemIndex,int32_t insertIndex,bool isSuccess)306 bool GridEventHub::FireOnItemDrop(const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex, bool isSuccess)
307 {
308 TAG_LOGI(AceLogTag::ACE_GRID, "itemIndex:%{public}d, insertIndex:%{public}d", itemIndex, insertIndex);
309 auto host = GetFrameNode();
310 CHECK_NULL_RETURN(host, false);
311 auto pattern = AceType::DynamicCast<GridPattern>(host->GetPattern());
312 CHECK_NULL_RETURN(pattern, false);
313 if (pattern->SupportAnimation()) {
314 insertIndex = (itemIndex == -1 || insertIndex == -1) ? insertIndex : pattern->GetOriginalIndex();
315 pattern->ClearDragState();
316 }
317
318 if (onItemDrop_) {
319 onItemDrop_(dragInfo, itemIndex, insertIndex, isSuccess);
320 host->ChildrenUpdatedFrom(0);
321 return true;
322 }
323 host->ChildrenUpdatedFrom(0);
324 return false;
325 }
326
FireOnItemDragMove(const ItemDragInfo & dragInfo,int32_t itemIndex,int32_t insertIndex) const327 void GridEventHub::FireOnItemDragMove(const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex) const
328 {
329 MoveItems(itemIndex, insertIndex);
330
331 if (onItemDragMove_) {
332 auto host = GetFrameNode();
333 CHECK_NULL_VOID(host);
334 auto pattern = AceType::DynamicCast<GridPattern>(host->GetPattern());
335 CHECK_NULL_VOID(pattern);
336 if (pattern->SupportAnimation()) {
337 insertIndex = (itemIndex == -1 || insertIndex == -1) ? insertIndex : pattern->GetOriginalIndex();
338 }
339 onItemDragMove_(dragInfo, itemIndex, insertIndex);
340 }
341 }
342
MoveItems(int32_t itemIndex,int32_t insertIndex) const343 void GridEventHub::MoveItems(int32_t itemIndex, int32_t insertIndex) const
344 {
345 auto host = GetFrameNode();
346 CHECK_NULL_VOID(host);
347 auto pattern = AceType::DynamicCast<GridPattern>(host->GetPattern());
348 CHECK_NULL_VOID(pattern);
349 if (!pattern->SupportAnimation()) {
350 return;
351 }
352 constexpr float ANIMATION_CURVE_VELOCITY = 0.0f; // The move animation spring curve velocity is 0.0
353 constexpr float ANIMATION_CURVE_MASS = 1.0f; // The move animation spring curve mass is 1.0
354 constexpr float ANIMATION_CURVE_STIFFNESS = 400.0f; // The move animation spring curve stiffness is 110.0
355 constexpr float ANIMATION_CURVE_DAMPING = 38.0f; // The move animation spring curve damping is 17.0
356 AnimationOption option;
357 constexpr int32_t duration = 400;
358 option.SetDuration(duration);
359 auto curve = MakeRefPtr<SpringCurve>(
360 ANIMATION_CURVE_VELOCITY, ANIMATION_CURVE_MASS, ANIMATION_CURVE_STIFFNESS, ANIMATION_CURVE_DAMPING);
361 option.SetCurve(curve);
362 AnimationUtils::Animate(
363 option, [pattern, itemIndex, insertIndex]() { pattern->MoveItems(itemIndex, insertIndex); }, nullptr);
364 }
365 } // namespace OHOS::Ace::NG