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/counter/counter_component.h"
17 
18 #include "core/components/counter/counter_element.h"
19 
20 namespace OHOS::Ace {
21 namespace {
22 
23 constexpr uint32_t CLICKED_BLEND_COLOR = 0x19000000;
24 constexpr char COUNTER_BUTTON_ADD[] = "+";
25 constexpr char COUNTER_BUTTON_LESS[] = "-";
26 constexpr double COUNTER_BORDER_WIDTH = 1.0;
27 constexpr double COUNTER_RADIUS_DELTA = 2.0;
28 constexpr int32_t COUNTER_ITEM_SIZE_DIFF = 2;
29 constexpr double STATE_FAIELD_OPACITY = 0.3;
30 
31 } // namespace
32 
CreateRenderNode()33 RefPtr<RenderNode> CounterComponent::CreateRenderNode()
34 {
35     return RenderCounter::Create();
36 }
37 
CreateElement()38 RefPtr<Element> CounterComponent::CreateElement()
39 {
40     return AceType::MakeRefPtr<CounterElement>();
41 }
42 
BuildChild(const RefPtr<ThemeManager> & themeManager)43 RefPtr<Component> CounterComponent::BuildChild(const RefPtr<ThemeManager>& themeManager)
44 {
45     if (!themeManager) {
46         return nullptr;
47     }
48 
49     counterTheme_ = AceType::DynamicCast<CounterTheme>(themeManager->GetTheme(CounterTheme::TypeId()));
50     if (!counterTheme_) {
51         return nullptr;
52     }
53 
54     // build up counter_component.
55     RefPtr<BoxComponent> counterBox = AceType::MakeRefPtr<BoxComponent>();
56     auto backDecoration = AceType::MakeRefPtr<Decoration>();
57     BorderEdge edge(Color::GRAY, Dimension(COUNTER_BORDER_WIDTH, DimensionUnit::VP), BorderStyle::NONE);
58     Border border(edge);
59     border.SetBorderRadius(Radius(GetControlRadius()));
60     backDecoration->SetBorder(border);
61     counterBox->SetBackDecoration(backDecoration);
62     counterBox->SetHeight(GetHeight());
63     counterBox->SetWidth(GetWidth());
64     std::list<RefPtr<Component>> rowChildren;
65     RefPtr<RowComponent> counterRow =
66         AceType::MakeRefPtr<RowComponent>(FlexAlign::FLEX_START, FlexAlign::CENTER, rowChildren);
67     counterRow->SetMainAxisSize(MainAxisSize::MIN);
68     BuildControl(counterTheme_, counterRow, decreButtonComponent_, std::string(COUNTER_BUTTON_LESS), true);
69     counterRow->AppendChild(BuildDivider());
70     RefPtr<BoxComponent> contentBox = AceType::MakeRefPtr<BoxComponent>();
71     BuildContent(counterTheme_, counterRow, contentBox);
72     counterRow->AppendChild(BuildDivider());
73     BuildControl(counterTheme_, counterRow, increButtonComponent_, std::string(COUNTER_BUTTON_ADD), false);
74     counterBox->SetChild(counterRow);
75 
76     displayComponent_ = AceType::MakeRefPtr<DisplayComponent>(counterBox);
77     if (propState_ == false) {
78         displayComponent_->SetOpacity(STATE_FAIELD_OPACITY);
79     }
80 
81     return displayComponent_;
82 }
83 
BuildDivider()84 RefPtr<DividerComponent> CounterComponent::BuildDivider()
85 {
86     auto divider = AceType::MakeRefPtr<DividerComponent>();
87     divider->SetStrokeWidth(Dimension(COUNTER_BORDER_WIDTH, DimensionUnit::VP));
88     divider->SetVertical(true);
89     divider->SetDividerColor(Color::GRAY);
90     return divider;
91 }
92 
BuildControl(const RefPtr<CounterTheme> & counterTheme,const RefPtr<RowComponent> & row,RefPtr<ButtonComponent> & button,std::string content,bool isLeft)93 void CounterComponent::BuildControl(const RefPtr<CounterTheme>& counterTheme, const RefPtr<RowComponent>& row,
94     RefPtr<ButtonComponent>& button, std::string content, bool isLeft)
95 {
96     std::list<RefPtr<Component>> buttonChildren;
97     auto textComponent = AceType::MakeRefPtr<TextComponent>(content);
98     textComponent->SetTextStyle(counterTheme->GetContentTextStyle());
99     buttonChildren.emplace_back(textComponent);
100     button = AceType::MakeRefPtr<ButtonComponent>(buttonChildren);
101     button->SetHeight(Dimension(GetHeight().Value() - COUNTER_RADIUS_DELTA * COUNTER_BORDER_WIDTH, GetHeight().Unit()));
102     button->SetWidth(
103         Dimension(GetControlWidth().Value() - COUNTER_RADIUS_DELTA * COUNTER_BORDER_WIDTH, GetControlWidth().Unit()));
104     button->SetBackgroundColor(propBackgroundColor_);
105     button->SetClickedColor(Color(CLICKED_BLEND_COLOR));
106     button->SetType(ButtonType::CUSTOM);
107 
108     // set up radius and click function for button.
109     if (isLeft) {
110         std::array<Radius, 4> radii = {
111             Radius(Dimension(GetControlRadius().Value() - COUNTER_BORDER_WIDTH, GetControlRadius().Unit())),
112             Radius(0.0_vp),
113             Radius(0.0_vp),
114             Radius(Dimension(GetControlRadius().Value() - COUNTER_BORDER_WIDTH, GetControlRadius().Unit()))
115         };
116         button->SetRectRadii(radii);
117         if (propState_) {
118             button->SetClickFunction([weak = AceType::WeakClaim(this)] {
119                 auto spThis = weak.Upgrade();
120                 if (spThis) {
121                     V2::ResumeEventCallback(spThis, &CounterComponent::GetOnDec);
122                 }
123             });
124         } else {
125             button->SetBackgroundColor(Color::GRAY);
126         }
127     } else {
128         std::array<Radius, 4> radii = {
129             Radius(0.0_vp),
130             Radius(Dimension(GetControlRadius().Value() - COUNTER_BORDER_WIDTH, GetControlRadius().Unit())),
131             Radius(Dimension(GetControlRadius().Value() - COUNTER_BORDER_WIDTH, GetControlRadius().Unit())),
132             Radius(0.0_vp)
133         };
134         button->SetRectRadii(radii);
135         if (propState_) {
136             button->SetClickFunction([weak = AceType::WeakClaim(this)] {
137                 auto spThis = weak.Upgrade();
138                 if (spThis) {
139                     V2::ResumeEventCallback(spThis, &CounterComponent::GetOnInc);
140                 }
141             });
142         } else {
143             button->SetBackgroundColor(Color::GRAY);
144         }
145     }
146 
147     row->AppendChild(button);
148 }
149 
BuildContent(const RefPtr<CounterTheme> & counterTheme,const RefPtr<RowComponent> & row,RefPtr<BoxComponent> & box)150 void CounterComponent::BuildContent(
151     const RefPtr<CounterTheme>& counterTheme, const RefPtr<RowComponent>& row, RefPtr<BoxComponent>& box)
152 {
153     box->SetAlignment(Alignment::CENTER);
154     if (!GetChildren().empty()) {
155         box->SetChild(GetChildren().front());
156     }
157 
158     if (GreatNotEqual(GetHeight().Value() - COUNTER_RADIUS_DELTA * COUNTER_BORDER_WIDTH, 0.0)) {
159         box->SetHeight(
160             Dimension(GetHeight().Value() - COUNTER_RADIUS_DELTA * COUNTER_BORDER_WIDTH, GetHeight().Unit()));
161     } else {
162         box->SetHeight(Dimension(0.0, DimensionUnit::VP));
163     }
164     if (GreatNotEqual(GetWidth().Value() - COUNTER_ITEM_SIZE_DIFF * GetControlWidth().Value(), 0.0)) {
165         box->SetWidth(
166             Dimension(GetWidth().Value() - COUNTER_ITEM_SIZE_DIFF * GetControlWidth().Value(), GetWidth().Unit()));
167     } else {
168         box->SetWidth(Dimension(0.0, DimensionUnit::VP));
169     }
170 
171     box->SetOverflow(Overflow::FORCE_CLIP);
172     auto backDecoration = AceType::MakeRefPtr<Decoration>();
173     backDecoration->SetBackgroundColor(propBackgroundColor_);
174     box->SetBackDecoration(backDecoration);
175     row->AppendChild(box);
176 }
177 
178 } // namespace OHOS::Ace
179