1 /*
2 * Copyright (c) 2020-2021 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
99 private:
100 static constexpr uint8_t ANIM_WAIT_COUNT = 50;
101 int16_t startPos_;
102 uint16_t textX_;
103 uint16_t labelX_;
104 int16_t offsetX_;
105 uint16_t waitCount_;
106 uint16_t speed_;
107 uint32_t preRunTime_;
108 float decimal_;
109 };
110
UILabel()111 UILabel::UILabel()
112 : labelText_(nullptr),
113 needRefresh_(false),
114 useTextColor_(false),
115 hasAnimator_(false),
116 lineBreakMode_(LINE_BREAK_ELLIPSIS),
117 ellipsisIndex_(Text::TEXT_ELLIPSIS_END_INV),
118 offsetX_(0),
119 textColor_(Color::White()),
120 animator_{nullptr}
121 {
122 Theme* theme = ThemeManager::GetInstance().GetCurrent();
123 Style& style = (theme != nullptr) ? (theme->GetLabelStyle()) : (StyleDefault::GetLabelStyle());
124 UIView::SetStyle(style);
125 animator_.speed = DEFAULT_ANIMATOR_SPEED;
126 }
127
~UILabel()128 UILabel::~UILabel()
129 {
130 if (hasAnimator_) {
131 delete animator_.animator;
132 animator_.animator = nullptr;
133 hasAnimator_ = false;
134 }
135 if (labelText_ != nullptr) {
136 delete labelText_;
137 labelText_ = nullptr;
138 }
139 }
140
InitLabelText()141 void UILabel::InitLabelText()
142 {
143 if (labelText_ == nullptr) {
144 labelText_ = new Text();
145 }
146 }
147
GetWidth()148 int16_t UILabel::GetWidth()
149 {
150 InitLabelText();
151 if (needRefresh_ && labelText_->IsExpandWidth()) {
152 ReMeasure();
153 }
154 return UIView::GetWidth();
155 }
156
GetHeight()157 int16_t UILabel::GetHeight()
158 {
159 InitLabelText();
160 if (needRefresh_ && labelText_->IsExpandHeight()) {
161 ReMeasure();
162 }
163 return UIView::GetHeight();
164 }
165
SetStyle(uint8_t key,int64_t value)166 void UILabel::SetStyle(uint8_t key, int64_t value)
167 {
168 UIView::SetStyle(key, value);
169 RefreshLabel();
170 }
171
SetText(const char * text)172 void UILabel::SetText(const char* text)
173 {
174 InitLabelText();
175 labelText_->SetText(text);
176 if (labelText_->IsNeedRefresh()) {
177 RefreshLabel();
178 }
179 }
180
SetLineBreakMode(const uint8_t lineBreakMode)181 void UILabel::SetLineBreakMode(const uint8_t lineBreakMode)
182 {
183 InitLabelText();
184 if ((lineBreakMode >= LINE_BREAK_MAX) || (lineBreakMode_ == lineBreakMode)) {
185 return;
186 }
187 lineBreakMode_ = lineBreakMode;
188 if ((lineBreakMode_ == LINE_BREAK_ADAPT) || (lineBreakMode_ == LINE_BREAK_STRETCH) ||
189 (lineBreakMode_ == LINE_BREAK_MARQUEE)) {
190 labelText_->SetExpandWidth(true);
191 } else {
192 labelText_->SetExpandWidth(false);
193 }
194 if ((lineBreakMode_ == LINE_BREAK_ADAPT) || (lineBreakMode_ == LINE_BREAK_WRAP)) {
195 labelText_->SetExpandHeight(true);
196 } else {
197 labelText_->SetExpandHeight(false);
198 }
199 if (lineBreakMode_ != LINE_BREAK_MARQUEE) {
200 offsetX_ = 0;
201 if (hasAnimator_) {
202 animator_.animator->Stop();
203 }
204 }
205 RefreshLabel();
206 }
207
SetAlign(UITextLanguageAlignment horizontalAlign,UITextLanguageAlignment verticalAlign)208 void UILabel::SetAlign(UITextLanguageAlignment horizontalAlign, UITextLanguageAlignment verticalAlign)
209 {
210 InitLabelText();
211 labelText_->SetAlign(horizontalAlign, verticalAlign);
212 if (labelText_->IsNeedRefresh()) {
213 RefreshLabel();
214 }
215 }
216
SetFontId(uint8_t fontId)217 void UILabel::SetFontId(uint8_t fontId)
218 {
219 InitLabelText();
220 labelText_->SetFontId(fontId);
221 if (labelText_->IsNeedRefresh()) {
222 RefreshLabel();
223 }
224 }
225
SetFont(const char * name,uint8_t size)226 void UILabel::SetFont(const char* name, uint8_t size)
227 {
228 InitLabelText();
229 labelText_->SetFont(name, size);
230 if (labelText_->IsNeedRefresh()) {
231 RefreshLabel();
232 }
233 }
234
GetTextWidth()235 uint16_t UILabel::GetTextWidth()
236 {
237 InitLabelText();
238 if (labelText_->IsNeedRefresh()) {
239 ReMeasure();
240 }
241 return labelText_->GetTextSize().x;
242 }
243
GetTextHeight()244 uint16_t UILabel::GetTextHeight()
245 {
246 InitLabelText();
247 if (labelText_->IsNeedRefresh()) {
248 ReMeasure();
249 }
250 return labelText_->GetTextSize().y;
251 }
252
SetWidth(int16_t width)253 void UILabel::SetWidth(int16_t width)
254 {
255 if (GetWidth() != width) {
256 UIView::SetWidth(width);
257 RefreshLabel();
258 }
259 }
260
SetHeight(int16_t height)261 void UILabel::SetHeight(int16_t height)
262 {
263 if (GetHeight() != height) {
264 UIView::SetHeight(height);
265 RefreshLabel();
266 }
267 }
268
RefreshLabel()269 void UILabel::RefreshLabel()
270 {
271 Invalidate();
272 ellipsisIndex_ = Text::TEXT_ELLIPSIS_END_INV;
273 if (!needRefresh_) {
274 needRefresh_ = true;
275 }
276 }
277
ReMeasure()278 void UILabel::ReMeasure()
279 {
280 if (!needRefresh_) {
281 return;
282 }
283 needRefresh_ = false;
284 InitLabelText();
285 Style style = GetStyleConst();
286 style.textColor_ = GetTextColor();
287 bool flag = false;
288 if ((transMap_ != nullptr) && !transMap_->IsInvalid()) {
289 transMap_->SetInvalid(true);
290 flag = true;
291 }
292 labelText_->ReMeasureTextSize(GetContentRect(), style);
293 Point textSize = labelText_->GetTextSize();
294 switch (lineBreakMode_) {
295 case LINE_BREAK_ADAPT:
296 Resize(textSize.x, textSize.y);
297 break;
298 case LINE_BREAK_STRETCH:
299 SetWidth(textSize.x);
300 break;
301 case LINE_BREAK_WRAP:
302 SetHeight(textSize.y);
303 break;
304 case LINE_BREAK_ELLIPSIS:
305 ellipsisIndex_ = labelText_->GetEllipsisIndex(GetContentRect(), style);
306 labelText_->ReMeasureTextWidthInEllipsisMode(GetContentRect(), style, ellipsisIndex_);
307 break;
308 case LINE_BREAK_MARQUEE:
309 RemeasureForMarquee(textSize.x);
310 break;
311 default:
312 break;
313 }
314 if ((transMap_ != nullptr) && flag) {
315 transMap_->SetInvalid(false);
316 }
317 }
318
RemeasureForMarquee(int16_t textWidth)319 void UILabel::RemeasureForMarquee(int16_t textWidth)
320 {
321 int16_t rectWidth = GetWidth();
322 if (textWidth > rectWidth) {
323 offsetX_ = GetRollStartPos();
324 if (labelText_->GetDirect() == TEXT_DIRECT_RTL) {
325 labelText_->SetAlign(TEXT_ALIGNMENT_RIGHT);
326 } else {
327 labelText_->SetAlign(TEXT_ALIGNMENT_LEFT);
328 }
329 if (hasAnimator_) {
330 static_cast<LabelAnimator*>(animator_.animator)->UpdateWidth(textWidth, rectWidth);
331 } else {
332 LabelAnimator* animator = new LabelAnimator(textWidth, rectWidth, offsetX_, this);
333 if (animator == nullptr) {
334 GRAPHIC_LOGE("new LabelAnimator fail");
335 return;
336 }
337 animator->SetAnimatorSpeed(animator_.speed);
338 animator_.animator = animator;
339 hasAnimator_ = true;
340 }
341 animator_.animator->Start();
342 } else {
343 offsetX_ = 0;
344 if (hasAnimator_) {
345 animator_.animator->Stop();
346 }
347 }
348 }
349
SetRollStartPos(int16_t pos)350 void UILabel::SetRollStartPos(int16_t pos)
351 {
352 if (hasAnimator_) {
353 static_cast<LabelAnimator*>(animator_.animator)->SetStartPos(pos);
354 } else {
355 animator_.pos = pos;
356 }
357 }
358
GetRollStartPos() const359 int16_t UILabel::GetRollStartPos() const
360 {
361 return hasAnimator_ ? static_cast<LabelAnimator*>(animator_.animator)->GetStartPos() : animator_.pos;
362 }
363
SetRollSpeed(uint16_t speed)364 void UILabel::SetRollSpeed(uint16_t speed)
365 {
366 if (hasAnimator_) {
367 static_cast<LabelAnimator*>(animator_.animator)->SetAnimatorSpeed(speed);
368 } else {
369 animator_.speed = speed;
370 }
371 }
372
OnDraw(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea)373 void UILabel::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
374 {
375 InitLabelText();
376 UIView::OnDraw(gfxDstBuffer, invalidatedArea);
377 Style style = GetStyleConst();
378 style.textColor_ = GetTextColor();
379 OpacityType opa = GetMixOpaScale();
380 labelText_->OnDraw(gfxDstBuffer, invalidatedArea, GetOrigRect(),
381 GetContentRect(), offsetX_, style, ellipsisIndex_, opa);
382 }
383 } // namespace OHOS