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_checkbox.h"
17 #include "default_resource/check_box_res.h"
18 #include "draw/draw_image.h"
19 #include "engines/gfx/gfx_engine_manager.h"
20 #include "imgdecode/cache_manager.h"
21
22 namespace OHOS {
23 namespace {
24 constexpr uint8_t DEFAULT_UNSELECT_BG_OPA = 168; // default background opacity
25 constexpr float DEFAULT_COEFFICIENT_START_DX = 0.22; // start point: x-cordinate offset
26 constexpr float DEFAULT_COEFFICIENT_START_DY = 0.5; // start point: y-cordinate offset
27 constexpr float DEFAULT_COEFFICIENT_MID_DX = 0.2; // middle point: y-cordinate offset
28 constexpr float DEFAULT_COEFFICIENT_MID_DY = 0.38; // middle point: y-cordinate offset
29 constexpr int16_t DEFAULT_RATIO_BORDER_RADIUS_LINE_WIDTH = 4;
30 constexpr uint8_t DEFAULT_BG_RED = 31;
31 constexpr uint8_t DEFAULT_BG_GREEN = 113;
32 constexpr uint8_t DEFAULT_BG_BLUE = 255;
33 #if DEFAULT_ANIMATION
34 constexpr int16_t DEFAULT_ANIMATOR_TIME = 200;
35 constexpr float BEZIER_CONTROL_POINT_X_1 = 0.33;
36 constexpr float BEZIER_CONTROL_POINT_X_2 = 0.67;
37 #endif
38 } // namespace
UICheckBox()39 UICheckBox::UICheckBox()
40 : state_(UNSELECTED),
41 onStateChangeListener_(nullptr),
42 width_(DEFAULT_HOT_WIDTH),
43 height_(DEFAULT_HOT_HEIGHT),
44 borderWidth_(DEFAULT_BORDER_WIDTH),
45 backgroundOpacity_(0)
46 {
47 touchable_ = true;
48 style_ = &(StyleDefault::GetBackgroundTransparentStyle());
49 #if defined(ENABLE_DEFAULT_CHECKBOX_IMAGE) && (ENABLE_DEFAULT_CHECKBOX_IMAGE == 1)
50 image_[UNSELECTED].SetSrc(GetCheckBoxOffInfo());
51 image_[SELECTED].SetSrc(GetCheckBoxOnInfo());
52 #endif
53 ImageHeader header = {0};
54 image_[UNSELECTED].GetHeader(header);
55 Resize(header.width, header.height);
56 #if DEFAULT_ANIMATION
57 runTime_ = 0;
58 checkBoxAnimator_ = Animator(this, this, DEFAULT_ANIMATOR_TIME, false);
59 #endif
60 selectedStateColor_ = Color::GetColorFromRGB(DEFAULT_BG_RED, DEFAULT_BG_GREEN, DEFAULT_BG_BLUE);
61 }
62
SetState(UICheckBoxState state,bool needAnimater)63 void UICheckBox::SetState(UICheckBoxState state, bool needAnimater)
64 {
65 if (state_ == state) {
66 return;
67 }
68 state_ = state;
69 if ((image_[SELECTED].GetSrcType() == IMG_SRC_UNKNOWN) || (image_[UNSELECTED].GetSrcType() == IMG_SRC_UNKNOWN)) {
70 #if DEFAULT_ANIMATION
71 if (needAnimater) {
72 checkBoxAnimator_.Start();
73 ResetCallback();
74 } else {
75 backgroundOpacity_ = (state_ == SELECTED) ? OPA_OPAQUE : 0;
76 }
77 #else
78 backgroundOpacity_ = (state_ == SELECTED) ? OPA_OPAQUE : 0;
79 #endif
80 }
81 if (onStateChangeListener_ != nullptr) {
82 onStateChangeListener_->OnChange(state);
83 }
84 Invalidate();
85 }
86
ReverseState()87 void UICheckBox::ReverseState()
88 {
89 if (state_ == SELECTED) {
90 SetState(UNSELECTED, true);
91 } else {
92 SetState(SELECTED, true);
93 }
94 }
95
OnClickEvent(const ClickEvent & event)96 bool UICheckBox::OnClickEvent(const ClickEvent& event)
97 {
98 ReverseState();
99 Invalidate();
100 return UIView::OnClickEvent(event);
101 }
102
SetImages(const char * selectedImageSrc,const char * unselectedImageSrc)103 void UICheckBox::SetImages(const char* selectedImageSrc, const char* unselectedImageSrc)
104 {
105 image_[SELECTED].SetSrc(selectedImageSrc);
106 image_[UNSELECTED].SetSrc(unselectedImageSrc);
107 }
108
SetImages(const ImageInfo * selectedImageSrc,const ImageInfo * unselectedImageSrc)109 void UICheckBox::SetImages(const ImageInfo* selectedImageSrc, const ImageInfo* unselectedImageSrc)
110 {
111 image_[SELECTED].SetSrc(selectedImageSrc);
112 image_[UNSELECTED].SetSrc(unselectedImageSrc);
113 }
114
CalculateSize()115 void UICheckBox::CalculateSize()
116 {
117 int16_t width = GetWidth();
118 int16_t height = GetHeight();
119 if ((width_ == width) && (height_ == height)) {
120 return;
121 }
122 width_ = width;
123 height_ = height;
124 int16_t minValue = (width_ > height_) ? height_ : width_;
125 borderWidth_ = DEFAULT_BORDER_WIDTH * minValue / DEFAULT_HOT_WIDTH;
126 }
127
SelectedStateSoftwareDrawing(BufferInfo & gfxDstBuffer,Rect rect,Rect trunc,int16_t borderRadius,int16_t rectLineWidth)128 void UICheckBox::SelectedStateSoftwareDrawing(BufferInfo& gfxDstBuffer,
129 Rect rect,
130 Rect trunc,
131 int16_t borderRadius,
132 int16_t rectLineWidth)
133 {
134 if (backgroundOpacity_ == 0) {
135 return;
136 }
137 Style styleSelect = StyleDefault::GetBackgroundTransparentStyle();
138 styleSelect.borderRadius_ = borderRadius;
139 styleSelect.bgColor_ = selectedStateColor_;
140 styleSelect.bgOpa_ = backgroundOpacity_;
141 BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
142 baseGfxEngine->DrawRect(gfxDstBuffer, rect, trunc, styleSelect, opaScale_);
143 int16_t dx = static_cast<int16_t>(borderWidth_ * DEFAULT_COEFFICIENT_START_DX);
144 int16_t dy = static_cast<int16_t>(borderWidth_ * DEFAULT_COEFFICIENT_START_DY);
145 Point start = {static_cast<int16_t>(rect.GetX() + dx), static_cast<int16_t>(rect.GetY() + dy)};
146 dx = static_cast<int16_t>(borderWidth_ * DEFAULT_COEFFICIENT_MID_DX);
147 Point mid = {static_cast<int16_t>(start.x + dx), static_cast<int16_t>(start.y + dx)};
148 dx = static_cast<int16_t>(borderWidth_ * DEFAULT_COEFFICIENT_MID_DY);
149 Point end = {static_cast<int16_t>(mid.x + dx), static_cast<int16_t>(mid.y - dx)};
150 const int16_t half = 2; // 2 :half
151 ArcInfo arcInfoLeft = {start,
152 {0, 0},
153 static_cast<uint16_t>(rectLineWidth),
154 SEMICIRCLE_IN_DEGREE + QUARTER_IN_DEGREE / half,
155 QUARTER_IN_DEGREE / half,
156 nullptr};
157 ArcInfo arcInfoMid = {mid,
158 {0, 0},
159 static_cast<uint16_t>(rectLineWidth),
160 SEMICIRCLE_IN_DEGREE - QUARTER_IN_DEGREE / half,
161 SEMICIRCLE_IN_DEGREE + QUARTER_IN_DEGREE / half,
162 nullptr};
163 ArcInfo arcInfoRight = {end,
164 {0, 0},
165 static_cast<uint16_t>(rectLineWidth),
166 CIRCLE_IN_DEGREE - QUARTER_IN_DEGREE / half,
167 SEMICIRCLE_IN_DEGREE - QUARTER_IN_DEGREE / half,
168 nullptr};
169 styleSelect.lineColor_ = Color::White();
170 styleSelect.lineOpa_ = backgroundOpacity_;
171 uint8_t opa = DrawUtils::GetMixOpacity(opaScale_, backgroundOpacity_);
172 baseGfxEngine->DrawArc(gfxDstBuffer, arcInfoLeft, trunc, styleSelect, opaScale_, CapType::CAP_NONE);
173 // 2 : double
174 baseGfxEngine->DrawLine(gfxDstBuffer, start, mid, trunc, rectLineWidth * 2, Color::White(), opa);
175 baseGfxEngine->DrawArc(gfxDstBuffer, arcInfoMid, trunc, styleSelect, opaScale_, CapType::CAP_NONE);
176 // 2 : double
177 baseGfxEngine->DrawLine(gfxDstBuffer, mid, end, trunc, rectLineWidth * 2, Color::White(), opa);
178 baseGfxEngine->DrawArc(gfxDstBuffer, arcInfoRight, trunc, styleSelect, opaScale_, CapType::CAP_NONE);
179 }
180
UnSelectedStateSoftwareDrawing(BufferInfo & gfxDstBuffer,Rect rect,Rect trunc,int16_t borderRadius,int16_t rectLineWidth)181 void UICheckBox::UnSelectedStateSoftwareDrawing(BufferInfo& gfxDstBuffer,
182 Rect rect,
183 Rect trunc,
184 int16_t borderRadius,
185 int16_t rectLineWidth)
186 {
187 Style styleUnSelect = StyleDefault::GetBackgroundTransparentStyle();
188 styleUnSelect.borderWidth_ = rectLineWidth;
189 styleUnSelect.borderRadius_ = borderRadius;
190 styleUnSelect.borderColor_ = Color::White();
191 styleUnSelect.borderOpa_ = DEFAULT_UNSELECT_BG_OPA;
192 BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, rect, trunc, styleUnSelect, opaScale_);
193 }
194
195 #if DEFAULT_ANIMATION
ResetCallback()196 void UICheckBox::ResetCallback()
197 {
198 if ((runTime_ != 0) && (checkBoxAnimator_.GetTime() != runTime_)) {
199 checkBoxAnimator_.SetRunTime(checkBoxAnimator_.GetTime() - runTime_);
200 }
201 }
202
Callback(UIView * view)203 void UICheckBox::Callback(UIView* view)
204 {
205 runTime_ = checkBoxAnimator_.GetRunTime();
206 float x = static_cast<float>(runTime_) / checkBoxAnimator_.GetTime();
207 float coefficient = Interpolation::GetBezierY(x, BEZIER_CONTROL_POINT_X_1, 0, BEZIER_CONTROL_POINT_X_2, 1);
208 backgroundOpacity_ = (state_ == SELECTED) ? (static_cast<uint8_t>(coefficient * OPA_OPAQUE)) :
209 (static_cast<uint8_t>((1 - coefficient) * OPA_OPAQUE));
210 Invalidate();
211 }
212
OnStop(UIView & view)213 void UICheckBox::OnStop(UIView& view)
214 {
215 backgroundOpacity_ = (state_ == SELECTED) ? OPA_OPAQUE : 0;
216 Invalidate();
217 }
218 #endif
219
OnDraw(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea)220 void UICheckBox::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
221 {
222 Rect trunc = invalidatedArea;
223 if ((image_[SELECTED].GetSrcType() != IMG_SRC_UNKNOWN) && (image_[UNSELECTED].GetSrcType() != IMG_SRC_UNKNOWN)) {
224 ImageHeader header = {0};
225 image_[state_].GetHeader(header);
226 int16_t imgWidth = header.width;
227 int16_t imgHeight = header.height;
228 Rect coords = GetContentRect();
229 coords.SetWidth(imgWidth);
230 coords.SetHeight(imgHeight);
231 BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, GetRect(), invalidatedArea, *style_, opaScale_);
232 int16_t offsetLeft = (GetWidth() - imgWidth) / 2; // 2 : half
233 int16_t offsetTop = (GetHeight() - imgHeight) / 2; // 2 : half
234 coords.SetX(coords.GetX() + offsetLeft);
235 coords.SetY(coords.GetY() + offsetTop);
236 if (trunc.Intersect(trunc, coords)) {
237 image_[state_].DrawImage(gfxDstBuffer, coords, trunc, *style_, opaScale_);
238 }
239 } else {
240 Rect contentRect = GetContentRect();
241 bool isIntersect = trunc.Intersect(trunc, contentRect);
242 if (!isIntersect) {
243 return;
244 }
245 CalculateSize();
246 int16_t rectLineWidth = borderWidth_ / DEFAULT_BORDER_WIDTH;
247 int16_t borderRadius = rectLineWidth * DEFAULT_RATIO_BORDER_RADIUS_LINE_WIDTH;
248 BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, GetRect(), invalidatedArea, *style_, opaScale_);
249 int16_t x = contentRect.GetX() + (width_ - borderWidth_) / 2; // 2: half
250 int16_t y = contentRect.GetY() + (height_ - borderWidth_) / 2; // 2: half
251 Rect rect(x, y, x + borderWidth_, y + borderWidth_);
252 #if DEFAULT_ANIMATION
253 UnSelectedStateSoftwareDrawing(gfxDstBuffer, rect, trunc, borderRadius, rectLineWidth);
254 SelectedStateSoftwareDrawing(gfxDstBuffer, rect, trunc, borderRadius, rectLineWidth);
255 #else
256 if (state_ == SELECTED) {
257 SelectedStateSoftwareDrawing(gfxDstBuffer, rect, trunc, borderRadius, rectLineWidth);
258 } else {
259 UnSelectedStateSoftwareDrawing(gfxDstBuffer, rect, trunc, borderRadius, rectLineWidth);
260 }
261 #endif
262 }
263 }
264
SetSelectedStateColor(ColorType color)265 void UICheckBox::SetSelectedStateColor(ColorType color)
266 {
267 selectedStateColor_ = color;
268 }
269
GetSelectedStateColor() const270 ColorType UICheckBox::GetSelectedStateColor() const
271 {
272 return selectedStateColor_;
273 }
274 } // namespace OHOS
275