• 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 #include "core/components_ng/render/paragraph.h"
32 
33 namespace OHOS::Ace::NG {
34 namespace {
35 using OnAccessibilityCallback = std::function<void()>;
36 } // namespace
37 
38 class TextSelectController : public Property {
39     DECLARE_ACE_TYPE(TextSelectController, AceType);
40 
41 public:
TextSelectController(const WeakPtr<Pattern> & pattern)42     explicit TextSelectController(const WeakPtr<Pattern>& pattern) : pattern_(pattern) {}
43     ~TextSelectController() override = default;
SetOnAccessibility(OnAccessibilityCallback && onAccessibilityCallback)44     void SetOnAccessibility(OnAccessibilityCallback&& onAccessibilityCallback)
45     {
46         if (onAccessibilityCallback) {
47             onAccessibilityCallback_ = std::move(onAccessibilityCallback);
48         }
49     }
50 
51     void FireSelectEvent();
52     void UpdateRecordCaretIndex(int32_t index) const;
53 
UpdateHandleIndex(int32_t handleIndex)54     void UpdateHandleIndex(int32_t handleIndex)
55     {
56         UpdateHandleIndex(handleIndex, handleIndex);
57     }
58 
GetStartIndex()59     inline int32_t GetStartIndex() const
60     {
61         return std::min(firstHandleInfo_.index, secondHandleInfo_.index);
62     }
63 
GetEndIndex()64     inline int32_t GetEndIndex() const
65     {
66         return std::max(firstHandleInfo_.index, secondHandleInfo_.index);
67     }
68 
GetCaretIndex()69     int32_t GetCaretIndex() const
70     {
71         return caretInfo_.index;
72     }
73 
GetFirstHandleIndex()74     int32_t GetFirstHandleIndex() const
75     {
76         return firstHandleInfo_.index;
77     }
78 
GetFirstHandleRect()79     RectF GetFirstHandleRect() const
80     {
81         return firstHandleInfo_.rect;
82     }
83 
GetSecondHandleIndex()84     int32_t GetSecondHandleIndex() const
85     {
86         return secondHandleInfo_.index;
87     }
88 
GetSecondHandleRect()89     RectF GetSecondHandleRect() const
90     {
91         return secondHandleInfo_.rect;
92     }
93 
GetFirstHandleOffset()94     OffsetF GetFirstHandleOffset() const
95     {
96         return firstHandleInfo_.rect.GetOffset();
97     }
98 
GetSecondHandleOffset()99     OffsetF GetSecondHandleOffset() const
100     {
101         return secondHandleInfo_.rect.GetOffset();
102     }
103 
UpdateCaretHeight(float height)104     void UpdateCaretHeight(float height)
105     {
106         caretInfo_.rect.SetHeight(height);
107         secondHandleInfo_.rect.SetHeight(height);
108     }
109 
GetCaretRect()110     RectF GetCaretRect() const
111     {
112         return caretInfo_.rect;
113     }
114 
GetSelectHeight()115     double GetSelectHeight() const
116     {
117         return std::max(firstHandleInfo_.rect.Height(), secondHandleInfo_.rect.Height());
118     }
119 
InitContentController(const RefPtr<ContentController> & controller)120     void InitContentController(const RefPtr<ContentController>& controller)
121     {
122         contentController_ = controller;
123     }
124 
IsSelected()125     inline bool IsSelected() const
126     {
127         return firstHandleInfo_.index >= 0 && secondHandleInfo_.index >= 0 &&
128                firstHandleInfo_.index != secondHandleInfo_.index;
129     }
130 
IsSelectedAll()131     inline bool IsSelectedAll() const
132     {
133         return firstHandleInfo_.index == 0 && secondHandleInfo_.index >= 0 &&
134                abs(firstHandleInfo_.index - secondHandleInfo_.index) ==
135                    static_cast<int32_t>(contentController_->GetWideText().length());
136     }
137 
IsHandleSamePosition()138     bool IsHandleSamePosition()
139     {
140         bool sameX = NearEqual(firstHandleInfo_.rect.GetX(), secondHandleInfo_.rect.GetX());
141         bool sameY = NearEqual(firstHandleInfo_.rect.GetY(), secondHandleInfo_.rect.GetY());
142         return (sameX && sameY);
143     }
144 
UpdateParagraph(const RefPtr<Paragraph> & paragraph)145     void UpdateParagraph(const RefPtr<Paragraph>& paragraph)
146     {
147         paragraph_ = paragraph;
148     }
149 
UpdateContentRect(const RectF & rect)150     void UpdateContentRect(const RectF& rect)
151     {
152         contentRect_ = rect;
153     }
154 
UpdateCaretWidth(float width)155     void UpdateCaretWidth(float width)
156     {
157         caretInfo_.rect.SetWidth(width);
158     }
159 
GetFirstHandleInfo()160     HandleInfoNG GetFirstHandleInfo() const
161     {
162         return firstHandleInfo_;
163     }
164 
GetSecondHandleInfo()165     HandleInfoNG GetSecondHandleInfo() const
166     {
167         return secondHandleInfo_;
168     }
169 
GetCaretInfo()170     HandleInfoNG GetCaretInfo() const
171     {
172         return caretInfo_;
173     }
174 
HasReverse()175     bool HasReverse()
176     {
177         return firstHandleInfo_.index > secondHandleInfo_.index;
178     }
179 
CaretAtLast()180     bool CaretAtLast() const
181     {
182         return caretInfo_.index == static_cast<int32_t>(contentController_->GetWideText().length());
183     }
184 
185     void ResetHandles();
186     void UpdateHandleIndex(int32_t firstHandleIndex, int32_t secondHandleIndex);
187     void UpdateCaretIndex(int32_t index);
188     void UpdateCaretInfoByOffset(const Offset& localOffset);
189     void UpdateSecondHandleInfoByMouseOffset(const Offset& localOffset);
190     void MoveSecondHandleByKeyBoard(int32_t index);
191     void UpdateSelectByOffset(const Offset& localOffset);
192     std::pair<int32_t, int32_t> GetSelectRangeByOffset(const Offset& localOffset);
193     void UpdateCaretOffset(TextAffinity textAffinity = TextAffinity::DOWNSTREAM);
194     void UpdateCaretOffset(const OffsetF& offset);
195     void UpdateFirstHandleOffset();
196     void UpdateSecondHandleOffset();
197     void MoveFirstHandleToContentRect(int32_t index);
198     void MoveSecondHandleToContentRect(int32_t index);
199     void MoveCaretToContentRect(
200         int32_t index, TextAffinity textAffinity = TextAffinity::UPSTREAM, bool isEditorValueChanged = true);
201     void MoveHandleToContentRect(RectF& handleRect, float boundaryAdjustment = 0.0f) const;
202     void AdjustHandleAtEdge(RectF& handleRect) const;
203     static int32_t GetGraphemeClusterLength(const std::wstring& text, int32_t extend, bool checkPrev = false);
204     void CalculateHandleOffset();
205     std::vector<RectF> GetSelectedRects() const;
206     RectF CalculateEmptyValueCaretRect() const;
207     std::string ToString() const;
208     int32_t ConvertTouchOffsetToPosition(const Offset& localOffset, bool isSelectionPos = false);
209 
210 private:
211     constexpr static uint32_t SECONDS_TO_MILLISECONDS = 1000;
212 
213     void FitCaretMetricsToContentRect(CaretMetricsF& caretMetrics);
214     void CalcCaretMetricsByPosition(int32_t extent, CaretMetricsF& caretCaretMetric, TextAffinity textAffinity);
215     void CalcCaretMetricsByPositionNearTouchOffset(
216         int32_t extent, CaretMetricsF& caretMetrics, const OffsetF& touchOffset);
217     // The cursor needs to fit the line where the touch is located.
218     void UpdateCaretRectByPositionNearTouchOffset(int32_t position, const Offset& touchOffset);
219     // ai text analysis or detect
220     bool NeedAIAnalysis(int32_t& index, const CaretUpdateType targetType, const Offset& touchOffset,
221         std::chrono::duration<float, std::ratio<1, SECONDS_TO_MILLISECONDS>> timeout);
222     bool IsLineBreakOrEndOfParagraph(int32_t pos) const;
223     void AdjustCursorPosition(int32_t& index, const Offset& touchOffset);
224     bool AdjustWordSelection(int32_t& index, int32_t& start, int32_t& end, const Offset& touchOffset);
225     bool IsClickAtBoundary(int32_t index, const Offset& touchOffset);
226     const TimeStamp& GetLastClickTime();
227 
228     ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(FirstIndex, int32_t, PROPERTY_UPDATE_RENDER);
229     ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(SecondIndex, int32_t, PROPERTY_UPDATE_RENDER);
230 
231     RectF contentRect_;
232     HandleInfoNG firstHandleInfo_;
233     HandleInfoNG secondHandleInfo_;
234     HandleInfoNG caretInfo_;
235     RefPtr<Paragraph> paragraph_;
236     RefPtr<ContentController> contentController_;
237     OnAccessibilityCallback onAccessibilityCallback_;
238     WeakPtr<Pattern> pattern_;
239     TimeStamp lastAiPosTimeStamp_;
240     TextAffinity textAffinity_ = TextAffinity::DOWNSTREAM;
241 };
242 } // namespace OHOS::Ace::NG
243 
244 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_TEXT_FIELD_PATTERN_TEXT_SELECT_CONTROLLER_H