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 22namespace OHOS { 23namespace { 24constexpr uint8_t DEFAULT_UNSELECT_BG_OPA = 168; // default background opacity 25constexpr float DEFAULT_COEFFICIENT_START_DX = 0.22; // start point: x-cordinate offset 26constexpr float DEFAULT_COEFFICIENT_START_DY = 0.5; // start point: y-cordinate offset 27constexpr float DEFAULT_COEFFICIENT_MID_DX = 0.2; // middle point: y-cordinate offset 28constexpr float DEFAULT_COEFFICIENT_MID_DY = 0.38; // middle point: y-cordinate offset 29constexpr int16_t DEFAULT_RATIO_BORDER_RADIUS_LINE_WIDTH = 4; 30constexpr uint8_t DEFAULT_BG_RED = 31; 31constexpr uint8_t DEFAULT_BG_GREEN = 113; 32constexpr uint8_t DEFAULT_BG_BLUE = 255; 33#if DEFAULT_ANIMATION 34constexpr int16_t DEFAULT_ANIMATOR_TIME = 200; 35constexpr float BEZIER_CONTROL_POINT_X_1 = 0.33; 36constexpr float BEZIER_CONTROL_POINT_X_2 = 0.67; 37#endif 38} // namespace 39UICheckBox::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 63void 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 87void UICheckBox::ReverseState() 88{ 89 if (state_ == SELECTED) { 90 SetState(UNSELECTED, true); 91 } else { 92 SetState(SELECTED, true); 93 } 94} 95 96bool UICheckBox::OnClickEvent(const ClickEvent& event) 97{ 98 ReverseState(); 99 Invalidate(); 100 return UIView::OnClickEvent(event); 101} 102 103void UICheckBox::SetImages(const char* selectedImageSrc, const char* unselectedImageSrc) 104{ 105 image_[SELECTED].SetSrc(selectedImageSrc); 106 image_[UNSELECTED].SetSrc(unselectedImageSrc); 107} 108 109void UICheckBox::SetImages(const ImageInfo* selectedImageSrc, const ImageInfo* unselectedImageSrc) 110{ 111 image_[SELECTED].SetSrc(selectedImageSrc); 112 image_[UNSELECTED].SetSrc(unselectedImageSrc); 113} 114 115void 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 128void 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 181void 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 196void UICheckBox::ResetCallback() 197{ 198 if ((runTime_ != 0) && (checkBoxAnimator_.GetTime() != runTime_)) { 199 checkBoxAnimator_.SetRunTime(checkBoxAnimator_.GetTime() - runTime_); 200 } 201} 202 203void 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 213void UICheckBox::OnStop(UIView& view) 214{ 215 backgroundOpacity_ = (state_ == SELECTED) ? OPA_OPAQUE : 0; 216 Invalidate(); 217} 218#endif 219 220void 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 265void UICheckBox::SetSelectedStateColor(ColorType color) 266{ 267 selectedStateColor_ = color; 268} 269 270ColorType UICheckBox::GetSelectedStateColor() const 271{ 272 return selectedStateColor_; 273} 274} // namespace OHOS 275