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