1 /*
2  * Copyright (c) 2022 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/list/list_event_hub.h"
17 
18 #include "base/utils/utils.h"
19 #include "core/components_ng/base/frame_node.h"
20 #include "core/components_ng/pattern/list/list_item_pattern.h"
21 #include "core/components_ng/pattern/list/list_layout_property.h"
22 #include "core/components_ng/pattern/list/list_pattern.h"
23 #include "core/components_ng/render/adapter/component_snapshot.h"
24 #include "core/pipeline_ng/pipeline_context.h"
25 
26 namespace OHOS::Ace::NG {
27 #if defined(PIXEL_MAP_SUPPORTED)
28 constexpr int32_t CREATE_PIXELMAP_TIME = 80;
29 #endif
30 
InitItemDragEvent(const RefPtr<GestureEventHub> & gestureHub)31 void ListEventHub::InitItemDragEvent(const RefPtr<GestureEventHub>& gestureHub)
32 {
33     auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
34         auto eventHub = weak.Upgrade();
35         CHECK_NULL_VOID(eventHub);
36         eventHub->HandleOnItemDragStart(info);
37     };
38 
39     auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
40         auto eventHub = weak.Upgrade();
41         CHECK_NULL_VOID(eventHub);
42         eventHub->HandleOnItemDragUpdate(info);
43     };
44 
45     auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
46         auto eventHub = weak.Upgrade();
47         CHECK_NULL_VOID(eventHub);
48         eventHub->HandleOnItemDragEnd(info);
49     };
50 
51     auto actionCancelTask = [weak = WeakClaim(this)]() {
52         auto eventHub = weak.Upgrade();
53         CHECK_NULL_VOID(eventHub);
54         eventHub->HandleOnItemDragCancel();
55     };
56 
57     auto dragEvent = MakeRefPtr<DragEvent>(
58         std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
59     gestureHub->SetDragEvent(dragEvent, { PanDirection::ALL }, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE);
60 }
61 
OnItemDragStart(const GestureEvent & info,const DragDropInfo & dragDropInfo)62 void ListEventHub::OnItemDragStart(const GestureEvent& info, const DragDropInfo& dragDropInfo)
63 {
64     auto pipeline = PipelineContext::GetCurrentContext();
65     CHECK_NULL_VOID(pipeline);
66     auto manager = pipeline->GetDragDropManager();
67     CHECK_NULL_VOID(manager);
68     if (dragDropInfo.pixelMap) {
69         dragDropProxy_ = manager->CreateAndShowDragWindow(dragDropInfo.pixelMap, info);
70     } else if (dragDropInfo.customNode) {
71         dragDropProxy_ = manager->CreateAndShowDragWindow(dragDropInfo.customNode, info);
72     }
73     CHECK_NULL_VOID(dragDropProxy_);
74     dragDropProxy_->OnItemDragStart(info, GetFrameNode());
75     if (!manager->IsDraggingPressed(info.GetPointerId())) {
76         HandleOnItemDragEnd(info);
77     }
78 }
79 
HandleOnItemDragStart(const GestureEvent & info)80 void ListEventHub::HandleOnItemDragStart(const GestureEvent& info)
81 {
82     auto host = GetFrameNode();
83     CHECK_NULL_VOID(host);
84     auto pipeline = host->GetContext();
85     CHECK_NULL_VOID(pipeline);
86 
87     auto globalX = static_cast<float>(info.GetGlobalPoint().GetX());
88     auto globalY = static_cast<float>(info.GetGlobalPoint().GetY());
89 
90     draggedIndex_ = GetListItemIndexByPosition(globalX, globalY, true);
91     if (draggedIndex_ == -1) {
92         return;
93     }
94 
95     OHOS::Ace::ItemDragInfo itemDragInfo;
96     itemDragInfo.SetX(globalX);
97     itemDragInfo.SetY(globalY);
98     auto customNode = FireOnItemDragStart(itemDragInfo, draggedIndex_);
99     CHECK_NULL_VOID(customNode);
100     auto dragDropManager = pipeline->GetDragDropManager();
101     CHECK_NULL_VOID(dragDropManager);
102     dragDropManager->SetDraggingPointer(info.GetPointerId());
103     dragDropManager->SetDraggingPressedState(true);
104 #if defined(PIXEL_MAP_SUPPORTED)
105     auto callback = [weakHost = WeakClaim(RawPtr(host)), info, weak = WeakClaim(this)](
106                         std::shared_ptr<Media::PixelMap> mediaPixelMap, int32_t /*arg*/,
107                         const std::function<void()>& /*unused*/) {
108         auto host = weakHost.Upgrade();
109         CHECK_NULL_VOID(host);
110         ContainerScope scope(host->GetInstanceId());
111         if (!mediaPixelMap) {
112             TAG_LOGE(AceLogTag::ACE_DRAG, "listItem drag start failed, custom component screenshot is empty.");
113             return;
114         }
115         auto pipeline = PipelineContext::GetCurrentContext();
116         CHECK_NULL_VOID(pipeline);
117         DragDropInfo dragDropInfo;
118         dragDropInfo.pixelMap = PixelMap::CreatePixelMap(reinterpret_cast<void*>(&mediaPixelMap));
119         auto taskScheduler = pipeline->GetTaskExecutor();
120         CHECK_NULL_VOID(taskScheduler);
121         taskScheduler->PostTask(
122             [weak, info, dragDropInfo]() {
123                 auto eventHub = weak.Upgrade();
124                 CHECK_NULL_VOID(eventHub);
125                 eventHub->OnItemDragStart(info, dragDropInfo);
126             },
127             TaskExecutor::TaskType::UI, "ArkUIListItemDragStart");
128     };
129     NG::ComponentSnapshot::Create(customNode, std::move(callback), true,
130         SnapshotParam(CREATE_PIXELMAP_TIME));
131 #else
132     DragDropInfo dragDropInfo;
133     dragDropInfo.customNode = customNode;
134     OnItemDragStart(info, dragDropInfo);
135 #endif
136 }
137 
HandleOnItemDragUpdate(const GestureEvent & info)138 void ListEventHub::HandleOnItemDragUpdate(const GestureEvent& info)
139 {
140     CHECK_NULL_VOID(dragDropProxy_);
141     dragDropProxy_->OnItemDragMove(info, draggedIndex_, DragType::LIST);
142 }
143 
HandleOnItemDragEnd(const GestureEvent & info)144 void ListEventHub::HandleOnItemDragEnd(const GestureEvent& info)
145 {
146     CHECK_NULL_VOID(dragDropProxy_);
147     dragDropProxy_->OnItemDragEnd(info, draggedIndex_, DragType::LIST);
148     dragDropProxy_->DestroyDragWindow();
149     dragDropProxy_ = nullptr;
150     draggedIndex_ = 0;
151 }
152 
HandleOnItemDragCancel()153 void ListEventHub::HandleOnItemDragCancel()
154 {
155     CHECK_NULL_VOID(dragDropProxy_);
156     dragDropProxy_->onItemDragCancel();
157     dragDropProxy_->DestroyDragWindow();
158     dragDropProxy_ = nullptr;
159     draggedIndex_ = 0;
160 }
161 
GetListItemIndexByPosition(float x,float y,bool strict)162 int32_t ListEventHub::GetListItemIndexByPosition(float x, float y, bool strict)
163 {
164     auto listNode = GetFrameNode();
165     CHECK_NULL_RETURN(listNode, 0);
166 
167     if (strict) {
168         auto itemFrameNode = listNode->FindChildByPositionWithoutChildTransform(x, y);
169         CHECK_NULL_RETURN(itemFrameNode, -1);
170         RefPtr<ListItemPattern> itemPattern = itemFrameNode->GetPattern<ListItemPattern>();
171         CHECK_NULL_RETURN(itemPattern, -1);
172         return itemPattern->GetIndexInList();
173     }
174 
175     auto listPattern = listNode->GetPattern<ListPattern>();
176     CHECK_NULL_RETURN(listPattern, 0);
177     return listPattern->GetItemIndexByPosition(x, y);
178 }
179 } // namespace OHOS::Ace::NG
180