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 21namespace OHOS { 22class LabelAnimator : public Animator, public AnimatorCallback { 23public: 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 37 virtual ~LabelAnimator() {} 38 39 int16_t GetStartPos() const 40 { 41 return startPos_; 42 } 43 44 void SetStartPos(int16_t pos) 45 { 46 startPos_ = pos; 47 } 48 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 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 93 void SetAnimatorSpeed(uint16_t animSpeed) 94 { 95 speed_ = animSpeed; 96 decimal_ = 0; 97 } 98 99 int16_t GetAnimatorSpeed() const 100 { 101 return speed_; 102 } 103 104private: 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 116UILabel::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 133UILabel::~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 146void UILabel::InitLabelText() 147{ 148 if (labelText_ == nullptr) { 149 labelText_ = new Text(); 150 } 151} 152 153int16_t UILabel::GetWidth() 154{ 155 InitLabelText(); 156 if (needRefresh_ && labelText_->IsExpandWidth()) { 157 ReMeasure(); 158 } 159 return UIView::GetWidth(); 160} 161 162int16_t UILabel::GetHeight() 163{ 164 InitLabelText(); 165 if (needRefresh_ && labelText_->IsExpandHeight()) { 166 ReMeasure(); 167 } 168 return UIView::GetHeight(); 169} 170 171void UILabel::SetStyle(uint8_t key, int64_t value) 172{ 173 UIView::SetStyle(key, value); 174 RefreshLabel(); 175} 176 177void UILabel::SetText(const char* text) 178{ 179 InitLabelText(); 180 labelText_->SetText(text); 181 if (labelText_->IsNeedRefresh()) { 182 RefreshLabel(); 183 } 184} 185 186 187void UILabel::SetText(const SpannableString* text) 188{ 189 InitLabelText(); 190 labelText_->SetSpannableString(text); 191 if (labelText_->IsNeedRefresh()) { 192 RefreshLabel(); 193 } 194} 195 196 197void 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 208void 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 219uint8_t UILabel::GetFontSize() 220{ 221 InitLabelText(); 222 return labelText_->GetFontSize(); 223} 224 225void 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 252void UILabel::SetAlign(UITextLanguageAlignment horizontalAlign, UITextLanguageAlignment verticalAlign) 253{ 254 InitLabelText(); 255 labelText_->SetAlign(horizontalAlign, verticalAlign); 256 if (labelText_->IsNeedRefresh()) { 257 RefreshLabel(); 258 } 259} 260 261void UILabel::SetFontId(uint16_t fontId) 262{ 263 InitLabelText(); 264 labelText_->SetFontId(fontId); 265 if (labelText_->IsNeedRefresh()) { 266 RefreshLabel(); 267 } 268} 269 270void 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 279uint16_t UILabel::GetTextWidth() 280{ 281 InitLabelText(); 282 if (labelText_->IsNeedRefresh()) { 283 ReMeasure(); 284 } 285 return labelText_->GetTextSize().x; 286} 287 288uint16_t UILabel::GetTextHeight() 289{ 290 InitLabelText(); 291 if (labelText_->IsNeedRefresh()) { 292 ReMeasure(); 293 } 294 return labelText_->GetTextSize().y; 295} 296 297void UILabel::SetWidth(int16_t width) 298{ 299 if (GetWidth() != width) { 300 UIView::SetWidth(width); 301 RefreshLabel(); 302 } 303} 304 305void UILabel::SetHeight(int16_t height) 306{ 307 if (GetHeight() != height) { 308 UIView::SetHeight(height); 309 RefreshLabel(); 310 } 311} 312 313void UILabel::RefreshLabel() 314{ 315 Invalidate(); 316 ellipsisIndex_ = Text::TEXT_ELLIPSIS_END_INV; 317 if (!needRefresh_) { 318 needRefresh_ = true; 319 } 320} 321 322void 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 363void 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 394void 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 403int16_t UILabel::GetRollStartPos() const 404{ 405 return hasAnimator_ ? static_cast<LabelAnimator*>(animator_.animator)->GetStartPos() : animator_.pos; 406} 407 408void 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 417uint16_t UILabel::GetRollSpeed() const 418{ 419 return hasAnimator_ ? static_cast<LabelAnimator*>(animator_.animator)->GetAnimatorSpeed() : animator_.speed; 420} 421 422void 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