1 /* 2 * Copyright (c) 2021-2023 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 "core/components/button/rosen_render_button.h" 17 18 #ifndef USE_ROSEN_DRAWING 19 #include "include/core/SkMaskFilter.h" 20 #include "include/core/SkPath.h" 21 #include "include/core/SkRRect.h" 22 #endif 23 24 #include "core/components/box/render_box.h" 25 #include "core/pipeline/base/rosen_render_context.h" 26 #ifdef OHOS_PLATFORM 27 #include "core/components/common/painter/rosen_svg_painter.h" 28 #endif 29 30 namespace OHOS::Ace { 31 namespace { 32 33 constexpr double HALF = 0.5; 34 35 // Definition for arc button of watch which intersected by circle and ellipse. 36 constexpr Dimension CIRCLE_DIAMETER = 233.0_vp; 37 constexpr Dimension OVAL_WIDTH = 260.0_vp; 38 constexpr Dimension OVAL_HEIGHT = 98.0_vp; 39 constexpr Dimension OFFSET_X = (OVAL_WIDTH - ARC_BUTTON_WIDTH) / 2.0; 40 constexpr Dimension OFFSET_Y = CIRCLE_DIAMETER - ARC_BUTTON_HEIGHT; 41 constexpr double CIRCLE_START_ANGLE = 0.759; 42 constexpr double CIRCLE_SWEEP_ANGLE = M_PI - CIRCLE_START_ANGLE * 2; 43 constexpr double OVAL_START_ANGLE = 4.0; 44 constexpr double OVAL_SWEEP_ANGLE = M_PI * 3 - OVAL_START_ANGLE * 2; 45 constexpr double RADIAN_TO_DEGREE = 180.0 / M_PI; 46 47 // Definition for download button in watch 48 constexpr Dimension CIRCLE_PROGRESS_THICKNESS = 2.0_vp; 49 constexpr Dimension WATCH_DOWNLOAD_SIZE_DELTA = 8.0_vp; 50 constexpr double PROGRESS_START_ANGLE = 1.5 * M_PI; 51 52 // Definition for animation 53 constexpr uint8_t DEFAULT_OPACITY = 255; 54 55 constexpr Dimension FOCUS_PADDING = 2.0_vp; 56 constexpr Dimension FOCUS_BORDER_WIDTH = 2.0_vp; 57 constexpr uint32_t FOCUS_BORDER_COLOR = 0xFF0A59F7; 58 constexpr uint32_t FOCUS_POPUP_BORDER_COLOR = 0xFFFFFFFF; 59 60 } // namespace 61 PerformLayout()62 void RosenRenderButton::PerformLayout() 63 { 64 RenderButton::PerformLayout(); 65 66 UpdateLayer(); 67 } 68 UpdateLayer()69 void RosenRenderButton::UpdateLayer() 70 { 71 float translateX = GetLayoutSize().Width() / 2 * (INIT_SCALE - scale_); 72 // The bottom of the component must be close to the bottom of the circle when the type is arc. 73 // The center point deviates 2 times downward. 74 float translateY = (buttonComponent_->GetType() == ButtonType::ARC) 75 ? GetLayoutSize().Height() * (INIT_SCALE - scale_) * 2 76 : GetLayoutSize().Height() / 2 * (1.0 - scale_); 77 Matrix4 translateMatrix = Matrix4::CreateTranslate(translateX, translateY, 0.0); 78 Matrix4 scaleMatrix = Matrix4::CreateScale(scale_, scale_, 1.0); 79 Matrix4 transformMatrix = translateMatrix * scaleMatrix; 80 81 transformLayer_ = transformMatrix; 82 opacityLayer_ = DEFAULT_OPACITY * opacity_; 83 } 84 85 #ifndef USE_ROSEN_DRAWING PaintLayer(SkCanvas * canvas)86 void RosenRenderButton::PaintLayer(SkCanvas* canvas) 87 #else 88 void RosenRenderButton::PaintLayer(RSCanvas* canvas) 89 #endif 90 { 91 #ifdef OHOS_PLATFORM 92 #ifndef USE_ROSEN_DRAWING 93 auto recordingCanvas = static_cast<Rosen::RSRecordingCanvas*>(canvas); 94 recordingCanvas->MultiplyAlpha(opacityLayer_ / 255.0f); 95 recordingCanvas->concat(RosenSvgPainter::ToSkMatrix(transformLayer_)); 96 #else 97 auto recordingCanvas = static_cast<RSRecordingCanvas*>(canvas); 98 recordingCanvas->ConcatMatrix(RosenSvgPainter::ToDrawingMatrix(transformLayer_)); 99 #endif 100 #endif 101 } 102 Paint(RenderContext & context,const Offset & offset)103 void RosenRenderButton::Paint(RenderContext& context, const Offset& offset) 104 { 105 if (!buttonComponent_) { 106 return; 107 } 108 if (isHover_) { 109 UpdateLayer(); 110 isHover_ = false; 111 } 112 PaintButtonAnimation(); 113 auto canvas = static_cast<RosenRenderContext&>(context).GetCanvas(); 114 if (canvas == nullptr) { 115 LOGE("Paint canvas is null"); 116 return; 117 } 118 PaintLayer(canvas); 119 if (buttonComponent_->GetType() == ButtonType::ICON) { 120 RenderNode::Paint(context, offset); 121 return; 122 } 123 DrawButton(canvas, offset); 124 auto pipeline = context_.Upgrade(); 125 if (isFocus_ && (isTablet_ || isPhone_) && pipeline && pipeline->GetIsTabKeyPressed()) { 126 // Need to use PipelineContext::ShowFocusAnimation 127 if (buttonComponent_->IsPopupButton()) { 128 PaintPopupFocus(context); 129 } else { 130 PaintFocus(context, offset); 131 } 132 SyncFocusGeometryProperties(); 133 } 134 RenderNode::Paint(context, offset); 135 } 136 PaintButtonAnimation()137 void RosenRenderButton::PaintButtonAnimation() 138 { 139 if (!animationRunning_) { 140 return; 141 } 142 UpdateLayer(); 143 if (isLastFrame_) { 144 animationRunning_ = false; 145 isOpacityAnimation_ = false; 146 isLastFrame_ = false; 147 isTouchAnimation_ = false; 148 } 149 } 150 Measure()151 Size RosenRenderButton::Measure() 152 { 153 // Layout size need includes border width, the border width is half outside of button, 154 // total width and height needs to add border width defined by user. 155 if (!buttonComponent_) { 156 return Size(); 157 } 158 widthDelta_ = NormalizeToPx(buttonComponent_->GetBorderEdge().GetWidth()); 159 double delta = widthDelta_ / 2; 160 offsetDelta_ = Offset(delta, delta); 161 if (buttonComponent_->GetType() == ButtonType::ARC) { 162 return buttonSize_ + Size(widthDelta_, widthDelta_); 163 } 164 if (NeedLayoutExtendToParant()) { 165 buttonSize_ = GetLayoutParam().GetMaxSize(); 166 } 167 MeasureButtonSize(); 168 if (buttonComponent_->GetType() == ButtonType::NORMAL) { 169 if (buttonComponent_->GetDeclarativeFlag()) { 170 ResetBoxRadius(); 171 } 172 if (!buttonComponent_->GetRadiusState() && buttonComponent_->IsInputButton()) { 173 rrectRadius_ = buttonSize_.Height() / 2.0; 174 } 175 } 176 return buttonSize_ + Size(widthDelta_, widthDelta_); 177 } 178 MeasureButtonSize()179 void RosenRenderButton::MeasureButtonSize() 180 { 181 if (buttonComponent_->GetType() == ButtonType::ICON) { 182 return; 183 } 184 if (NearEqual(GetLayoutParam().GetMaxSize().Width(), Size::INFINITE_SIZE) || (!widthDefined_)) { 185 buttonSize_.SetWidth(0.0); 186 } 187 if (buttonComponent_->GetType() == ButtonType::CAPSULE) { 188 MeasureCapsule(); 189 return; 190 } 191 if (buttonComponent_->GetType() == ButtonType::CIRCLE) { 192 MeasureCircle(); 193 return; 194 } 195 if (isWatch_ && (buttonComponent_->GetType() == ButtonType::DOWNLOAD)) { 196 if (buttonComponent_->GetRadiusState() || widthDefined_ || heightDefined_) { 197 MeasureCircle(); 198 progressDiameter_ = rrectRadius_ * 2 - NormalizeToPx(WATCH_DOWNLOAD_SIZE_DELTA); 199 } else { 200 buttonSize_ = Size(progressDiameter_ + NormalizeToPx(WATCH_DOWNLOAD_SIZE_DELTA), 201 progressDiameter_ + NormalizeToPx(WATCH_DOWNLOAD_SIZE_DELTA)); 202 } 203 } 204 } 205 MeasureCapsule()206 void RosenRenderButton::MeasureCapsule() 207 { 208 if (GreatNotEqual(rrectRadius_, buttonSize_.Height() / 2.0)) { 209 return; 210 } 211 rrectRadius_ = buttonSize_.Height() / 2.0; 212 ResetBoxRadius(); 213 } 214 MeasureCircle()215 void RosenRenderButton::MeasureCircle() 216 { 217 if (!buttonComponent_->GetRadiusState()) { 218 if (widthDefined_ || heightDefined_) { 219 double minSize = std::min(GetLayoutParam().GetMaxSize().Width(), GetLayoutParam().GetMaxSize().Height()); 220 if (buttonComponent_->GetDeclarativeFlag()) { 221 minSize = widthDefined_ ? std::min(buttonSize_.Width(), buttonSize_.Height()) : buttonSize_.Height(); 222 } 223 rrectRadius_ = (minSize - widthDelta_) / 2.0; 224 } 225 } else { 226 auto constrainedSize = 227 GetLayoutParam().Constrain(Size(rrectRadius_ * 2.0 + widthDelta_, rrectRadius_ * 2.0 + widthDelta_)); 228 rrectRadius_ = (std::min(constrainedSize.Width(), constrainedSize.Height()) - widthDelta_) / 2.0; 229 } 230 buttonSize_.SetWidth(rrectRadius_ * 2.0); 231 buttonSize_.SetHeight(rrectRadius_ * 2.0); 232 ResetBoxRadius(); 233 } 234 ResetBoxRadius()235 void RosenRenderButton::ResetBoxRadius() 236 { 237 if (!buttonComponent_->GetRadiusState() && buttonComponent_->GetDeclarativeFlag()) { 238 return; 239 } 240 auto parent = GetParent().Upgrade(); 241 if (!parent) { 242 return; 243 } 244 auto box = AceType::DynamicCast<RenderBox>(parent); 245 if (box) { 246 auto backDecoration = box->GetBackDecoration(); 247 if (backDecoration) { 248 auto border = backDecoration->GetBorder(); 249 backDecoration->SetBorderRadius(Radius(rrectRadius_ + NormalizeToPx(border.Top().GetWidth()))); 250 } 251 } 252 } 253 254 #ifndef USE_ROSEN_DRAWING DrawShape(SkCanvas * canvas,const Offset & offset,bool isStroke)255 void RosenRenderButton::DrawShape(SkCanvas* canvas, const Offset& offset, bool isStroke) 256 { 257 SkPaint paint; 258 if (isStroke) { 259 uint32_t focusColorValue = buttonComponent_->GetFocusColor().GetValue(); 260 uint32_t borderColorValue = buttonComponent_->GetBorderEdge().GetColor().GetValue(); 261 paint.setColor(needFocusColor_ ? focusColorValue : borderColorValue); 262 paint.setStyle(SkPaint::Style::kStroke_Style); 263 paint.setStrokeWidth(NormalizeToPx(borderEdge_.GetWidth())); 264 } else { 265 paint.setColor(GetStateColor()); 266 paint.setStyle(SkPaint::Style::kFill_Style); 267 } 268 paint.setAntiAlias(true); 269 SkRRect rRect; 270 271 if (buttonComponent_->GetType() == ButtonType::CUSTOM) { 272 ConvertToSkVector(buttonComponent_->GetRectRadii(), radii_); 273 rRect.setRectRadii(SkRect::MakeIWH(buttonSize_.Width(), buttonSize_.Height()), radii_); 274 } else { 275 rRect.setRectXY(SkRect::MakeIWH(buttonSize_.Width(), buttonSize_.Height()), rrectRadius_, rrectRadius_); 276 } 277 rRect.offset(offset.GetX(), offset.GetY()); 278 279 #ifdef OHOS_PLATFORM 280 auto recordingCanvas = static_cast<Rosen::RSRecordingCanvas*>(canvas); 281 if (buttonComponent_->GetType() == ButtonType::CAPSULE) { 282 recordingCanvas->DrawAdaptiveRRectScale(0.5f, paint); 283 } else { 284 recordingCanvas->DrawAdaptiveRRect(rRect.getSimpleRadii().x(), paint); 285 } 286 #else 287 canvas->drawRRect(rRect, paint); 288 #endif 289 } 290 #else DrawShape(RSCanvas * canvas,const Offset & offset,bool isStroke)291 void RosenRenderButton::DrawShape(RSCanvas* canvas, const Offset& offset, bool isStroke) 292 { 293 RSRoundRect rRect; 294 295 if (isStroke) { 296 RSPen pen; 297 uint32_t focusColorValue = buttonComponent_->GetFocusColor().GetValue(); 298 uint32_t borderColorValue = buttonComponent_->GetBorderEdge().GetColor().GetValue(); 299 pen.SetColor(needFocusColor_ ? focusColorValue : borderColorValue); 300 pen.SetWidth(NormalizeToPx(borderEdge_.GetWidth())); 301 pen.SetAntiAlias(true); 302 303 if (buttonComponent_->GetType() == ButtonType::CUSTOM) { 304 ConvertToVector(buttonComponent_->GetRectRadii(), radii_); 305 rRect = RSRoundRect(RSRect(0, 0, static_cast<RSScalar>(buttonSize_.Width()), 306 static_cast<RSScalar>(buttonSize_.Height())), radii_); 307 } else { 308 rRect = RSRoundRect(RSRect(0, 0, static_cast<RSScalar>(buttonSize_.Width()), 309 static_cast<RSScalar>(buttonSize_.Height())), 310 rrectRadius_, rrectRadius_); 311 } 312 rRect.Offset(offset.GetX(), offset.GetY()); 313 314 canvas->AttachPen(pen); 315 canvas->DrawRoundRect(rRect); 316 canvas->DetachPen(); 317 } else { 318 RSBrush brush; 319 brush.SetColor(GetStateColor()); 320 brush.SetAntiAlias(true); 321 322 if (buttonComponent_->GetType() == ButtonType::CUSTOM) { 323 ConvertToVector(buttonComponent_->GetRectRadii(), radii_); 324 rRect = RSRoundRect(RSRect(0, 0, static_cast<RSScalar>(buttonSize_.Width()), 325 static_cast<RSScalar>(buttonSize_.Height())), radii_); 326 } else { 327 rRect = RSRoundRect(RSRect(0, 0, static_cast<RSScalar>(buttonSize_.Width()), 328 static_cast<RSScalar>(buttonSize_.Height())), 329 rrectRadius_, rrectRadius_); 330 } 331 rRect.Offset(offset.GetX(), offset.GetY()); 332 333 canvas->AttachBrush(brush); 334 canvas->DrawRoundRect(rRect); 335 canvas->DetachBrush(); 336 } 337 } 338 #endif 339 340 #ifndef USE_ROSEN_DRAWING DrawArc(SkCanvas * canvas,const Offset & offset)341 void RosenRenderButton::DrawArc(SkCanvas* canvas, const Offset& offset) 342 { 343 double offsetDelta = NormalizeToPx((OVAL_WIDTH - CIRCLE_DIAMETER)) / 2; 344 SkPath arcPath; 345 arcPath.addArc({ 0, NormalizeToPx(OFFSET_Y), NormalizeToPx(OVAL_WIDTH), NormalizeToPx(OVAL_HEIGHT + OFFSET_Y) }, 346 OVAL_START_ANGLE * RADIAN_TO_DEGREE, OVAL_SWEEP_ANGLE * RADIAN_TO_DEGREE); 347 arcPath.addArc({ offsetDelta, 0, NormalizeToPx(CIRCLE_DIAMETER) + offsetDelta, NormalizeToPx(CIRCLE_DIAMETER) }, 348 CIRCLE_START_ANGLE * RADIAN_TO_DEGREE, CIRCLE_SWEEP_ANGLE * RADIAN_TO_DEGREE); 349 arcPath.offset(offset.GetX() - NormalizeToPx(OFFSET_X), offset.GetY() - NormalizeToPx(OFFSET_Y)); 350 351 SkPaint paint; 352 paint.setColor(GetStateColor()); 353 paint.setStyle(SkPaint::Style::kFill_Style); 354 paint.setAntiAlias(true); 355 canvas->drawPath(arcPath, paint); 356 } 357 #else DrawArc(RSCanvas * canvas,const Offset & offset)358 void RosenRenderButton::DrawArc(RSCanvas* canvas, const Offset& offset) 359 { 360 double offsetDelta = NormalizeToPx((OVAL_WIDTH - CIRCLE_DIAMETER)) / 2; 361 RSRecordingPath arcPath; 362 arcPath.AddArc( 363 RSRect(0, NormalizeToPx(OFFSET_Y), NormalizeToPx(OVAL_WIDTH), NormalizeToPx(OVAL_HEIGHT + OFFSET_Y)), 364 OVAL_START_ANGLE * RADIAN_TO_DEGREE, OVAL_SWEEP_ANGLE * RADIAN_TO_DEGREE); 365 arcPath.AddArc( 366 RSRect(offsetDelta, 0, NormalizeToPx(CIRCLE_DIAMETER) + offsetDelta, NormalizeToPx(CIRCLE_DIAMETER)), 367 CIRCLE_START_ANGLE * RADIAN_TO_DEGREE, CIRCLE_SWEEP_ANGLE * RADIAN_TO_DEGREE); 368 arcPath.Offset(offset.GetX() - NormalizeToPx(OFFSET_X), offset.GetY() - NormalizeToPx(OFFSET_Y)); 369 370 RSBrush brush; 371 brush.SetColor(GetStateColor()); 372 brush.SetAntiAlias(true); 373 canvas->AttachBrush(brush); 374 canvas->DrawPath(arcPath); 375 canvas->DetachBrush(); 376 } 377 #endif 378 379 #ifndef USE_ROSEN_DRAWING DrawLineProgress(SkCanvas * canvas,const Offset & offset)380 void RosenRenderButton::DrawLineProgress(SkCanvas* canvas, const Offset& offset) 381 { 382 SkPaint paint; 383 paint.setColor(needFocusColor_ ? progressFocusColor_.GetValue() : progressColor_.GetValue()); 384 paint.setStyle(SkPaint::Style::kFill_Style); 385 paint.setAntiAlias(true); 386 SkRRect rRect; 387 rRect.setRectXY(SkRect::MakeWH(buttonSize_.Width(), buttonSize_.Height()), rrectRadius_, rrectRadius_); 388 rRect.offset(offset.GetX(), offset.GetY()); 389 canvas->save(); 390 canvas->clipRRect(rRect, true); 391 canvas->drawRect({ offset.GetX(), offset.GetY(), progressWidth_, buttonSize_.Height() }, paint); 392 canvas->restore(); 393 } 394 #else DrawLineProgress(RSCanvas * canvas,const Offset & offset)395 void RosenRenderButton::DrawLineProgress(RSCanvas* canvas, const Offset& offset) 396 { 397 RSBrush brush; 398 brush.SetColor(needFocusColor_ ? progressFocusColor_.GetValue() : progressColor_.GetValue()); 399 brush.SetAntiAlias(true); 400 RSRoundRect rRect( 401 RSRect(0, 0, buttonSize_.Width(), buttonSize_.Height()), rrectRadius_, rrectRadius_); 402 rRect.Offset(offset.GetX(), offset.GetY()); 403 canvas->Save(); 404 canvas->ClipRoundRect(rRect, RSClipOp::INTERSECT, true); 405 canvas->AttachBrush(brush); 406 canvas->DrawRect({ offset.GetX(), offset.GetY(), progressWidth_, buttonSize_.Height() }); 407 canvas->DetachBrush(); 408 canvas->Restore(); 409 } 410 #endif 411 412 #ifndef USE_ROSEN_DRAWING DrawLineProgressAnimation(SkCanvas * canvas,const Offset & offset)413 void RosenRenderButton::DrawLineProgressAnimation(SkCanvas* canvas, const Offset& offset) 414 { 415 double offsetX = offset.GetX(); 416 double offsetY = offset.GetY(); 417 double radius = buttonSize_.Height() / 2.0; 418 SkPath path; 419 path.addArc({ offsetX, offsetY, buttonSize_.Height() + offsetX, buttonSize_.Height() + offsetY }, 90, 180); 420 if (LessNotEqual(progressWidth_, radius)) { 421 path.addArc({ progressWidth_ + offsetX, offsetY, buttonSize_.Height() - progressWidth_ + offsetX, 422 buttonSize_.Height() + offsetY }, 423 270, -180); 424 } else if (GreatNotEqual(progressWidth_, buttonSize_.Width() - radius)) { 425 path.addRect( 426 { radius + offsetX, offsetY, buttonSize_.Width() - radius + offsetX, buttonSize_.Height() + offsetY }); 427 path.addArc({ (buttonSize_.Width() - radius) * 2.0 - progressWidth_ + offsetX, offsetY, 428 progressWidth_ + offsetX, buttonSize_.Height() + offsetY }, 429 270, 180); 430 } else { 431 path.addRect({ radius + offsetX, offsetY, progressWidth_ + offsetX, buttonSize_.Height() + offsetY }); 432 } 433 SkPaint paint; 434 paint.setColor(progressColor_.GetValue()); 435 paint.setStyle(SkPaint::Style::kFill_Style); 436 paint.setAntiAlias(true); 437 canvas->drawPath(path, paint); 438 } 439 #else DrawLineProgressAnimation(RSCanvas * canvas,const Offset & offset)440 void RosenRenderButton::DrawLineProgressAnimation(RSCanvas* canvas, const Offset& offset) 441 { 442 double offsetX = offset.GetX(); 443 double offsetY = offset.GetY(); 444 double radius = buttonSize_.Height() / 2.0; 445 RSRecordingPath path; 446 path.AddArc(RSRect(offsetX, offsetY, buttonSize_.Height() + offsetX, buttonSize_.Height() + offsetY), 447 90, 180); 448 if (LessNotEqual(progressWidth_, radius)) { 449 path.AddArc(RSRect(progressWidth_ + offsetX, offsetY, 450 buttonSize_.Height() - progressWidth_ + offsetX, buttonSize_.Height() + offsetY), 451 270, -180); 452 } else if (GreatNotEqual(progressWidth_, buttonSize_.Width() - radius)) { 453 path.AddRect(RSRect(radius + offsetX, offsetY, buttonSize_.Width() - radius + offsetX, 454 buttonSize_.Height() + offsetY), 455 RSPathDirection::CW_DIRECTION); 456 path.AddArc(RSRect((buttonSize_.Width() - radius) * 2.0 - progressWidth_ + offsetX, offsetY, 457 progressWidth_ + offsetX, buttonSize_.Height() + offsetY), 458 270, 180); 459 } else { 460 path.AddRect( 461 RSRect(radius + offsetX, offsetY, progressWidth_ + offsetX, buttonSize_.Height() + offsetY), 462 RSPathDirection::CW_DIRECTION); 463 } 464 RSBrush brush; 465 brush.SetColor(progressColor_.GetValue()); 466 brush.SetAntiAlias(true); 467 canvas->AttachBrush(brush); 468 canvas->DrawPath(path); 469 canvas->DetachBrush(); 470 } 471 #endif 472 473 #ifndef USE_ROSEN_DRAWING DrawCircleProgress(SkCanvas * canvas,const Offset & offset)474 void RosenRenderButton::DrawCircleProgress(SkCanvas* canvas, const Offset& offset) 475 { 476 SkPaint paint; 477 paint.setAntiAlias(true); 478 paint.setColor(progressColor_.GetValue()); 479 paint.setStyle(SkPaint::Style::kStroke_Style); 480 paint.setStrokeWidth(NormalizeToPx(CIRCLE_PROGRESS_THICKNESS)); 481 paint.setStrokeCap(SkPaint::kRound_Cap); 482 canvas->drawArc( 483 { offset.GetX(), offset.GetY(), progressDiameter_ + offset.GetX(), progressDiameter_ + offset.GetY() }, 484 PROGRESS_START_ANGLE * RADIAN_TO_DEGREE, 360 * progressPercent_, false, paint); 485 } 486 #else DrawCircleProgress(RSCanvas * canvas,const Offset & offset)487 void RosenRenderButton::DrawCircleProgress(RSCanvas* canvas, const Offset& offset) 488 { 489 RSPen pen; 490 pen.SetAntiAlias(true); 491 pen.SetColor(progressColor_.GetValue()); 492 pen.SetWidth(NormalizeToPx(CIRCLE_PROGRESS_THICKNESS)); 493 pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP); 494 canvas->AttachPen(pen); 495 canvas->DrawArc(RSRect(offset.GetX(), offset.GetY(), 496 progressDiameter_ + offset.GetX(), progressDiameter_ + offset.GetY()), 497 PROGRESS_START_ANGLE * RADIAN_TO_DEGREE, 360 * progressPercent_); 498 canvas->DetachPen(); 499 } 500 #endif 501 502 #ifndef USE_ROSEN_DRAWING DrawDownloadButton(SkCanvas * canvas,const Offset & offset)503 void RosenRenderButton::DrawDownloadButton(SkCanvas* canvas, const Offset& offset) 504 #else 505 void RosenRenderButton::DrawDownloadButton(RSCanvas* canvas, const Offset& offset) 506 #endif 507 { 508 if (isWatch_) { 509 #ifndef USE_ROSEN_DRAWING 510 SkPaint paint; 511 paint.setAntiAlias(true); 512 paint.setStyle(SkPaint::Style::kFill_Style); 513 canvas->save(); 514 paint.setColor(GetStateColor()); 515 canvas->drawCircle(offset.GetX() + buttonSize_.Width() / 2, offset.GetY() + buttonSize_.Height() / 2, 516 (progressDiameter_ + NormalizeToPx(WATCH_DOWNLOAD_SIZE_DELTA)) / 2, paint); 517 canvas->restore(); 518 #else 519 RSBrush brush; 520 brush.SetAntiAlias(true); 521 canvas->Save(); 522 brush.SetColor(GetStateColor()); 523 canvas->AttachBrush(brush); 524 canvas->DrawCircle( 525 RSPoint(offset.GetX() + buttonSize_.Width() / 2, offset.GetY() + buttonSize_.Height() / 2), 526 (progressDiameter_ + NormalizeToPx(WATCH_DOWNLOAD_SIZE_DELTA)) / 2); 527 canvas->DetachBrush(); 528 canvas->Restore(); 529 #endif 530 if (progressDisplay_) { 531 DrawCircleProgress(canvas, offset + Offset((buttonSize_.Width() - progressDiameter_) / 2, 532 (buttonSize_.Height() - progressDiameter_) / 2)); 533 } 534 return; 535 } 536 537 DrawShape(canvas, offset); 538 if (isPhone_) { 539 DrawShape(canvas, offset, true); 540 if (progressDisplay_) { 541 if (GreatOrEqual(rrectRadius_, buttonSize_.Height() / 2.0)) { 542 DrawLineProgressAnimation(canvas, offset); 543 } else { 544 DrawLineProgress(canvas, offset); 545 } 546 } 547 return; 548 } 549 if (progressDisplay_) { 550 DrawShape(canvas, offset, true); 551 DrawLineProgress(canvas, offset); 552 } 553 } 554 555 #ifndef USE_ROSEN_DRAWING DrawButton(SkCanvas * canvas,const Offset & inOffset)556 void RosenRenderButton::DrawButton(SkCanvas* canvas, const Offset& inOffset) 557 #else 558 void RosenRenderButton::DrawButton(RSCanvas* canvas, const Offset& inOffset) 559 #endif 560 { 561 Offset offset = inOffset + offsetDelta_; 562 if (buttonComponent_->GetType() == ButtonType::ARC) { 563 DrawArc(canvas, offset); 564 return; 565 } 566 if (buttonComponent_->GetType() == ButtonType::DOWNLOAD) { 567 DrawDownloadButton(canvas, offset); 568 return; 569 } 570 571 // Paint button with border 572 if (NormalizeToPx(buttonComponent_->GetBorderEdge().GetWidth()) > 0.0) { 573 DrawShape(canvas, offset); 574 DrawShape(canvas, offset, true); 575 return; 576 } 577 DrawShape(canvas, offset); 578 } 579 GetStateColor()580 uint32_t RosenRenderButton::GetStateColor() 581 { 582 if (!buttonComponent_) { 583 return Color().GetValue(); 584 } 585 if (!buttonComponent_->GetStateEffect()) { 586 return buttonComponent_->GetBackgroundColor().GetValue(); 587 } 588 if (needHoverColor_) { 589 return buttonComponent_->GetHoverColor().GetValue(); 590 } 591 if (buttonComponent_->GetDisabledState()) { 592 return buttonComponent_->GetDisabledColor().GetValue(); 593 } 594 if (needFocusColor_) { 595 return buttonComponent_->GetFocusColor().GetValue(); 596 } 597 Color backgroundColor = buttonComponent_->GetBackgroundColor(); 598 if (NeedClickedColor(backgroundColor)) { 599 return isClicked_ ? clickedColor_.GetValue() : backgroundColor.GetValue(); 600 } 601 if (!isMoveEventValid_) { 602 maskingOpacity_ = 0.0; 603 } 604 uint32_t animationColor; 605 if (isWatch_) { 606 animationColor = backgroundColor.BlendColor(Color::WHITE.ChangeOpacity(maskingOpacity_)).GetValue(); 607 } else { 608 animationColor = backgroundColor.BlendColor(Color::BLACK.ChangeOpacity(maskingOpacity_)).GetValue(); 609 } 610 return animationColor; 611 } 612 NeedClickedColor(const Color & backgroundColor)613 bool RosenRenderButton::NeedClickedColor(const Color& backgroundColor) 614 { 615 if (setClickColor_) { 616 return true; 617 } 618 if (clickedColor_ != defaultClickedColor_) { 619 return true; 620 } else { 621 if (backgroundColor == Color::TRANSPARENT) { 622 return true; 623 } 624 } 625 return false; 626 } 627 HasEffectiveTransform() const628 bool RosenRenderButton::HasEffectiveTransform() const 629 { 630 return scale_ != INIT_SCALE; 631 } 632 633 #ifndef USE_ROSEN_DRAWING ConvertToSkVector(const std::array<Radius,4> & radii,SkVector * skRadii)634 void RosenRenderButton::ConvertToSkVector(const std::array<Radius, 4>& radii, SkVector* skRadii) 635 #else 636 void RosenRenderButton::ConvertToVector(const std::array<Radius, 4>& radii, std::vector<RSPoint>& pRadii) 637 #endif 638 { 639 auto context = context_.Upgrade(); 640 if (!context) { 641 return; 642 } 643 double dipScale = context->GetDipScale(); 644 for (int32_t i = 0; i < 4; ++i) { 645 #ifndef USE_ROSEN_DRAWING 646 skRadii[i].set(SkDoubleToScalar(std::max(radii[i].GetX().ConvertToPx(dipScale), 0.0)), 647 SkDoubleToScalar(std::max(radii[i].GetY().ConvertToPx(dipScale), 0.0))); 648 #else 649 pRadii[i].SetX(static_cast<float>(std::max(radii[i].GetX().ConvertToPx(dipScale), 0.0))); 650 pRadii[i].SetY(static_cast<float>(std::max(radii[i].GetY().ConvertToPx(dipScale), 0.0))); 651 #endif 652 } 653 } 654 PaintFocus(RenderContext & context,const Offset & offset)655 void RosenRenderButton::PaintFocus(RenderContext& context, const Offset& offset) 656 { 657 auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas(); 658 if (!canvas) { 659 LOGE("paint canvas is null"); 660 return; 661 } 662 Size canvasSize = GetLayoutSize(); 663 double focusBorderHeight = canvasSize.Height() + NormalizeToPx(FOCUS_PADDING * 2 + FOCUS_BORDER_WIDTH); 664 double focusBorderWidth = canvasSize.Width() + NormalizeToPx(FOCUS_PADDING * 2 + FOCUS_BORDER_WIDTH); 665 double focusRadius = focusBorderHeight * HALF; 666 if (!buttonComponent_) { 667 return; 668 } 669 if (buttonComponent_->GetType() == ButtonType::NORMAL) { 670 focusRadius = rrectRadius_ + NormalizeToPx(FOCUS_PADDING); 671 } 672 673 #ifndef USE_ROSEN_DRAWING 674 SkPaint paint; 675 paint.setColor(FOCUS_BORDER_COLOR); 676 paint.setStyle(SkPaint::Style::kStroke_Style); 677 paint.setStrokeWidth(NormalizeToPx(FOCUS_BORDER_WIDTH)); 678 paint.setAntiAlias(true); 679 SkRRect rRect; 680 rRect.setRectXY(SkRect::MakeIWH(focusBorderWidth, focusBorderHeight), focusRadius, focusRadius); 681 rRect.offset(-NormalizeToPx(FOCUS_PADDING + FOCUS_BORDER_WIDTH * HALF), 682 -NormalizeToPx(FOCUS_PADDING + FOCUS_BORDER_WIDTH * HALF)); 683 canvas->drawRRect(rRect, paint); 684 #else 685 RSPen pen; 686 pen.SetColor(FOCUS_BORDER_COLOR); 687 pen.SetWidth(NormalizeToPx(FOCUS_BORDER_WIDTH)); 688 pen.SetAntiAlias(true); 689 RSRoundRect rRect(RSRect(0, 0, focusBorderWidth, focusBorderHeight), focusRadius, focusRadius); 690 rRect.Offset(-NormalizeToPx(FOCUS_PADDING + FOCUS_BORDER_WIDTH * HALF), 691 -NormalizeToPx(FOCUS_PADDING + FOCUS_BORDER_WIDTH * HALF)); 692 canvas->AttachPen(pen); 693 canvas->DrawRoundRect(rRect); 694 canvas->DetachPen(); 695 #endif 696 } 697 698 #ifndef USE_ROSEN_DRAWING PaintPopupFocus(RenderContext & context)699 void RosenRenderButton::PaintPopupFocus(RenderContext& context) 700 { 701 auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas(); 702 if (!canvas) { 703 LOGE("paint canvas is null"); 704 return; 705 } 706 Size canvasSize = GetLayoutSize(); 707 double focusBorderHeight = canvasSize.Height() - NormalizeToPx(FOCUS_BORDER_WIDTH) / HALF; 708 double focusBorderWidth = canvasSize.Width() - NormalizeToPx(FOCUS_BORDER_WIDTH) / HALF; 709 double focusRadius = focusBorderHeight * HALF; 710 if (!buttonComponent_) { 711 return; 712 } 713 714 SkPaint paint; 715 paint.setColor(FOCUS_POPUP_BORDER_COLOR); 716 paint.setStyle(SkPaint::Style::kStroke_Style); 717 paint.setStrokeWidth(NormalizeToPx(FOCUS_BORDER_WIDTH)); 718 paint.setAntiAlias(true); 719 SkRRect rRect; 720 rRect.setRectXY(SkRect::MakeIWH(focusBorderWidth, focusBorderHeight), focusRadius, focusRadius); 721 rRect.offset(NormalizeToPx(FOCUS_BORDER_WIDTH), NormalizeToPx(FOCUS_BORDER_WIDTH)); 722 canvas->drawRRect(rRect, paint); 723 } 724 #else PaintPopupFocus(RenderContext & context)725 void RosenRenderButton::PaintPopupFocus(RenderContext& context) 726 { 727 auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas(); 728 if (!canvas) { 729 LOGE("paint canvas is null"); 730 return; 731 } 732 Size canvasSize = GetLayoutSize(); 733 double focusBorderHeight = canvasSize.Height() - NormalizeToPx(FOCUS_BORDER_WIDTH) / HALF; 734 double focusBorderWidth = canvasSize.Width() - NormalizeToPx(FOCUS_BORDER_WIDTH) / HALF; 735 double focusRadius = focusBorderHeight * HALF; 736 if (!buttonComponent_) { 737 return; 738 } 739 740 RSPen pen; 741 pen.SetColor(FOCUS_POPUP_BORDER_COLOR); 742 pen.SetWidth(NormalizeToPx(FOCUS_BORDER_WIDTH)); 743 pen.SetAntiAlias(true); 744 745 RSRoundRect rRect(RSRect(0, 0, focusBorderWidth, focusBorderHeight), focusRadius, focusRadius); 746 rRect.Offset(NormalizeToPx(FOCUS_BORDER_WIDTH), NormalizeToPx(FOCUS_BORDER_WIDTH)); 747 748 canvas->AttachPen(pen); 749 canvas->DrawRoundRect(rRect); 750 canvas->DetachPen(); 751 } 752 #endif 753 SyncFocusGeometryProperties()754 void RosenRenderButton::SyncFocusGeometryProperties() 755 { 756 auto rsNode = GetRSNode(); 757 if (!rsNode) { 758 return; 759 } 760 Size boundsSize = GetLayoutSize(); 761 double focusBorderHeight = boundsSize.Height() + NormalizeToPx(FOCUS_PADDING * 2 + FOCUS_BORDER_WIDTH); 762 double focusBorderWidth = boundsSize.Width() + NormalizeToPx(FOCUS_PADDING * 2 + FOCUS_BORDER_WIDTH); 763 Offset boundsOffset = GetPaintOffset() + Offset(-NormalizeToPx(FOCUS_PADDING + FOCUS_BORDER_WIDTH * HALF), 764 -NormalizeToPx(FOCUS_PADDING + FOCUS_BORDER_WIDTH * HALF)); 765 boundsOffset += Offset(-NormalizeToPx(FOCUS_PADDING), -NormalizeToPx(FOCUS_PADDING)); 766 focusBorderWidth += 2 * NormalizeToPx(FOCUS_PADDING); 767 focusBorderHeight += 2 *NormalizeToPx(FOCUS_PADDING); 768 rsNode->SetBounds(boundsOffset.GetX(), boundsOffset.GetY(), focusBorderWidth, focusBorderHeight); 769 if (IsTailRenderNode()) { 770 Offset frameOffset = GetPaintOffset(); 771 Size frameSize = GetLayoutSize(); 772 rsNode->SetFrame(frameOffset.GetX(), frameOffset.GetY(), frameSize.Width(), frameSize.Height()); 773 } 774 } 775 776 } // namespace OHOS::Ace 777