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 #include "core/components_ng/pattern/app_bar/atomic_service_pattern.h"
16
17 #include "base/utils/utils.h"
18 #include "core/common/container.h"
19 #include "core/components_ng/pattern/button/button_pattern.h"
20 #include "core/components_ng/pattern/divider/divider_render_property.h"
21 #include "core/components_ng/pattern/image/image_layout_property.h"
22 #include "core/components_ng/pattern/image/image_render_property.h"
23 #include "core/components_ng/pattern/text/text_layout_property.h"
24 #include "core/components_ng/property/calc_length.h"
25 #include "core/components_ng/property/measure_property.h"
26 #include "core/pipeline_ng/pipeline_context.h"
27
28 namespace OHOS::Ace::NG {
29 constexpr int32_t ATOMIC_SERVICE_MIN_SIZE = 2;
30 constexpr int32_t FIRST_OVERLAY_INDEX = 1;
31
BeforeCreateLayoutWrapper()32 void AtomicServicePattern::BeforeCreateLayoutWrapper()
33 {
34 auto pipeline = PipelineContext::GetCurrentContext();
35 CHECK_NULL_VOID(pipeline);
36 auto host = GetHost();
37 CHECK_NULL_VOID(host);
38 auto manager = pipeline->GetSafeAreaManager();
39 CHECK_NULL_VOID(manager);
40 manager->SetIsAtomicService(true);
41 manager->AddGeoRestoreNode(host);
42 auto systemSafeArea = manager->GetSystemSafeArea();
43 auto theme = pipeline->GetTheme<AppBarTheme>();
44 CHECK_NULL_VOID(theme);
45 float topMargin = theme->GetMenuBarTopMargin().ConvertToPx();
46 topMargin += systemSafeArea.top_.Length();
47 UpdateOverlayLayout();
48 auto menuBarRow = GetMenuBarRow();
49 CHECK_NULL_VOID(menuBarRow);
50 auto renderContext = menuBarRow->GetRenderContext();
51 renderContext->UpdatePosition(OffsetT<Dimension>(0.0_vp, Dimension(topMargin, DimensionUnit::PX)));
52
53 auto menuBar = GetMenuBar();
54 if (settedColorMode.has_value()) {
55 UpdateMenuBarColor(theme, menuBar, settedColorMode.value());
56 } else {
57 UpdateMenuBarColor(theme, menuBar, SystemProperties::GetColorMode() != ColorMode::DARK);
58 }
59 UpdateLayoutMargin();
60 }
61
UpdateLayoutMargin()62 void AtomicServicePattern::UpdateLayoutMargin()
63 {
64 auto pipeline = PipelineContext::GetCurrentContext();
65 CHECK_NULL_VOID(pipeline);
66 auto safeArea = pipeline->GetSafeArea();
67 auto atom = GetHost();
68 CHECK_NULL_VOID(atom);
69 MarginProperty margin;
70 margin.left = CalcLength(safeArea.left_.Length());
71 margin.right = CalcLength(safeArea.right_.Length());
72 margin.top = CalcLength(safeArea.top_.Length());
73 margin.bottom = CalcLength(safeArea.bottom_.Length());
74 // update stage margin
75 auto stage = AceType::DynamicCast<FrameNode>(atom->GetChildAtIndex(0));
76 CHECK_NULL_VOID(stage);
77 auto layoutProperty = stage->GetLayoutProperty();
78 CHECK_NULL_VOID(layoutProperty);
79 layoutProperty->UpdateMargin(margin);
80 stage->MarkModifyDone();
81 stage->MarkDirtyNode();
82 // update menuBarRow margin
83 MarginProperty appBarmargin;
84 appBarmargin.left = CalcLength(safeArea.left_.Length());
85 appBarmargin.right = CalcLength(safeArea.right_.Length());
86 auto menuBarRow = GetMenuBarRow();
87 CHECK_NULL_VOID(menuBarRow);
88 auto property = menuBarRow->GetLayoutProperty();
89 CHECK_NULL_VOID(property);
90 property->UpdateMargin(appBarmargin);
91 menuBarRow->MarkModifyDone();
92 menuBarRow->MarkDirtyNode();
93 }
94
UpdateOverlayLayout()95 void AtomicServicePattern::UpdateOverlayLayout()
96 {
97 auto atom = GetHost();
98 CHECK_NULL_VOID(atom);
99 if (atom->GetChildren().size() <= ATOMIC_SERVICE_MIN_SIZE) {
100 return;
101 }
102 for (int index = FIRST_OVERLAY_INDEX;
103 index <= static_cast<int32_t>(atom->GetChildren().size()) - ATOMIC_SERVICE_MIN_SIZE; index++) {
104 auto overlay = AceType::DynamicCast<FrameNode>(atom->GetChildAtIndex(index));
105 CHECK_NULL_VOID(overlay);
106 auto overlayRender = overlay->GetRenderContext();
107 overlayRender->UpdatePosition(OffsetT<Dimension>());
108 overlay->MarkModifyDone();
109 overlay->MarkDirtyNode();
110 }
111 }
112
OnAttachToFrameNode()113 void AtomicServicePattern::OnAttachToFrameNode()
114 {
115 auto host = GetHost();
116 CHECK_NULL_VOID(host);
117 host->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
118 auto pipeline = PipelineContext::GetCurrentContext();
119 CHECK_NULL_VOID(pipeline);
120 host->GetRenderContext()->UpdateBackgroundColor(pipeline->GetAppBgColor());
121 }
122
OnLanguageConfigurationUpdate()123 void AtomicServicePattern::OnLanguageConfigurationUpdate()
124 {
125 UpdateLayout();
126 }
127
OnColorConfigurationUpdate()128 void AtomicServicePattern::OnColorConfigurationUpdate()
129 {
130 auto host = GetHost();
131 CHECK_NULL_VOID(host);
132 auto pipeline = PipelineContext::GetCurrentContext();
133 CHECK_NULL_VOID(pipeline);
134 host->GetRenderContext()->UpdateBackgroundColor(pipeline->GetAppBgColor());
135 if (settedColorMode.has_value()) {
136 UpdateColor(settedColorMode);
137 } else {
138 UpdateColor(SystemProperties::GetColorMode() != ColorMode::DARK);
139 }
140 }
141
GetMenuBarRow()142 RefPtr<FrameNode> AtomicServicePattern::GetMenuBarRow()
143 {
144 auto atom = GetHost();
145 CHECK_NULL_RETURN(atom, nullptr);
146 auto menuBarRow = AceType::DynamicCast<FrameNode>(atom->GetChildren().back());
147 return menuBarRow;
148 }
149
GetMenuBar()150 RefPtr<FrameNode> AtomicServicePattern::GetMenuBar()
151 {
152 auto menuBarRow = GetMenuBarRow();
153 CHECK_NULL_RETURN(menuBarRow, nullptr);
154 auto menuBar = AceType::DynamicCast<FrameNode>(menuBarRow->GetChildAtIndex(0));
155 return menuBar;
156 }
157
GetMenuButton()158 RefPtr<FrameNode> AtomicServicePattern::GetMenuButton()
159 {
160 auto menuBar = GetMenuBar();
161 CHECK_NULL_RETURN(menuBar, nullptr);
162 auto menuButton = AceType::DynamicCast<FrameNode>(menuBar->GetChildAtIndex(0));
163 return menuButton;
164 }
165
GetDivider()166 RefPtr<FrameNode> AtomicServicePattern::GetDivider()
167 {
168 auto menuBar = GetMenuBar();
169 CHECK_NULL_RETURN(menuBar, nullptr);
170 auto divider = AceType::DynamicCast<FrameNode>(menuBar->GetChildAtIndex(1));
171 return divider;
172 }
173
GetCloseButton()174 RefPtr<FrameNode> AtomicServicePattern::GetCloseButton()
175 {
176 auto menuBar = GetMenuBar();
177 CHECK_NULL_RETURN(menuBar, nullptr);
178 auto closeButton = AceType::DynamicCast<FrameNode>(menuBar->GetChildAtIndex(2));
179 return closeButton;
180 }
181
GetMenuIcon()182 RefPtr<FrameNode> AtomicServicePattern::GetMenuIcon()
183 {
184 auto menuButton = GetMenuButton();
185 CHECK_NULL_RETURN(menuButton, nullptr);
186 auto menuIcon = AceType::DynamicCast<FrameNode>(menuButton->GetChildAtIndex(0));
187 return menuIcon;
188 }
189
GetCloseIcon()190 RefPtr<FrameNode> AtomicServicePattern::GetCloseIcon()
191 {
192 auto closeButton = GetCloseButton();
193 CHECK_NULL_RETURN(closeButton, nullptr);
194 auto closeIcon = AceType::DynamicCast<FrameNode>(closeButton->GetChildAtIndex(0));
195 return closeIcon;
196 }
197
UpdateColor(std::optional<bool> isLight)198 void AtomicServicePattern::UpdateColor(std::optional<bool> isLight)
199 {
200 auto pipeline = PipelineContext::GetCurrentContext();
201 CHECK_NULL_VOID(pipeline);
202 auto theme = pipeline->GetTheme<AppBarTheme>();
203 if (!(isLight.has_value())) {
204 isLight = SystemProperties::GetColorMode() != ColorMode::DARK;
205 }
206 auto menuButton = GetMenuButton();
207 UpdateButtonColor(theme, menuButton, isLight.value());
208 auto divider = GetDivider();
209 UpdateDividerColor(theme, divider, isLight.value());
210 auto closeButton = GetCloseButton();
211 UpdateButtonColor(theme, closeButton, isLight.value());
212
213 auto menuIcon = GetMenuIcon();
214 UpdateIconColor(theme, menuIcon, isLight.value());
215 auto closeIcon = GetCloseIcon();
216 UpdateIconColor(theme, closeIcon, isLight.value());
217 }
218
UpdateMenuBarColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & menuBar,bool isLight)219 void AtomicServicePattern::UpdateMenuBarColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& menuBar, bool isLight)
220 {
221 CHECK_NULL_VOID(theme);
222 CHECK_NULL_VOID(menuBar);
223 auto renderContext = menuBar->GetRenderContext();
224 // background effect、border color
225 EffectOption option;
226 BorderColorProperty borderColor;
227 option.radius = theme->GetBlurRadius();
228 if (isLight) {
229 option.color = theme->GetBlurColorLight();
230 borderColor.SetColor(theme->GetBorderColorLight());
231 } else {
232 option.color = theme->GetBlurColorDark();
233 borderColor.SetColor(theme->GetBorderColorDark());
234 }
235 renderContext->UpdateBackgroundEffect(option);
236 renderContext->UpdateBorderColor(borderColor);
237
238 menuBar->MarkModifyDone();
239 menuBar->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
240 }
241
UpdateButtonColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & button,bool isLight)242 void AtomicServicePattern::UpdateButtonColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& button, bool isLight)
243 {
244 CHECK_NULL_VOID(theme);
245 CHECK_NULL_VOID(button);
246 // pressed color
247 auto buttonPattern = button->GetPattern<ButtonPattern>();
248 CHECK_NULL_VOID(buttonPattern);
249 if (isLight) {
250 buttonPattern->SetClickedColor(theme->GetClickEffectColorLight());
251 } else {
252 buttonPattern->SetClickedColor(theme->GetClickEffectColorDark());
253 }
254 // focus border color
255 if (isLight) {
256 buttonPattern->SetFocusBorderColor(theme->GetFocusedOutlineColorLight());
257 } else {
258 buttonPattern->SetFocusBorderColor(theme->GetFocusedOutlineColorDark());
259 }
260
261 button->MarkModifyDone();
262 button->MarkDirtyNode();
263 }
264
UpdateDividerColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & divider,bool isLight)265 void AtomicServicePattern::UpdateDividerColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& divider, bool isLight)
266 {
267 CHECK_NULL_VOID(theme);
268 CHECK_NULL_VOID(divider);
269
270 auto renderProperty = divider->GetPaintProperty<DividerRenderProperty>();
271 if (isLight) {
272 renderProperty->UpdateDividerColor(theme->GetDividerColorLight());
273 } else {
274 renderProperty->UpdateDividerColor(theme->GetDividerColorDark());
275 }
276
277 divider->MarkModifyDone();
278 divider->MarkDirtyNode();
279 }
280
UpdateIconColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & icon,bool isLight)281 void AtomicServicePattern::UpdateIconColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& icon, bool isLight)
282 {
283 CHECK_NULL_VOID(theme);
284 CHECK_NULL_VOID(icon);
285 // fill color
286 auto color = isLight ? theme->GetIconColorLight() : theme->GetIconColorDark();
287 ACE_UPDATE_NODE_PAINT_PROPERTY(ImageRenderProperty, SvgFillColor, color, icon);
288 ACE_UPDATE_NODE_RENDER_CONTEXT(ForegroundColor, color, icon);
289 icon->MarkModifyDone();
290 icon->MarkDirtyNode();
291 }
292
UpdateLayout()293 void AtomicServicePattern::UpdateLayout()
294 {
295 auto pipeline = PipelineContext::GetCurrentContext();
296 CHECK_NULL_VOID(pipeline);
297 auto theme = pipeline->GetTheme<AppBarTheme>();
298 CHECK_NULL_VOID(theme);
299 bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
300
301 auto menuBar = GetMenuBar();
302 UpdateMenuBarLayout(theme, menuBar, isRtl);
303
304 auto menuButton = GetMenuButton();
305 UpdateButtonLayout(theme, menuButton, !isRtl);
306 auto closeButton = GetCloseButton();
307 UpdateButtonLayout(theme, closeButton, isRtl);
308
309 auto menuIcon = GetMenuIcon();
310 UpdateIconLayout(theme, menuIcon, !isRtl);
311 auto closeIcon = GetCloseIcon();
312 UpdateIconLayout(theme, closeIcon, isRtl);
313 }
314
UpdateMenuBarLayout(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & menuBar,bool isRtl)315 void AtomicServicePattern::UpdateMenuBarLayout(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& menuBar, bool isRtl)
316 {
317 CHECK_NULL_VOID(theme);
318 CHECK_NULL_VOID(menuBar);
319
320 MarginProperty margin;
321 if (isRtl) {
322 margin.left = CalcLength(theme->GetMenuBarRightMargin());
323 margin.right = CalcLength(theme->GetMenuBarLeftMargin());
324 } else {
325 margin.left = CalcLength(theme->GetMenuBarLeftMargin());
326 margin.right = CalcLength(theme->GetMenuBarRightMargin());
327 }
328 menuBar->GetLayoutProperty<LinearLayoutProperty>()->UpdateMargin(margin);
329
330 menuBar->MarkModifyDone();
331 menuBar->MarkDirtyNode();
332 }
333
UpdateButtonLayout(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & button,bool isLeft)334 void AtomicServicePattern::UpdateButtonLayout(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& button, bool isLeft)
335 {
336 CHECK_NULL_VOID(theme);
337 CHECK_NULL_VOID(button);
338
339 auto bent = theme->GetBentRadius();
340 auto rightAngle = theme->GetRightAngle();
341 auto leftBorderRadius = BorderRadiusProperty(bent, rightAngle, rightAngle, bent);
342 auto rightBorderRadius = BorderRadiusProperty(rightAngle, bent, bent, rightAngle);
343
344 auto layoutProperty = button->GetLayoutProperty<ButtonLayoutProperty>();
345 layoutProperty->UpdateBorderRadius(isLeft ? leftBorderRadius : rightBorderRadius);
346
347 button->MarkModifyDone();
348 button->MarkDirtyNode();
349 }
350
UpdateIconLayout(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & icon,bool isLeft)351 void AtomicServicePattern::UpdateIconLayout(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& icon, bool isLeft)
352 {
353 CHECK_NULL_VOID(theme);
354 CHECK_NULL_VOID(icon);
355
356 MarginProperty margin;
357 margin.top = CalcLength(theme->GetIconVerticalMargin());
358 margin.bottom = CalcLength(theme->GetIconVerticalMargin());
359 if (isLeft) {
360 margin.left = CalcLength(theme->GetIconOutsideMargin());
361 margin.right = CalcLength(theme->GetIconInsideMargin());
362 } else {
363 margin.left = CalcLength(theme->GetIconInsideMargin());
364 margin.right = CalcLength(theme->GetIconOutsideMargin());
365 }
366 icon->GetLayoutProperty<ImageLayoutProperty>()->UpdateMargin(margin);
367
368 icon->MarkModifyDone();
369 icon->MarkDirtyNode();
370 }
371 } // namespace OHOS::Ace::NG
372