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