1 /*
2 * Copyright (c) 2020-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_label.h"
17 #include "font/ui_font.h"
18 #include "gfx_utils/graphic_log.h"
19 #include "themes/theme_manager.h"
20
21 namespace OHOS {
22 class LabelAnimator : public Animator, public AnimatorCallback {
23 public:
LabelAnimator(uint16_t textX,uint16_t labelX,int16_t startPos,UIView * view)24 LabelAnimator(uint16_t textX, uint16_t labelX, int16_t startPos, UIView* view)
25 : Animator(this, view, 0, true),
26 startPos_(startPos),
27 textX_(textX),
28 labelX_(labelX),
29 offsetX_(startPos),
30 waitCount_(ANIM_WAIT_COUNT),
31 speed_(0),
32 preRunTime_(0),
33 decimal_(0)
34 {
35 }
36
~LabelAnimator()37 virtual ~LabelAnimator() {}
38
GetStartPos() const39 int16_t GetStartPos() const
40 {
41 return startPos_;
42 }
43
SetStartPos(int16_t pos)44 void SetStartPos(int16_t pos)
45 {
46 startPos_ = pos;
47 }
48
UpdateWidth(uint16_t textWidth,uint16_t labelWidth)49 void UpdateWidth(uint16_t textWidth, uint16_t labelWidth)
50 {
51 textX_ = textWidth;
52 labelX_ = labelWidth;
53 waitCount_ = ANIM_WAIT_COUNT;
54 preRunTime_ = 0;
55 decimal_ = 0;
56 offsetX_ = startPos_;
57 static_cast<UILabel*>(view_)->offsetX_ = offsetX_;
58 view_->Invalidate();
59 }
60
Callback(UIView * view)61 void Callback(UIView* view) override
62 {
63 if (view == nullptr) {
64 return;
65 }
66
67 uint32_t curTime = GetRunTime();
68 if (waitCount_ > 0) {
69 waitCount_--;
70 preRunTime_ = curTime;
71 return;
72 }
73 if (curTime == preRunTime_) {
74 return;
75 }
76 uint32_t time = (curTime > preRunTime_) ? (curTime - preRunTime_) : (UINT32_MAX - preRunTime_ + curTime);
77 // 1000: 1000 milliseconds is 1 second
78 float floatStep = (static_cast<float>(time * speed_) / 1000) + decimal_;
79 uint16_t integerStep = static_cast<uint16_t>(floatStep);
80 decimal_ = floatStep - integerStep;
81 preRunTime_ = curTime;
82
83 if (integerStep != 0) {
84 offsetX_ -= integerStep;
85 } else {
86 return;
87 }
88 offsetX_ = ((offsetX_ - labelX_) % (textX_ + labelX_)) + labelX_;
89 static_cast<UILabel*>(view)->offsetX_ = offsetX_;
90 view->Invalidate();
91 }
92
SetAnimatorSpeed(uint16_t animSpeed)93 void SetAnimatorSpeed(uint16_t animSpeed)
94 {
95 speed_ = animSpeed;
96 decimal_ = 0;
97 }
98
GetAnimatorSpeed() const99 int16_t GetAnimatorSpeed() const
100 {
101 return speed_;
102 }
103
104 private:
105 static constexpr uint8_t ANIM_WAIT_COUNT = 50;
106 int16_t startPos_;
107 uint16_t textX_;
108 uint16_t labelX_;
109 int16_t offsetX_;
110 uint16_t waitCount_;
111 uint16_t speed_;
112 uint32_t preRunTime_;
113 float decimal_;
114 };
115
UILabel()116 UILabel::UILabel()
117 : labelText_(nullptr),
118 needRefresh_(false),
119 useTextColor_(false),
120 hasAnimator_(false),
121 lineBreakMode_(LINE_BREAK_ELLIPSIS),
122 ellipsisIndex_(Text::TEXT_ELLIPSIS_END_INV),
123 offsetX_(0),
124 textColor_(Color::White()),
125 animator_{nullptr}
126 {
127 Theme* theme = ThemeManager::GetInstance().GetCurrent();
128 Style& style = (theme != nullptr) ? (theme->GetLabelStyle()) : (StyleDefault::GetLabelStyle());
129 UIView::SetStyle(style);
130 animator_.speed = DEFAULT_ANIMATOR_SPEED;
131 }
132
~UILabel()133 UILabel::~UILabel()
134 {
135 if (hasAnimator_) {
136 delete animator_.animator;
137 animator_.animator = nullptr;
138 hasAnimator_ = false;
139 }
140 if (labelText_ != nullptr) {
141 delete labelText_;
142 labelText_ = nullptr;
143 }
144 }
145
InitLabelText()146 void UILabel::InitLabelText()
147 {
148 if (labelText_ == nullptr) {
149 labelText_ = new Text();
150 }
151 }
152
GetWidth()153 int16_t UILabel::GetWidth()
154 {
155 InitLabelText();
156 if (needRefresh_ && labelText_->IsExpandWidth()) {
157 ReMeasure();
158 }
159 return UIView::GetWidth();
160 }
161
GetHeight()162 int16_t UILabel::GetHeight()
163 {
164 InitLabelText();
165 if (needRefresh_ && labelText_->IsExpandHeight()) {
166 ReMeasure();
167 }
168 return UIView::GetHeight();
169 }
170
SetStyle(uint8_t key,int64_t value)171 void UILabel::SetStyle(uint8_t key, int64_t value)
172 {
173 UIView::SetStyle(key, value);
174 RefreshLabel();
175 }
176
SetText(const char * text)177 void UILabel::SetText(const char* text)
178 {
179 InitLabelText();
180 labelText_->SetText(text);
181 if (labelText_->IsNeedRefresh()) {
182 RefreshLabel();
183 }
184 }
185
186 #if defined(ENABLE_SPANNABLE_STRING) && ENABLE_SPANNABLE_STRING
SetText(const SpannableString * text)187 void UILabel::SetText(const SpannableString* text)
188 {
189 InitLabelText();
190 labelText_->SetSpannableString(text);
191 if (labelText_->IsNeedRefresh()) {
192 RefreshLabel();
193 }
194 }
195 #endif
196
SetAbsoluteSizeSpan(uint16_t start,uint16_t end,uint8_t size)197 void UILabel::SetAbsoluteSizeSpan(uint16_t start, uint16_t end, uint8_t size)
198 {
199 if (labelText_ == nullptr) {
200 return;
201 }
202 labelText_->SetAbsoluteSizeSpan(start, end, size);
203 if (labelText_->IsNeedRefresh()) {
204 RefreshLabel();
205 }
206 }
207
SetRelativeSizeSpan(uint16_t start,uint16_t end,float size)208 void UILabel::SetRelativeSizeSpan(uint16_t start, uint16_t end, float size)
209 {
210 if (labelText_ == nullptr) {
211 return;
212 }
213 labelText_->SetRelativeSizeSpan(start, end, size);
214 if (labelText_->IsNeedRefresh()) {
215 RefreshLabel();
216 }
217 }
218
SetLineBreakMode(const uint8_t lineBreakMode)219 void UILabel::SetLineBreakMode(const uint8_t lineBreakMode)
220 {
221 InitLabelText();
222 if ((lineBreakMode >= LINE_BREAK_MAX) || (lineBreakMode_ == lineBreakMode)) {
223 return;
224 }
225 lineBreakMode_ = lineBreakMode;
226 if ((lineBreakMode_ == LINE_BREAK_ADAPT) || (lineBreakMode_ == LINE_BREAK_STRETCH) ||
227 (lineBreakMode_ == LINE_BREAK_MARQUEE)) {
228 labelText_->SetExpandWidth(true);
229 } else {
230 labelText_->SetExpandWidth(false);
231 }
232 if ((lineBreakMode_ == LINE_BREAK_ADAPT) || (lineBreakMode_ == LINE_BREAK_WRAP)) {
233 labelText_->SetExpandHeight(true);
234 } else {
235 labelText_->SetExpandHeight(false);
236 }
237 if (lineBreakMode_ != LINE_BREAK_MARQUEE) {
238 offsetX_ = 0;
239 if (hasAnimator_) {
240 animator_.animator->Stop();
241 }
242 }
243 RefreshLabel();
244 }
245
SetAlign(UITextLanguageAlignment horizontalAlign,UITextLanguageAlignment verticalAlign)246 void UILabel::SetAlign(UITextLanguageAlignment horizontalAlign, UITextLanguageAlignment verticalAlign)
247 {
248 InitLabelText();
249 labelText_->SetAlign(horizontalAlign, verticalAlign);
250 if (labelText_->IsNeedRefresh()) {
251 RefreshLabel();
252 }
253 }
254
SetFontId(uint16_t fontId)255 void UILabel::SetFontId(uint16_t fontId)
256 {
257 InitLabelText();
258 labelText_->SetFontId(fontId);
259 if (labelText_->IsNeedRefresh()) {
260 RefreshLabel();
261 }
262 }
263
SetFont(const char * name,uint8_t size)264 void UILabel::SetFont(const char* name, uint8_t size)
265 {
266 InitLabelText();
267 labelText_->SetFont(name, size);
268 if (labelText_->IsNeedRefresh()) {
269 RefreshLabel();
270 }
271 }
272
GetTextWidth()273 uint16_t UILabel::GetTextWidth()
274 {
275 InitLabelText();
276 if (labelText_->IsNeedRefresh()) {
277 ReMeasure();
278 }
279 return labelText_->GetTextSize().x;
280 }
281
GetTextHeight()282 uint16_t UILabel::GetTextHeight()
283 {
284 InitLabelText();
285 if (labelText_->IsNeedRefresh()) {
286 ReMeasure();
287 }
288 return labelText_->GetTextSize().y;
289 }
290
SetWidth(int16_t width)291 void UILabel::SetWidth(int16_t width)
292 {
293 if (GetWidth() != width) {
294 UIView::SetWidth(width);
295 RefreshLabel();
296 }
297 }
298
SetHeight(int16_t height)299 void UILabel::SetHeight(int16_t height)
300 {
301 if (GetHeight() != height) {
302 UIView::SetHeight(height);
303 RefreshLabel();
304 }
305 }
306
RefreshLabel()307 void UILabel::RefreshLabel()
308 {
309 Invalidate();
310 ellipsisIndex_ = Text::TEXT_ELLIPSIS_END_INV;
311 if (!needRefresh_) {
312 needRefresh_ = true;
313 }
314 }
315
ReMeasure()316 void UILabel::ReMeasure()
317 {
318 if (!needRefresh_) {
319 return;
320 }
321 needRefresh_ = false;
322 InitLabelText();
323 Style style = GetStyleConst();
324 style.textColor_ = GetTextColor();
325 bool flag = false;
326 if ((transMap_ != nullptr) && !transMap_->IsInvalid()) {
327 transMap_->SetInvalid(true);
328 flag = true;
329 }
330 labelText_->ReMeasureTextSize(GetContentRect(), style);
331 Point textSize = labelText_->GetTextSize();
332 switch (lineBreakMode_) {
333 case LINE_BREAK_ADAPT:
334 Resize(textSize.x, textSize.y);
335 break;
336 case LINE_BREAK_STRETCH:
337 SetWidth(textSize.x);
338 break;
339 case LINE_BREAK_WRAP:
340 SetHeight(textSize.y);
341 break;
342 case LINE_BREAK_ELLIPSIS:
343 ellipsisIndex_ = labelText_->GetEllipsisIndex(GetContentRect(), style);
344 labelText_->ReMeasureTextWidthInEllipsisMode(GetContentRect(), style, ellipsisIndex_);
345 break;
346 case LINE_BREAK_MARQUEE:
347 RemeasureForMarquee(textSize.x);
348 break;
349 default:
350 break;
351 }
352 if ((transMap_ != nullptr) && flag) {
353 transMap_->SetInvalid(false);
354 }
355 }
356
RemeasureForMarquee(int16_t textWidth)357 void UILabel::RemeasureForMarquee(int16_t textWidth)
358 {
359 int16_t rectWidth = GetWidth();
360 if (textWidth > rectWidth) {
361 offsetX_ = GetRollStartPos();
362 if (labelText_->GetDirect() == TEXT_DIRECT_RTL) {
363 labelText_->SetAlign(TEXT_ALIGNMENT_RIGHT);
364 } else {
365 labelText_->SetAlign(TEXT_ALIGNMENT_LEFT);
366 }
367 if (hasAnimator_) {
368 static_cast<LabelAnimator*>(animator_.animator)->UpdateWidth(textWidth, rectWidth);
369 } else {
370 LabelAnimator* animator = new LabelAnimator(textWidth, rectWidth, offsetX_, this);
371 if (animator == nullptr) {
372 GRAPHIC_LOGE("new LabelAnimator fail");
373 return;
374 }
375 animator->SetAnimatorSpeed(animator_.speed);
376 animator_.animator = animator;
377 hasAnimator_ = true;
378 }
379 animator_.animator->Start();
380 } else {
381 offsetX_ = 0;
382 if (hasAnimator_) {
383 animator_.animator->Stop();
384 }
385 }
386 }
387
SetRollStartPos(int16_t pos)388 void UILabel::SetRollStartPos(int16_t pos)
389 {
390 if (hasAnimator_) {
391 static_cast<LabelAnimator*>(animator_.animator)->SetStartPos(pos);
392 } else {
393 animator_.pos = pos;
394 }
395 }
396
GetRollStartPos() const397 int16_t UILabel::GetRollStartPos() const
398 {
399 return hasAnimator_ ? static_cast<LabelAnimator*>(animator_.animator)->GetStartPos() : animator_.pos;
400 }
401
SetRollSpeed(uint16_t speed)402 void UILabel::SetRollSpeed(uint16_t speed)
403 {
404 if (hasAnimator_) {
405 static_cast<LabelAnimator*>(animator_.animator)->SetAnimatorSpeed(speed);
406 } else {
407 animator_.speed = speed;
408 }
409 }
410
GetRollSpeed() const411 uint16_t UILabel::GetRollSpeed() const
412 {
413 return hasAnimator_ ? static_cast<LabelAnimator*>(animator_.animator)->GetAnimatorSpeed() : animator_.speed;
414 }
415
OnDraw(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea)416 void UILabel::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
417 {
418 InitLabelText();
419 UIView::OnDraw(gfxDstBuffer, invalidatedArea);
420 Style style = GetStyleConst();
421 style.textColor_ = GetTextColor();
422 OpacityType opa = GetMixOpaScale();
423 labelText_->OnDraw(gfxDstBuffer, invalidatedArea, GetOrigRect(),
424 GetContentRect(), offsetX_, style, ellipsisIndex_, opa);
425 }
426 } // namespace OHOS
427