/* * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "components/ui_radio_button.h" #include "common/image.h" #include "components/root_view.h" #include "components/ui_view_group.h" #include "draw/draw_image.h" #include "engines/gfx/gfx_engine_manager.h" #include "gfx_utils/graphic_log.h" #include "imgdecode/cache_manager.h" #include "securec.h" namespace { constexpr int16_t DEFAULT_RADIUS_BIG = 11; constexpr int16_t DEFAULT_RADIUS_SMALL = 6; constexpr int16_t DEFAULT_LINE_WIDTH = 1; #if DEFAULT_ANIMATION constexpr float SCALE_BEZIER_CONTROL_POINT_X_1 = 0.33; constexpr float SCALE_BEZIER_CONTROL_POINT_X_2 = 0.67; constexpr float ALPHA_BEZIER_CONTROL_POINT_X_1 = 0.2; constexpr float ALPHA_BEZIER_CONTROL_POINT_X_2 = 0.2; #endif } // namespace namespace OHOS { UIRadioButton::UIRadioButton() : UIRadioButton(nullptr) {} UIRadioButton::UIRadioButton(const char* name) : name_(nullptr), radiusBig_(DEFAULT_RADIUS_BIG), radiusSmall_(DEFAULT_RADIUS_SMALL), currentRadius_(0), lineWidth_(DEFAULT_LINE_WIDTH) { SetName(name); image_[UNSELECTED].SetSrc(""); image_[SELECTED].SetSrc(""); Resize(width_, height_); } bool UIRadioButton::OnClickEvent(const ClickEvent& event) { SetState(SELECTED, true); Invalidate(); UIView* view = this; while ((view != nullptr) && (view->GetParent() != nullptr)) { view = view->GetParent(); } FindRadioButtonAndChangeState(view); return UIView::OnClickEvent(event); } void UIRadioButton::CalculateSize() { width_ = GetWidth(); height_ = GetHeight(); int16_t minValue = (width_ > height_) ? height_ : width_; radiusBig_ = DEFAULT_RADIUS_BIG * minValue / DEFAULT_HOT_WIDTH; radiusSmall_ = DEFAULT_RADIUS_SMALL * minValue / DEFAULT_HOT_WIDTH; if (minValue >= DEFAULT_HOT_WIDTH) { lineWidth_ = DEFAULT_LINE_WIDTH * minValue / DEFAULT_HOT_WIDTH; } #if DEFAULT_ANIMATION if (checkBoxAnimator_.GetState() != Animator::START) { currentRadius_ = (state_ == SELECTED) ? radiusSmall_ : 0; } #else currentRadius_ = (state_ == SELECTED) ? radiusSmall_ : 0; #endif } void UIRadioButton::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) { if ((image_[SELECTED].GetSrcType() != IMG_SRC_UNKNOWN) && (image_[UNSELECTED].GetSrcType() != IMG_SRC_UNKNOWN)) { UICheckBox::OnDraw(gfxDstBuffer, invalidatedArea); } else { CalculateSize(); BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance(); baseGfxEngine->DrawRect(gfxDstBuffer, GetRect(), invalidatedArea, *style_, opaScale_); Rect contentRect = GetContentRect(); int16_t dx = width_ >> 1; int16_t dy = height_ >> 1; int16_t x = contentRect.GetX() + dx; int16_t y = contentRect.GetY() + dy; ArcInfo arcInfoBig = {{x, y}, {0}, radiusBig_, 0, CIRCLE_IN_DEGREE, nullptr}; ArcInfo arcInfoSmall = {{x, y}, {0}, currentRadius_, 0, CIRCLE_IN_DEGREE, nullptr}; Rect trunc = invalidatedArea; bool isIntersect = trunc.Intersect(trunc, contentRect); if (isIntersect) { Style style = StyleDefault::GetBackgroundTransparentStyle(); if (backgroundOpacity_ != OPA_OPAQUE) { style.lineColor_ = Color::White(); style.lineWidth_ = lineWidth_; // 0xa8 : opacity of drawing unselected button arc edge. baseGfxEngine->DrawArc(gfxDstBuffer, arcInfoBig, trunc, style, 0xa8, CapType::CAP_NONE); } style.lineWidth_ = arcInfoBig.radius; style.lineColor_ = selectedStateColor_; baseGfxEngine->DrawArc(gfxDstBuffer, arcInfoBig, trunc, style, backgroundOpacity_, CapType::CAP_NONE); style.lineWidth_ = arcInfoSmall.radius; style.lineColor_ = Color::White(); baseGfxEngine->DrawArc(gfxDstBuffer, arcInfoSmall, trunc, style, OPA_OPAQUE, CapType::CAP_NONE); } } } void UIRadioButton::SetName(const char* name) { if (name == nullptr) { return; } if (name_ != nullptr) { UIFree(name_); name_ = nullptr; } uint32_t nameLen = static_cast(strlen(name) + 1); if (nameLen > MAX_TEXT_LENGTH) { return; } name_ = static_cast(UIMalloc(nameLen)); if (name_ != nullptr) { if (memcpy_s(name_, nameLen, name, nameLen) != EOK) { UIFree(name_); name_ = nullptr; return; } } } void UIRadioButton::FindRadioButtonAndChangeState(UIView* view) { if ((view == nullptr) || (name_ == nullptr)) { return; } if (view->IsViewGroup()) { UIView* childView = static_cast(view)->GetChildrenHead(); while (childView != nullptr) { FindRadioButtonAndChangeState(childView); childView = childView->GetNextSibling(); } } if ((view == this) || (view->GetViewType() != UI_RADIO_BUTTON)) { return; } UIRadioButton* uiRadioButtonInfo = static_cast(view); if ((uiRadioButtonInfo->GetName() != nullptr) && (strcmp(uiRadioButtonInfo->GetName(), name_) == 0)) { uiRadioButtonInfo->SetState(UNSELECTED, true); } } #if DEFAULT_ANIMATION void UIRadioButton::Callback(UIView* view) { runTime_ = checkBoxAnimator_.GetRunTime(); float x = static_cast(runTime_) / checkBoxAnimator_.GetTime(); float coefficient = Interpolation::GetBezierY(x, SCALE_BEZIER_CONTROL_POINT_X_1, 0, SCALE_BEZIER_CONTROL_POINT_X_2, 1); backgroundOpacity_ = (state_ == SELECTED) ? (static_cast(coefficient * OPA_OPAQUE)) : (static_cast((1 - coefficient) * OPA_OPAQUE)); coefficient = Interpolation::GetBezierY(x, ALPHA_BEZIER_CONTROL_POINT_X_1, 0, ALPHA_BEZIER_CONTROL_POINT_X_2, 1); currentRadius_ = (state_ == SELECTED) ? (static_cast(coefficient * radiusSmall_)) : (static_cast((1 - coefficient) * radiusSmall_)); Invalidate(); } #endif } // namespace OHOS