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_toggle_button.h"
17 
18 #include "common/image.h"
19 #include "engines/gfx/gfx_engine_manager.h"
20 #include "imgdecode/cache_manager.h"
21 namespace {
22 constexpr int16_t TOGGLE_BTN_WIDTH = 32;
23 constexpr int16_t TOGGLE_BTN_CORNER_RADIUS = 11;
24 constexpr int16_t TOGGLE_BTN_RADIUS_DIFF = 2;
25 constexpr uint8_t TOGGLE_BTN_UNSELECTED_OPA = 97;
26 #if DEFAULT_ANIMATION
27 constexpr int16_t DEFAULT_ANIMATOR_TIME = 150;
28 constexpr float BEZIER_CONTROL_POINT_X_1 = 0.2;
29 constexpr float BEZIER_CONTROL_POINT_X_2 = 0.2;
30 #endif
31 } // namespace
32 namespace OHOS {
UIToggleButton()33 UIToggleButton::UIToggleButton()
34     : corner_(TOGGLE_BTN_CORNER_RADIUS),
35       radius_(TOGGLE_BTN_CORNER_RADIUS - TOGGLE_BTN_RADIUS_DIFF),
36       rectWidth_(TOGGLE_BTN_WIDTH)
37 {
38     backgroundOpacity_ = TOGGLE_BTN_UNSELECTED_OPA;
39     image_[UNSELECTED].SetSrc("");
40     image_[SELECTED].SetSrc("");
41 #if DEFAULT_ANIMATION
42     checkBoxAnimator_.SetTime(DEFAULT_ANIMATOR_TIME);
43 #endif
44     Resize(width_, height_);
45 }
46 
SetState(bool state)47 void UIToggleButton::SetState(bool state)
48 {
49     if (state) {
50         UICheckBox::SetState(SELECTED);
51     } else {
52         UICheckBox::SetState(UNSELECTED);
53     }
54     Invalidate();
55 }
56 
CalculateSize()57 void UIToggleButton::CalculateSize()
58 {
59     width_ = GetWidth();
60     height_ = GetHeight();
61     int16_t minValue = (width_ > height_) ? height_ : width_;
62     corner_ = TOGGLE_BTN_CORNER_RADIUS * minValue / DEFAULT_HOT_HEIGHT;
63     int16_t radiusDiff = TOGGLE_BTN_RADIUS_DIFF * minValue / DEFAULT_HOT_WIDTH;
64     radius_ = corner_ - radiusDiff;
65     rectWidth_ = TOGGLE_BTN_WIDTH * minValue / DEFAULT_HOT_WIDTH;
66 
67     Rect contentRect = GetContentRect();
68     int16_t dx = (width_ - rectWidth_) / 2; // 2: half
69     int16_t dy = (height_ / 2) - corner_;   // 2: half
70     int16_t x = contentRect.GetX() + dx;
71     int16_t y = contentRect.GetY() + dy;
72     leftCenter_ = {static_cast<int16_t>(x + corner_), static_cast<int16_t>(y + corner_)};
73     rightCenter_ = {static_cast<int16_t>(x + rectWidth_ - corner_), static_cast<int16_t>(y + corner_)};
74 #if DEFAULT_ANIMATION
75     if (checkBoxAnimator_.GetState() != Animator::START) {
76         if (IsRtl()) {
77             currentCenter_ = (state_ == SELECTED) ? leftCenter_ : rightCenter_;
78         } else {
79             currentCenter_ = (state_ == SELECTED) ? rightCenter_ : leftCenter_;
80         }
81         backgroundOpacity_ = (state_ == SELECTED) ? OPA_OPAQUE : TOGGLE_BTN_UNSELECTED_OPA;
82         bgColor_ = (state_ == SELECTED) ? selectedStateColor_ : Color::White();
83     }
84 #else
85     if (IsRtl()) {
86         currentCenter_ = (state_ == SELECTED) ? leftCenter_ : rightCenter_;
87     } else {
88         currentCenter_ = (state_ == SELECTED) ? rightCenter_ : leftCenter_;
89     }
90     backgroundOpacity_ = (state_ == SELECTED) ? OPA_OPAQUE : TOGGLE_BTN_UNSELECTED_OPA;
91     bgColor_ = (state_ == SELECTED) ? selectedStateColor_ : Color::White();
92 #endif
93     rectMid_.SetRect(x, y, x + rectWidth_, y + (corner_ << 1) + 1);
94 }
95 
OnDraw(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea)96 void UIToggleButton::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
97 {
98     if ((image_[SELECTED].GetSrcType() != IMG_SRC_UNKNOWN) && (image_[UNSELECTED].GetSrcType() != IMG_SRC_UNKNOWN)) {
99         UICheckBox::OnDraw(gfxDstBuffer, invalidatedArea);
100     } else {
101         CalculateSize();
102         BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
103         baseGfxEngine->DrawRect(gfxDstBuffer, GetRect(), invalidatedArea, *style_, opaScale_);
104         Rect contentRect = GetContentRect();
105         Rect trunc = invalidatedArea;
106         bool isIntersect = trunc.Intersect(trunc, contentRect);
107         if (!isIntersect) {
108             return;
109         }
110         Style styleUnSelect = StyleDefault::GetBackgroundTransparentStyle();
111         styleUnSelect.bgColor_ = bgColor_;
112         styleUnSelect.bgOpa_ = backgroundOpacity_;
113         styleUnSelect.borderRadius_ = corner_;
114         baseGfxEngine->DrawRect(gfxDstBuffer, rectMid_, trunc, styleUnSelect, opaScale_);
115         ArcInfo arcInfoLeft = {currentCenter_, {0}, radius_, 0, CIRCLE_IN_DEGREE, nullptr};
116         styleUnSelect.lineColor_ = Color::White();
117         styleUnSelect.lineWidth_ = radius_;
118         baseGfxEngine->DrawArc(gfxDstBuffer, arcInfoLeft, trunc, styleUnSelect, OPA_OPAQUE,
119                                CapType::CAP_NONE);
120     }
121 }
122 #if DEFAULT_ANIMATION
Callback(UIView * view)123 void UIToggleButton::Callback(UIView* view)
124 {
125     runTime_ = checkBoxAnimator_.GetRunTime();
126     float x = static_cast<float>(runTime_) / checkBoxAnimator_.GetTime();
127     float coefficient = Interpolation::GetBezierY(x, BEZIER_CONTROL_POINT_X_1, 0, BEZIER_CONTROL_POINT_X_2, 1);
128     if (state_ == SELECTED) {
129         currentCenter_.y = rightCenter_.y;
130         if (IsRtl()) {
131             currentCenter_.x = rightCenter_.x - static_cast<uint16_t>((rightCenter_.x - leftCenter_.x) * coefficient);
132         } else {
133             currentCenter_.x = static_cast<int16_t>((rightCenter_.x - leftCenter_.x) * coefficient) + leftCenter_.x;
134         }
135         backgroundOpacity_ =
136             static_cast<uint8_t>(TOGGLE_BTN_UNSELECTED_OPA + (OPA_OPAQUE - TOGGLE_BTN_UNSELECTED_OPA) * coefficient);
137         bgColor_ =
138             Color::GetMixColor(selectedStateColor_, Color::White(), static_cast<uint8_t>(OPA_OPAQUE * coefficient));
139     } else {
140         currentCenter_.y = leftCenter_.y;
141         if (IsRtl()) {
142             currentCenter_.x = static_cast<int16_t>((rightCenter_.x - leftCenter_.x) * coefficient) + leftCenter_.x;
143         } else {
144             currentCenter_.x = rightCenter_.x - static_cast<uint16_t>((rightCenter_.x - leftCenter_.x) * coefficient);
145         }
146         backgroundOpacity_ = static_cast<uint8_t>(OPA_OPAQUE - (OPA_OPAQUE - TOGGLE_BTN_UNSELECTED_OPA) * coefficient);
147         bgColor_ = Color::GetMixColor(selectedStateColor_, Color::White(),
148                                       static_cast<uint8_t>(OPA_OPAQUE * (1 - coefficient)));
149     }
150     Invalidate();
151 }
152 
OnStop(UIView & view)153 void UIToggleButton::OnStop(UIView& view)
154 {
155     if (state_ == SELECTED) {
156         bgColor_ = selectedStateColor_;
157     } else {
158         bgColor_ = Color::White();
159     }
160     backgroundOpacity_ = (state_ == SELECTED) ? OPA_OPAQUE : TOGGLE_BTN_UNSELECTED_OPA;
161     Invalidate();
162 }
163 #endif
164 
EnableRtl(bool isRtl)165 void UIToggleButton::EnableRtl(bool isRtl)
166 {
167     isRtl_ = isRtl;
168 }
169 
IsRtl()170 bool UIToggleButton::IsRtl()
171 {
172     return isRtl_;
173 }
174 } // namespace OHOS
175