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 * Stands for selection indexes 52 * We use base/destination to indicate the start/end position because of uncertain direction. 53 */ 54 struct HandleInfo { 55 int32_t index = 0; 56 RectF rect; 57 AddRectYHandleInfo58 void AddRectY(float deltaY) 59 { 60 auto newOffset = rect.GetOffset(); 61 newOffset.AddY(deltaY); 62 rect.SetOffset(newOffset); 63 } 64 AddRectXHandleInfo65 void AddRectX(float deltaX) 66 { 67 auto newOffset = rect.GetOffset(); 68 newOffset.AddX(deltaX); 69 rect.SetOffset(newOffset); 70 } 71 }; 72 struct TextSelector { 73 TextSelector() = default; TextSelectorTextSelector74 TextSelector(int32_t base, int32_t destination) : baseOffset(base), destinationOffset(destination) {} 75 SetOnAccessibilityTextSelector76 void SetOnAccessibility(OnAccessibilityCallback&& onAccessibilityCallback) 77 { 78 if (onAccessibilityCallback) { 79 onAccessibilityCallback_ = std::move(onAccessibilityCallback); 80 } 81 } 82 FireAccessibilityCallbackTextSelector83 void FireAccessibilityCallback() const 84 { 85 if (onAccessibilityCallback_) { 86 onAccessibilityCallback_(); 87 } 88 } 89 UpdateTextSelector90 void Update(int32_t base, int32_t destination) 91 { 92 if (base == baseOffset && destination == destinationOffset) { 93 return; 94 } 95 bool isChanged = baseOffset != destinationOffset || base != destination; 96 baseOffset = base; 97 if (baseOffset >= 0) { 98 lastValidStart = baseOffset; 99 } 100 destinationOffset = destination; 101 if (isChanged) { 102 FireAccessibilityCallback(); 103 } 104 } 105 106 // Usually called when none is selected. UpdateTextSelector107 void Update(int32_t both) 108 { 109 if ((baseOffset != both) || (destinationOffset != both)) { 110 if (baseOffset != destinationOffset) { 111 FireAccessibilityCallback(); 112 } 113 } 114 baseOffset = both; 115 destinationOffset = both; 116 if (baseOffset >= 0) { 117 lastValidStart = baseOffset; 118 } 119 } 120 ReverseTextSelectorTextSelector121 void ReverseTextSelector() 122 { 123 if (baseOffset > destinationOffset) { 124 Update(destinationOffset, baseOffset); 125 } 126 } 127 128 bool operator==(const TextSelector& other) const 129 { 130 return baseOffset == other.baseOffset && destinationOffset == other.destinationOffset; 131 } 132 133 bool operator!=(const TextSelector& other) const 134 { 135 return !operator==(other); 136 } 137 GetTextStartTextSelector138 inline int32_t GetTextStart() const 139 { 140 return std::min(baseOffset, destinationOffset); 141 } 142 GetTextEndTextSelector143 inline int32_t GetTextEnd() const 144 { 145 return std::max(baseOffset, destinationOffset); 146 } 147 GetStartTextSelector148 inline int32_t GetStart() const 149 { 150 return baseOffset; 151 } 152 GetEndTextSelector153 inline int32_t GetEnd() const 154 { 155 return destinationOffset; 156 } 157 IsValidTextSelector158 inline bool IsValid() const 159 { 160 return baseOffset > -1 && destinationOffset > -1; 161 } 162 SelectNothingTextSelector163 inline bool SelectNothing() const 164 { 165 return !IsValid() || baseOffset == destinationOffset; 166 } 167 MoveSelectionLeftTextSelector168 bool MoveSelectionLeft() 169 { 170 destinationOffset = std::max(0, destinationOffset - 1); 171 return destinationOffset == baseOffset; 172 } 173 MoveSelectionRightTextSelector174 bool MoveSelectionRight() 175 { 176 destinationOffset = std::min(charCount, destinationOffset + 1); 177 return destinationOffset == baseOffset; 178 } 179 GetSelectHeightTextSelector180 double GetSelectHeight() const 181 { 182 return std::max(firstHandle.Height(), secondHandle.Height()); 183 } 184 StartEqualToDestTextSelector185 bool StartEqualToDest() const 186 { 187 return baseOffset == destinationOffset; 188 } 189 StartGreaterDestTextSelector190 bool StartGreaterDest() const 191 { 192 return baseOffset > destinationOffset; 193 } 194 ContainsRangeTextSelector195 bool ContainsRange(const std::pair<int32_t, int32_t>& range) const 196 { 197 return IsValid() && GetTextStart() <= range.first && range.second <= GetTextEnd(); 198 } 199 ToStringTextSelector200 std::string ToString() 201 { 202 std::string result; 203 result.append("baseOffset: "); 204 result.append(std::to_string(baseOffset)); 205 result.append(", selectionBaseOffset: "); 206 result.append(selectionBaseOffset.ToString()); 207 result.append(", destinationOffset: "); 208 result.append(std::to_string(destinationOffset)); 209 result.append(", selectionDestinationOffset: "); 210 result.append(selectionDestinationOffset.ToString()); 211 result.append(", firstHandle: "); 212 result.append(firstHandle.ToString()); 213 result.append(", secondHandle: "); 214 result.append(secondHandle.ToString()); 215 result.append(", firstHandleOffset_: "); 216 result.append(firstHandleOffset_.ToString()); 217 result.append(", secondHandleOffset_: "); 218 result.append(secondHandleOffset_.ToString()); 219 return result; 220 } 221 222 // May larger than, smaller than or equal to destinationOffset. 223 int32_t baseOffset = -1; 224 OffsetF selectionBaseOffset; 225 226 // When paints caret, this is where the caret position is. 227 int32_t destinationOffset = -1; 228 OffsetF selectionDestinationOffset; 229 230 int32_t charCount = 0; 231 RectF firstHandle; 232 RectF secondHandle; 233 OffsetF firstHandleOffset_; 234 OffsetF secondHandleOffset_; 235 OnAccessibilityCallback onAccessibilityCallback_; 236 int32_t lastValidStart = 0; 237 }; 238 239 enum class TextSpanType : int32_t { 240 TEXT = 0, 241 IMAGE, 242 MIXED, 243 BUILDER, 244 NONE, 245 }; 246 247 enum class TextResponseType : int32_t { 248 RIGHT_CLICK = 0, 249 LONG_PRESS, 250 SELECTED_BY_MOUSE, 251 NONE, 252 }; 253 254 enum class SelectionMenuType : int32_t { 255 SELECTION_MENU = 0, 256 PREVIEW_MENU = 1, 257 }; 258 259 struct PreviewMenuOptions { 260 HapticFeedbackMode hapticFeedbackMode = HapticFeedbackMode::DISABLED; 261 }; 262 263 struct SelectMenuParam { 264 std::function<void(int32_t, int32_t)> onAppear; 265 std::function<void()> onDisappear; 266 std::function<void(int32_t, int32_t)> onMenuShow; 267 std::function<void(int32_t, int32_t)> onMenuHide; 268 bool isValid = true; 269 PreviewMenuOptions previewMenuOptions; 270 }; 271 272 struct SelectionMenuParams { 273 TextSpanType type; 274 std::function<void()> buildFunc; 275 std::function<void(int32_t, int32_t)> onAppear; 276 std::function<void()> onDisappear; 277 TextResponseType responseType; 278 std::function<void(int32_t, int32_t)> onMenuShow; 279 std::function<void(int32_t, int32_t)> onMenuHide; 280 bool isValid = true; 281 SelectionMenuParamsSelectionMenuParams282 SelectionMenuParams(TextSpanType _type, std::function<void()> _buildFunc, 283 std::function<void(int32_t, int32_t)> _onAppear, std::function<void()> _onDisappear, 284 TextResponseType _responseType) 285 : type(_type), buildFunc(_buildFunc), onAppear(_onAppear), onDisappear(_onDisappear), 286 responseType(_responseType) 287 {} 288 }; 289 290 struct TextSpanTypeMapper { GetTextSpanTypeFromJsTypeTextSpanTypeMapper291 static bool GetTextSpanTypeFromJsType(int32_t spanTypeId, NG::TextSpanType& spanType) 292 { 293 std::unordered_map<int32_t, NG::TextSpanType> spanTypeMap = { 294 { 0, NG::TextSpanType::TEXT }, 295 { 1, NG::TextSpanType::IMAGE }, 296 { 2, NG::TextSpanType::MIXED }, 297 { 3, NG::TextSpanType::NONE } 298 }; 299 if (spanTypeMap.find(spanTypeId) != spanTypeMap.end()) { 300 spanType = spanTypeMap[spanTypeId]; 301 return true; 302 } 303 spanType = static_cast<NG::TextSpanType>(spanTypeId); 304 return false; 305 } 306 GetJsSpanTypeTextSpanTypeMapper307 static int32_t GetJsSpanType(const NG::TextSpanType& spanType, bool isValid) 308 { 309 std::unordered_map<NG::TextSpanType, int32_t> spanTypeMap = { 310 { NG::TextSpanType::TEXT, 0 }, 311 { NG::TextSpanType::IMAGE, 1 }, 312 { NG::TextSpanType::MIXED, 2 }, 313 { NG::TextSpanType::NONE, 3 } 314 }; 315 if (isValid) { 316 return spanTypeMap[spanType]; 317 } 318 return static_cast<int32_t>(spanType); 319 } 320 }; 321 322 } // namespace OHOS::Ace::NG 323 324 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_TEXT_FIELD_TEXT_SELECTOR_H 325