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