• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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