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