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