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/select_content_overlay/select_content_overlay_pattern.h"
17 
18 #include "base/memory/ace_type.h"
19 #include "base/utils/utils.h"
20 #include "core/components/text_overlay/text_overlay_theme.h"
21 #include "core/components_ng/pattern/select_overlay/select_overlay_pattern.h"
22 #include "core/components_ng/property/property.h"
23 
24 namespace OHOS::Ace::NG {
UpdateMenuIsShow(bool menuIsShow,bool noAnimation)25 void SelectContentOverlayPattern::UpdateMenuIsShow(bool menuIsShow, bool noAnimation)
26 {
27     if (info_->menuInfo.menuIsShow == menuIsShow) {
28         return;
29     }
30     auto host = GetHost();
31     CHECK_NULL_VOID(host);
32     auto selectOverlayNode = AceType::DynamicCast<SelectOverlayNode>(host);
33     CHECK_NULL_VOID(selectOverlayNode);
34     info_->menuInfo.menuIsShow = menuIsShow;
35     selectOverlayNode->UpdateToolBar(false, noAnimation);
36 }
37 
UpdateMenuInfo(const SelectMenuInfo & info)38 void SelectContentOverlayPattern::UpdateMenuInfo(const SelectMenuInfo& info)
39 {
40     auto host = DynamicCast<SelectOverlayNode>(GetHost());
41     CHECK_NULL_VOID(host);
42     auto itemChanged = info_->menuInfo.IsIconChanged(info);
43     info_->menuInfo = info;
44     host->UpdateToolBar(itemChanged, true);
45 }
46 
UpdateIsShowHandleLine(bool isHandleLineShow)47 void SelectContentOverlayPattern::UpdateIsShowHandleLine(bool isHandleLineShow)
48 {
49     if (info_->isHandleLineShow == isHandleLineShow) {
50         return;
51     }
52     auto host = DynamicCast<SelectOverlayNode>(GetHost());
53     CHECK_NULL_VOID(host);
54     info_->isHandleLineShow = isHandleLineShow;
55     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
56 }
57 
UpdateIsSingleHandle(bool isSingleHandle)58 void SelectContentOverlayPattern::UpdateIsSingleHandle(bool isSingleHandle)
59 {
60     if (info_->isSingleHandle == isSingleHandle) {
61         return;
62     }
63     auto host = DynamicCast<SelectOverlayNode>(GetHost());
64     CHECK_NULL_VOID(host);
65     info_->isSingleHandle = isSingleHandle;
66     host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
67 }
68 
RestartHiddenHandleTask(bool isDelay)69 void SelectContentOverlayPattern::RestartHiddenHandleTask(bool isDelay)
70 {
71     CancelHiddenHandleTask();
72     StartHiddenHandleTask(isDelay);
73 }
74 
CancelHiddenHandleTask()75 void SelectContentOverlayPattern::CancelHiddenHandleTask()
76 {
77     hiddenHandleTask_.Cancel();
78     isHiddenHandle_ = false;
79     auto host = DynamicCast<SelectOverlayNode>(GetHost());
80     CHECK_NULL_VOID(host);
81     UpdateHandleHotZone();
82     host->GetOrCreateGestureEventHub()->SetHitTestMode(info_->hitTestMode);
83     host->GetOrCreateGestureEventHub()->AddClickEvent(clickEvent_);
84     host->GetOrCreateGestureEventHub()->AddPanEvent(panEvent_, { PanDirection::ALL }, 1, DEFAULT_PAN_DISTANCE);
85     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
86 }
87 
GetSelectMenuInfo()88 SelectMenuInfo SelectContentOverlayPattern::GetSelectMenuInfo()
89 {
90     return info_->menuInfo;
91 }
92 
CheckHandleReverse()93 void SelectContentOverlayPattern::CheckHandleReverse()
94 {
95     CHECK_NULL_VOID(!info_->isSingleHandle);
96     auto firstRect = GetHandlePaintRect(info_->firstHandle);
97     auto secondRect = GetHandlePaintRect(info_->secondHandle);
98     auto isReversed = info_->handleReverse;
99     if (info_->checkHandleReverse) {
100         isReversed = info_->checkHandleReverse(firstRect, secondRect);
101     } else if (IsHandleInSameLine(firstRect, secondRect)) {
102         isReversed = GreatNotEqual(firstRect.Left(), secondRect.Left());
103     } else {
104         isReversed = GreatNotEqual(firstRect.Top(), secondRect.Top());
105     }
106     if (isReversed != info_->handleReverse) {
107         info_->handleReverse = isReversed;
108         if (info_->onHandleReverse) {
109             info_->onHandleReverse(info_->handleReverse);
110         }
111     }
112 }
113 
IsHandleInSameLine(const RectF & first,const RectF & second)114 bool SelectContentOverlayPattern::IsHandleInSameLine(const RectF& first, const RectF& second)
115 {
116     float lowerHandleTop = 0.0f;
117     RectF heigherHandleRect;
118     if (GreatNotEqual(first.Top(), second.Top())) {
119         lowerHandleTop = first.Top() + 0.5f;
120         heigherHandleRect = second;
121     } else {
122         lowerHandleTop = second.Top() + 0.5f;
123         heigherHandleRect = first;
124     }
125     return GreatNotEqual(lowerHandleTop, heigherHandleRect.Top()) &&
126            LessNotEqual(lowerHandleTop, heigherHandleRect.Bottom());
127 }
128 
UpdateHandleHotZone()129 void SelectContentOverlayPattern::UpdateHandleHotZone()
130 {
131     if (!CheckIfNeedHandle()) {
132         return;
133     }
134     if (info_->handleLevelMode == HandleLevelMode::OVERLAY &&
135         (info_->firstHandle.isPaintHandleWithPoints || info_->secondHandle.isPaintHandleWithPoints)) {
136         UpdateHandleHotZoneWithPoint();
137     } else {
138         SelectOverlayPattern::UpdateHandleHotZone();
139     }
140 }
141 
UpdateHandleHotZoneWithPoint()142 bool SelectContentOverlayPattern::UpdateHandleHotZoneWithPoint()
143 {
144     auto host = GetHost();
145     CHECK_NULL_RETURN(host, false);
146     auto pipeline = host->GetContext();
147     CHECK_NULL_RETURN(pipeline, false);
148     auto theme = pipeline->GetTheme<TextOverlayTheme>();
149     CHECK_NULL_RETURN(theme, false);
150     auto hotZone = theme->GetHandleHotZoneRadius().ConvertToPx();
151     auto radius =
152         (theme->GetHandleDiameter().ConvertToPx() + theme->GetHandleDiameterStrokeWidth().ConvertToPx()) / 2.0f;
153     firstHandleRegion_.SetSize({ hotZone * 2, hotZone * 2 });
154     secondHandleRegion_.SetSize({ hotZone * 2, hotZone * 2 });
155     if (info_->isSingleHandle) {
156         if (!info_->firstHandle.isShow && info_->secondHandle.isShow) {
157             // Use the second handle to make a single handle.
158             auto centerOffset = GetHandleHotZoneOffset(false, radius, false);
159             auto offsetX = centerOffset.GetX() - hotZone;
160             auto offsetY = centerOffset.GetY() - hotZone;
161             UpdateHandleHotRegion(secondHandleRegion_, { offsetX, offsetY });
162             firstHandleRegion_.Reset();
163         } else {
164             // Use the first handle to make a single handle.
165             auto centerOffset = GetHandleHotZoneOffset(true, radius, false);
166             auto offsetX = centerOffset.GetX() - hotZone;
167             auto offsetY = centerOffset.GetY() - hotZone;
168             UpdateHandleHotRegion(firstHandleRegion_, { offsetX, offsetY });
169             secondHandleRegion_.Reset();
170         }
171         return true;
172     }
173     auto firstCenter = GetHandleHotZoneOffset(true, radius, !info_->handleReverse);
174     auto secondCenter = GetHandleHotZoneOffset(false, radius, info_->handleReverse);
175     firstHandleRegion_.SetOffset({ firstCenter.GetX() - hotZone, firstCenter.GetY() - hotZone });
176     secondHandleRegion_.SetOffset({ secondCenter.GetX() - hotZone, secondCenter.GetY() - hotZone });
177 
178     std::vector<DimensionRect> responseRegion;
179     DimensionRect firstRegion = ConvertToHotRect(firstHandleRegion_);
180     responseRegion.emplace_back(firstRegion);
181     DimensionRect secondRegion = ConvertToHotRect(secondHandleRegion_);
182     responseRegion.emplace_back(secondRegion);
183     if (IsCustomMenu()) {
184         AddMenuResponseRegion(responseRegion);
185     }
186     host->GetOrCreateGestureEventHub()->SetResponseRegion(responseRegion);
187     return true;
188 }
189 
UpdateHandleHotRegion(RectF & hotRegion,const OffsetF & offset)190 void SelectContentOverlayPattern::UpdateHandleHotRegion(RectF& hotRegion, const OffsetF& offset)
191 {
192     auto host = GetHost();
193     CHECK_NULL_VOID(host);
194     hotRegion.SetOffset(offset);
195     DimensionRect newRegion = ConvertToHotRect(hotRegion);
196     std::vector<DimensionRect> responseRegion;
197     responseRegion.emplace_back(newRegion);
198     host->GetOrCreateGestureEventHub()->SetResponseRegion(responseRegion);
199 }
200 
ConvertToHotRect(const RectF & rect)201 DimensionRect SelectContentOverlayPattern::ConvertToHotRect(const RectF& rect)
202 {
203     DimensionRect newRegion;
204     newRegion.SetSize({ Dimension(rect.GetSize().Width()), Dimension(rect.GetSize().Height()) });
205     newRegion.SetOffset(DimensionOffset(Offset(rect.GetOffset().GetX(), rect.GetOffset().GetY())));
206     return newRegion;
207 }
208 
GetHandleHotZoneOffset(bool isFirst,float raidus,bool handleOnTop)209 OffsetF SelectContentOverlayPattern::GetHandleHotZoneOffset(bool isFirst, float raidus, bool handleOnTop)
210 {
211     auto startPoint = isFirst ? info_->firstHandle.paintInfo.startPoint : info_->secondHandle.paintInfo.startPoint;
212     auto endPoint = isFirst ? info_->firstHandle.paintInfo.endPoint : info_->secondHandle.paintInfo.endPoint;
213     return SelectOverlayContentModifier::CalculateCenterPoint(startPoint, endPoint, raidus, handleOnTop);
214 }
215 
UpdateViewPort(const std::optional<RectF> & viewPort)216 void SelectContentOverlayPattern::UpdateViewPort(const std::optional<RectF>& viewPort)
217 {
218     auto host = GetHost();
219     CHECK_NULL_VOID(host);
220     info_->ancestorViewPort = viewPort;
221     host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
222 }
223 
UpdateSelectArea(const RectF & selectArea)224 void SelectContentOverlayPattern::UpdateSelectArea(const RectF& selectArea)
225 {
226     SelectOverlayPattern::UpdateSelectArea(selectArea);
227     if (info_->menuInfo.menuIsShow && selectArea.IsEmpty()) {
228         UpdateMenuIsShow(false);
229     }
230 }
231 
SetHandleCircleIsShow(bool isFirst,bool isShow)232 void SelectContentOverlayPattern::SetHandleCircleIsShow(bool isFirst, bool isShow)
233 {
234     auto& handleInfo = isFirst ? info_->firstHandle : info_->secondHandle;
235     if (handleInfo.isCircleShow != isShow) {
236         handleInfo.isCircleShow = isShow;
237         auto host = GetHost();
238         CHECK_NULL_VOID(host);
239         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
240     }
241 }
242 
SetIsHandleLineShow(bool isShow)243 void SelectContentOverlayPattern::SetIsHandleLineShow(bool isShow)
244 {
245     if (info_->isHandleLineShow != isShow) {
246         info_->isHandleLineShow = isShow;
247         auto host = GetHost();
248         CHECK_NULL_VOID(host);
249         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
250     }
251 }
252 } // namespace OHOS::Ace::NG
253