1 /*
2 * Copyright (c) 2024 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/rich_editor/one_step_drag_controller.h"
17
18 namespace OHOS::Ace::NG {
19
20 /* begin OneStepDragParam */
OneStepDragParam(const Builder & builder,const SelectMenuParam & selectMenuParam,TextSpanType spanType,TagFilter tagFilter)21 OneStepDragParam::OneStepDragParam(const Builder& builder, const SelectMenuParam& selectMenuParam,
22 TextSpanType spanType, TagFilter tagFilter) : spanType_(spanType), tagFilter_(tagFilter)
23 {
24 menuBuilder = builder;
25 onAppear = [onAppearFunc = selectMenuParam.onAppear, onMenuShowFunc = selectMenuParam.onMenuShow](
26 int32_t start, int32_t end) {
27 IF_TRUE(onAppearFunc, onAppearFunc(start, end));
28 IF_TRUE(onMenuShowFunc, onMenuShowFunc(start, end));
29 };
30 onDisappear = [onDisappearFunc = selectMenuParam.onDisappear, onMenuHideFunc = selectMenuParam.onMenuHide](
31 int32_t start, int32_t end) {
32 IF_TRUE(onMenuHideFunc, onMenuHideFunc(start, end));
33 IF_TRUE(onDisappearFunc, onDisappearFunc());
34 };
35 menuParam.previewMode = MenuPreviewMode::IMAGE;
36 menuParam.type = MenuType::CONTEXT_MENU;
37 menuParam.previewAnimationOptions.scaleFrom = 1.0f;
38 menuParam.previewBorderRadius = BorderRadiusProperty(Dimension(0));
39 menuParam.backgroundBlurStyle = static_cast<int>(BlurStyle::NO_MATERIAL);
40 menuParam.hapticFeedbackMode = selectMenuParam.previewMenuOptions.hapticFeedbackMode;
41 }
42
EnableDrag(const RefPtr<FrameNode> & frameNode) const43 void OneStepDragParam::EnableDrag(const RefPtr<FrameNode>& frameNode) const
44 {
45 auto hub = frameNode->GetOrCreateGestureEventHub();
46 CHECK_NULL_VOID(hub);
47 hub->SetHitTestMode((menuBuilder != nullptr) ? HitTestMode::HTMDEFAULT : HitTestMode::HTMNONE);
48
49 frameNode->SetDraggable(true);
50 auto gestureHub = frameNode->GetOrCreateGestureEventHub();
51 CHECK_NULL_VOID(gestureHub);
52 gestureHub->InitDragDropEvent();
53 }
54
BindContextMenu(const RefPtr<FrameNode> & frameNode)55 void OneStepDragParam::BindContextMenu(const RefPtr<FrameNode>& frameNode)
56 {
57 #ifndef ACE_UNITTEST
58 CHECK_NULL_VOID(frameNode);
59 auto resType = ResponseType::LONG_PRESS;
60 auto menuParam = GetMenuParam(frameNode);
61 ViewStackProcessor::GetInstance()->Push(frameNode);
62 ViewAbstractModel::GetInstance()->BindContextMenu(resType, menuBuilder, menuParam, previewBuilder);
63 ViewAbstractModel::GetInstance()->BindDragWithContextMenuParams(menuParam);
64 ViewStackProcessor::GetInstance()->Finish();
65 #endif
66 }
67
FillJsonValue(const std::unique_ptr<JsonValue> & jsonValue) const68 void OneStepDragParam::FillJsonValue(const std::unique_ptr<JsonValue>& jsonValue) const
69 {
70 CHECK_NULL_VOID(jsonValue);
71 auto jsonItem = JsonUtil::Create(true);
72 jsonItem->Put("spanType", static_cast<int32_t>(spanType_));
73 jsonItem->Put("responseType", static_cast<int32_t>(TextResponseType::LONG_PRESS));
74 jsonItem->Put("menuType", static_cast<int32_t>(SelectionMenuType::PREVIEW_MENU));
75 jsonValue->Put(jsonItem);
76 }
77
HandleDirtyNodes()78 void OneStepDragParam::HandleDirtyNodes()
79 {
80 while (!dirtyFrameNodes.empty()) {
81 auto weakNode = dirtyFrameNodes.front();
82 dirtyFrameNodes.pop();
83 auto frameNode = weakNode.Upgrade();
84 BindContextMenu(frameNode);
85 }
86 }
87
MarkDirtyNode(const WeakPtr<FrameNode> & dirtyFrameNode)88 inline void OneStepDragParam::MarkDirtyNode(const WeakPtr<FrameNode>& dirtyFrameNode)
89 {
90 dirtyFrameNodes.push(dirtyFrameNode);
91 }
92
93 template<typename T>
SetEnableEventResponse(int32_t start,int32_t end,std::list<WeakPtr<T>> & nodes)94 void OneStepDragParam::SetEnableEventResponse(int32_t start, int32_t end, std::list<WeakPtr<T>>& nodes)
95 {
96 CHECK_NULL_VOID(menuBuilder);
97 for (auto it = nodes.begin(); it != nodes.end();) {
98 auto node = it->Upgrade();
99 if (!node) {
100 it = nodes.erase(it);
101 continue;
102 }
103 ++it;
104 auto hub = node->GetOrCreateGestureEventHub();
105 CHECK_NULL_CONTINUE(hub);
106 auto spanItem = node->GetSpanItem();
107 bool enableResponse = start > spanItem->rangeStart || spanItem->position > end;
108 hub->SetHitTestMode(enableResponse ? HitTestMode::HTMDEFAULT : HitTestMode::HTMNONE);
109 }
110 }
111 /* end OneStepDragParam */
112
113 /* begin ImageOneStepDragParam */
GetMenuParam(const RefPtr<FrameNode> & frameNode) const114 MenuParam ImageOneStepDragParam::GetMenuParam(const RefPtr<FrameNode>& frameNode) const
115 {
116 auto imageNode = AceType::DynamicCast<ImageSpanNode>(frameNode);
117 CHECK_NULL_RETURN(imageNode, menuParam);
118 auto res = menuParam;
119 res.onAppear = [weak = AceType::WeakClaim(AceType::RawPtr(imageNode)), onAppear = this->onAppear]() {
120 CHECK_NULL_VOID(onAppear);
121 auto imageNode = weak.Upgrade();
122 CHECK_NULL_VOID(imageNode);
123 const auto& spanItem = imageNode->GetSpanItem();
124 onAppear(spanItem->rangeStart, spanItem->position);
125 };
126 res.onDisappear = [weak = AceType::WeakClaim(AceType::RawPtr(imageNode)), onDisappear = this->onDisappear]() {
127 CHECK_NULL_VOID(onDisappear);
128 auto imageNode = weak.Upgrade();
129 CHECK_NULL_VOID(imageNode);
130 const auto& spanItem = imageNode->GetSpanItem();
131 onDisappear(spanItem->rangeStart, spanItem->position);
132 };
133 res.previewAnimationOptions.scaleTo = CalcImageScale(imageNode);
134 return res;
135 }
136
EnableOneStepDrag(const RefPtr<FrameNode> & frameNode)137 void ImageOneStepDragParam::EnableOneStepDrag(const RefPtr<FrameNode>& frameNode)
138 {
139 // image need to update [scaleTo] when size change, bindContextMenu when HandleDirtyNodes
140 EnableDrag(frameNode);
141 }
142
CalcImageScale(const RefPtr<ImageSpanNode> & imageNode) const143 float ImageOneStepDragParam::CalcImageScale(const RefPtr<ImageSpanNode>& imageNode) const
144 {
145 float scale = 1.1f;
146 auto dispSize = imageNode->GetGeometryNode()->GetMarginFrameSize();
147 CHECK_NULL_RETURN(dispSize.IsPositive(), scale);
148 auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
149 CHECK_NULL_RETURN(imageLayoutProperty, scale);
150 auto imageSourceInfo = imageLayoutProperty->GetImageSourceInfoValue();
151 CHECK_NULL_RETURN(imageSourceInfo.IsPixmap(), scale);
152 auto pixelMap = imageSourceInfo.GetPixmap();
153 CHECK_NULL_RETURN(pixelMap, scale);
154 auto realWidth = pixelMap->GetWidth();
155 auto realHeight = pixelMap->GetHeight();
156 scale = std::max((float) realWidth / dispSize.Width(), (float) realHeight / dispSize.Height());
157 TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "realSize=[%{public}d,%{public}d], scale=%{public}.2f",
158 realWidth, realHeight, scale);
159 return std::max(scale, 1.1f);
160 }
161 /* end ImageOneStepDragParam */
162
163 /* begin PlaceholderOneStepDragParam */
GetMenuParam(const RefPtr<FrameNode> & frameNode) const164 MenuParam PlaceholderOneStepDragParam::GetMenuParam(const RefPtr<FrameNode>& frameNode) const
165 {
166 auto placeholderNode = AceType::DynamicCast<PlaceholderSpanNode>(frameNode);
167 CHECK_NULL_RETURN(placeholderNode, menuParam);
168 auto res = menuParam;
169 res.onAppear = [weak = AceType::WeakClaim(AceType::RawPtr(placeholderNode)), onAppear = this->onAppear]() {
170 CHECK_NULL_VOID(onAppear);
171 auto placeholderNode = weak.Upgrade();
172 CHECK_NULL_VOID(placeholderNode);
173 const auto& spanItem = placeholderNode->GetSpanItem();
174 onAppear(spanItem->rangeStart, spanItem->position);
175 };
176 res.onDisappear = [weak = AceType::WeakClaim(AceType::RawPtr(placeholderNode)), onDisappear = this->onDisappear]() {
177 CHECK_NULL_VOID(onDisappear);
178 auto placeholderNode = weak.Upgrade();
179 CHECK_NULL_VOID(placeholderNode);
180 const auto& spanItem = placeholderNode->GetSpanItem();
181 onDisappear(spanItem->rangeStart, spanItem->position);
182 };
183 return res;
184 }
185
EnableDrag(const RefPtr<FrameNode> & frameNode) const186 void PlaceholderOneStepDragParam::EnableDrag(const RefPtr<FrameNode>& frameNode) const
187 {
188 OneStepDragParam::EnableDrag(frameNode);
189 auto eventHub = frameNode->GetOrCreateEventHub<EventHub>();
190 CHECK_NULL_VOID(eventHub);
191 auto dragStart = [](const RefPtr<OHOS::Ace::DragEvent>&, const std::string&) -> DragDropInfo {
192 return DragDropInfo();
193 };
194 eventHub->SetDefaultOnDragStart(std::move(dragStart));
195 }
196
EnableOneStepDrag(const RefPtr<FrameNode> & frameNode)197 void PlaceholderOneStepDragParam::EnableOneStepDrag(const RefPtr<FrameNode>& frameNode)
198 {
199 EnableDrag(frameNode);
200 BindContextMenu(frameNode);
201 }
202 /* end PlaceholderOneStepDragParam */
203
204 /* begin OneStepDragController */
205 // handle existing nodes, when bindSelectionMenu
SetMenuParam(TextSpanType spanType,const Builder & builder,const SelectMenuParam & menuParam)206 bool OneStepDragController::SetMenuParam(TextSpanType spanType, const Builder& builder,
207 const SelectMenuParam& menuParam)
208 {
209 const auto& dragParam = CreateDragParam(spanType, builder, menuParam);
210 CHECK_NULL_RETURN(dragParam, false);
211
212 auto pattern = pattern_.Upgrade();
213 CHECK_NULL_RETURN(pattern, false);
214 auto host = pattern->GetContentHost();
215 CHECK_NULL_RETURN(host, false);
216 const auto& tagFilter = dragParam->tagFilter_;
217 CHECK_NULL_RETURN(tagFilter, false);
218
219 for (const auto& uiNode : host->GetChildren()) {
220 const auto& tag = uiNode->GetTag();
221 CHECK_NULL_CONTINUE(tagFilter(tag));
222 auto frameNode = AceType::DynamicCast<FrameNode>(uiNode);
223 CHECK_NULL_CONTINUE(frameNode);
224 dragParam->EnableDrag(frameNode);
225 dragParam->BindContextMenu(frameNode);
226 }
227 return true;
228 }
229
230 // handle new added node
EnableOneStepDrag(TextSpanType spanType,const RefPtr<FrameNode> & frameNode)231 void OneStepDragController::EnableOneStepDrag(TextSpanType spanType, const RefPtr<FrameNode>& frameNode)
232 {
233 const auto& dragParam = GetDragParam(spanType);
234 CHECK_NULL_VOID(frameNode && dragParam);
235 dragParam->EnableOneStepDrag(frameNode);
236 CopyDragCallback(spanType, frameNode);
237 }
238
GetJsonRange(const TextSpanType spanType,const RefPtr<FrameNode> & frameNode)239 std::string OneStepDragController::GetJsonRange(const TextSpanType spanType, const RefPtr<FrameNode>& frameNode)
240 {
241 RefPtr<SpanItem> spanItem;
242 if (spanType == TextSpanType::IMAGE) {
243 auto imageNode = AceType::DynamicCast<ImageSpanNode>(frameNode);
244 IF_TRUE(imageNode, spanItem = imageNode->GetSpanItem());
245 } else if (spanType == TextSpanType::BUILDER) {
246 auto placeholderNode = AceType::DynamicCast<PlaceholderSpanNode>(frameNode);
247 IF_TRUE(placeholderNode, spanItem = placeholderNode->GetSpanItem());
248 }
249 CHECK_NULL_RETURN(spanItem, "");
250 auto jsonRange = JsonUtil::Create(true);
251 jsonRange->Put("rangeStart", spanItem->rangeStart);
252 jsonRange->Put("rangeEnd", spanItem->position);
253 return jsonRange->ToString();
254 }
255
CopyDragCallback(TextSpanType spanType,const RefPtr<FrameNode> & frameNode)256 void OneStepDragController::CopyDragCallback(TextSpanType spanType, const RefPtr<FrameNode>& frameNode)
257 {
258 auto pattern = pattern_.Upgrade();
259 CHECK_NULL_VOID(pattern);
260 auto host = pattern->GetHost();
261 CHECK_NULL_VOID(host);
262
263 auto hostEventHub = host->GetOrCreateEventHub<EventHub>();
264 auto frameNodeEventHub = frameNode->GetOrCreateEventHub<EventHub>();
265 CHECK_NULL_VOID(hostEventHub && frameNodeEventHub);
266
267 // start
268 auto start = hostEventHub->GetOnDragStart();
269 auto oneStepDragStart = [weakNode = AceType::WeakClaim(AceType::RawPtr(frameNode)), start, spanType](
270 const RefPtr<OHOS::Ace::DragEvent>& event, const std::string& extraParams) -> DragDropInfo {
271 auto frameNode = weakNode.Upgrade();
272 auto jsonStr = OneStepDragController::GetJsonRange(spanType, frameNode);
273 return start(event, jsonStr);
274 };
275 IF_TRUE(start, frameNodeEventHub->SetOnDragStart(std::move(oneStepDragStart)));
276
277 // end
278 auto end = hostEventHub->GetCustomerOnDragEndFunc();
279 auto oneStepDragEnd = [end, weakPattern = pattern_, scopeId = Container::CurrentId()]
280 (const RefPtr<OHOS::Ace::DragEvent>& event) {
281 ContainerScope scope(scopeId);
282 IF_TRUE(end, end(event));
283 };
284 frameNodeEventHub->SetCustomerOnDragFunc(DragFuncType::DRAG_END, std::move(oneStepDragEnd));
285 }
286
SetEnableEventResponse(const TextSelector & selector,std::list<WeakPtr<ImageSpanNode>> & imageNodes,std::list<WeakPtr<PlaceholderSpanNode>> & builderNodes)287 void OneStepDragController::SetEnableEventResponse(const TextSelector& selector,
288 std::list<WeakPtr<ImageSpanNode>>& imageNodes, std::list<WeakPtr<PlaceholderSpanNode>>& builderNodes)
289 {
290 auto start = selector.GetTextStart();
291 auto end = selector.GetTextEnd();
292 IF_PRESENT(imageDragParam_, SetEnableEventResponse(start, end, imageNodes));
293 IF_PRESENT(placeholderDragParam_, SetEnableEventResponse(start, end, builderNodes));
294 }
295
296
FillJsonValue(const std::unique_ptr<JsonValue> & jsonValue)297 void OneStepDragController::FillJsonValue(const std::unique_ptr<JsonValue>& jsonValue)
298 {
299 IF_PRESENT(imageDragParam_, FillJsonValue(jsonValue));
300 IF_PRESENT(placeholderDragParam_, FillJsonValue(jsonValue));
301 }
302
MarkDirtyNode(const WeakPtr<ImageSpanNode> & dirtyFrameNode)303 void OneStepDragController::MarkDirtyNode(const WeakPtr<ImageSpanNode>& dirtyFrameNode)
304 {
305 IF_PRESENT(imageDragParam_, MarkDirtyNode(dirtyFrameNode));
306 }
307
HandleDirtyNodes()308 void OneStepDragController::HandleDirtyNodes()
309 {
310 IF_PRESENT(imageDragParam_, HandleDirtyNodes());
311 IF_PRESENT(placeholderDragParam_, HandleDirtyNodes());
312 }
313
GetDragParam(TextSpanType spanType) const314 const std::unique_ptr<OneStepDragParam>& OneStepDragController::GetDragParam(TextSpanType spanType) const
315 {
316 IF_TRUE(spanType == TextSpanType::IMAGE, return imageDragParam_);
317 IF_TRUE(spanType == TextSpanType::BUILDER, return placeholderDragParam_);
318 return invalidParam;
319 }
320
CreateDragParam(TextSpanType spanType,const Builder & builder,const SelectMenuParam & menuParam)321 const std::unique_ptr<OneStepDragParam>& OneStepDragController::CreateDragParam(TextSpanType spanType,
322 const Builder& builder, const SelectMenuParam& menuParam)
323 {
324 if (spanType == TextSpanType::IMAGE) {
325 return imageDragParam_ = std::make_unique<ImageOneStepDragParam>(builder, menuParam);
326 }
327 if (spanType == TextSpanType::BUILDER) {
328 return placeholderDragParam_ = std::make_unique<PlaceholderOneStepDragParam>(builder, menuParam);
329 }
330 return invalidParam;
331 }
332 /* end OneStepDragController */
333
334 } // namespace OHOS::Ace::NG