• 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         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