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