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_radio_button.h"
17a3e0fd82Sopenharmony_ci
18a3e0fd82Sopenharmony_ci#include "common/image.h"
19a3e0fd82Sopenharmony_ci#include "components/root_view.h"
20a3e0fd82Sopenharmony_ci#include "components/ui_view_group.h"
21a3e0fd82Sopenharmony_ci#include "draw/draw_image.h"
22a3e0fd82Sopenharmony_ci#include "engines/gfx/gfx_engine_manager.h"
23a3e0fd82Sopenharmony_ci#include "gfx_utils/graphic_log.h"
24a3e0fd82Sopenharmony_ci#include "imgdecode/cache_manager.h"
25a3e0fd82Sopenharmony_ci#include "securec.h"
26a3e0fd82Sopenharmony_ci
27a3e0fd82Sopenharmony_cinamespace {
28a3e0fd82Sopenharmony_ciconstexpr int16_t DEFAULT_RADIUS_BIG = 11;
29a3e0fd82Sopenharmony_ciconstexpr int16_t DEFAULT_RADIUS_SMALL = 6;
30a3e0fd82Sopenharmony_ciconstexpr int16_t DEFAULT_LINE_WIDTH = 1;
31a3e0fd82Sopenharmony_ci#if DEFAULT_ANIMATION
32a3e0fd82Sopenharmony_ciconstexpr float SCALE_BEZIER_CONTROL_POINT_X_1 = 0.33;
33a3e0fd82Sopenharmony_ciconstexpr float SCALE_BEZIER_CONTROL_POINT_X_2 = 0.67;
34a3e0fd82Sopenharmony_ciconstexpr float ALPHA_BEZIER_CONTROL_POINT_X_1 = 0.2;
35a3e0fd82Sopenharmony_ciconstexpr float ALPHA_BEZIER_CONTROL_POINT_X_2 = 0.2;
36a3e0fd82Sopenharmony_ci#endif
37a3e0fd82Sopenharmony_ci} // namespace
38a3e0fd82Sopenharmony_cinamespace OHOS {
39a3e0fd82Sopenharmony_ciUIRadioButton::UIRadioButton() : UIRadioButton(nullptr) {}
40a3e0fd82Sopenharmony_ciUIRadioButton::UIRadioButton(const char* name)
41a3e0fd82Sopenharmony_ci    : name_(nullptr),
42a3e0fd82Sopenharmony_ci      radiusBig_(DEFAULT_RADIUS_BIG),
43a3e0fd82Sopenharmony_ci      radiusSmall_(DEFAULT_RADIUS_SMALL),
44a3e0fd82Sopenharmony_ci      currentRadius_(0),
45a3e0fd82Sopenharmony_ci      lineWidth_(DEFAULT_LINE_WIDTH)
46a3e0fd82Sopenharmony_ci{
47a3e0fd82Sopenharmony_ci    SetName(name);
48a3e0fd82Sopenharmony_ci    image_[UNSELECTED].SetSrc("");
49a3e0fd82Sopenharmony_ci    image_[SELECTED].SetSrc("");
50a3e0fd82Sopenharmony_ci    Resize(width_, height_);
51a3e0fd82Sopenharmony_ci}
52a3e0fd82Sopenharmony_ci
53a3e0fd82Sopenharmony_cibool UIRadioButton::OnClickEvent(const ClickEvent& event)
54a3e0fd82Sopenharmony_ci{
55a3e0fd82Sopenharmony_ci    SetState(SELECTED, true);
56a3e0fd82Sopenharmony_ci    Invalidate();
57a3e0fd82Sopenharmony_ci    UIView* view = this;
58a3e0fd82Sopenharmony_ci    while ((view != nullptr) && (view->GetParent() != nullptr)) {
59a3e0fd82Sopenharmony_ci        view = view->GetParent();
60a3e0fd82Sopenharmony_ci    }
61a3e0fd82Sopenharmony_ci    FindRadioButtonAndChangeState(view);
62a3e0fd82Sopenharmony_ci    return UIView::OnClickEvent(event);
63a3e0fd82Sopenharmony_ci}
64a3e0fd82Sopenharmony_ci
65a3e0fd82Sopenharmony_civoid UIRadioButton::CalculateSize()
66a3e0fd82Sopenharmony_ci{
67a3e0fd82Sopenharmony_ci    width_ = GetWidth();
68a3e0fd82Sopenharmony_ci    height_ = GetHeight();
69a3e0fd82Sopenharmony_ci    int16_t minValue = (width_ > height_) ? height_ : width_;
70a3e0fd82Sopenharmony_ci    radiusBig_ = DEFAULT_RADIUS_BIG * minValue / DEFAULT_HOT_WIDTH;
71a3e0fd82Sopenharmony_ci    radiusSmall_ = DEFAULT_RADIUS_SMALL * minValue / DEFAULT_HOT_WIDTH;
72a3e0fd82Sopenharmony_ci    if (minValue >= DEFAULT_HOT_WIDTH) {
73a3e0fd82Sopenharmony_ci        lineWidth_ = DEFAULT_LINE_WIDTH * minValue / DEFAULT_HOT_WIDTH;
74a3e0fd82Sopenharmony_ci    }
75a3e0fd82Sopenharmony_ci#if DEFAULT_ANIMATION
76a3e0fd82Sopenharmony_ci    if (checkBoxAnimator_.GetState() != Animator::START) {
77a3e0fd82Sopenharmony_ci        currentRadius_ = (state_ == SELECTED) ? radiusSmall_ : 0;
78a3e0fd82Sopenharmony_ci    }
79a3e0fd82Sopenharmony_ci#else
80a3e0fd82Sopenharmony_ci    currentRadius_ = (state_ == SELECTED) ? radiusSmall_ : 0;
81a3e0fd82Sopenharmony_ci#endif
82a3e0fd82Sopenharmony_ci}
83a3e0fd82Sopenharmony_ci
84a3e0fd82Sopenharmony_civoid UIRadioButton::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
85a3e0fd82Sopenharmony_ci{
86a3e0fd82Sopenharmony_ci    if ((image_[SELECTED].GetSrcType() != IMG_SRC_UNKNOWN) && (image_[UNSELECTED].GetSrcType() != IMG_SRC_UNKNOWN)) {
87a3e0fd82Sopenharmony_ci        UICheckBox::OnDraw(gfxDstBuffer, invalidatedArea);
88a3e0fd82Sopenharmony_ci    } else {
89a3e0fd82Sopenharmony_ci        CalculateSize();
90a3e0fd82Sopenharmony_ci        BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
91a3e0fd82Sopenharmony_ci        baseGfxEngine->DrawRect(gfxDstBuffer, GetRect(), invalidatedArea, *style_, opaScale_);
92a3e0fd82Sopenharmony_ci        Rect contentRect = GetContentRect();
93a3e0fd82Sopenharmony_ci        int16_t dx = width_ >> 1;
94a3e0fd82Sopenharmony_ci        int16_t dy = height_ >> 1;
95a3e0fd82Sopenharmony_ci        int16_t x = contentRect.GetX() + dx;
96a3e0fd82Sopenharmony_ci        int16_t y = contentRect.GetY() + dy;
97a3e0fd82Sopenharmony_ci        ArcInfo arcInfoBig = {{x, y}, {0}, radiusBig_, 0, CIRCLE_IN_DEGREE, nullptr};
98a3e0fd82Sopenharmony_ci        ArcInfo arcInfoSmall = {{x, y}, {0}, currentRadius_, 0, CIRCLE_IN_DEGREE, nullptr};
99a3e0fd82Sopenharmony_ci        Rect trunc = invalidatedArea;
100a3e0fd82Sopenharmony_ci        bool isIntersect = trunc.Intersect(trunc, contentRect);
101a3e0fd82Sopenharmony_ci        if (isIntersect) {
102a3e0fd82Sopenharmony_ci            Style style = StyleDefault::GetBackgroundTransparentStyle();
103a3e0fd82Sopenharmony_ci            if (backgroundOpacity_ != OPA_OPAQUE) {
104a3e0fd82Sopenharmony_ci                style.lineColor_ = Color::White();
105a3e0fd82Sopenharmony_ci                style.lineWidth_ = lineWidth_;
106a3e0fd82Sopenharmony_ci                // 0xa8 : opacity of drawing unselected button arc edge.
107a3e0fd82Sopenharmony_ci                baseGfxEngine->DrawArc(gfxDstBuffer, arcInfoBig, trunc, style, 0xa8, CapType::CAP_NONE);
108a3e0fd82Sopenharmony_ci            }
109a3e0fd82Sopenharmony_ci            style.lineWidth_ = arcInfoBig.radius;
110a3e0fd82Sopenharmony_ci            style.lineColor_ = selectedStateColor_;
111a3e0fd82Sopenharmony_ci            baseGfxEngine->DrawArc(gfxDstBuffer, arcInfoBig, trunc, style, backgroundOpacity_,
112a3e0fd82Sopenharmony_ci                                   CapType::CAP_NONE);
113a3e0fd82Sopenharmony_ci            style.lineWidth_ = arcInfoSmall.radius;
114a3e0fd82Sopenharmony_ci            style.lineColor_ = Color::White();
115a3e0fd82Sopenharmony_ci            baseGfxEngine->DrawArc(gfxDstBuffer, arcInfoSmall, trunc, style, OPA_OPAQUE,
116a3e0fd82Sopenharmony_ci                                   CapType::CAP_NONE);
117a3e0fd82Sopenharmony_ci        }
118a3e0fd82Sopenharmony_ci    }
119a3e0fd82Sopenharmony_ci}
120a3e0fd82Sopenharmony_ci
121a3e0fd82Sopenharmony_civoid UIRadioButton::SetName(const char* name)
122a3e0fd82Sopenharmony_ci{
123a3e0fd82Sopenharmony_ci    if (name == nullptr) {
124a3e0fd82Sopenharmony_ci        return;
125a3e0fd82Sopenharmony_ci    }
126a3e0fd82Sopenharmony_ci    if (name_ != nullptr) {
127a3e0fd82Sopenharmony_ci        UIFree(name_);
128a3e0fd82Sopenharmony_ci        name_ = nullptr;
129a3e0fd82Sopenharmony_ci    }
130a3e0fd82Sopenharmony_ci    uint32_t nameLen = static_cast<uint32_t>(strlen(name) + 1);
131a3e0fd82Sopenharmony_ci    if (nameLen > MAX_TEXT_LENGTH) {
132a3e0fd82Sopenharmony_ci        return;
133a3e0fd82Sopenharmony_ci    }
134a3e0fd82Sopenharmony_ci    name_ = static_cast<char*>(UIMalloc(nameLen));
135a3e0fd82Sopenharmony_ci    if (name_ != nullptr) {
136a3e0fd82Sopenharmony_ci        if (memcpy_s(name_, nameLen, name, nameLen) != EOK) {
137a3e0fd82Sopenharmony_ci            UIFree(name_);
138a3e0fd82Sopenharmony_ci            name_ = nullptr;
139a3e0fd82Sopenharmony_ci            return;
140a3e0fd82Sopenharmony_ci        }
141a3e0fd82Sopenharmony_ci    }
142a3e0fd82Sopenharmony_ci}
143a3e0fd82Sopenharmony_ci
144a3e0fd82Sopenharmony_civoid UIRadioButton::FindRadioButtonAndChangeState(UIView* view)
145a3e0fd82Sopenharmony_ci{
146a3e0fd82Sopenharmony_ci    if ((view == nullptr) || (name_ == nullptr)) {
147a3e0fd82Sopenharmony_ci        return;
148a3e0fd82Sopenharmony_ci    }
149a3e0fd82Sopenharmony_ci    if (view->IsViewGroup()) {
150a3e0fd82Sopenharmony_ci        UIView* childView = static_cast<UIViewGroup*>(view)->GetChildrenHead();
151a3e0fd82Sopenharmony_ci        while (childView != nullptr) {
152a3e0fd82Sopenharmony_ci            FindRadioButtonAndChangeState(childView);
153a3e0fd82Sopenharmony_ci            childView = childView->GetNextSibling();
154a3e0fd82Sopenharmony_ci        }
155a3e0fd82Sopenharmony_ci    }
156a3e0fd82Sopenharmony_ci    if ((view == this) || (view->GetViewType() != UI_RADIO_BUTTON)) {
157a3e0fd82Sopenharmony_ci        return;
158a3e0fd82Sopenharmony_ci    }
159a3e0fd82Sopenharmony_ci    UIRadioButton* uiRadioButtonInfo = static_cast<UIRadioButton*>(view);
160a3e0fd82Sopenharmony_ci    if ((uiRadioButtonInfo->GetName() != nullptr) && (strcmp(uiRadioButtonInfo->GetName(), name_) == 0)) {
161a3e0fd82Sopenharmony_ci        uiRadioButtonInfo->SetState(UNSELECTED, true);
162a3e0fd82Sopenharmony_ci    }
163a3e0fd82Sopenharmony_ci}
164a3e0fd82Sopenharmony_ci#if DEFAULT_ANIMATION
165a3e0fd82Sopenharmony_civoid UIRadioButton::Callback(UIView* view)
166a3e0fd82Sopenharmony_ci{
167a3e0fd82Sopenharmony_ci    runTime_ = checkBoxAnimator_.GetRunTime();
168a3e0fd82Sopenharmony_ci    float x = static_cast<float>(runTime_) / checkBoxAnimator_.GetTime();
169a3e0fd82Sopenharmony_ci    float coefficient =
170a3e0fd82Sopenharmony_ci        Interpolation::GetBezierY(x, SCALE_BEZIER_CONTROL_POINT_X_1, 0, SCALE_BEZIER_CONTROL_POINT_X_2, 1);
171a3e0fd82Sopenharmony_ci    backgroundOpacity_ = (state_ == SELECTED) ? (static_cast<uint8_t>(coefficient * OPA_OPAQUE)) :
172a3e0fd82Sopenharmony_ci                                                (static_cast<uint8_t>((1 - coefficient) * OPA_OPAQUE));
173a3e0fd82Sopenharmony_ci    coefficient = Interpolation::GetBezierY(x, ALPHA_BEZIER_CONTROL_POINT_X_1, 0, ALPHA_BEZIER_CONTROL_POINT_X_2, 1);
174a3e0fd82Sopenharmony_ci    currentRadius_ = (state_ == SELECTED) ? (static_cast<uint8_t>(coefficient * radiusSmall_)) :
175a3e0fd82Sopenharmony_ci                                            (static_cast<uint8_t>((1 - coefficient) * radiusSmall_));
176a3e0fd82Sopenharmony_ci    Invalidate();
177a3e0fd82Sopenharmony_ci}
178a3e0fd82Sopenharmony_ci#endif
179a3e0fd82Sopenharmony_ci} // namespace OHOS
180