• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-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_PATTERN_TEXT_SELECT_CONTROLLER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_TEXT_FIELD_PATTERN_TEXT_SELECT_CONTROLLER_H
18 
19 #include <cstdint>
20 #include <functional>
21 
22 #include "base/geometry/ng/offset_t.h"
23 #include "base/geometry/ng/rect_t.h"
24 #include "base/memory/ace_type.h"
25 #include "base/memory/referenced.h"
26 #include "core/components_ng/pattern/pattern.h"
27 #include "core/components_ng/pattern/text_field/content_controller.h"
28 #include "core/components_ng/pattern/text_field/text_field_layout_property.h"
29 #include "core/components_ng/pattern/text_field/text_selector.h"
30 #include "core/components_ng/property/property.h"
31 
32 namespace OHOS::Ace::NG {
33 namespace {
34 using OnAccessibilityCallback = std::function<void()>;
35 } // namespace
36 
37 enum class TouchPosition {
38     LEFT = 0,
39     MID = 1,
40     RIGHT
41 };
42 
43 class TextSelectController : public Property {
44     DECLARE_ACE_TYPE(TextSelectController, AceType);
45 
46 public:
TextSelectController(const WeakPtr<Pattern> & pattern)47     explicit TextSelectController(const WeakPtr<Pattern>& pattern) : pattern_(pattern) {}
48     ~TextSelectController() override = default;
SetOnAccessibility(OnAccessibilityCallback && onAccessibilityCallback)49     void SetOnAccessibility(OnAccessibilityCallback&& onAccessibilityCallback)
50     {
51         if (onAccessibilityCallback) {
52             onAccessibilityCallback_ = std::move(onAccessibilityCallback);
53         }
54     }
55 
56     void FireSelectEvent();
57 
UpdateHandleIndex(int32_t handleIndex)58     void UpdateHandleIndex(int32_t handleIndex)
59     {
60         UpdateHandleIndex(handleIndex, handleIndex);
61     }
62 
GetStartIndex()63     inline int32_t GetStartIndex() const
64     {
65         return std::min(firstHandleInfo_.index, secondHandleInfo_.index);
66     }
67 
GetEndIndex()68     inline int32_t GetEndIndex() const
69     {
70         return std::max(firstHandleInfo_.index, secondHandleInfo_.index);
71     }
72 
GetCaretIndex()73     int32_t GetCaretIndex() const
74     {
75         return caretInfo_.index;
76     }
77 
GetFirstHandleIndex()78     int32_t GetFirstHandleIndex() const
79     {
80         return firstHandleInfo_.index;
81     }
82 
GetFirstHandleRect()83     RectF GetFirstHandleRect() const
84     {
85         return firstHandleInfo_.rect;
86     }
87 
GetSecondHandleIndex()88     int32_t GetSecondHandleIndex() const
89     {
90         return secondHandleInfo_.index;
91     }
92 
GetSecondHandleRect()93     RectF GetSecondHandleRect() const
94     {
95         return secondHandleInfo_.rect;
96     }
97 
GetFirstHandleOffset()98     OffsetF GetFirstHandleOffset() const
99     {
100         return firstHandleInfo_.rect.GetOffset();
101     }
102 
GetSecondHandleOffset()103     OffsetF GetSecondHandleOffset() const
104     {
105         return secondHandleInfo_.rect.GetOffset();
106     }
107 
UpdateCaretHeight(float height)108     void UpdateCaretHeight(float height)
109     {
110         caretInfo_.rect.SetHeight(height);
111         secondHandleInfo_.rect.SetHeight(height);
112     }
113 
GetCaretRect()114     RectF GetCaretRect() const
115     {
116         return caretInfo_.rect;
117     }
118 
GetFloatingCaretRect()119     RectF GetFloatingCaretRect() const
120     {
121         return floatingCaretInfo_.rect;
122     }
123 
UpdateFloatingCaretInfo(const OffsetF & offset)124     void UpdateFloatingCaretInfo(const OffsetF& offset)
125     {
126         floatingCaretInfo_.UpdateOffset(offset);
127     }
128 
GetSelectHeight()129     double GetSelectHeight() const
130     {
131         return std::max(firstHandleInfo_.rect.Height(), secondHandleInfo_.rect.Height());
132     }
133 
InitContentController(const RefPtr<ContentController> & controller)134     void InitContentController(const RefPtr<ContentController>& controller)
135     {
136         contentController_ = controller;
137     }
138 
IsSelected()139     inline bool IsSelected() const
140     {
141         return firstHandleInfo_.index >= 0 && secondHandleInfo_.index >= 0 &&
142                firstHandleInfo_.index != secondHandleInfo_.index;
143     }
144 
IsSelectedAll()145     inline bool IsSelectedAll() const
146     {
147         return firstHandleInfo_.index == 0 && secondHandleInfo_.index >= 0 &&
148                abs(firstHandleInfo_.index - secondHandleInfo_.index) ==
149                    static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
150     }
151 
IsHandleSamePosition()152     bool IsHandleSamePosition() const
153     {
154         bool sameX = NearEqual(firstHandleInfo_.rect.GetX(), secondHandleInfo_.rect.GetX());
155         bool sameY = NearEqual(firstHandleInfo_.rect.GetY(), secondHandleInfo_.rect.GetY());
156         return (sameX && sameY);
157     }
158 
UpdateParagraph(const RefPtr<Paragraph> & paragraph)159     void UpdateParagraph(const RefPtr<Paragraph>& paragraph)
160     {
161         paragraph_ = paragraph;
162     }
163 
UpdateContentRect(const RectF & rect)164     void UpdateContentRect(const RectF& rect)
165     {
166         contentRect_ = rect;
167     }
168 
UpdateCaretWidth(float width)169     void UpdateCaretWidth(float width)
170     {
171         caretInfo_.rect.SetWidth(width);
172         caretInfo_.originalRect.SetWidth(SelectHandleInfo::GetDefaultLineWidth().ConvertToPx());
173     }
174 
GetFirstHandleInfo()175     HandleInfoNG GetFirstHandleInfo() const
176     {
177         return firstHandleInfo_;
178     }
179 
GetSecondHandleInfo()180     HandleInfoNG GetSecondHandleInfo() const
181     {
182         return secondHandleInfo_;
183     }
184 
GetCaretInfo()185     HandleInfoNG GetCaretInfo() const
186     {
187         return caretInfo_;
188     }
189 
HasReverse()190     bool HasReverse() const
191     {
192         return firstHandleInfo_.index > secondHandleInfo_.index;
193     }
194 
CaretAtLast()195     bool CaretAtLast() const
196     {
197         return caretInfo_.index == static_cast<int32_t>(contentController_->GetTextUtf16Value().length());
198     }
199 
200     int32_t ConvertTouchOffsetToPosition(const Offset& localOffset, bool isSelectionPos = false) const;
201     void ResetHandles();
202     void UpdateHandleIndex(int32_t firstHandleIndex, int32_t secondHandleIndex);
203     void UpdateCaretIndex(int32_t index);
204     void UpdateCaretInfoByOffset(const Offset& localOffset, bool moveContent = true, bool floatCaret = false);
205     OffsetF CalcCaretOffsetByOffset(const Offset& localOffset);
206     void UpdateSecondHandleInfoByMouseOffset(const Offset& localOffset);
207     void MoveSecondHandleByKeyBoard(int32_t index, std::optional<TextAffinity> textAffinity = std::nullopt);
208     void UpdateSelectByOffset(const Offset& localOffset);
209     void UpdateSelectPragraphByOffset(const Offset& localOffset);
210     std::pair<int32_t, int32_t> GetSelectRangeByOffset(const Offset& localOffset);
211     std::pair<int32_t, int32_t> GetSelectParagraphByOffset(const Offset& localOffset);
212     void UpdateCaretOffset(TextAffinity textAffinity = TextAffinity::DOWNSTREAM, bool moveHandle = true);
213     void UpdateCaretOffset(const OffsetF& offset);
214     void UpdateFirstHandleOffset();
215     void UpdateSecondHandleOffset();
216     void MoveFirstHandleToContentRect(int32_t index, bool moveHandle = true, bool moveContent = true);
217     void MoveSecondHandleToContentRect(int32_t index, bool moveHandle = true, bool moveContent = true);
218     void MoveCaretToContentRect(int32_t index, TextAffinity textAffinity = TextAffinity::UPSTREAM,
219         bool isEditorValueChanged = true, bool moveContent = true);
220     void MoveCaretAnywhere(const Offset& touchOffset);
221     void MoveHandleToContentRect(RectF& handleRect, float boundaryAdjustment = 0.0f) const;
222     void AdjustHandleAtEdge(RectF& handleRect) const;
223     void AdjustHandleOffset(RectF& handleRect) const;
224     static int32_t GetGraphemeClusterLength(const std::u16string& text, int32_t extend, bool checkPrev = false);
225     void CalculateHandleOffset();
226     std::vector<RectF> GetSelectedRects() const;
227     RectF CalculateEmptyValueCaretRect(float width = 0.0f);
228     std::string ToString() const;
229     bool IsTouchAtLineEnd(const Offset& localOffset) const;
230     TouchPosition GetTouchLinePos(const Offset& localOffset);
231     void GetSubParagraphByOffset(int32_t pos, int32_t &start, int32_t &end);
232     void UpdateSelectWithBlank(const Offset& localOffset);
233     void AdjustHandleInBoundary(RectF& handleRect) const;
234     void AdjustHandleOffsetWithBoundary(RectF& handleRect);
235     void AdjustAllHandlesWithBoundary();
236 
237 private:
238     constexpr static uint32_t SECONDS_TO_MILLISECONDS = 1000;
239 
240     void FitCaretMetricsToContentRect(CaretMetricsF& caretMetrics);
241     void FitCaretMetricsToTouchPoint(CaretMetricsF& caretMetrics, const Offset& touchOffset);
242     void CalcCaretMetricsByPosition(int32_t extent, CaretMetricsF& caretCaretMetric, TextAffinity textAffinity);
243     void CalcCaretMetricsByPositionNearTouchOffset(
244         int32_t extent, CaretMetricsF& caretMetrics, const OffsetF& touchOffset);
245     // The cursor needs to fit the line where the touch is located.
246     void UpdateCaretRectByPositionNearTouchOffset(int32_t position, const Offset& touchOffset);
247 
248     // ai text analysis or detect
249     bool NeedAIAnalysis(int32_t& index, const CaretUpdateType targetType, const Offset& touchOffset,
250         std::chrono::duration<float, std::ratio<1, SECONDS_TO_MILLISECONDS>> timeout);
251     void AdjustCursorPosition(int32_t& index, const Offset& touchOffset);
252     bool AdjustWordSelection(int32_t& index, int32_t& start, int32_t& end, const Offset& touchOffset);
253     bool IsClickAtBoundary(int32_t index, const Offset& touchOffset);
254     const TimeStamp& GetLastClickTime() const;
255     void UpdateCaretOriginalRect(const OffsetF& offset);
256     void SetCaretRectAtEmptyValue();
257 
258     ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(FirstIndex, int32_t, PROPERTY_UPDATE_RENDER);
259     ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(SecondIndex, int32_t, PROPERTY_UPDATE_RENDER);
260 
261     RectF contentRect_;
262     HandleInfoNG firstHandleInfo_;
263     HandleInfoNG secondHandleInfo_;
264     HandleInfoNG caretInfo_;
265     HandleInfoNG floatingCaretInfo_;
266     RefPtr<Paragraph> paragraph_;
267     RefPtr<ContentController> contentController_;
268     OnAccessibilityCallback onAccessibilityCallback_;
269     WeakPtr<Pattern> pattern_;
270     TimeStamp lastAiPosTimeStamp_;
271     TextAffinity textAffinity_ = TextAffinity::DOWNSTREAM;
272 };
273 } // namespace OHOS::Ace::NG
274 
275 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_TEXT_FIELD_PATTERN_TEXT_SELECT_CONTROLLER_H