1 /*
2 * Copyright (c) 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_ng/pattern/rating/rating_modifier.h"
17
18 #include "base/geometry/ng/offset_t.h"
19 #include "core/components/rating/rating_theme.h"
20 #include "core/components_ng/render/drawing_prop_convertor.h"
21 #include "core/components_ng/render/image_painter.h"
22
23 namespace OHOS::Ace::NG {
RatingModifier()24 RatingModifier::RatingModifier()
25 : needDraw_(AceType::MakeRefPtr<PropertyBool>(false)),
26 starNum_(AceType::MakeRefPtr<PropertyInt>(0)),
27 touchStar_(AceType::MakeRefPtr<PropertyInt>(0)),
28 drawScore_(AceType::MakeRefPtr<PropertyFloat>(.0f)),
29 stepSize_(AceType::MakeRefPtr<PropertyFloat>(.0f)),
30 contentOffset_(AceType::MakeRefPtr<PropertyOffsetF>(OffsetF())),
31 contentSize_(AceType::MakeRefPtr<PropertySizeF>(SizeF())),
32 boardColor_(AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::TRANSPARENT)))
33 {
34 AttachProperty(needDraw_);
35 AttachProperty(starNum_);
36 AttachProperty(touchStar_);
37 AttachProperty(drawScore_);
38 AttachProperty(stepSize_);
39 AttachProperty(contentOffset_);
40 AttachProperty(contentSize_);
41 AttachProperty(boardColor_);
42 }
43
onDraw(DrawingContext & context)44 void RatingModifier::onDraw(DrawingContext& context)
45 {
46 CHECK_NULL_VOID(foregroundImageCanvas_);
47 CHECK_NULL_VOID(secondaryImageCanvas_);
48 CHECK_NULL_VOID(backgroundImageCanvas_);
49 // step1: check if touch down any stars.
50 PaintBoard(context);
51 PaintStar(context);
52 SetNeedDraw(false);
53 }
54
PaintBoard(DrawingContext & context)55 void RatingModifier::PaintBoard(DrawingContext& context)
56 {
57 auto pipeline = PipelineBase::GetCurrentContext();
58 CHECK_NULL_VOID(pipeline);
59 auto ratingTheme = pipeline->GetTheme<RatingTheme>();
60 CHECK_NULL_VOID(ratingTheme);
61 // animate color
62 LinearColor bgColor = boardColor_->Get();
63 auto pressBorderRadius = ratingTheme->GetFocusBorderRadius();
64 auto& canvas = context.canvas;
65
66 auto singleStarImagePaintConfig = foregroundImageCanvas_->GetPaintConfig();
67 const float singleStarWidth = contentSize_->Get().Width() / static_cast<float>(starNum_->Get());
68 const float singleStarHeight = contentSize_->Get().Height();
69 auto offset = contentOffset_->Get();
70 auto touchStar = touchStar_->Get();
71 auto starNum = starNum_->Get();
72 if (touchStar >= 0 && touchStar < starNum) {
73 RSBrush rsBrush(ToRSColor(bgColor));
74 rsBrush.SetAntiAlias(true);
75 const RSRect rsRect(offset.GetX() + singleStarWidth * static_cast<float>(touchStar), offset.GetY(),
76 offset.GetX() + singleStarWidth * static_cast<float>((touchStar + 1)), offset.GetY() + singleStarHeight);
77 const RSRoundRect rsRoundRect(rsRect, static_cast<float>(pressBorderRadius.ConvertToPx()),
78 static_cast<float>(pressBorderRadius.ConvertToPx()));
79 canvas.Save();
80 canvas.ClipRoundRect(rsRoundRect, RSClipOp::INTERSECT);
81 canvas.DrawBackground(rsBrush);
82 canvas.Restore();
83 }
84 }
85
PaintStar(DrawingContext & context)86 void RatingModifier::PaintStar(DrawingContext& context)
87 {
88 const ImagePainter foregroundImagePainter(foregroundImageCanvas_);
89 const ImagePainter secondaryImagePainter(secondaryImageCanvas_);
90 const ImagePainter backgroundPainter(backgroundImageCanvas_);
91
92 auto& canvas = context.canvas;
93 auto offset = contentOffset_->Get();
94 auto starNum = starNum_->Get();
95 auto drawScore = drawScore_->Get();
96 auto config = foregroundImageCanvas_->GetPaintConfig();
97 const float singleStarWidth = contentSize_->Get().Width() / static_cast<float>(starNum_->Get());
98 const float singleStarHeight = contentSize_->Get().Height();
99 // step2: calculate 3 images repeat times.
100 const int32_t foregroundImageRepeatNum = ceil(drawScore);
101 const float secondaryImageRepeatNum = foregroundImageRepeatNum - drawScore;
102 const int32_t backgroundImageRepeatNum = starNum - foregroundImageRepeatNum;
103 // step3: draw the foreground images.
104 canvas.Save();
105 auto offsetTemp = offset;
106 auto contentSize = SizeF(singleStarWidth, singleStarHeight);
107 // step2.1: calculate the clip area in order to display the secondary image.
108 auto clipRect1 = RSRect(offset.GetX(), offsetTemp.GetY(),
109 static_cast<float>(offset.GetX() + singleStarWidth * drawScore), offset.GetY() + singleStarHeight);
110 canvas.ClipRect(clipRect1, RSClipOp::INTERSECT);
111 for (int32_t i = 0; i < foregroundImageRepeatNum; i++) {
112 foregroundImagePainter.DrawImage(canvas, offsetTemp, contentSize);
113 offsetTemp.SetX(static_cast<float>(offsetTemp.GetX() + singleStarWidth));
114 }
115 canvas.Restore();
116
117 // step3: if drawScore is a decimal, it needs to draw the secondary image.
118 if (secondaryImageRepeatNum != 0) {
119 canvas.Save();
120 auto clipRect2 = RSRect(static_cast<float>(offset.GetX() + singleStarWidth * drawScore), offsetTemp.GetY(),
121 static_cast<float>(offset.GetX() + singleStarWidth * static_cast<float>(foregroundImageRepeatNum)),
122 offset.GetY() + singleStarHeight);
123 // step3.1: calculate the clip area which already occupied by the foreground image.
124 canvas.ClipRect(clipRect2, RSClipOp::INTERSECT);
125 offsetTemp.SetX(static_cast<float>(offsetTemp.GetX() - singleStarWidth));
126 secondaryImagePainter.DrawImage(canvas, offsetTemp, contentSize);
127 offsetTemp.SetX(offsetTemp.GetX() + singleStarWidth);
128 canvas.Restore();
129 }
130
131 // step4: draw background image.
132 for (int32_t i = 0; i < backgroundImageRepeatNum; i++) {
133 backgroundPainter.DrawImage(canvas, offsetTemp, contentSize);
134 if (i < backgroundImageRepeatNum - 1) {
135 offsetTemp.SetX(offsetTemp.GetX() + singleStarWidth);
136 }
137 }
138 }
139 } // namespace OHOS::Ace::NG
140