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
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
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
GetFontSize()219 uint8_t UILabel::GetFontSize()
220 {
221 InitLabelText();
222 return labelText_->GetFontSize();
223 }
224
SetLineBreakMode(const uint8_t lineBreakMode)225 void UILabel::SetLineBreakMode(const uint8_t lineBreakMode)
226 {
227 InitLabelText();
228 if ((lineBreakMode >= LINE_BREAK_MAX) || (lineBreakMode_ == lineBreakMode)) {
229 return;
230 }
231 lineBreakMode_ = lineBreakMode;
232 if ((lineBreakMode_ == LINE_BREAK_ADAPT) || (lineBreakMode_ == LINE_BREAK_STRETCH) ||
233 (lineBreakMode_ == LINE_BREAK_MARQUEE)) {
234 labelText_->SetExpandWidth(true);
235 } else {
236 labelText_->SetExpandWidth(false);
237 }
238 if ((lineBreakMode_ == LINE_BREAK_ADAPT) || (lineBreakMode_ == LINE_BREAK_WRAP)) {
239 labelText_->SetExpandHeight(true);
240 } else {
241 labelText_->SetExpandHeight(false);
242 }
243 if (lineBreakMode_ != LINE_BREAK_MARQUEE) {
244 offsetX_ = 0;
245 if (hasAnimator_) {
246 animator_.animator->Stop();
247 }
248 }
249 RefreshLabel();
250 }
251
SetAlign(UITextLanguageAlignment horizontalAlign,UITextLanguageAlignment verticalAlign)252 void UILabel::SetAlign(UITextLanguageAlignment horizontalAlign, UITextLanguageAlignment verticalAlign)
253 {
254 InitLabelText();
255 labelText_->SetAlign(horizontalAlign, verticalAlign);
256 if (labelText_->IsNeedRefresh()) {
257 RefreshLabel();
258 }
259 }
260
SetFontId(uint16_t fontId)261 void UILabel::SetFontId(uint16_t fontId)
262 {
263 InitLabelText();
264 labelText_->SetFontId(fontId);
265 if (labelText_->IsNeedRefresh()) {
266 RefreshLabel();
267 }
268 }
269
SetFont(const char * name,uint8_t size)270 void UILabel::SetFont(const char* name, uint8_t size)
271 {
272 InitLabelText();
273 labelText_->SetFont(name, size);
274 if (labelText_->IsNeedRefresh()) {
275 RefreshLabel();
276 }
277 }
278
GetTextWidth()279 uint16_t UILabel::GetTextWidth()
280 {
281 InitLabelText();
282 if (labelText_->IsNeedRefresh()) {
283 ReMeasure();
284 }
285 return labelText_->GetTextSize().x;
286 }
287
GetTextHeight()288 uint16_t UILabel::GetTextHeight()
289 {
290 InitLabelText();
291 if (labelText_->IsNeedRefresh()) {
292 ReMeasure();
293 }
294 return labelText_->GetTextSize().y;
295 }
296
SetWidth(int16_t width)297 void UILabel::SetWidth(int16_t width)
298 {
299 if (GetWidth() != width) {
300 UIView::SetWidth(width);
301 RefreshLabel();
302 }
303 }
304
SetHeight(int16_t height)305 void UILabel::SetHeight(int16_t height)
306 {
307 if (GetHeight() != height) {
308 UIView::SetHeight(height);
309 RefreshLabel();
310 }
311 }
312
RefreshLabel()313 void UILabel::RefreshLabel()
314 {
315 Invalidate();
316 ellipsisIndex_ = Text::TEXT_ELLIPSIS_END_INV;
317 if (!needRefresh_) {
318 needRefresh_ = true;
319 }
320 }
321
ReMeasure()322 void UILabel::ReMeasure()
323 {
324 if (!needRefresh_) {
325 return;
326 }
327 needRefresh_ = false;
328 InitLabelText();
329 Style style = GetStyleConst();
330 style.textColor_ = GetTextColor();
331 bool flag = false;
332 if ((transMap_ != nullptr) && !transMap_->IsInvalid()) {
333 transMap_->SetInvalid(true);
334 flag = true;
335 }
336 labelText_->ReMeasureTextSize(GetContentRect(), style);
337 Point textSize = labelText_->GetTextSize();
338 switch (lineBreakMode_) {
339 case LINE_BREAK_ADAPT:
340 Resize(textSize.x, textSize.y);
341 break;
342 case LINE_BREAK_STRETCH:
343 SetWidth(textSize.x);
344 break;
345 case LINE_BREAK_WRAP:
346 SetHeight(textSize.y);
347 break;
348 case LINE_BREAK_ELLIPSIS:
349 ellipsisIndex_ = labelText_->GetEllipsisIndex(GetContentRect(), style);
350 labelText_->ReMeasureTextWidthInEllipsisMode(GetContentRect(), style, ellipsisIndex_);
351 break;
352 case LINE_BREAK_MARQUEE:
353 RemeasureForMarquee(textSize.x);
354 break;
355 default:
356 break;
357 }
358 if ((transMap_ != nullptr) && flag) {
359 transMap_->SetInvalid(false);
360 }
361 }
362
RemeasureForMarquee(int16_t textWidth)363 void UILabel::RemeasureForMarquee(int16_t textWidth)
364 {
365 int16_t rectWidth = GetWidth();
366 if (textWidth > rectWidth) {
367 offsetX_ = GetRollStartPos();
368 if (labelText_->GetDirect() == TEXT_DIRECT_RTL) {
369 labelText_->SetAlign(TEXT_ALIGNMENT_RIGHT, GetVerAlign());
370 } else {
371 labelText_->SetAlign(TEXT_ALIGNMENT_LEFT, GetVerAlign());
372 }
373 if (hasAnimator_) {
374 static_cast<LabelAnimator*>(animator_.animator)->UpdateWidth(textWidth, rectWidth);
375 } else {
376 LabelAnimator* animator = new LabelAnimator(textWidth, rectWidth, offsetX_, this);
377 if (animator == nullptr) {
378 GRAPHIC_LOGE("new LabelAnimator fail");
379 return;
380 }
381 animator->SetAnimatorSpeed(animator_.speed);
382 animator_.animator = animator;
383 hasAnimator_ = true;
384 }
385 animator_.animator->Start();
386 } else {
387 offsetX_ = 0;
388 if (hasAnimator_) {
389 animator_.animator->Stop();
390 }
391 }
392 }
393
SetRollStartPos(int16_t pos)394 void UILabel::SetRollStartPos(int16_t pos)
395 {
396 if (hasAnimator_) {
397 static_cast<LabelAnimator*>(animator_.animator)->SetStartPos(pos);
398 } else {
399 animator_.pos = pos;
400 }
401 }
402
GetRollStartPos() const403 int16_t UILabel::GetRollStartPos() const
404 {
405 return hasAnimator_ ? static_cast<LabelAnimator*>(animator_.animator)->GetStartPos() : animator_.pos;
406 }
407
SetRollSpeed(uint16_t speed)408 void UILabel::SetRollSpeed(uint16_t speed)
409 {
410 if (hasAnimator_) {
411 static_cast<LabelAnimator*>(animator_.animator)->SetAnimatorSpeed(speed);
412 } else {
413 animator_.speed = speed;
414 }
415 }
416
GetRollSpeed() const417 uint16_t UILabel::GetRollSpeed() const
418 {
419 return hasAnimator_ ? static_cast<LabelAnimator*>(animator_.animator)->GetAnimatorSpeed() : animator_.speed;
420 }
421
OnDraw(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea)422 void UILabel::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
423 {
424 InitLabelText();
425 UIView::OnDraw(gfxDstBuffer, invalidatedArea);
426 Style style = GetStyleConst();
427 style.textColor_ = GetTextColor();
428 OpacityType opa = GetMixOpaScale();
429 labelText_->OnDraw(gfxDstBuffer, invalidatedArea, GetOrigRect(),
430 GetContentRect(), offsetX_, style, ellipsisIndex_, opa);
431 }
432 } // namespace OHOS
433