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