1 /*
2  * Copyright (c) 2022-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 #include "core/components_ng/pattern/menu/menu_paint_method.h"
16 
17 #include "base/utils/utils.h"
18 #include "core/components/select/select_theme.h"
19 #include "core/components_ng/layout/layout_algorithm.h"
20 #include "core/components_ng/pattern/menu/menu_paint_property.h"
21 #include "core/components_ng/pattern/menu/menu_theme.h"
22 #include "core/components_ng/render/canvas_image.h"
23 #include "core/components_ng/render/divider_painter.h"
24 #include "core/components_ng/render/drawing_prop_convertor.h"
25 #include "core/pipeline/pipeline_base.h"
26 #include "core/pipeline_ng/pipeline_context.h"
27 
28 namespace OHOS::Ace::NG {
29 namespace {
30 constexpr Dimension BEZIER_HORIZON_OFFSET_FIRST = 1.3_vp;
31 constexpr Dimension BEZIER_HORIZON_OFFSET_SECOND = 3.2_vp;
32 constexpr Dimension BEZIER_HORIZON_OFFSET_THIRD = 6.6_vp;
33 constexpr Dimension BEZIER_HORIZON_OFFSET_FOURTH = 16.0_vp;
34 constexpr Dimension BEZIER_VERTICAL_OFFSET_FIRST = 0.1_vp;
35 constexpr Dimension BEZIER_VERTICAL_OFFSET_SECOND = 3.0_vp;
36 constexpr Dimension BEZIER_VERTICAL_OFFSET_THIRD = 8.0_vp;
37 } // namespace
38 
GetTopPath(float arrowX,float arrowY,RSPath & path)39 void MenuPaintMethod::GetTopPath(float arrowX, float arrowY, RSPath& path)
40 {
41     path.MoveTo(arrowX - horizonOffsetForth_, arrowY - verticalOffsetThird_);
42     path.QuadTo(arrowX - horizonOffsetThird_, arrowY - verticalOffsetThird_, arrowX - horizonOffsetSecond_,
43         arrowY - verticalOffsetSecond_);
44     path.QuadTo(arrowX - horizonOffsetFirst_, arrowY + verticalOffsetFirst_, arrowX, arrowY);
45     path.QuadTo(arrowX + horizonOffsetFirst_, arrowY + verticalOffsetFirst_, arrowX + horizonOffsetSecond_,
46         arrowY - verticalOffsetSecond_);
47     path.QuadTo(arrowX + horizonOffsetThird_, arrowY - verticalOffsetThird_, arrowX + horizonOffsetForth_,
48         arrowY - verticalOffsetThird_);
49 }
50 
GetBottomPath(float arrowX,float arrowY,RSPath & path)51 void MenuPaintMethod::GetBottomPath(float arrowX, float arrowY, RSPath& path)
52 {
53     path.MoveTo(arrowX - horizonOffsetForth_, arrowY + verticalOffsetThird_);
54     path.QuadTo(arrowX - horizonOffsetThird_, arrowY + verticalOffsetThird_, arrowX - horizonOffsetSecond_,
55         arrowY + verticalOffsetSecond_);
56     path.QuadTo(arrowX - horizonOffsetFirst_, arrowY - verticalOffsetFirst_, arrowX, arrowY);
57     path.QuadTo(arrowX + horizonOffsetFirst_, arrowY - verticalOffsetFirst_, arrowX + horizonOffsetSecond_,
58         arrowY + verticalOffsetSecond_);
59     path.QuadTo(arrowX + horizonOffsetThird_, arrowY + verticalOffsetThird_, arrowX + horizonOffsetForth_,
60         arrowY + verticalOffsetThird_);
61 }
62 
GetRightPath(float arrowX,float arrowY,RSPath & path)63 void MenuPaintMethod::GetRightPath(float arrowX, float arrowY, RSPath& path)
64 {
65     path.MoveTo(arrowX + verticalOffsetThird_, arrowY - horizonOffsetForth_);
66     path.QuadTo(arrowX + verticalOffsetThird_, arrowY - horizonOffsetThird_, arrowX + verticalOffsetSecond_,
67         arrowY - horizonOffsetSecond_);
68     path.QuadTo(arrowX - verticalOffsetFirst_, arrowY - horizonOffsetFirst_, arrowX, arrowY);
69     path.QuadTo(arrowX - verticalOffsetFirst_, arrowY + horizonOffsetFirst_, arrowX + verticalOffsetSecond_,
70         arrowY + horizonOffsetSecond_);
71     path.QuadTo(arrowX + verticalOffsetThird_, arrowY + horizonOffsetThird_, arrowX + verticalOffsetThird_,
72         arrowY + horizonOffsetForth_);
73 }
74 
GetLeftPath(float arrowX,float arrowY,RSPath & path)75 void MenuPaintMethod::GetLeftPath(float arrowX, float arrowY, RSPath& path)
76 {
77     path.MoveTo(arrowX - verticalOffsetThird_, arrowY - horizonOffsetForth_);
78     path.QuadTo(arrowX - verticalOffsetThird_, arrowY - horizonOffsetThird_, arrowX - verticalOffsetSecond_,
79         arrowY - horizonOffsetSecond_);
80     path.QuadTo(arrowX + verticalOffsetFirst_, arrowY - horizonOffsetFirst_, arrowX, arrowY);
81     path.QuadTo(arrowX + verticalOffsetFirst_, arrowY + horizonOffsetFirst_, arrowX - verticalOffsetSecond_,
82         arrowY + horizonOffsetSecond_);
83     path.QuadTo(arrowX - verticalOffsetThird_, arrowY + horizonOffsetThird_, arrowX - verticalOffsetThird_,
84         arrowY + horizonOffsetForth_);
85 }
86 
UpdateArrowPath(Placement placement,float arrowX,float arrowY,RSPath & path)87 void MenuPaintMethod::UpdateArrowPath(Placement placement, float arrowX, float arrowY, RSPath& path)
88 {
89     horizonOffsetFirst_ = BEZIER_HORIZON_OFFSET_FIRST.ConvertToPx();
90     horizonOffsetSecond_ = BEZIER_HORIZON_OFFSET_SECOND.ConvertToPx();
91     horizonOffsetThird_ = BEZIER_HORIZON_OFFSET_THIRD.ConvertToPx();
92     horizonOffsetForth_ = BEZIER_HORIZON_OFFSET_FOURTH.ConvertToPx();
93     verticalOffsetFirst_ = BEZIER_VERTICAL_OFFSET_FIRST.ConvertToPx();
94     verticalOffsetSecond_ = BEZIER_VERTICAL_OFFSET_SECOND.ConvertToPx();
95     verticalOffsetThird_ = BEZIER_VERTICAL_OFFSET_THIRD.ConvertToPx();
96     switch (placement) {
97         case Placement::TOP:
98         case Placement::TOP_LEFT:
99         case Placement::TOP_RIGHT:
100             GetTopPath(arrowX, arrowY, path);
101             break;
102         case Placement::BOTTOM:
103         case Placement::BOTTOM_LEFT:
104         case Placement::BOTTOM_RIGHT:
105             GetBottomPath(arrowX, arrowY, path);
106             break;
107         case Placement::RIGHT:
108         case Placement::RIGHT_BOTTOM:
109         case Placement::RIGHT_TOP:
110             GetRightPath(arrowX, arrowY, path);
111             break;
112         case Placement::LEFT:
113         case Placement::LEFT_BOTTOM:
114         case Placement::LEFT_TOP:
115             GetLeftPath(arrowX, arrowY, path);
116             break;
117         default:
118             break;
119     }
120 }
121 
GetOverlayDrawFunction(PaintWrapper * paintWrapper)122 CanvasDrawFunction MenuPaintMethod::GetOverlayDrawFunction(PaintWrapper* paintWrapper)
123 {
124     return [weak = WeakClaim(this), paintWrapper](RSCanvas& canvas) {
125         auto menu = weak.Upgrade();
126         if (menu) {
127             auto props = DynamicCast<MenuPaintProperty>(paintWrapper->GetPaintProperty());
128             CHECK_NULL_VOID(props);
129             if (props->GetEnableArrow().has_value()) {
130                 if (!props->GetEnableArrow().value() || !props->GetArrowPosition().has_value() ||
131                     !props->GetArrowPlacement().has_value()) {
132                     return;
133                 }
134                 auto arrowPosition = props->GetArrowPosition().value();
135                 auto arrowPlaceMent = props->GetArrowPlacement().value();
136                 auto arrowX = arrowPosition.GetX();
137                 auto arrowY = arrowPosition.GetY();
138                 RSPath path;
139                 menu->UpdateArrowPath(arrowPlaceMent, arrowX, arrowY, path);
140                 RSBrush brush;
141                 auto pipeline = PipelineBase::GetCurrentContext();
142                 CHECK_NULL_VOID(pipeline);
143                 auto selectTheme = pipeline->GetTheme<SelectTheme>();
144                 CHECK_NULL_VOID(selectTheme);
145                 auto backgroundColor = selectTheme->GetBackgroundColor();
146                 brush.SetColor(static_cast<int>(backgroundColor.GetValue()));
147                 brush.SetAntiAlias(true);
148                 canvas.AttachBrush(brush);
149                 canvas.DrawPath(path);
150                 canvas.DetachBrush();
151             }
152         }
153     };
154 }
155 } // namespace OHOS::Ace::NG
156