1 /*
2  * Copyright (c) 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 "core/components/triangle/render_triangle.h"
17 
18 #include "core/components/triangle/triangle_component.h"
19 
20 namespace OHOS::Ace {
21 
Calculate(double xOffset,double yOffset)22 bool TriangleRotationCalculator::Calculate(double xOffset, double yOffset)
23 {
24     // calculate bottom angle
25     const double PI = 3.14;
26     double width = x2_ - x1_;
27     double height = y3_ - y1_;
28     if (NearZero(height) || NearZero(width)) {
29         return false;
30     }
31     double bottomAngle = PI - std::atan(width / 2.0 / height) * 2.0;
32     double topAngle = PI - std::atan(height * 2.0 / width);
33     // calculate out arc 1
34     Point centerPoint;
35     centerPoint.SetX(x1_ + radius_ * std::tan(topAngle / 2.0));
36     centerPoint.SetY(y1_ + radius_);
37     double endAngle = PI + PI / 2.0;
38     double startAngle = endAngle - topAngle;
39     outArc1_.SetCenterPoint(centerPoint);
40     outArc1_.SetRadius(radius_);
41     outArc1_.SetStartAngle(startAngle);
42     outArc1_.SetEndAngle(endAngle);
43     // calculate out arc 2
44     centerPoint.SetX(x2_ - radius_ * std::tan(topAngle / 2.0));
45     centerPoint.SetY(y2_ + radius_);
46     startAngle = PI + PI / 2.0;
47     endAngle = startAngle + topAngle;
48     outArc2_.SetCenterPoint(centerPoint);
49     outArc2_.SetRadius(radius_);
50     outArc2_.SetStartAngle(startAngle);
51     outArc2_.SetEndAngle(endAngle);
52     // calculate out arc3
53     centerPoint.SetX(x3_);
54     centerPoint.SetY(y3_ - radius_ / std::cos(bottomAngle / 2.0));
55     startAngle = PI / 2.0 - bottomAngle / 2.0;
56     endAngle = startAngle + bottomAngle;
57     outArc3_.SetCenterPoint(centerPoint);
58     outArc3_.SetRadius(radius_);
59     outArc3_.SetStartAngle(startAngle);
60     outArc3_.SetEndAngle(endAngle);
61     // move with inner diff
62     double topDiff = radius_ * std::tan(topAngle / 2.0) - radius_;
63     double rate = height * 2.0 / width;
64     double newHeight = (width / 2.0 + topDiff) * rate;
65     double bottomDiff = newHeight - height;
66     outArc1_.Move(0.0 - topDiff, 0.0);
67     outArc2_.Move(topDiff, 0.0);
68     outArc3_.Move(0.0, bottomDiff);
69     // rotate with center point of triangle
70     centerPoint.SetX(x3_);
71     centerPoint.SetY((y1_ + y3_ + bottomDiff) / 2.0);
72     outArc1_.Rotate(centerPoint, angle_);
73     outArc2_.Rotate(centerPoint, angle_);
74     outArc3_.Rotate(centerPoint, angle_);
75     // move with offset
76     outArc1_.Move(xOffset, yOffset);
77     outArc2_.Move(xOffset, yOffset);
78     outArc3_.Move(xOffset, yOffset);
79     return true;
80 }
81 
IsDown() const82 bool TriangleRotationCalculator::IsDown() const
83 {
84     return NearZero(angle_);
85 }
86 
Update(const RefPtr<Component> & component)87 void RenderTriangle::Update(const RefPtr<Component>& component)
88 {
89     auto triangle = AceType::DynamicCast<TriangleComponent>(component);
90     if (!triangle) {
91         LOGE("input component is incorrect type or null.");
92         return;
93     }
94 
95     width_ = triangle->GetWidth();
96     height_ = triangle->GetHeight();
97     color_ = triangle->GetColor();
98     padding_ = triangle->GetPadding();
99     MarkNeedLayout();
100 }
101 
PerformLayout()102 void RenderTriangle::PerformLayout()
103 {
104     CalculateTrianglePoints();
105     SetLayoutSize(Size(NormalizeToPx(width_), NormalizeToPx(height_)));
106 }
107 
CalculateTrianglePoints()108 void RenderTriangle::CalculateTrianglePoints()
109 {
110     double width = NormalizeToPx(width_);
111     double height = NormalizeToPx(height_);
112     double padding = NormalizeToPx(padding_);
113     double x1 = padding;
114     double y1 = padding;
115     double x2 = width - padding;
116     double y2 = padding;
117     double x3 = (x1 + x2) / 2.0f; // the average
118     double y3 = height - padding;
119     data_.SetPointOne(x1, y1);
120     data_.SetPointTwo(x2, y2);
121     data_.SetPointThree(x3, y3);
122 }
123 
HandleClick()124 void RenderTriangle::HandleClick()
125 {
126     if (!onClick_) {
127         return; // for select that no need to change direction
128     }
129 
130     bool down = data_.IsDown();
131     down = !down;
132     onClick_(down);
133 }
134 
OnTouchTestHit(const Offset &,const TouchRestrict &,TouchTestResult & result)135 void RenderTriangle::OnTouchTestHit(const Offset&, const TouchRestrict&, TouchTestResult& result)
136 {
137     if (!click_) {
138         click_ = AceType::MakeRefPtr<ClickRecognizer>();
139         auto weak = WeakClaim(this);
140         click_->SetOnClick([weak = WeakClaim(this)](const ClickInfo&) {
141             auto refPtr = weak.Upgrade();
142             if (refPtr) {
143                 refPtr->HandleClick();
144             }
145         });
146     }
147     if (onClick_) {
148         click_->SetIsExternalGesture(true);
149         result.emplace_back(click_);
150     }
151 }
152 
153 } // namespace OHOS::Ace
154