1a3e0fd82Sopenharmony_ci/*
2a3e0fd82Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3a3e0fd82Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4a3e0fd82Sopenharmony_ci * you may not use this file except in compliance with the License.
5a3e0fd82Sopenharmony_ci * You may obtain a copy of the License at
6a3e0fd82Sopenharmony_ci *
7a3e0fd82Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8a3e0fd82Sopenharmony_ci *
9a3e0fd82Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10a3e0fd82Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11a3e0fd82Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12a3e0fd82Sopenharmony_ci * See the License for the specific language governing permissions and
13a3e0fd82Sopenharmony_ci * limitations under the License.
14a3e0fd82Sopenharmony_ci */
15a3e0fd82Sopenharmony_ci
16a3e0fd82Sopenharmony_ci#include "components/ui_arc_label.h"
17a3e0fd82Sopenharmony_ci
18a3e0fd82Sopenharmony_ci#include "common/typed_text.h"
19a3e0fd82Sopenharmony_ci#include "draw/draw_label.h"
20a3e0fd82Sopenharmony_ci#include "engines/gfx/gfx_engine_manager.h"
21a3e0fd82Sopenharmony_ci#include "font/ui_font.h"
22a3e0fd82Sopenharmony_ci#include "themes/theme_manager.h"
23a3e0fd82Sopenharmony_ci
24a3e0fd82Sopenharmony_cinamespace OHOS {
25a3e0fd82Sopenharmony_cistatic constexpr uint16_t DEFAULT_ARC_LABEL_ROLL_COUNT = 1;
26a3e0fd82Sopenharmony_cistatic constexpr uint16_t DEFAULT_ARC_LABEL_ANIMATOR_SPEED = 10;
27a3e0fd82Sopenharmony_ci
28a3e0fd82Sopenharmony_ciclass ArcLabelAnimator : public Animator, public AnimatorCallback {
29a3e0fd82Sopenharmony_cipublic:
30a3e0fd82Sopenharmony_ci    ArcLabelAnimator(uint16_t rollCount, UIView* view)
31a3e0fd82Sopenharmony_ci        : Animator(this, view, 0, true),
32a3e0fd82Sopenharmony_ci          waitCount_(ANIM_WAIT_COUNT),
33a3e0fd82Sopenharmony_ci          speed_(0),
34a3e0fd82Sopenharmony_ci          preRunTime_(0),
35a3e0fd82Sopenharmony_ci          decimal_(0),
36a3e0fd82Sopenharmony_ci          rollCount_(rollCount)
37a3e0fd82Sopenharmony_ci    {
38a3e0fd82Sopenharmony_ci    }
39a3e0fd82Sopenharmony_ci
40a3e0fd82Sopenharmony_ci    virtual ~ArcLabelAnimator() {}
41a3e0fd82Sopenharmony_ci
42a3e0fd82Sopenharmony_ci    void Callback(UIView* view) override
43a3e0fd82Sopenharmony_ci    {
44a3e0fd82Sopenharmony_ci        if (view == nullptr || rollCount_ == 0) {
45a3e0fd82Sopenharmony_ci            return;
46a3e0fd82Sopenharmony_ci        }
47a3e0fd82Sopenharmony_ci
48a3e0fd82Sopenharmony_ci        uint32_t curTime = GetRunTime();
49a3e0fd82Sopenharmony_ci        if (waitCount_ > 0) {
50a3e0fd82Sopenharmony_ci            waitCount_--;
51a3e0fd82Sopenharmony_ci            preRunTime_ = curTime;
52a3e0fd82Sopenharmony_ci            return;
53a3e0fd82Sopenharmony_ci        }
54a3e0fd82Sopenharmony_ci        if (curTime == preRunTime_) {
55a3e0fd82Sopenharmony_ci            return;
56a3e0fd82Sopenharmony_ci        }
57a3e0fd82Sopenharmony_ci        uint32_t time = (curTime > preRunTime_) ? (curTime - preRunTime_) : (UINT32_MAX - preRunTime_ + curTime);
58a3e0fd82Sopenharmony_ci        // 1000: 1000 milliseconds is 1 second
59a3e0fd82Sopenharmony_ci        float floatStep = (static_cast<float>(time * speed_) / 1000) + decimal_;
60a3e0fd82Sopenharmony_ci        uint16_t integerStep = static_cast<uint16_t>(floatStep);
61a3e0fd82Sopenharmony_ci        decimal_ = floatStep - integerStep;
62a3e0fd82Sopenharmony_ci        preRunTime_ = curTime;
63a3e0fd82Sopenharmony_ci
64a3e0fd82Sopenharmony_ci        if (integerStep == 0) {
65a3e0fd82Sopenharmony_ci            return;
66a3e0fd82Sopenharmony_ci        }
67a3e0fd82Sopenharmony_ci
68a3e0fd82Sopenharmony_ci        CalculatedOffsetAngle(view);
69a3e0fd82Sopenharmony_ci    }
70a3e0fd82Sopenharmony_ci
71a3e0fd82Sopenharmony_ci    void SetRollSpeed(uint16_t speed)
72a3e0fd82Sopenharmony_ci    {
73a3e0fd82Sopenharmony_ci        speed_ = speed;
74a3e0fd82Sopenharmony_ci    }
75a3e0fd82Sopenharmony_ci
76a3e0fd82Sopenharmony_ci    int16_t GetRollSpeed() const
77a3e0fd82Sopenharmony_ci    {
78a3e0fd82Sopenharmony_ci        return speed_;
79a3e0fd82Sopenharmony_ci    }
80a3e0fd82Sopenharmony_ci
81a3e0fd82Sopenharmony_ci    void SetRollCount(uint16_t rollCount)
82a3e0fd82Sopenharmony_ci    {
83a3e0fd82Sopenharmony_ci        rollCount_ = rollCount;
84a3e0fd82Sopenharmony_ci    }
85a3e0fd82Sopenharmony_ci
86a3e0fd82Sopenharmony_ci    void RegisterScrollListener(ArcLabelScrollListener* scrollListener)
87a3e0fd82Sopenharmony_ci    {
88a3e0fd82Sopenharmony_ci        scrollListener_ = scrollListener;
89a3e0fd82Sopenharmony_ci    }
90a3e0fd82Sopenharmony_ci
91a3e0fd82Sopenharmony_ciprivate:
92a3e0fd82Sopenharmony_ci    void CalculatedOffsetAngle(UIView* view)
93a3e0fd82Sopenharmony_ci    {
94a3e0fd82Sopenharmony_ci        if (view == nullptr) {
95a3e0fd82Sopenharmony_ci            return;
96a3e0fd82Sopenharmony_ci        }
97a3e0fd82Sopenharmony_ci        UIArcLabel* arcLabel = static_cast<UIArcLabel*>(view);
98a3e0fd82Sopenharmony_ci        if (arcLabel == nullptr) {
99a3e0fd82Sopenharmony_ci            return;
100a3e0fd82Sopenharmony_ci        }
101a3e0fd82Sopenharmony_ci
102a3e0fd82Sopenharmony_ci        int16_t startAngle = arcLabel->GetArcTextStartAngle();
103a3e0fd82Sopenharmony_ci        int16_t endAngle = arcLabel->GetArcTextEndAngle();
104a3e0fd82Sopenharmony_ci        uint16_t arcAngle = (startAngle < endAngle) ? (endAngle - startAngle) :
105a3e0fd82Sopenharmony_ci            (startAngle - endAngle);
106a3e0fd82Sopenharmony_ci
107a3e0fd82Sopenharmony_ci        if (arcLabel->offsetAngle_ < arcAngle) {
108a3e0fd82Sopenharmony_ci            arcLabel->offsetAngle_ += DEFAULT_CHANGE_ANGLE;
109a3e0fd82Sopenharmony_ci        } else {
110a3e0fd82Sopenharmony_ci            rollCount_--;
111a3e0fd82Sopenharmony_ci            if (rollCount_ > 0) {
112a3e0fd82Sopenharmony_ci                arcLabel->offsetAngle_ = arcLabel->animator_.secondLapOffsetAngle_;
113a3e0fd82Sopenharmony_ci            }
114a3e0fd82Sopenharmony_ci        }
115a3e0fd82Sopenharmony_ci
116a3e0fd82Sopenharmony_ci        if (rollCount_ == 0) {
117a3e0fd82Sopenharmony_ci            if (scrollListener_) {
118a3e0fd82Sopenharmony_ci                scrollListener_->Finish();
119a3e0fd82Sopenharmony_ci            }
120a3e0fd82Sopenharmony_ci            Stop();
121a3e0fd82Sopenharmony_ci        }
122a3e0fd82Sopenharmony_ci        view->Invalidate();
123a3e0fd82Sopenharmony_ci    }
124a3e0fd82Sopenharmony_ci
125a3e0fd82Sopenharmony_ciprivate:
126a3e0fd82Sopenharmony_ci    static constexpr uint8_t ANIM_WAIT_COUNT = 50;
127a3e0fd82Sopenharmony_ci    static constexpr float DEFAULT_CHANGE_ANGLE = 1.0f;
128a3e0fd82Sopenharmony_ci    uint16_t waitCount_;
129a3e0fd82Sopenharmony_ci    uint16_t speed_;
130a3e0fd82Sopenharmony_ci    uint32_t preRunTime_;
131a3e0fd82Sopenharmony_ci    float decimal_;
132a3e0fd82Sopenharmony_ci
133a3e0fd82Sopenharmony_ci    uint16_t rollCount_;
134a3e0fd82Sopenharmony_ci    ArcLabelScrollListener* scrollListener_;
135a3e0fd82Sopenharmony_ci};
136a3e0fd82Sopenharmony_ci
137a3e0fd82Sopenharmony_ciUIArcLabel::UIArcLabel()
138a3e0fd82Sopenharmony_ci    : arcLabelText_(nullptr),
139a3e0fd82Sopenharmony_ci      compatibilityMode_(true),
140a3e0fd82Sopenharmony_ci      offsetAngle_(0.0f),
141a3e0fd82Sopenharmony_ci      arcTextInfo_{0},
142a3e0fd82Sopenharmony_ci      needRefresh_(false),
143a3e0fd82Sopenharmony_ci      hasAnimator_(false),
144a3e0fd82Sopenharmony_ci      textSize_({0, 0}),
145a3e0fd82Sopenharmony_ci      radius_(0),
146a3e0fd82Sopenharmony_ci      startAngle_(0),
147a3e0fd82Sopenharmony_ci      endAngle_(0),
148a3e0fd82Sopenharmony_ci      arcCenter_({0, 0}),
149a3e0fd82Sopenharmony_ci      orientation_(TextOrientation::INSIDE)
150a3e0fd82Sopenharmony_ci{
151a3e0fd82Sopenharmony_ci    Theme* theme = ThemeManager::GetInstance().GetCurrent();
152a3e0fd82Sopenharmony_ci    style_ = (theme != nullptr) ? &(theme->GetLabelStyle()) : &(StyleDefault::GetLabelStyle());
153a3e0fd82Sopenharmony_ci
154a3e0fd82Sopenharmony_ci    animator_.animator = nullptr;
155a3e0fd82Sopenharmony_ci    animator_.scrollListener = nullptr;
156a3e0fd82Sopenharmony_ci    animator_.speed = DEFAULT_ARC_LABEL_ANIMATOR_SPEED;
157a3e0fd82Sopenharmony_ci    animator_.rollCount = DEFAULT_ARC_LABEL_ROLL_COUNT;
158a3e0fd82Sopenharmony_ci    animator_.secondLapOffsetAngle_ = 0.0f;
159a3e0fd82Sopenharmony_ci}
160a3e0fd82Sopenharmony_ci
161a3e0fd82Sopenharmony_ciUIArcLabel::~UIArcLabel()
162a3e0fd82Sopenharmony_ci{
163a3e0fd82Sopenharmony_ci    if (arcLabelText_ != nullptr) {
164a3e0fd82Sopenharmony_ci        delete arcLabelText_;
165a3e0fd82Sopenharmony_ci        arcLabelText_ = nullptr;
166a3e0fd82Sopenharmony_ci    }
167a3e0fd82Sopenharmony_ci
168a3e0fd82Sopenharmony_ci    if (hasAnimator_) {
169a3e0fd82Sopenharmony_ci        delete animator_.animator;
170a3e0fd82Sopenharmony_ci        animator_.animator = nullptr;
171a3e0fd82Sopenharmony_ci        hasAnimator_ = false;
172a3e0fd82Sopenharmony_ci    }
173a3e0fd82Sopenharmony_ci}
174a3e0fd82Sopenharmony_ci
175a3e0fd82Sopenharmony_civoid UIArcLabel::SetStyle(uint8_t key, int64_t value)
176a3e0fd82Sopenharmony_ci{
177a3e0fd82Sopenharmony_ci    UIView::SetStyle(key, value);
178a3e0fd82Sopenharmony_ci    RefreshArcLabel();
179a3e0fd82Sopenharmony_ci}
180a3e0fd82Sopenharmony_ci
181a3e0fd82Sopenharmony_civoid UIArcLabel::SetText(const char* text)
182a3e0fd82Sopenharmony_ci{
183a3e0fd82Sopenharmony_ci    if (text == nullptr) {
184a3e0fd82Sopenharmony_ci        return;
185a3e0fd82Sopenharmony_ci    }
186a3e0fd82Sopenharmony_ci    InitArcLabelText();
187a3e0fd82Sopenharmony_ci    arcLabelText_->SetText(text);
188a3e0fd82Sopenharmony_ci    if (arcLabelText_->IsNeedRefresh()) {
189a3e0fd82Sopenharmony_ci        RefreshArcLabel();
190a3e0fd82Sopenharmony_ci    }
191a3e0fd82Sopenharmony_ci}
192a3e0fd82Sopenharmony_ci
193a3e0fd82Sopenharmony_ciconst char* UIArcLabel::GetText() const
194a3e0fd82Sopenharmony_ci{
195a3e0fd82Sopenharmony_ci    return (arcLabelText_ == nullptr) ? nullptr : arcLabelText_->GetText();
196a3e0fd82Sopenharmony_ci}
197a3e0fd82Sopenharmony_ci
198a3e0fd82Sopenharmony_civoid UIArcLabel::SetAlign(UITextLanguageAlignment horizontalAlign)
199a3e0fd82Sopenharmony_ci{
200a3e0fd82Sopenharmony_ci    InitArcLabelText();
201a3e0fd82Sopenharmony_ci    arcLabelText_->SetAlign(horizontalAlign, TEXT_ALIGNMENT_TOP);
202a3e0fd82Sopenharmony_ci    if (arcLabelText_->IsNeedRefresh()) {
203a3e0fd82Sopenharmony_ci        RefreshArcLabel();
204a3e0fd82Sopenharmony_ci    }
205a3e0fd82Sopenharmony_ci}
206a3e0fd82Sopenharmony_ci
207a3e0fd82Sopenharmony_ciUITextLanguageAlignment UIArcLabel::GetHorAlign()
208a3e0fd82Sopenharmony_ci{
209a3e0fd82Sopenharmony_ci    InitArcLabelText();
210a3e0fd82Sopenharmony_ci    return arcLabelText_->GetHorAlign();
211a3e0fd82Sopenharmony_ci}
212a3e0fd82Sopenharmony_ci
213a3e0fd82Sopenharmony_ciUITextLanguageDirect UIArcLabel::GetDirect()
214a3e0fd82Sopenharmony_ci{
215a3e0fd82Sopenharmony_ci    InitArcLabelText();
216a3e0fd82Sopenharmony_ci    return arcLabelText_->GetDirect();
217a3e0fd82Sopenharmony_ci}
218a3e0fd82Sopenharmony_ci
219a3e0fd82Sopenharmony_civoid UIArcLabel::SetFontId(uint16_t fontId)
220a3e0fd82Sopenharmony_ci{
221a3e0fd82Sopenharmony_ci    InitArcLabelText();
222a3e0fd82Sopenharmony_ci    arcLabelText_->SetFontId(fontId);
223a3e0fd82Sopenharmony_ci    if (arcLabelText_->IsNeedRefresh()) {
224a3e0fd82Sopenharmony_ci        RefreshArcLabel();
225a3e0fd82Sopenharmony_ci    }
226a3e0fd82Sopenharmony_ci}
227a3e0fd82Sopenharmony_ci
228a3e0fd82Sopenharmony_ciuint16_t UIArcLabel::GetFontId()
229a3e0fd82Sopenharmony_ci{
230a3e0fd82Sopenharmony_ci    InitArcLabelText();
231a3e0fd82Sopenharmony_ci    return arcLabelText_->GetFontId();
232a3e0fd82Sopenharmony_ci}
233a3e0fd82Sopenharmony_ci
234a3e0fd82Sopenharmony_civoid UIArcLabel::SetFont(const char* name, uint8_t size)
235a3e0fd82Sopenharmony_ci{
236a3e0fd82Sopenharmony_ci    if (name == nullptr) {
237a3e0fd82Sopenharmony_ci        return;
238a3e0fd82Sopenharmony_ci    }
239a3e0fd82Sopenharmony_ci    InitArcLabelText();
240a3e0fd82Sopenharmony_ci    arcLabelText_->SetFont(name, size);
241a3e0fd82Sopenharmony_ci    if (arcLabelText_->IsNeedRefresh()) {
242a3e0fd82Sopenharmony_ci        RefreshArcLabel();
243a3e0fd82Sopenharmony_ci    }
244a3e0fd82Sopenharmony_ci}
245a3e0fd82Sopenharmony_ci
246a3e0fd82Sopenharmony_civoid UIArcLabel::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
247a3e0fd82Sopenharmony_ci{
248a3e0fd82Sopenharmony_ci    InitArcLabelText();
249a3e0fd82Sopenharmony_ci    const char* text = arcLabelText_->GetText();
250a3e0fd82Sopenharmony_ci    if ((text == nullptr) || (radius_ == 0)) {
251a3e0fd82Sopenharmony_ci        return;
252a3e0fd82Sopenharmony_ci    }
253a3e0fd82Sopenharmony_ci    OpacityType opa = GetMixOpaScale();
254a3e0fd82Sopenharmony_ci    UIView::OnDraw(gfxDstBuffer, invalidatedArea);
255a3e0fd82Sopenharmony_ci    DrawArcText(gfxDstBuffer, invalidatedArea, opa, arcTextInfo_, orientation_);
256a3e0fd82Sopenharmony_ci}
257a3e0fd82Sopenharmony_ci
258a3e0fd82Sopenharmony_civoid UIArcLabel::DrawArcText(BufferInfo& gfxDstBuffer,
259a3e0fd82Sopenharmony_ci                             const Rect& mask,
260a3e0fd82Sopenharmony_ci                             OpacityType opaScale,
261a3e0fd82Sopenharmony_ci                             ArcTextInfo arcTextInfo,
262a3e0fd82Sopenharmony_ci                             TextOrientation orientation)
263a3e0fd82Sopenharmony_ci{
264a3e0fd82Sopenharmony_ci    Point center;
265a3e0fd82Sopenharmony_ci    center.x = arcTextInfo_.arcCenter.x + GetRect().GetX();
266a3e0fd82Sopenharmony_ci    center.y = arcTextInfo_.arcCenter.y + GetRect().GetY();
267a3e0fd82Sopenharmony_ci    Rect temp = mask;
268a3e0fd82Sopenharmony_ci    if (compatibilityMode_ && hasAnimator_) {
269a3e0fd82Sopenharmony_ci        temp.SetLeft(center.x - radius_);
270a3e0fd82Sopenharmony_ci        temp.SetTop(center.y - radius_);
271a3e0fd82Sopenharmony_ci        temp.SetWidth(radius_ * 2); // 2 mean diameter
272a3e0fd82Sopenharmony_ci        temp.SetHeight(radius_ * 2);
273a3e0fd82Sopenharmony_ci    }
274a3e0fd82Sopenharmony_ci    arcTextInfo.hasAnimator = hasAnimator_;
275a3e0fd82Sopenharmony_ci
276a3e0fd82Sopenharmony_ci    DrawLabel::DrawArcText(gfxDstBuffer, temp, arcLabelText_->GetText(), center, arcLabelText_->GetFontId(),
277a3e0fd82Sopenharmony_ci                           arcLabelText_->GetFontSize(), arcTextInfo, offsetAngle_,
278a3e0fd82Sopenharmony_ci                           orientation, *style_, opaScale, compatibilityMode_);
279a3e0fd82Sopenharmony_ci}
280a3e0fd82Sopenharmony_ci
281a3e0fd82Sopenharmony_ciRect UIArcLabel::GetArcTextRect(const char* text, uint16_t fontId, uint8_t fontSize, const Point& arcCenter,
282a3e0fd82Sopenharmony_ci                                int16_t letterSpace, TextOrientation orientation, const ArcTextInfo& arcTextInfo)
283a3e0fd82Sopenharmony_ci{
284a3e0fd82Sopenharmony_ci    return TypedText::GetArcTextRect(text, fontId, fontSize, arcCenter, letterSpace, orientation, arcTextInfo);
285a3e0fd82Sopenharmony_ci}
286a3e0fd82Sopenharmony_ci
287a3e0fd82Sopenharmony_civoid UIArcLabel::RefreshArcLabel()
288a3e0fd82Sopenharmony_ci{
289a3e0fd82Sopenharmony_ci    Invalidate();
290a3e0fd82Sopenharmony_ci    if (!needRefresh_) {
291a3e0fd82Sopenharmony_ci        needRefresh_ = true;
292a3e0fd82Sopenharmony_ci    }
293a3e0fd82Sopenharmony_ci}
294a3e0fd82Sopenharmony_ci
295a3e0fd82Sopenharmony_civoid UIArcLabel::ReMeasure()
296a3e0fd82Sopenharmony_ci{
297a3e0fd82Sopenharmony_ci    if (!needRefresh_) {
298a3e0fd82Sopenharmony_ci        return;
299a3e0fd82Sopenharmony_ci    }
300a3e0fd82Sopenharmony_ci    needRefresh_ = false;
301a3e0fd82Sopenharmony_ci    InitArcLabelText();
302a3e0fd82Sopenharmony_ci
303a3e0fd82Sopenharmony_ci    MeasureArcTextInfo();
304a3e0fd82Sopenharmony_ci    arcTextInfo_.shapingFontId = arcLabelText_->GetShapingFontId();
305a3e0fd82Sopenharmony_ci    arcTextInfo_.codePoints = arcLabelText_->GetCodePoints();
306a3e0fd82Sopenharmony_ci    arcTextInfo_.codePointsNum = arcLabelText_->GetCodePointNum();
307a3e0fd82Sopenharmony_ci    Rect textRect =
308a3e0fd82Sopenharmony_ci        GetArcTextRect(arcLabelText_->GetText(), arcLabelText_->GetFontId(), arcLabelText_->GetFontSize(),
309a3e0fd82Sopenharmony_ci                       arcCenter_, style_->letterSpace_, orientation_, arcTextInfo_);
310a3e0fd82Sopenharmony_ci    int16_t arcTextWidth = textRect.GetWidth();
311a3e0fd82Sopenharmony_ci    int16_t arcTextHeight = textRect.GetHeight();
312a3e0fd82Sopenharmony_ci
313a3e0fd82Sopenharmony_ci    if (compatibilityMode_) {
314a3e0fd82Sopenharmony_ci        SetPosition(textRect.GetX(), textRect.GetY());
315a3e0fd82Sopenharmony_ci        Resize(arcTextWidth, arcTextHeight);
316a3e0fd82Sopenharmony_ci    }
317a3e0fd82Sopenharmony_ci
318a3e0fd82Sopenharmony_ci    arcTextInfo_.arcCenter.x = arcCenter_.x - GetX() + style_->borderWidth_ + style_->paddingLeft_;
319a3e0fd82Sopenharmony_ci    arcTextInfo_.arcCenter.y = arcCenter_.y - GetY() + style_->borderWidth_ + style_->paddingTop_;
320a3e0fd82Sopenharmony_ci    textSize_.x = arcTextWidth;
321a3e0fd82Sopenharmony_ci    textSize_.y = arcTextHeight;
322a3e0fd82Sopenharmony_ci    Invalidate();
323a3e0fd82Sopenharmony_ci}
324a3e0fd82Sopenharmony_ci
325a3e0fd82Sopenharmony_ciuint32_t UIArcLabel::GetLineEnd(int16_t maxLength)
326a3e0fd82Sopenharmony_ci{
327a3e0fd82Sopenharmony_ci    const char* text = arcLabelText_->GetText();
328a3e0fd82Sopenharmony_ci    if (text == nullptr) {
329a3e0fd82Sopenharmony_ci        return 0;
330a3e0fd82Sopenharmony_ci    }
331a3e0fd82Sopenharmony_ci
332a3e0fd82Sopenharmony_ci    return TypedText::GetNextLine(&text[arcTextInfo_.lineStart], arcLabelText_->GetFontId(),
333a3e0fd82Sopenharmony_ci        arcLabelText_->GetFontSize(), style_->letterSpace_, maxLength);
334a3e0fd82Sopenharmony_ci}
335a3e0fd82Sopenharmony_ci
336a3e0fd82Sopenharmony_civoid UIArcLabel::MeasureArcTextInfo()
337a3e0fd82Sopenharmony_ci{
338a3e0fd82Sopenharmony_ci    const char* text = arcLabelText_->GetText();
339a3e0fd82Sopenharmony_ci    if (text == nullptr) {
340a3e0fd82Sopenharmony_ci        return;
341a3e0fd82Sopenharmony_ci    }
342a3e0fd82Sopenharmony_ci    uint16_t letterHeight = UIFont::GetInstance()->GetHeight(arcLabelText_->GetFontId(), arcLabelText_->GetFontSize());
343a3e0fd82Sopenharmony_ci    if (compatibilityMode_) {
344a3e0fd82Sopenharmony_ci        arcTextInfo_.radius = ((orientation_ == TextOrientation::INSIDE) ? radius_ : (radius_ - letterHeight));
345a3e0fd82Sopenharmony_ci    } else {
346a3e0fd82Sopenharmony_ci        arcTextInfo_.radius = radius_;
347a3e0fd82Sopenharmony_ci    }
348a3e0fd82Sopenharmony_ci    if (arcTextInfo_.radius == 0) {
349a3e0fd82Sopenharmony_ci        return;
350a3e0fd82Sopenharmony_ci    }
351a3e0fd82Sopenharmony_ci
352a3e0fd82Sopenharmony_ci    uint16_t arcAngle;
353a3e0fd82Sopenharmony_ci    if (startAngle_ < endAngle_) {
354a3e0fd82Sopenharmony_ci        arcAngle = endAngle_ - startAngle_;
355a3e0fd82Sopenharmony_ci        arcTextInfo_.direct = TEXT_DIRECT_LTR; // Clockwise
356a3e0fd82Sopenharmony_ci        arcLabelText_->SetDirect(TEXT_DIRECT_LTR);
357a3e0fd82Sopenharmony_ci    } else {
358a3e0fd82Sopenharmony_ci        arcAngle = startAngle_ - endAngle_;
359a3e0fd82Sopenharmony_ci        arcTextInfo_.direct = TEXT_DIRECT_RTL; // Counterclockwise
360a3e0fd82Sopenharmony_ci        arcLabelText_->SetDirect(TEXT_DIRECT_RTL);
361a3e0fd82Sopenharmony_ci    }
362a3e0fd82Sopenharmony_ci
363a3e0fd82Sopenharmony_ci    OnMeasureArcTextInfo(arcAngle, letterHeight);
364a3e0fd82Sopenharmony_ci}
365a3e0fd82Sopenharmony_ci
366a3e0fd82Sopenharmony_civoid UIArcLabel::OnMeasureArcTextInfo(const uint16_t arcAngle, const uint16_t letterHeight)
367a3e0fd82Sopenharmony_ci{
368a3e0fd82Sopenharmony_ci    const char* text = arcLabelText_->GetText();
369a3e0fd82Sopenharmony_ci    if (text == nullptr) {
370a3e0fd82Sopenharmony_ci        return;
371a3e0fd82Sopenharmony_ci    }
372a3e0fd82Sopenharmony_ci
373a3e0fd82Sopenharmony_ci    // calculate max arc length
374a3e0fd82Sopenharmony_ci    float maxLength = static_cast<float>((UI_PI * radius_ * arcAngle) / SEMICIRCLE_IN_DEGREE);
375a3e0fd82Sopenharmony_ci    arcTextInfo_.lineStart = 0;
376a3e0fd82Sopenharmony_ci
377a3e0fd82Sopenharmony_ci    Rect rect;
378a3e0fd82Sopenharmony_ci    rect.SetWidth(static_cast<int16_t>(maxLength));
379a3e0fd82Sopenharmony_ci    arcLabelText_->ReMeasureTextSize(rect, *style_);
380a3e0fd82Sopenharmony_ci
381a3e0fd82Sopenharmony_ci    arcTextInfo_.lineEnd = GetLineEnd(static_cast<int16_t>(maxLength));
382a3e0fd82Sopenharmony_ci    arcTextInfo_.startAngle = startAngle_ > CIRCLE_IN_DEGREE ? startAngle_ % CIRCLE_IN_DEGREE : startAngle_;
383a3e0fd82Sopenharmony_ci    arcTextInfo_.endAngle = endAngle_ > CIRCLE_IN_DEGREE ? endAngle_ % CIRCLE_IN_DEGREE : endAngle_;
384a3e0fd82Sopenharmony_ci
385a3e0fd82Sopenharmony_ci    int16_t actLength = GetArcLength();
386a3e0fd82Sopenharmony_ci    if ((arcLabelText_->GetHorAlign() != TEXT_ALIGNMENT_LEFT) && (actLength < maxLength)) {
387a3e0fd82Sopenharmony_ci        float gapLength = maxLength - actLength;
388a3e0fd82Sopenharmony_ci        if (arcLabelText_->GetHorAlign() == TEXT_ALIGNMENT_CENTER) {
389a3e0fd82Sopenharmony_ci            gapLength = gapLength / 2; // 2: half
390a3e0fd82Sopenharmony_ci        }
391a3e0fd82Sopenharmony_ci        arcTextInfo_.startAngle += TypedText::GetAngleForArcLen(gapLength, letterHeight, arcTextInfo_.radius,
392a3e0fd82Sopenharmony_ci                                                                arcTextInfo_.direct, orientation_);
393a3e0fd82Sopenharmony_ci    }
394a3e0fd82Sopenharmony_ci
395a3e0fd82Sopenharmony_ci    int16_t maxTextLength = arcLabelText_->GetMetaTextWidth(*style_);
396a3e0fd82Sopenharmony_ci
397a3e0fd82Sopenharmony_ci    float maxTextAngle = 0.0f;
398a3e0fd82Sopenharmony_ci    if (compatibilityMode_) {
399a3e0fd82Sopenharmony_ci        maxTextAngle = TypedText::GetAngleForArcLen(maxTextLength, letterHeight, arcTextInfo_.radius,
400a3e0fd82Sopenharmony_ci            arcTextInfo_.direct, orientation_);
401a3e0fd82Sopenharmony_ci    } else {
402a3e0fd82Sopenharmony_ci        maxTextAngle = TypedText::GetAngleForArcLen(maxTextLength, style_->letterSpace_, arcTextInfo_.radius);
403a3e0fd82Sopenharmony_ci        maxTextAngle = arcLabelText_->GetDirect() == TEXT_DIRECT_RTL ? -maxTextAngle : maxTextAngle;
404a3e0fd82Sopenharmony_ci    }
405a3e0fd82Sopenharmony_ci
406a3e0fd82Sopenharmony_ci    if (arcLabelText_->GetDirect() == TEXT_DIRECT_LTR) {
407a3e0fd82Sopenharmony_ci        animator_.secondLapOffsetAngle_ = -maxTextAngle;
408a3e0fd82Sopenharmony_ci    } else if (arcLabelText_->GetDirect() == TEXT_DIRECT_RTL) {
409a3e0fd82Sopenharmony_ci        animator_.secondLapOffsetAngle_ = maxTextAngle;
410a3e0fd82Sopenharmony_ci    }
411a3e0fd82Sopenharmony_ci}
412a3e0fd82Sopenharmony_ci
413a3e0fd82Sopenharmony_ciuint16_t UIArcLabel::GetArcLength()
414a3e0fd82Sopenharmony_ci{
415a3e0fd82Sopenharmony_ci    const char* text = arcLabelText_->GetText();
416a3e0fd82Sopenharmony_ci    if (text == nullptr) {
417a3e0fd82Sopenharmony_ci        return 0;
418a3e0fd82Sopenharmony_ci    }
419a3e0fd82Sopenharmony_ci
420a3e0fd82Sopenharmony_ci    return TypedText::GetTextWidth(&text[arcTextInfo_.lineStart], arcLabelText_->GetFontId(),
421a3e0fd82Sopenharmony_ci                                   arcLabelText_->GetFontSize(), (arcTextInfo_.lineEnd - arcTextInfo_.lineStart),
422a3e0fd82Sopenharmony_ci                                   style_->letterSpace_);
423a3e0fd82Sopenharmony_ci}
424a3e0fd82Sopenharmony_ci
425a3e0fd82Sopenharmony_civoid UIArcLabel::Start()
426a3e0fd82Sopenharmony_ci{
427a3e0fd82Sopenharmony_ci    if (arcLabelText_->GetDirect() == TEXT_DIRECT_RTL) {
428a3e0fd82Sopenharmony_ci        arcLabelText_->SetAlign(TEXT_ALIGNMENT_RIGHT, TEXT_ALIGNMENT_CENTER);
429a3e0fd82Sopenharmony_ci    } else {
430a3e0fd82Sopenharmony_ci        arcLabelText_->SetAlign(TEXT_ALIGNMENT_LEFT, TEXT_ALIGNMENT_CENTER);
431a3e0fd82Sopenharmony_ci    }
432a3e0fd82Sopenharmony_ci    if (hasAnimator_) {
433a3e0fd82Sopenharmony_ci        static_cast<ArcLabelAnimator*>(animator_.animator)->SetRollCount(animator_.rollCount);
434a3e0fd82Sopenharmony_ci    } else {
435a3e0fd82Sopenharmony_ci        ArcLabelAnimator* animator = new ArcLabelAnimator(animator_.rollCount, this);
436a3e0fd82Sopenharmony_ci        if (animator == nullptr) {
437a3e0fd82Sopenharmony_ci            GRAPHIC_LOGE("new ArcLabelAnimator fail");
438a3e0fd82Sopenharmony_ci            return;
439a3e0fd82Sopenharmony_ci        }
440a3e0fd82Sopenharmony_ci        animator->SetRollSpeed(animator_.speed);
441a3e0fd82Sopenharmony_ci        animator->RegisterScrollListener(animator_.scrollListener);
442a3e0fd82Sopenharmony_ci        animator_.animator = animator;
443a3e0fd82Sopenharmony_ci        hasAnimator_ = true;
444a3e0fd82Sopenharmony_ci    }
445a3e0fd82Sopenharmony_ci    animator_.animator->Start();
446a3e0fd82Sopenharmony_ci}
447a3e0fd82Sopenharmony_ci
448a3e0fd82Sopenharmony_civoid UIArcLabel::Stop()
449a3e0fd82Sopenharmony_ci{
450a3e0fd82Sopenharmony_ci    if (hasAnimator_) {
451a3e0fd82Sopenharmony_ci        static_cast<ArcLabelAnimator*>(animator_.animator)->Stop();
452a3e0fd82Sopenharmony_ci    }
453a3e0fd82Sopenharmony_ci}
454a3e0fd82Sopenharmony_ci
455a3e0fd82Sopenharmony_civoid UIArcLabel::SetRollCount(const uint16_t rollCount)
456a3e0fd82Sopenharmony_ci{
457a3e0fd82Sopenharmony_ci    if (hasAnimator_) {
458a3e0fd82Sopenharmony_ci        static_cast<ArcLabelAnimator*>(animator_.animator)->SetRollCount(rollCount);
459a3e0fd82Sopenharmony_ci    } else {
460a3e0fd82Sopenharmony_ci        animator_.rollCount = rollCount;
461a3e0fd82Sopenharmony_ci    }
462a3e0fd82Sopenharmony_ci}
463a3e0fd82Sopenharmony_ci
464a3e0fd82Sopenharmony_civoid UIArcLabel::RegisterScrollListener(ArcLabelScrollListener* scrollListener)
465a3e0fd82Sopenharmony_ci{
466a3e0fd82Sopenharmony_ci    if (hasAnimator_) {
467a3e0fd82Sopenharmony_ci        static_cast<ArcLabelAnimator*>(animator_.animator)->RegisterScrollListener(scrollListener);
468a3e0fd82Sopenharmony_ci    } else {
469a3e0fd82Sopenharmony_ci        animator_.scrollListener = scrollListener;
470a3e0fd82Sopenharmony_ci    }
471a3e0fd82Sopenharmony_ci}
472a3e0fd82Sopenharmony_ci
473a3e0fd82Sopenharmony_civoid UIArcLabel::SetRollSpeed(const uint16_t speed)
474a3e0fd82Sopenharmony_ci{
475a3e0fd82Sopenharmony_ci    if (hasAnimator_) {
476a3e0fd82Sopenharmony_ci        static_cast<ArcLabelAnimator*>(animator_.animator)->SetRollSpeed(speed);
477a3e0fd82Sopenharmony_ci    } else {
478a3e0fd82Sopenharmony_ci        animator_.speed = speed;
479a3e0fd82Sopenharmony_ci    }
480a3e0fd82Sopenharmony_ci}
481a3e0fd82Sopenharmony_ci
482a3e0fd82Sopenharmony_ciuint16_t UIArcLabel::GetRollSpeed() const
483a3e0fd82Sopenharmony_ci{
484a3e0fd82Sopenharmony_ci    if (hasAnimator_) {
485a3e0fd82Sopenharmony_ci        return static_cast<ArcLabelAnimator*>(animator_.animator)->GetRollSpeed();
486a3e0fd82Sopenharmony_ci    }
487a3e0fd82Sopenharmony_ci
488a3e0fd82Sopenharmony_ci    return animator_.speed;
489a3e0fd82Sopenharmony_ci}
490a3e0fd82Sopenharmony_ci} // namespace OHOS
491