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/menu/menu_item_group/menu_item_group_pattern.h"
17
18 #include <queue>
19
20 #include "core/components_ng/base/ui_node.h"
21 #include "core/components_ng/pattern/menu/menu_item/menu_item_pattern.h"
22 #include "core/components_ng/pattern/menu/menu_layout_property.h"
23 #include "core/components_ng/pattern/menu/menu_pattern.h"
24 #include "core/components_ng/pattern/text/text_layout_property.h"
25 #include "core/components_v2/inspector/inspector_constants.h"
26
27 namespace OHOS::Ace::NG {
OnMountToParentDone()28 void MenuItemGroupPattern::OnMountToParentDone()
29 {
30 ModifyFontSize();
31 ModifyDivider();
32 auto host = GetHost();
33 CHECK_NULL_VOID(host);
34 bool needDivider = false;
35 const auto& children = host->GetChildren();
36 for (const auto& child : children) {
37 if (child->GetTag() == V2::MENU_ITEM_ETS_TAG) {
38 auto itemNode = AceType::DynamicCast<FrameNode>(child);
39 CHECK_NULL_VOID(itemNode);
40 auto itemPattern = itemNode->GetPattern<MenuItemPattern>();
41 CHECK_NULL_VOID(itemPattern);
42 itemPattern->UpdateTextNodes();
43 itemPattern->UpdateNeedDivider(needDivider);
44 needDivider = true;
45 }
46 }
47 }
48
ModifyFontSize()49 void MenuItemGroupPattern::ModifyFontSize()
50 {
51 auto menu = GetMenu();
52 CHECK_NULL_VOID(menu);
53 auto menuProperty = menu->GetLayoutProperty<MenuLayoutProperty>();
54 CHECK_NULL_VOID(menuProperty);
55 auto menuFontSize = menuProperty->GetFontSize();
56 if (!menuFontSize.has_value()) {
57 return;
58 }
59
60 if (headerContent_) {
61 auto headerProperty = headerContent_->GetLayoutProperty<TextLayoutProperty>();
62 CHECK_NULL_VOID(headerProperty);
63 headerProperty->UpdateFontSize(menuFontSize.value());
64 headerContent_->MarkModifyDone();
65 }
66
67 if (footerContent_) {
68 auto footerProperty = footerContent_->GetLayoutProperty<TextLayoutProperty>();
69 CHECK_NULL_VOID(footerProperty);
70 footerProperty->UpdateFontSize(menuFontSize.value());
71 footerContent_->MarkModifyDone();
72 }
73 }
74
AddHeader(const RefPtr<NG::UINode> & header)75 void MenuItemGroupPattern::AddHeader(const RefPtr<NG::UINode>& header)
76 {
77 auto host = GetHost();
78 CHECK_NULL_VOID(host);
79 if (headerIndex_ < 0) {
80 headerIndex_ = itemStartIndex_;
81 host->AddChild(header);
82 itemStartIndex_++;
83 } else {
84 host->ReplaceChild(host->GetChildAtIndex(headerIndex_), header);
85 }
86 auto frameNode = AceType::DynamicCast<FrameNode>(header);
87 CHECK_NULL_VOID(frameNode);
88 if (headerContent_) {
89 headerContent_->MarkModifyDone();
90 headerContent_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
91 }
92 }
93
AddFooter(const RefPtr<NG::UINode> & footer)94 void MenuItemGroupPattern::AddFooter(const RefPtr<NG::UINode>& footer)
95 {
96 auto host = GetHost();
97 CHECK_NULL_VOID(host);
98 if (footerIndex_ < 0) {
99 footerIndex_ = itemStartIndex_;
100 host->AddChild(footer);
101 itemStartIndex_++;
102 } else {
103 host->ReplaceChild(host->GetChildAtIndex(footerIndex_), footer);
104 }
105 auto frameNode = AceType::DynamicCast<FrameNode>(footer);
106 CHECK_NULL_VOID(frameNode);
107 if (footerContent_) {
108 footerContent_->MarkModifyDone();
109 footerContent_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
110 }
111 }
112
GetMenu()113 RefPtr<FrameNode> MenuItemGroupPattern::GetMenu()
114 {
115 auto host = GetHost();
116 CHECK_NULL_RETURN(host, nullptr);
117 auto parent = host->GetParent();
118 while (parent) {
119 if (parent->GetTag() == V2::MENU_ETS_TAG) {
120 return DynamicCast<FrameNode>(parent);
121 }
122 parent = parent->GetParent();
123 }
124 return nullptr;
125 }
126
GetHeaderContent()127 std::string MenuItemGroupPattern::GetHeaderContent()
128 {
129 CHECK_NULL_RETURN(headerContent_, "");
130 auto content = headerContent_->GetLayoutProperty<TextLayoutProperty>();
131 CHECK_NULL_RETURN(content, "");
132 return content->GetContentValue("");
133 }
134
UpdateMenuItemIconInfo()135 void MenuItemGroupPattern::UpdateMenuItemIconInfo()
136 {
137 auto host = GetHost();
138 CHECK_NULL_VOID(host);
139 std::queue<RefPtr<UINode>> nodes;
140 nodes.emplace(host);
141 while (!nodes.empty()) {
142 auto currentNode = nodes.front();
143 nodes.pop();
144 if (DynamicCast<FrameNode>(currentNode) && DynamicCast<FrameNode>(currentNode)->GetPattern<MenuItemPattern>()) {
145 auto itemPattern = DynamicCast<FrameNode>(currentNode)->GetPattern<MenuItemPattern>();
146 hasSelectIcon_ |= itemPattern->HasSelectIcon();
147 hasStartIcon_ |= itemPattern->HasStartIcon();
148 }
149 for (const auto& child : currentNode->GetChildren()) {
150 nodes.emplace(child);
151 }
152 }
153 }
154
ModifyDivider()155 void MenuItemGroupPattern::ModifyDivider()
156 {
157 auto menu = GetMenu();
158 CHECK_NULL_VOID(menu);
159 auto menuProperty = menu->GetLayoutProperty<MenuLayoutProperty>();
160 CHECK_NULL_VOID(menuProperty);
161
162 auto divider = menuProperty->GetItemGroupDivider();
163 if (divider.has_value()) {
164 auto host = GetHost();
165 CHECK_NULL_VOID(host);
166 auto paintProperty = host->GetPaintProperty<MenuItemGroupPaintProperty>();
167 CHECK_NULL_VOID(paintProperty);
168 paintProperty->UpdateStrokeWidth(divider->strokeWidth);
169 paintProperty->UpdateStartMargin(divider->startMargin);
170 paintProperty->UpdateEndMargin(divider->endMargin);
171 paintProperty->UpdateDividerColor(divider->color);
172 paintProperty->UpdateNeedHeaderDivider(true);
173 paintProperty->UpdateNeedFooterDivider(true);
174 }
175 }
176
OnExtItemPressed(bool press,bool beforeGroup)177 void MenuItemGroupPattern::OnExtItemPressed(bool press, bool beforeGroup)
178 {
179 auto host = GetHost();
180 CHECK_NULL_VOID(host);
181 auto paintProperty = host->GetPaintProperty<MenuItemGroupPaintProperty>();
182 CHECK_NULL_VOID(paintProperty);
183 if (beforeGroup) {
184 paintProperty->UpdateNeedHeaderDivider(!press);
185 } else {
186 paintProperty->UpdateNeedFooterDivider(!press);
187 }
188 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
189 }
190
OnIntItemPressed(int32_t index,bool press)191 void MenuItemGroupPattern::OnIntItemPressed(int32_t index, bool press)
192 {
193 auto host = GetHost();
194 CHECK_NULL_VOID(host);
195 const size_t size = host->GetChildren().size();
196 auto parent = host->GetParent();
197 CHECK_NULL_VOID(parent);
198 auto currentIndex = parent->GetChildIndex(host);
199 if (index == itemStartIndex_ && headerContent_ == nullptr) {
200 OnExtItemPressed(press, true); // beforeGroup=true just to hide header divider
201 auto prevNode = parent->GetChildAtIndex(currentIndex - 1);
202 if (prevNode != nullptr && prevNode->GetTag() == V2::MENU_ITEM_GROUP_ETS_TAG) {
203 auto pattern = DynamicCast<FrameNode>(prevNode)->GetPattern<MenuItemGroupPattern>();
204 CHECK_NULL_VOID(pattern);
205 pattern->OnExtItemPressed(press, false); // hide common divider for 2 group if another group before
206 }
207 }
208 if (size > 0 && index == static_cast<int32_t>(size - 1) && footerContent_ == nullptr) {
209 OnExtItemPressed(press, false); // beforeGroup=false just to hide footer divider
210 auto nextNode = parent->GetChildAtIndex(currentIndex + 1);
211 if (nextNode != nullptr && nextNode->GetTag() == V2::MENU_ITEM_GROUP_ETS_TAG) {
212 auto pattern = DynamicCast<FrameNode>(nextNode)->GetPattern<MenuItemGroupPattern>();
213 CHECK_NULL_VOID(pattern);
214 pattern->OnExtItemPressed(press, true); // hide common divider for 2 group if another group after
215 }
216 }
217 }
218 } // namespace OHOS::Ace::NG
219