1 /*
2  * Copyright (c) 2021-2022 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 "frameworks/bridge/common/dom/dom_tab_bar.h"
17 
18 #include "frameworks/bridge/common/utils/utils.h"
19 
20 namespace OHOS::Ace::Framework {
21 
DOMTabBar(NodeId nodeId,const std::string & nodeName)22 DOMTabBar::DOMTabBar(NodeId nodeId, const std::string& nodeName) : DOMNode(nodeId, nodeName)
23 {
24     std::list<RefPtr<Component>> tabBars;
25     RefPtr<TabController> controller;
26     tabBarIndicator_ = AceType::MakeRefPtr<TabBarIndicatorComponent>();
27     tabBarChild_ = AceType::MakeRefPtr<TabBarComponent>(tabBars, controller, tabBarIndicator_);
28 }
29 
InitializeStyle()30 void DOMTabBar::InitializeStyle()
31 {
32     RefPtr<TabTheme> theme = GetTheme<TabTheme>();
33     if (!theme) {
34         return;
35     }
36     if (boxComponent_) {
37         boxComponent_->SetColor(theme->GetBackgroundColor());
38         boxComponent_->SetHasBackgroundColor(true);
39     }
40     auto paddingDimension = theme->GetPadding();
41     padding_ = Edge(paddingDimension.Value(), 0.0, paddingDimension.Value(), 0.0, paddingDimension.Unit());
42 }
43 
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)44 bool DOMTabBar::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
45 {
46     if (attr.first == DOM_TAB_BAR_MODE) {
47         tabBarMode_ = ConvertStrToTabBarMode(attr.second);
48         return true;
49     }
50     return false;
51 }
52 
SetSpecializedStyle(const std::pair<std::string,std::string> & style)53 bool DOMTabBar::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
54 {
55     static const std::unordered_map<std::string, void (*)(const std::string&, DOMTabBar&)> styleOperators = {
56         { DOM_PADDING,
57             [](const std::string& val, DOMTabBar& node) {
58                 node.padding_ = node.ParseEdge(val);
59             } },
60         { DOM_PADDING_END,
61             [](const std::string& val, DOMTabBar& node) {
62                 if (node.IsRightToLeft()) {
63                     node.padding_.SetLeft(node.ParseDimension(val));
64                 } else {
65                     node.padding_.SetRight(node.ParseDimension(val));
66                 }
67             } },
68         { DOM_PADDING_LEFT,
69             [](const std::string& val, DOMTabBar& node) {
70                 node.padding_.SetLeft(node.ParseDimension(val));
71             } },
72         { DOM_PADDING_RIGHT,
73             [](const std::string& val, DOMTabBar& node) {
74                 node.padding_.SetRight(node.ParseDimension(val));
75             } },
76         { DOM_PADDING_START,
77             [](const std::string& val, DOMTabBar& node) {
78                 if (node.IsRightToLeft()) {
79                     node.padding_.SetRight(node.ParseDimension(val));
80                 } else {
81                     node.padding_.SetLeft(node.ParseDimension(val));
82                 }
83             } },
84         { DOM_INDICATOR_COLOR,
85             [](const std::string& val, DOMTabBar& node) {
86                node.indicatorColor_= node.ParseColor(val);
87             }},
88     };
89     auto operatorIter = styleOperators.find(style.first);
90     if (operatorIter != styleOperators.end()) {
91         operatorIter->second(style.second, *this);
92         return true;
93     }
94     return false;
95 }
96 
OnChildNodeAdded(const RefPtr<DOMNode> & child,int32_t slot)97 void DOMTabBar::OnChildNodeAdded(const RefPtr<DOMNode>& child, int32_t slot)
98 {
99     if (!child) {
100         return;
101     }
102     if (tabBarChild_) {
103         tabBarChild_->InsertChild(slot, child->GetRootComponent());
104     }
105 }
106 
UpdateIndex(uint32_t currentIndex)107 void DOMTabBar::UpdateIndex(uint32_t currentIndex)
108 {
109     uint32_t index = 0;
110     for (const auto& childNode : GetChildList()) {
111         if (index == currentIndex) {
112             OnChildActive(childNode, true);
113         } else if (index == lastIndex_) {
114             OnChildActive(childNode, false);
115         }
116         index++;
117     }
118     lastIndex_ = currentIndex;
119 }
120 
OnMounted(const RefPtr<DOMNode> & parentNode)121 void DOMTabBar::OnMounted(const RefPtr<DOMNode>& parentNode)
122 {
123     if (!parentNode) {
124         return;
125     }
126     if (parentNode->GetTag() == DOM_NODE_TAG_TABS) {
127         const auto& parentNodeTmp = AceType::DynamicCast<DOMTabs>(parentNode);
128         if (!parentNodeTmp) {
129             return;
130         }
131         lastIndex_ = parentNodeTmp->GetTabIndex();
132         controllerId_ = parentNodeTmp->GetTabControllerId();
133         const auto& controller = parentNodeTmp->GetTabController();
134         controller->SetIndexWithoutChangeContent(static_cast<int32_t>(lastIndex_));
135         tabBarChild_->SetController(controller);
136         PrepareChangeListener();
137     }
138 }
139 
OnChildNodeRemoved(const RefPtr<DOMNode> & child)140 void DOMTabBar::OnChildNodeRemoved(const RefPtr<DOMNode>& child)
141 {
142     if (!child) {
143         return;
144     }
145     if (tabBarChild_) {
146         tabBarChild_->RemoveChild(child->GetRootComponent());
147     }
148 }
149 
ResetInitializedStyle()150 void DOMTabBar::ResetInitializedStyle()
151 {
152     if (!boxComponent_) {
153         return;
154     }
155     RefPtr<TabTheme> theme = GetTheme<TabTheme>();
156     if (theme) {
157         if (indicatorColor_.has_value()) {
158             tabBarChild_->SetIndicatorColor(indicatorColor_.value());
159         }
160         tabBarChild_->InitStyle(theme);
161         if (vertical_) {
162             if (LessOrEqual(GetWidth().Value(), 0.0)) {
163                 boxComponent_->SetWidth(theme->GetDefaultWidth().Value(), theme->GetDefaultWidth().Unit());
164             }
165         } else {
166             if (LessOrEqual(GetHeight().Value(), 0.0)) {
167                 boxComponent_->SetHeight(theme->GetDefaultHeight().Value(), theme->GetDefaultHeight().Unit());
168             }
169         }
170     }
171 }
172 
PrepareSpecializedComponent()173 void DOMTabBar::PrepareSpecializedComponent()
174 {
175     tabBarChild_->SetTextDirection(IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR);
176     tabBarChild_->SetMode(tabBarMode_);
177     const auto& parentNodeTmp = AceType::DynamicCast<DOMTabs>(parentNode_.Upgrade());
178     if (parentNodeTmp) {
179         vertical_ = parentNodeTmp->IsVertical();
180     }
181     tabBarChild_->SetVertical(vertical_);
182     ResetInitializedStyle();
183     tabBarChild_->SetPadding(padding_);
184 }
185 
PrepareChangeListener()186 void DOMTabBar::PrepareChangeListener()
187 {
188     // used for initalized the active tabBarItem
189     auto weak = AceType::WeakClaim(this);
190     auto changeCallback = [weak](uint32_t currentIndex) {
191         auto tabBarNode = weak.Upgrade();
192         if (!tabBarNode) {
193             return;
194         }
195         tabBarNode->UpdateIndex(currentIndex);
196     };
197     auto changeMarker = BackEndEventManager<void(uint32_t)>::GetInstance().GetAvailableMarker();
198     BackEndEventManager<void(uint32_t)>::GetInstance().BindBackendEvent(changeMarker, changeCallback);
199     tabBarChild_->SetDomChangeEventId(changeMarker);
200 }
201 
OnChildActive(const RefPtr<DOMNode> & node,bool active)202 void DOMTabBar::OnChildActive(const RefPtr<DOMNode>& node, bool active)
203 {
204     node->OnActive(active);
205     for (const auto& childNode : node->GetChildList()) {
206         childNode->OnActive(active);
207     }
208 }
209 
ParseEdge(const std::string & value) const210 Edge DOMTabBar::ParseEdge(const std::string& value) const
211 {
212     Edge edge;
213     std::vector<std::string> offsets;
214     StringUtils::StringSplitter(value, ' ', offsets);
215     switch (offsets.size()) {
216         case 1:
217             edge.SetLeft(ParseDimension(offsets[0]));
218             edge.SetRight(ParseDimension(offsets[0]));
219             edge.SetTop(ParseDimension(offsets[0]));
220             edge.SetBottom(ParseDimension(offsets[0]));
221             break;
222         case 2:
223             edge.SetLeft(ParseDimension(offsets[0]));
224             edge.SetRight(ParseDimension(offsets[1]));
225             edge.SetTop(ParseDimension(offsets[0]));
226             edge.SetBottom(ParseDimension(offsets[0]));
227             break;
228         case 3:
229             edge.SetLeft(ParseDimension(offsets[1]));
230             edge.SetRight(ParseDimension(offsets[1]));
231             edge.SetTop(ParseDimension(offsets[0]));
232             edge.SetBottom(ParseDimension(offsets[2]));
233             break;
234         case 4:
235             edge.SetLeft(ParseDimension(offsets[3]));
236             edge.SetRight(ParseDimension(offsets[1]));
237             edge.SetTop(ParseDimension(offsets[0]));
238             edge.SetBottom(ParseDimension(offsets[2]));
239             break;
240         default:
241             break;
242     }
243     return edge;
244 }
245 
246 } // namespace OHOS::Ace::Framework
247