1 /*
2 * Copyright (c) 2022 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 #include "components/ui_edit_text.h"
17
18 #include <codecvt>
19 #include <locale>
20
21 #include "font/ui_font.h"
22 #include "gfx_utils/graphic_log.h"
23 #include "securec.h"
24 #include "themes/theme_manager.h"
25
26 namespace OHOS {
27 namespace {
28 constexpr char16_t PASSWORD_DOT = u'•'; // dot for password type
29 constexpr uint16_t DEFAULT_TEXT_OFFSET = 5;
30 constexpr uint16_t DEFAULT_CURSOR_OFFSET = 2;
31 constexpr uint16_t DEFAULT_CURSOR_WIDTH = 2;
32 } // namespace name
33
34 class CursorAnimator : public Animator, public AnimatorCallback {
35 public:
CursorAnimator(UIEditText * view)36 explicit CursorAnimator(UIEditText* view) : Animator(this, view, 0, true), editText_(view) {}
37
~CursorAnimator()38 virtual ~CursorAnimator() {}
39
Callback(UIView * view)40 void Callback(UIView* view) override
41 {
42 if ((view == nullptr) || (editText_ == nullptr)) {
43 return;
44 }
45
46 uint32_t curTime = GetRunTime();
47 if (curTime == preTime_) {
48 return;
49 }
50 uint32_t duration = (curTime > preTime_) ? (curTime - preTime_) : (UINT32_MAX - preTime_ + curTime);
51 if (duration < CURSOR_ANIMATOT_DURATION) {
52 return;
53 }
54 preTime_ = curTime;
55 editText_->drawCursor_ = !editText_->drawCursor_;
56 view->Invalidate();
57 }
58
StartAnimator()59 void StartAnimator()
60 {
61 if (editText_ == nullptr) {
62 return;
63 }
64 Start();
65 preTime_ = GetRunTime();
66 editText_->drawCursor_ = false;
67 }
68
StopAnimator()69 void StopAnimator()
70 {
71 if (editText_ == nullptr) {
72 return;
73 }
74 Stop();
75 editText_->drawCursor_ = false;
76 editText_->Invalidate();
77 }
78
79 private:
80 uint32_t preTime_ = 0;
81 UIEditText* editText_ = nullptr;
82 static constexpr uint16_t CURSOR_ANIMATOT_DURATION = 650;
83 };
84
UIEditText()85 UIEditText::UIEditText()
86 : inputText_(nullptr),
87 placeholderText_(nullptr),
88 needRefresh_(false),
89 useTextColor_(false),
90 isFocused_(false),
91 drawCursor_(false),
92 maxLength_(MAX_TEXT_LENGTH),
93 placeholderEllipsisIndex_(Text::TEXT_ELLIPSIS_END_INV),
94 offsetX_(DEFAULT_TEXT_OFFSET),
95 textColor_(Color::White()),
96 placeholderColor_(Color::Gray()),
97 cursorColor_(Color::White()),
98 onChangeListener_(nullptr),
99 cursorAnimator_(nullptr)
100 {
101 touchable_ = true;
102 focusable_ = true;
103 Theme* theme = ThemeManager::GetInstance().GetCurrent();
104 Style& style = (theme != nullptr) ? (theme->GetEditTextStyle()) : (StyleDefault::GetEditTextStyle());
105 UIView::SetStyle(style);
106 }
107
~UIEditText()108 UIEditText::~UIEditText()
109 {
110 if (cursorAnimator_ != nullptr) {
111 delete cursorAnimator_;
112 cursorAnimator_ = nullptr;
113 }
114 if (inputText_ != nullptr) {
115 delete inputText_;
116 inputText_ = nullptr;
117 }
118 if (placeholderText_ != nullptr) {
119 delete placeholderText_;
120 placeholderText_ = nullptr;
121 }
122 }
123
OnPressEvent(const PressEvent & event)124 bool UIEditText::OnPressEvent(const PressEvent& event)
125 {
126 if (touchable_) {
127 RequestFocus();
128 }
129 return UIView::OnPressEvent(event);
130 }
131
Focus()132 void UIEditText::Focus()
133 {
134 if (focusable_) {
135 if (cursorAnimator_ == nullptr) {
136 cursorAnimator_ = new CursorAnimator(this);
137 }
138 static_cast<CursorAnimator*>(cursorAnimator_)->StartAnimator();
139 isFocused_ = true;
140 }
141 UpdateOffsetX();
142 Invalidate();
143 UIView::Focus();
144 }
145
Blur()146 void UIEditText::Blur()
147 {
148 if (cursorAnimator_ != nullptr) {
149 static_cast<CursorAnimator*>(cursorAnimator_)->StopAnimator();
150 }
151 isFocused_ = false;
152 UpdateOffsetX();
153 Invalidate();
154 UIView::Blur();
155 }
156
InitText()157 void UIEditText::InitText()
158 {
159 if (inputText_ == nullptr) {
160 inputText_ = new Text();
161 inputText_->SetAlign(TEXT_ALIGNMENT_LEFT, TEXT_ALIGNMENT_CENTER);
162 inputText_->SetExpandWidth(true);
163 inputText_->SetExpandHeight(false);
164 }
165
166 if (placeholderText_ == nullptr) {
167 placeholderText_ = new Text();
168 placeholderText_->SetAlign(TEXT_ALIGNMENT_LEFT, TEXT_ALIGNMENT_CENTER);
169 placeholderText_->SetExpandWidth(false);
170 placeholderText_->SetExpandHeight(false);
171 }
172 }
173
SetStyle(Style & style)174 void UIEditText::SetStyle(Style& style)
175 {
176 UIView::SetStyle(style);
177 RefreshText();
178 }
179
SetStyle(uint8_t key,int64_t value)180 void UIEditText::SetStyle(uint8_t key, int64_t value)
181 {
182 UIView::SetStyle(key, value);
183 RefreshText();
184 }
185
SetText(const char * text)186 void UIEditText::SetText(const char* text)
187 {
188 InitText();
189 if (text == nullptr) {
190 return;
191 }
192 SetText(std::string(text));
193 }
194
SetText(std::string text)195 void UIEditText::SetText(std::string text)
196 {
197 UpdateTextString(text);
198 UpdateInnerText();
199 }
200
GetText()201 const char* UIEditText::GetText()
202 {
203 return textStr_.c_str();
204 }
205
UpdateTextString(std::string text)206 void UIEditText::UpdateTextString(std::string text)
207 {
208 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert;
209 std::wstring wideText = convert.from_bytes(text);
210 uint32_t textLen = wideText.length();
211 uint16_t maxLength = GetMaxLength();
212 if (textLen > maxLength) {
213 textLen = maxLength;
214 }
215 std::wstring newWideText = wideText.substr(0, textLen);
216 std::string newText = convert.to_bytes(newWideText);
217 CheckValueChange(newText);
218 textStr_ = newText;
219
220 std::wstring dotString = std::wstring(newWideText.length(), PASSWORD_DOT);
221 passwordStr_ = convert.to_bytes(dotString);
222 }
223
GetInnerText()224 std::string UIEditText::GetInnerText()
225 {
226 return textStr_;
227 }
228
GetInnerPassword()229 std::string UIEditText::GetInnerPassword()
230 {
231 return passwordStr_;
232 }
233
SetPlaceholder(const char * text)234 void UIEditText::SetPlaceholder(const char* text)
235 {
236 InitText();
237 placeholderText_->SetText(text);
238 if (placeholderText_->IsNeedRefresh()) {
239 RefreshText();
240 }
241 }
242
GetPlaceholder()243 const char* UIEditText::GetPlaceholder()
244 {
245 if ((placeholderText_ == nullptr) || placeholderText_->GetText() == nullptr) {
246 return "";
247 } else {
248 return placeholderText_->GetText();
249 }
250 }
251
SetFontId(uint16_t fontId)252 void UIEditText::SetFontId(uint16_t fontId)
253 {
254 InitText();
255 inputText_->SetFontId(fontId);
256 placeholderText_->SetFontId(fontId);
257 if (inputText_->IsNeedRefresh()) {
258 RefreshText();
259 }
260 }
261
SetFont(const char * name,uint8_t size)262 void UIEditText::SetFont(const char* name, uint8_t size)
263 {
264 InitText();
265 inputText_->SetFont(name, size);
266 placeholderText_->SetFont(name, size);
267 if (inputText_->IsNeedRefresh()) {
268 RefreshText();
269 }
270 }
271
GetTextWidth()272 uint16_t UIEditText::GetTextWidth()
273 {
274 InitText();
275 if (inputText_->IsNeedRefresh()) {
276 ReMeasure();
277 }
278 return inputText_->GetTextSize().x;
279 }
280
GetTextHeight()281 uint16_t UIEditText::GetTextHeight()
282 {
283 InitText();
284 if (inputText_->IsNeedRefresh()) {
285 ReMeasure();
286 }
287 return inputText_->GetTextSize().y;
288 }
289
RefreshText()290 void UIEditText::RefreshText()
291 {
292 Invalidate();
293 placeholderEllipsisIndex_ = Text::TEXT_ELLIPSIS_END_INV;
294 if (!needRefresh_) {
295 needRefresh_ = true;
296 }
297 }
298
ReMeasure()299 void UIEditText::ReMeasure()
300 {
301 if (!needRefresh_) {
302 return;
303 }
304 needRefresh_ = false;
305 InitText();
306 Style style = GetStyleConst();
307 style.textColor_ = GetTextColor();
308 Rect contentRect = GetContentRect();
309 int16_t width = contentRect.GetWidth() - DEFAULT_TEXT_OFFSET * 2; // 2: left and right space
310 contentRect.SetWidth(width > 0 ? width : 0);
311 inputText_->ReMeasureTextSize(contentRect, style);
312 placeholderText_->ReMeasureTextSize(contentRect, style);
313 placeholderEllipsisIndex_ = placeholderText_->GetEllipsisIndex(contentRect, style);
314 placeholderText_->ReMeasureTextWidthInEllipsisMode(contentRect, style, placeholderEllipsisIndex_);
315
316 UpdateOffsetX();
317 }
318
UpdateOffsetX()319 void UIEditText::UpdateOffsetX()
320 {
321 if (isFocused_) {
322 Point textSize = inputText_->GetTextSize();
323 Rect contentRect = GetContentRect();
324 int16_t curWidth = textSize.x + DEFAULT_TEXT_OFFSET * 2;
325 if (contentRect.GetWidth() > curWidth) {
326 offsetX_ = DEFAULT_TEXT_OFFSET;
327 } else {
328 offsetX_ = contentRect.GetWidth() - curWidth;
329 }
330 } else {
331 offsetX_ = DEFAULT_TEXT_OFFSET;
332 }
333 }
334
OnDraw(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea)335 void UIEditText::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
336 {
337 InitText();
338 UIView::OnDraw(gfxDstBuffer, invalidatedArea);
339
340 bool drawPlaceholder = false;
341 if (inputText_->GetText() != nullptr && strlen(inputText_->GetText()) > 0) {
342 Style style = GetStyleConst();
343 style.textColor_ = GetTextColor();
344 OpacityType opa = GetMixOpaScale();
345 inputText_->OnDraw(gfxDstBuffer, invalidatedArea, GetOrigRect(), GetContentRect(), offsetX_, style,
346 Text::TEXT_ELLIPSIS_END_INV, opa);
347 drawPlaceholder = false;
348 } else {
349 Style style = GetStyleConst();
350 style.textColor_ = GetPlaceholderColor();
351 OpacityType opa = GetMixOpaScale();
352 placeholderText_->OnDraw(gfxDstBuffer, invalidatedArea, GetOrigRect(), GetContentRect(), DEFAULT_TEXT_OFFSET,
353 style, placeholderEllipsisIndex_, opa);
354 drawPlaceholder = true;
355 }
356
357 DrawCursor(gfxDstBuffer, invalidatedArea, drawPlaceholder);
358 }
359
DrawCursor(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea,bool drawPlaceholder)360 void UIEditText::DrawCursor(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, bool drawPlaceholder)
361 {
362 if (!(isFocused_ && drawCursor_)) {
363 return;
364 }
365
366 Style* cursorStyle = new Style();
367 cursorStyle->SetStyle(STYLE_BACKGROUND_COLOR, cursorColor_.full);
368 cursorStyle->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
369
370 Rect viewRect;
371 int16_t cursorSpace = DEFAULT_CURSOR_OFFSET;
372 if (drawPlaceholder) {
373 viewRect.SetLeft(GetOrigRect().GetX() + cursorSpace + offsetX_);
374 } else {
375 int16_t width = inputText_->GetTextSize().x;
376 viewRect.SetLeft(GetOrigRect().GetX() + width + cursorSpace + offsetX_);
377 }
378 viewRect.SetTop(GetOrigRect().GetTop() + (GetRect().GetHeight() - inputText_->GetFontSize()) / 2); // 2: harf size
379 viewRect.SetHeight(inputText_->GetFontSize());
380 viewRect.SetWidth(DEFAULT_CURSOR_WIDTH);
381
382 BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, viewRect, invalidatedArea, *cursorStyle, OPA_OPAQUE);
383 delete cursorStyle;
384 }
385
InsertText(std::string text)386 void UIEditText::InsertText(std::string text)
387 {
388 SetText(textStr_ + text);
389 if (cursorAnimator_ != nullptr) {
390 static_cast<CursorAnimator*>(cursorAnimator_)->StartAnimator();
391 }
392 }
393
DeleteBackward(uint32_t length)394 void UIEditText::DeleteBackward(uint32_t length)
395 {
396 if ((length == 0) || (textStr_.length() == 0)) {
397 return;
398 }
399 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert;
400 std::wstring wideText = convert.from_bytes(textStr_);
401 uint32_t textLen = wideText.length();
402 if (length > textLen) {
403 textLen = 0;
404 } else {
405 textLen -= length;
406 }
407 std::wstring newWideText = std::wstring(wideText, 0, textLen);
408 std::string newText = convert.to_bytes(newWideText);
409
410 SetText(newText);
411 if (cursorAnimator_ != nullptr) {
412 static_cast<CursorAnimator*>(cursorAnimator_)->StartAnimator();
413 }
414 }
415
UpdateInnerText()416 void UIEditText::UpdateInnerText()
417 {
418 InitText();
419 if (inputType_ == InputType::TEXT_TYPE) {
420 inputText_->SetText(GetInnerText().c_str());
421 } else {
422 inputText_->SetText(GetInnerPassword().c_str());
423 }
424 RefreshText();
425 }
426
SetMaxLength(uint16_t maxLength)427 void UIEditText::SetMaxLength(uint16_t maxLength)
428 {
429 InitText();
430 if (maxLength > MAX_TEXT_LENGTH) {
431 maxLength = MAX_TEXT_LENGTH;
432 }
433 maxLength_ = maxLength;
434 if (textStr_.length() > maxLength) {
435 SetText(textStr_.substr(0, maxLength));
436 }
437 }
438
GetMaxLength()439 uint16_t UIEditText::GetMaxLength()
440 {
441 return maxLength_;
442 }
443
SetInputType(InputType inputType)444 void UIEditText::SetInputType(InputType inputType)
445 {
446 if (inputType_ == inputType) {
447 return;
448 }
449 inputType_ = inputType;
450
451 // update view
452 UpdateInnerText();
453 }
454
CheckValueChange(std::string text)455 void UIEditText::CheckValueChange(std::string text)
456 {
457 if (onChangeListener_ == nullptr) {
458 return;
459 }
460
461 if (textStr_.compare(text) != 0) {
462 onChangeListener_->OnChange(*this, text.c_str());
463 }
464 }
465 } // namespace OHOS
466