• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_TEXT_FIELD_TEXT_SELECTOR_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_TEXT_FIELD_TEXT_SELECTOR_H
18 
19 #include <cstdint>
20 #include <string>
21 #include <functional>
22 
23 #include "base/geometry/ng/offset_t.h"
24 #include "base/geometry/ng/rect_t.h"
25 #include "frameworks/core/components/common/properties/decoration.h"
26 
27 // avoid windows build error about macro defined in wincon.h
28 #ifdef DOUBLE_CLICK
29 #undef DOUBLE_CLICK
30 #endif
31 
32 namespace OHOS::Ace::NG {
33 
34 using OnAccessibilityCallback = std::function<void()>;
35 
36 enum class CaretUpdateType {
37     PRESSED,
38     LONG_PRESSED,
39     ICON_PRESSED,
40     DEL,
41     EVENT,
42     HANDLE_MOVE,
43     HANDLE_MOVE_DONE,
44     INPUT,
45     NONE,
46     RIGHT_CLICK,
47     VISIBLE_PASSWORD_ICON,
48     DOUBLE_CLICK
49 };
50 
51 enum class AIResetSelectionReason {
52     INIT_SELECTION = 0,
53     SHOW_FOR_CANCEL = 1,
54     LONG_PRESS = 2,
55     CLICK = 3,
56     DRAG_START = 4,
57     DRAG_START_ON_CHILDREN = 5,
58     CLOSE_CONTEXT_MENU = 6
59 };
60 /**
61  * Stands for selection indexes
62  * We use base/destination to indicate the start/end position because of uncertain direction.
63  */
64 struct HandleInfo {
65     int32_t index = 0;
66     RectF rect;
67 
AddRectYHandleInfo68     void AddRectY(float deltaY)
69     {
70         auto newOffset = rect.GetOffset();
71         newOffset.AddY(deltaY);
72         rect.SetOffset(newOffset);
73     }
74 
AddRectXHandleInfo75     void AddRectX(float deltaX)
76     {
77         auto newOffset = rect.GetOffset();
78         newOffset.AddX(deltaX);
79         rect.SetOffset(newOffset);
80     }
81 };
82 struct TextSelector {
83     TextSelector() = default;
TextSelectorTextSelector84     TextSelector(int32_t base, int32_t destination) : baseOffset(base), destinationOffset(destination) {}
85 
SetOnAccessibilityTextSelector86     void SetOnAccessibility(OnAccessibilityCallback&& onAccessibilityCallback)
87     {
88         if (onAccessibilityCallback) {
89             onAccessibilityCallback_ = std::move(onAccessibilityCallback);
90         }
91     }
92 
FireAccessibilityCallbackTextSelector93     void FireAccessibilityCallback() const
94     {
95         if (onAccessibilityCallback_) {
96             onAccessibilityCallback_();
97         }
98     }
99 
UpdateTextSelector100     void Update(int32_t base, int32_t destination)
101     {
102         if (base == baseOffset && destination == destinationOffset) {
103             return;
104         }
105         bool isChanged = baseOffset != destinationOffset || base != destination;
106         baseOffset = base;
107         if (baseOffset >= 0) {
108             lastValidStart = baseOffset;
109         }
110         destinationOffset = destination;
111         if (isChanged) {
112             FireAccessibilityCallback();
113         }
114     }
115 
116     // Usually called when none is selected.
UpdateTextSelector117     void Update(int32_t both)
118     {
119         if ((baseOffset != both) || (destinationOffset != both)) {
120             if (baseOffset != destinationOffset) {
121                 FireAccessibilityCallback();
122             }
123         }
124         baseOffset = both;
125         destinationOffset = both;
126         if (baseOffset >= 0) {
127             lastValidStart = baseOffset;
128         }
129     }
130 
ReverseTextSelectorTextSelector131     void ReverseTextSelector()
132     {
133         if (baseOffset > destinationOffset) {
134             Update(destinationOffset, baseOffset);
135         }
136     }
137 
138     bool operator==(const TextSelector& other) const
139     {
140         return baseOffset == other.baseOffset && destinationOffset == other.destinationOffset;
141     }
142 
143     bool operator!=(const TextSelector& other) const
144     {
145         return !operator==(other);
146     }
147 
GetTextStartTextSelector148     inline int32_t GetTextStart() const
149     {
150         return std::min(baseOffset, destinationOffset);
151     }
152 
GetTextEndTextSelector153     inline int32_t GetTextEnd() const
154     {
155         return std::max(baseOffset, destinationOffset);
156     }
157 
GetStartTextSelector158     inline int32_t GetStart() const
159     {
160         return baseOffset;
161     }
162 
GetEndTextSelector163     inline int32_t GetEnd() const
164     {
165         return destinationOffset;
166     }
167 
IsValidTextSelector168     inline bool IsValid() const
169     {
170         return baseOffset > -1 && destinationOffset > -1;
171     }
172 
SelectNothingTextSelector173     inline bool SelectNothing() const
174     {
175         return !IsValid() || baseOffset == destinationOffset;
176     }
177 
MoveSelectionLeftTextSelector178     bool MoveSelectionLeft()
179     {
180         destinationOffset = std::max(0, destinationOffset - 1);
181         return destinationOffset == baseOffset;
182     }
183 
MoveSelectionRightTextSelector184     bool MoveSelectionRight()
185     {
186         destinationOffset = std::min(charCount, destinationOffset + 1);
187         return destinationOffset == baseOffset;
188     }
189 
GetSelectHeightTextSelector190     double GetSelectHeight() const
191     {
192         return std::max(firstHandle.Height(), secondHandle.Height());
193     }
194 
StartEqualToDestTextSelector195     bool StartEqualToDest() const
196     {
197         return baseOffset == destinationOffset;
198     }
199 
StartGreaterDestTextSelector200     bool StartGreaterDest() const
201     {
202         return baseOffset > destinationOffset;
203     }
204 
ContainsRangeTextSelector205     bool ContainsRange(const std::pair<int32_t, int32_t>& range) const
206     {
207         return IsValid() && GetTextStart() <= range.first && range.second <= GetTextEnd();
208     }
209 
ResetAiSelectedTextSelector210     void ResetAiSelected()
211     {
212         aiStart = std::nullopt;
213         aiEnd = std::nullopt;
214     }
215 
ToStringTextSelector216     std::string ToString()
217     {
218         std::string result;
219         result.append("baseOffset: ");
220         result.append(std::to_string(baseOffset));
221         result.append(", selectionBaseOffset: ");
222         result.append(selectionBaseOffset.ToString());
223         result.append(", destinationOffset: ");
224         result.append(std::to_string(destinationOffset));
225         result.append(", selectionDestinationOffset: ");
226         result.append(selectionDestinationOffset.ToString());
227         result.append(", firstHandle: ");
228         result.append(firstHandle.ToString());
229         result.append(", secondHandle: ");
230         result.append(secondHandle.ToString());
231         result.append(", firstHandleOffset_: ");
232         result.append(firstHandleOffset_.ToString());
233         result.append(", secondHandleOffset_: ");
234         result.append(secondHandleOffset_.ToString());
235         return result;
236     }
237 
238     // May larger than, smaller than or equal to destinationOffset.
239     int32_t baseOffset = -1;
240     OffsetF selectionBaseOffset;
241 
242     // When paints caret, this is where the caret position is.
243     int32_t destinationOffset = -1;
244     OffsetF selectionDestinationOffset;
245 
246     std::optional<int32_t> aiStart;
247     std::optional<int32_t> aiEnd;
248 
249     int32_t charCount = 0;
250     RectF firstHandle;
251     RectF secondHandle;
252     OffsetF firstHandleOffset_;
253     OffsetF secondHandleOffset_;
254     OnAccessibilityCallback onAccessibilityCallback_;
255     int32_t lastValidStart = 0;
256 };
257 
258 enum class TextSpanType : int32_t {
259     TEXT = 0,
260     IMAGE,
261     MIXED,
262     BUILDER,
263     NONE,
264 };
265 
266 enum class TextResponseType : int32_t {
267     RIGHT_CLICK = 0,
268     LONG_PRESS,
269     SELECTED_BY_MOUSE,
270     NONE,
271 };
272 
273 enum class SelectionMenuType : int32_t {
274     SELECTION_MENU = 0,
275     PREVIEW_MENU = 1,
276 };
277 
278 struct PreviewMenuOptions {
279     HapticFeedbackMode hapticFeedbackMode = HapticFeedbackMode::DISABLED;
280 };
281 
282 struct SelectMenuParam {
283     std::function<void(int32_t, int32_t)> onAppear;
284     std::function<void()> onDisappear;
285     std::function<void(int32_t, int32_t)> onMenuShow;
286     std::function<void(int32_t, int32_t)> onMenuHide;
287     bool isValid = true;
288     PreviewMenuOptions previewMenuOptions;
289 };
290 
291 struct SelectionMenuParams {
292     TextSpanType type;
293     std::function<void()> buildFunc;
294     std::function<void(int32_t, int32_t)> onAppear;
295     std::function<void()> onDisappear;
296     TextResponseType responseType;
297     std::function<void(int32_t, int32_t)> onMenuShow;
298     std::function<void(int32_t, int32_t)> onMenuHide;
299     bool isValid = true;
300 
SelectionMenuParamsSelectionMenuParams301     SelectionMenuParams(TextSpanType _type, std::function<void()> _buildFunc,
302         std::function<void(int32_t, int32_t)> _onAppear, std::function<void()> _onDisappear,
303         TextResponseType _responseType)
304         : type(_type), buildFunc(_buildFunc), onAppear(_onAppear), onDisappear(_onDisappear),
305           responseType(_responseType)
306     {}
307 };
308 
309 struct TextSpanTypeMapper {
GetTextSpanTypeFromJsTypeTextSpanTypeMapper310     static bool GetTextSpanTypeFromJsType(int32_t spanTypeId, NG::TextSpanType& spanType)
311     {
312         std::unordered_map<int32_t, NG::TextSpanType> spanTypeMap = {
313             { 0, NG::TextSpanType::TEXT },
314             { 1, NG::TextSpanType::IMAGE },
315             { 2, NG::TextSpanType::MIXED },
316             { 3, NG::TextSpanType::NONE }
317         };
318         if (spanTypeMap.find(spanTypeId) != spanTypeMap.end()) {
319             spanType = spanTypeMap[spanTypeId];
320             return true;
321         }
322         spanType = static_cast<NG::TextSpanType>(spanTypeId);
323         return false;
324     }
325 
GetJsSpanTypeTextSpanTypeMapper326     static int32_t GetJsSpanType(const NG::TextSpanType& spanType, bool isValid)
327     {
328         std::unordered_map<NG::TextSpanType, int32_t> spanTypeMap = {
329             { NG::TextSpanType::TEXT, 0 },
330             { NG::TextSpanType::IMAGE, 1 },
331             { NG::TextSpanType::MIXED, 2 },
332             { NG::TextSpanType::NONE, 3 }
333         };
334         if (isValid) {
335             return spanTypeMap[spanType];
336         }
337         return static_cast<int32_t>(spanType);
338     }
339 };
340 
341 } // namespace OHOS::Ace::NG
342 
343 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_TEXT_FIELD_TEXT_SELECTOR_H
344